From f81c2213a299fb4363789468d08ea0c26ff29762 Mon Sep 17 00:00:00 2001 From: Xiangfu Liu Date: Sun, 16 Aug 2009 13:36:15 +0800 Subject: [PATCH] add-2.6.24-kernel-patch Signed-off-by: Xiangfu Liu --- .../xburst/patches-2.6.24/001-board.patch | 233914 --------------- .../patches-2.6.24/002-yaffs2_dists.patch | 8842 - 2 files changed, 242756 deletions(-) delete mode 100644 target/linux/xburst/patches-2.6.24/001-board.patch delete mode 100644 target/linux/xburst/patches-2.6.24/002-yaffs2_dists.patch diff --git a/target/linux/xburst/patches-2.6.24/001-board.patch b/target/linux/xburst/patches-2.6.24/001-board.patch deleted file mode 100644 index 289fcb938..000000000 --- a/target/linux/xburst/patches-2.6.24/001-board.patch +++ /dev/null @@ -1,233914 +0,0 @@ -diff -urN linux-2.6.24.7.old/Changelog linux-2.6.24.7/Changelog ---- linux-2.6.24.7.old/Changelog 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/Changelog 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,364 @@ -+2009.02.17 -+* Modify oss driver to support jz4750 i2s codec. -+ Update Files: -+ sound/oss/Kconfig -+ sound/oss/Makefile -+ sound/oss/jz_i2s.c -+ Add Files: -+ sound/oss/jzdlv.h -+ sound/oss/jzdlv.c -+ -+2008.12.08 -+* Power management is supported for jz4750. -+ Update Files: -+ arch/mips/jz4750/pm.c -+ drivers/char/jzchar/poweroff.c -+ -+2008.12.04 -+* Whether NAND multiple planes operation for one partition is used or not could be -+ determined by the value of use_planes in partition_info[] in drivers/mtd/nand/jz47xx_nand.c -+ Updated files: -+ include/linux/mtd/partitions.h -+ drivers/mtd/nand/nand_base.c -+ drivers/mtd/nand/jz4740_nand.c -+ drivers/mtd/mtdpart.c -+* Supported 4KB page size nand with 2 planes -+ Update Files: -+ include/linux/mtd/nand.h -+ drivers/mtd/nand/nand_base.c -+ fs/yaffs2/utils/mkyaffs2image.c -+ drivers/mtd/mtd-utils/nandwrite_mlc.c -+ -+ -+2008.11.07 -+* The ubi was modified to support MTD of 64bit. -+ Updated file: -+ drivers/mtd/ubi/io.c -+* The ubi and ubifs were modified by changing vmalloc and vfree to kmalloc and kfree -+ to provide DMA buffer for NAND driver. But the NAND driver will use DMA buffer in -+ itself instead of in ubi and ubifs when CONFIG_MTD_NAND_DMABUF is defined. -+ Updated files: -+ drivers/mtd/ubi/build.c -+ drivers/mtd/ubi/cdev.c -+ drivers/mtd/ubi/gluebi.c -+ drivers/mtd/ubi/misc.c -+ drivers/mtd/ubi/scan.c -+ drivers/mtd/ubi/ubiblk.c -+ drivers/mtd/ubi/upd.c -+ drivers/mtd/ubi/vtbl.c -+ fs/ubifs/build.c -+ fs/ubifs/log.c -+ fs/ubifs/lpt.c -+ fs/ubifs/lpt_commit.c -+ fs/ubifs/orphan.c -+ fs/ubifs/recovery.c -+ fs/ubifs/replay.c -+ fs/ubifs/super.c -+ -+ -+2008.10.31 -+* Converted MTD from 32bit to 64bit to support the NAND larger than 4GB, and yaffs2 was -+ modified accordingly. -+ Updated file: -+ include/mtd/mtd-abi.h -+ include/linux/mtd/mtd.h -+ include/linux/mtd/partitions.h -+ include/linux/mtd/nand.h -+ drivers/mtd/mtdcore.c -+ drivers/mtd/mtdchar.c -+ drivers/mtd/mtdpart.c -+ drivers/mtd/mtdblock-jz.c -+ drivers/mtd/nand/nand_base.c -+ drivers/mtd/nand/nand_bbt.c -+ drivers/mtd/mtd-utils/include/mtd/mtd-abi.h -+ drivers/mtd/mtd-utils/flash_eraseall.c -+ drivers/mtd/mtd-utils/nandwrite_mlc.c -+ drivers/mtd/mtd-utils/nandwrite.c -+ fs/yaffs2/yaffs_fs.c -+ fs/yaffs2/yaffs_mtdif.c -+ fs/yaffs2/yaffs_mtdif2.c -+ -+2008.10.29 -+* Modified yaffs2 utils mkyaffs2image to support writting 4KB pagesize NAND. NAND layout -+ is (0 - raw(512B pagesize), 1 - nand_oob_64(2KB pagesize), 2 - nand_oob_128(4KB pagesize)). -+ -+ Updated file: -+ fs/yaffs2/utils/mkyaffs2image.c -+ -+2008.10.27 -+* Supported multiply chip selecting for NAND flash. -+ Updated files: -+ include/linux/mtd/nand.h -+ drivers/mtd/nand/nand_base.c -+ drivers/mtd/nand/jz4750_nand.c -+ drivers/mtd/nand/jz4740_nand.c -+ -+2008.10.23 -+* Modified yaffs2 utils mkyaffs2image to enable writing soft reed-solomn ECC for -+ yaffs2 file system information in oob area of MLC nand, getting CONFIG_YAFFS_ECC_RS -+ from .config, so when CONFIG_YAFFS_ECC_RS is changed, mkyaffs2image should be built -+ again. -+ Updated files: -+ fs/yaffs2/yaffs_ecc.c -+ fs/yaffs2/utils/Makefile -+ Added files: -+ fs/yaffs2/utils/ssfdc_rs_ecc.c -+ fs/yaffs2/utils/ssfdc_rs_ecc.h -+ -+2008.09.26 -+ -+* Fixed a fatal bug for mplayer, which may cause some files cannot be played and -+ the system is crashed. -+ Updated file: arch/mips/jz4740/proc.c -+ -+2008.08.30 -+* For jz4750, DMA clock for each channel should be enabled before using the channel. -+ So REG_DMAC_DMACKE and __dmac_channel_enable_clk(n) were added. -+ Updated files: -+ include/asm-mips/mach-jz4750/regs.h -+ include/asm-mips/mach-jz4750/ops.h -+ Regen, -+ -+2008.08.19 -+* Modify jzfb_mmap() for cacheable framebuffer access. -+ Updated files: -+ drivers/video/jzlcd.c -+ drivers/video/jz4740_slcd.c -+ drivers/video/jz4750_lcd.c -+ -+2008.08.15 -+* Modify ipu interface to toggle PID of MPlayer in TLB. -+* Modify OSS ioctl function to play movie with mono channel better. -+ Update Files: -+ arch/mips/jz4740/proc.c -+ sound/oss/jz_i2s.c -+ Richard Feng, -+ -+2008.08.04 -+* Check whether the free block is erased before erasing it, 'unsigned int' instead of -+ 'unsigned short' was used to store block number, and heap sort for lifetime after -+ erasing a block was replaced by another faster method. -+ Update File: -+ drivers/mtd/mtdblock-jz.uu -+ -+* Cache read was used in nand_read_page_hwecc_rs() for Jz4740. -+ Update File: -+ drivers/mtd/nand/nand_base.c -+ -+* Faster timing in REG_EMC_SMCR1 whose value is 0x09221200 was used. -+ Update File: -+ drivers/mtd/nand/jz4740_nand.c -+ -+ Regen, -+ -+2008.07.21 -+* Supported 4KB page size nand -+ Update File: -+ drivers/mtd/nand/nand_base.c -+ include/linux/mtd/nand.h -+ include/mtd/mtd-abi.h -+ drivers/mtd/mtd-utils/include/mtd/mtd-abi.h -+ Regen, -+ -+2008.07.18 -+* Soft reed solomon ECC was supported for yaffs2 information which is 16 bytes in nand -+ oob, and it should be used for MLC nand. -+ Update File: -+ fs/yaffs2/yaffs_ecc.c -+ fs/yaffs2/yaffs_ecc.h -+ fs/yaffs2/yaffs_fs.c -+ fs/yaffs2/yaffs_packedtags2.c -+ Regen, -+ -+2008.07.10 -+* Added support to generate any frequency baud rate of uart for both Jz4740 and Jz4750. -+ Update File: -+ drivers/serial/8250.c -+ Regen, -+ -+2008.07.03 -+* Modified Jz4750's INTC, CIM, TSSI, macros. -+ Update Files: -+ include/asm-mips/mach-jz4750/regs.h -+ include/asm-mips/mach-jz4750/ops.h -+ -+2008.06.24 -+* Combined Jz4750 SLCD Controller support into drivers/video/jz4750_lcd.c. -+* drivers/video/jz4750_lcd.c, now support: LCD Controller, Slcd Controller, TVE. -+* And add smart lcd panel TRULY_TFT_GG1P0319LTSW_W support. -+ Update Files: -+ drivers/video/Kconfig -+ drivers/video/jz4750_lcd.h -+ drivers/video/jz4750_lcd.c -+ Wolfgang Wang, -+ -+2008.06.20 -+* Add Jz4750 LCDC and TVE driver. -+ Update Files: -+ arch/asm-mips/mach-jz4750/regs.h -+ arch/asm-mips/mach-jz4750/ops.h -+ drivers/video/Kconfig -+ drivers/video/Makefile -+ Add Files: -+ drivers/video/jz4750_lcd.h -+ drivers/video/jz4750_lcd.c -+ drivers/video/jz4750_tve.h -+ drivers/video/jz4750_tve.c -+ -+2008.06.12 -+* Modified CONFIG_FB_JZXXX macros, rename drivers/video/jzslcd.x to drivers/video/jz4740_slcd.x -+ Update Files: -+ drivers/video/Kconfig -+ drivers/video/Makefile -+ arch/mips/configs/dipper_defconfig -+ arch/mips/configs/leo_defconfig -+ arch/mips/configs/lyra_defconfig -+ arch/mips/configs/pavo_defconfig -+ arch/mips/configs/virgo_defconfig -+ -+ -+2008.06.10 -+* Add jz_clocksource, upgrade the system time's accuracy from 10ms to about 1(or 2) us. -+ but the system timer remained 10ms. -+ Files modified: -+ arch/mips/jz4730/time.c -+ arch/mips/jz4740/time.c -+ arch/mips/jz4750/time.c -+ -+ -+2008.05.31 -+ -+* Updated UBIFS. -+ -+2008.05.30 -+ -+* Added JZ4720 virgo board support. -+ -+2008.05.29 -+ -+* Added definition of CONFIG_SOC_JZ4725 and CONFIG_SOC_JZ4720. -+* Added selection of 4-bit/1-bit data bus for MMC/SD card driver. -+* Added dipper_defconfig for JZ4725 DIPPER board. -+ -+2008.05.29: -+ -+* Modified sound/oss/jz_i2s.c to increase the sound buffer. -+* Modified pavo_defconfig to select the oss sound driver by default. -+* Fixed jzlcd.h for jz4730 pmp. -+* Modified jzcs8900a.c to not test the chip ID. -+ -+2008.05.22: -+ -+* jzcs8900a.c: fixed the bug of "No network devices available". -+ -+2008.05.13: -+ -+* Rewrote all of the UBI and UBIFS codes. -+ -+2008.05.07: -+* Add GPIO group E group F irq, DMAC1 irq. Add SSI1 macros. -+ -+ -+2008.05.06: -+ -+* Modified MMC/SD driver jz_mmc.c to support PM callback. -+ -+2008.05.04: -+ -+* Fixed a bug of mtdblock-jz.uu of using the badblock_table. -+ -+2008.04.26: -+ -+* Patch jz4740_nand.c to optimize the RS correction algorithm. -+ -+2008.04.24 -+* Jzlcd driver add Framebuffer Rotate support. -+ Update files: -+ drivers/video/Kconfig -+ drivers/video/jzlcd.h -+ drivers/video/jzlcd.c -+ -+ -+2008.04.21: -+* Modified LCD_CFG_MODE_INTER_CCIR656 define -+ #define LCD_CFG_MODE_INTER_CCIR656 (5 << LCD_CFG_MODE_BIT) -+ should be ==>> -+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) -+ Update files: -+ include/asm-mips/mach-jz4730/regs.h -+ include/asm-mips/mach-jz4740/regs.h -+ include/asm-mips/mach-jz4750/regs.h -+ -+2008.04.14: -+ -+* Modify drivers/video/jzslcd.c to suport Smart LCD switches between -+ always refresh and event-driven refresh . -+ -+2008.04.01: -+ -+* Support multi-framebuffers, update files: -+ drivers/video/Kconfig, add: CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+ drivers/video/jzlcd.h -+ drivers/video/jzlcd.c -+ arch/mips/configs/pavo_defconfig, add: CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+ -+ -+2008.03.29: -+ -+* Modified sound/soc/jz4740/jz4740-i2s.c to support 32KHz PCM sample. -+ -+2008.03.28 -+ -+* Ported new mtd-utils and mkfs.ubifs. -+ -+2008.03.27 -+ -+* board_fuwa.h, change GPIO_DISP_OFF_N to GPD25. -+* Added lyra_defconfig for JZ4740 LYRA (MP4) board. -+ -+2008.03.24: -+ -+* Added jzslcd.c for Smart LCD framebuffer driver. -+* Modified rtc_jz.c to use some functions in rtc library instead of our function. -+ -+* Added jz_keypad.c and gpio_keys.c for scan keypad drivers. -+ -+2008.03.19: -+ -+* Added block-jz.c to support block device layer on top of ubi. -+ -+ -+2008.03.17: -+ -+* Modified jz4740_udc.c to enable the suspend irq when host unloads us. -+ -+* pavo_defconfig: select CONFIG_WIRELESS_EXT, CONFIG_PNP and CONFIG_SERIAL_8250_PNP. -+ -+ -+2008.03.14: -+ -+* Modified jz_ts.c jz_ts.h and sadc.c to release CPU by interrupt mode instead of pio mode. -+ -+ -+2008.03.13: -+ -+* Fixed a bug in jz4740_udc.c and jz4730_udc.c during rmmod the driver. -+ -+ -+2008.03.10: -+ -+* Modified jz_i2s.c to fix the jz_audio_release(). -+ -+2008.03.08: -+ -+* Fixed udc_hotplug.c to avoid the "unexpected IRQ". -+* Fixed jz4740/cpufreq.c of calculating the new_mclk. -+ -+2008.03.05: -+ -+* Modified drivers/video/console/fbcon.c by adding fb_flashcursor selection. -+ -+ -+2008.03.04: -+ -+* Initial release. -diff -urN linux-2.6.24.7.old/README-JZ linux-2.6.24.7/README-JZ ---- linux-2.6.24.7.old/README-JZ 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/README-JZ 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1181 @@ -+ -+ Linux 2.6 Kernel Release for Ingenic -+ -+ (Updated: 2008-12-29) -+ -+------------- -+** Content ** -+------------- -+ -+** Quick start ** -+** Supported SOC and Platforms ** -+** Overview of source tree ** -+** NAND Flash Filesystem ** -+** UBI, UBIFS and UBI Block Layer ** -+** UBI and UBIFS images ** -+** YAFFS2 ** -+** MTD Block Layer ** -+** About Bad Blocks of NAND ** -+** SLC and MLC NAND Flash ** -+** Initramfs ** -+** Audio full duplex mode ** -+** Support ** -+ -+ -+----------------- -+** Quick Start ** -+----------------- -+ -+To build linux 2.6, you needs a mipsel-linux-gcc version 4. Please -+download it from Ingenic website http://www.ingenic.cn. -+ -+You should have downloaded the linux-2.6.24.3.tar.bz2 and the latest kernel -+patch. The patch file was named as "linux-2.6.24.3-jz-yyyymmdd.patch.gz". -+ -+Follow next steps to install the full kernel source: -+ -+ $ tar -xjf linux-2.6.24.3.tar.bz2 -+ $ cd linux-2.6.24.3 -+ $ gzip -cd ../linux-2.6.24.3-jz-yyyymmdd.patch.gz | patch -p1 -+ -+Now you can configure and build the kernel. -+ -+First, you need to do a 'make board_defconfig' to select a board. -+ -+For example: -+ -+ - make pavo_defconfig # JZ4740 PAVO board default configuration -+ - make pmp_defconfig # JZ4730 PMP ver 2.x board default configuration -+ - make dipper_defconfig # JZ4725 PMP ver 1.x board default configuration -+ -+Then, configure and compile the kernel: -+ -+ - make xconfig or make menuconfig, if you want to change the configuration. -+ - make, make uImage, or make zImage, to build the kernel. -+ -+The ELF format kernel image is linux-2.6.24.3/vmlinux. -+The U-Boot format kernel image is linux-2.6.24.3/arch/mips/boot/uImage. -+The compressed raw kernel image is linux-2.6.24.3/arch/mips/boot/compressed/zImage. -+ -+ -+--------------------------------- -+** Supported SOC and Platforms ** -+--------------------------------- -+ -+This release supports several platforms based on JZ4730, JZ4740 and JZ4750. -+ -+JZ4750 based platforms: -+ -+ - apus: JZ4750 development board -+ -+JZ4740 based platforms: -+ -+ - pavo: JZ4740 reference board -+ - leo: JZ4740 development board -+ -+JZ4730 based platforms: -+ -+ - pmp: JZ4730 reference board version 2.x -+ -+JZ4725 based platforms: -+ -+ - dipper: JZ4725 reference board version 1.x -+ -+ -+----------------------------- -+** Overview of source tree ** -+----------------------------- -+ -+ - Changelog : Revision history -+ - README-JZ : This file -+ - arch/mips/ -+ - kernel/ : MIPS kernel common code -+ - mm/ : MIPS memory common code -+ - jz4730/ : JZ4730 code -+ - jz4740/ : JZ4740 JZ4725 JZ4720 code -+ - jz4750/ : JZ4750 code -+ - configs/ -+ - apus_defconfig : jz4750 based apus default configuration -+ - pavo_defconfig : jz4740 based pavo default configuration -+ - pmp_defconfig : jz4730 based pmp default configuration -+ - dipper_defconfig : jz4725 based dipper default configuration -+ - include/asm-mips/ : MIPS asm common include -+ - jzsoc.h : JZ SoC common include -+ - mach-jz4730/ : JZ4730 SoC headers -+ - mach-jz4740/ : JZ4740 JZ4725 JZ4720 SoC headers -+ - mach-jz4750/ : JZ4750 SoC headers -+ - fs/ -+ - jffs2/ : JFFS2 file system -+ - yaffs2/ : YAFFS2 file system -+ - utils/ : YAFFS2 utilities, like mkyaffs2image -+ - ubifs/ : ubifs file system -+ - mkfs.ubifs/ : mkfs.ubifs util to create UBIFS -+ - sound/ -+ oss/ : OSS audio driver -+ soc/jz4740/ : JZ4740 ALSA audio driver -+ - drivers/ -+ - char/ -+ - serial.c : serial port driver -+ - rtc_pcf8563.c : PCF8563 RTC driver -+ - rtc_jz.c : JZSOC On-Chip RTC driver -+ - jzchar/ : jzchar devices -+ - jz_ts.c : generic touch screen driver -+ - sadc.c : JZ4740 SADC driver -+ - ak4182.c : AK4182 touch driver -+ - udc_hotplug.c : UDC hotplug management -+ - poweroff.c : suspend/poweroff management -+ - input/keyboard/ -+ - jz_keypad.c : scan keypad driver -+ - gpio_keys.c : gpio keypad driver -+ - media/video/ -+ - jz_cim.c : generic camera driver -+ - jz_sensor.c : generic sensor driver -+ - mmc/host/ -+ - jz_mmc.c : jz mmc/sd card driver -+ - mtd/ -+ - mtdblock-jz.c : NAND Flash translation layer driver -+ - nand/ -+ - nand_base.c : NAND flash interface to MTD -+ - jz4730_nand.c : NAND flash definition on JZ4730 boards -+ - jz4740_nand.c : NAND flash definition on JZ4740 boards -+ - jz4750_nand.c : NAND flash definition on JZ4750 boards -+ - ubi/ : MTD utilities like flash_eraseall, nandwrite etc. -+ - ubiblk.c : UBI block layer driver on top of UBI -+ - mtd-utils/ : MTD and UBI utilities, like flash_eraseall, nandwrite and ubimkvol etc. -+ - ubi-utils : UBI utils like ubimkvol/ubirmvol/ubinize etc. -+ - net/ -+ - jz_eth.c : JZ4730 On-Chip ethernet driver -+ - jzcs8900a.c : cs8900a ethernet driver -+ - serial/ -+ - 8250.c : standard 16550A serial driver -+ - usb/ : USB OHCI host driver -+ - usb/host/ -+ ohci-jz.c : JZ OHCI driver -+ - usb/gadget/ -+ - jz4730_udc.c : JZ4730 UDC low-level driver -+ - jz4740_udc.c : JZ4740 and JZ4750 UDC low-level driver -+ - file_storage.c : USB mass storage class driver -+ - serial.c : USB serial class driver -+ - video/ -+ - jzlcd.c : JZ LCD controller framebuffer driver for JZ4730 and JZ4740 -+ - jz4740_slcd.c : JZ Smart LCD controller framebuffer driver for JZ4740 -+ - jz4750_lcd.c : JZ LCD and Smart LCD controller driver for JZ4750 -+ - jz4750_tve.c : JZ TV encoder controller driver for JZ4750 -+ - watchdog/ -+ - jz_wdt.c : JZ On-Chip watchdog driver -+ -+ -+--------------------------- -+** NAND Flash Filesystem ** -+--------------------------- -+ -+NAND Flash is the main non-volatile storage for most embedded devices. -+So, it's very important to implement a stable and reasonable filesystem on -+NAND flash. -+ -+In Linux, the MTD subsystem provides a common interface for operating with -+many flash devices, such as NOR, NAND etc. And the MTD subsystem was modified -+by Ingenic to support the NAND larger than 2GB. -+ -+Above MTD layer, we can implement the YAFFS2 filesystem. Or we can implement -+a MTD block device, on top of it we can implement the general filesystem -+such as FAT and EXT2. -+ -+The Linux 2.6 kernel also implements the UBI (Unsorted Block Images). UBI -+is a software layer above MTD layer which admits of LVM-like logical volumes -+on top of MTD devices, hides some complexities of flash chips like wear -+and bad blocks and provides some other useful capabilities. Please, consult -+the MTD web site for more details (www.linux-mtd.infradead.org). -+ -+On top of UBI, we can implement the UBIFS filesystem. We can also emulate -+block devices above UBI, such that we can use the general filesystem such as -+FAT and EXT2 on it. -+ -+The architecture of the NAND flash filesystem is illustrated as below: -+ -+ -+ -+ +-----------+ +-------------+ +-------------+ -+ | YAFFS2 | | UBIFS | | FAT or EXT2 | Filesystems -+ +-----------+ +-------------+ +-------------+ -+ \ | / \ -+ \ | / \ -+ \ | / \ -+ \ | +-----------------+ +-----------------+ -+ \ | | UBI Block Layer | | MTD Block Layer | -+ \ | +-----------------+ +-----------------+ -+ \ | / / -+ \ | / / -+ \ +-------------+ / -+ \ | UBI | / -+ \ +-------------+ / -+ \ | / -+ +-------------------------------------------+ -+ | MTD | -+ +-------------------------------------------+ -+ | -+ +--------------------+ -+ | nand_base.c | -+ +--------------------+ -+ | -+ +--------------------+ -+ | jz4740_nand.c | -+ +--------------------+ -+ -+ -+The related source codes are listed below: -+ -+fs/yaffs2: YAFFS2 -+fs/ubifs: UBIFS -+fs/fat: FAT -+fs/ext2: EXT2 -+drivers/mtd: MTD -+drivers/mtd/ubi: UBI -+drivers/mtd/ubi/ubiblk.c: UBI Block Layer -+drivers/mtd/mtdblock-jz.c: MTD Block Layer -+drivers/mtd/mtd-utils: MTD and UBI utils (flash_eraseall/ubimkvol/ubinfo/ubinize etc.) -+fs/ubifs/mkfs.ubifs: UBIFS util to create ubifs image (mkfs.ubifs) -+fs/yaffs2/util: YAFFS2 util (mkyaffs2image) -+ -+To build mtd utils, go to drivers/mtd/mtd-utils, type 'make' and -+'make install DESTDIR=/nfsroot/root26'. -+ -+To build yaffs2 util, go to fs/yaffs2/utils and type 'make'. -+ -+To build ubifs util, go to fs/ubifs/mkfs.ubifs and type 'make'. -+ -+Except 'UBI Block Layer' and 'MTD Block Layer', which are implement by Ingenic -+ourself, the others are general in the linux kernel tree. -+ -+User can select any one of these drivers to implement the filesystem. It all -+depends on yourself. -+ -+Following sections will describe how to use these drivers in details. -+ -+ -+------------------------------------ -+** UBI, UBIFS and UBI Block Layer ** -+------------------------------------ -+ -+UBIFS is a new flash file system which is designed to work on top of UBI. -+ -+Here is a short and unsorted list of some of UBIFS features: -+ -+* write-back support - This dramatically improves the throughput of the -+file-system comparing to JFFS2, which is write-through; -+ -+* fast mount time -+ -+* tolerance to unclean reboots - UBIFS is a journaling file system and it -+tolerates sudden crashes and unclean reboots; -+ -+* fast I/O - even with write-back disabled; -+ -+* on-the-flight compression - the data is stored in compressed form on -+the flash media, which makes it possible to put considerably more data to -+the flash as if the data would not be compressed; -+ -+Please, consult the MTD web site for more details (www.linux-mtd.infradead.org). -+ -+The UBI and UBIFS can be compiled as modules or built into the kernel. -+ -+To enable UBI, you need to select following configurations: -+ -+CONFIG_MTD_UBI: Enable UBI -+CONFIG_MTD_UBI_WL_THRESHOLD: UBI wear-leveling threshold -+CONFIG_MTD_UBI_BEB_RESERVE: Percentage of reserved eraseblocks for bad eraseblocks handling -+ -+To enable 'UBI Block Layer', you need to select following configurations: -+ -+CONFIG_MTD_UBI_BLKDEVS: Common interface to block layer for UBI -+CONFIG_MTD_UBI_BLOCK: Emulate block devices -+ -+To enable UBIFS, you need to select following configurations: -+ -+CONFIG_UBIFS_FS: UBIFS file system support -+CONFIG_UBIFS_COMPRESSION_OPTIONS: Advanced compression options for UBIFS -+CONFIG_UBIFS_LZO: UBIFS LZO compression support -+CONFIG_UBIFS_ZLIB: UBIFS ZLIB compression support -+CONFIG_UBIFS_FS_DEBUG: UBIFS debugging -+ -+If you want to compile as modules, take next steps: -+ -+Type 'make modules' to compile the modules. -+ -+Type 'make modules_install INSTALL_MOD_PATH=/nfsroot/root26' to install the -+modules to the target root. -+ -+You also need to compile the MTD and UBIFS utilities and install them to the -+target root. -+ -+ -+Now boot your board and mounted root FS with these modules, and below is a -+simple guide to test and use the UBIFS and 'UBI Block Layer': -+ -+Here we will create UBI volumes on mtd5. -+ -+First, format mtd5: -+ -+# flash_eraseall /dev/mtd5 -+Erasing 256 Kibyte @ 1ffc0000 -- 99 % complete. -+ -+Install UBI module, attached it to mtd5: -+ -+# modprobe ubi mtd=5 -+UBI: empty MTD device detected -+UBI: create volume table (copy #1) -+UBI: create volume table (copy #2) -+UBI: attached mtd5 to ubi0 -+UBI: MTD device name: "NAND VFAT partition" -+UBI: MTD device size: 512 MiB -+UBI: physical eraseblock size: 262144 bytes (256 KiB) -+UBI: logical eraseblock size: 258048 bytes -+UBI: number of good PEBs: 2048 -+UBI: number of bad PEBs: 0 -+UBI: smallest flash I/O unit: 2048 -+UBI: VID header offset: 2048 (aligned 2048) -+UBI: data offset: 4096 -+UBI: max. allowed volumes: 128 -+UBI: wear-leveling threshold: 4096 -+UBI: number of internal volumes: 1 -+UBI: number of user volumes: 0 -+UBI: available PEBs: 2024 -+UBI: total number of reserved PEBs: 24 -+UBI: number of PEBs reserved for bad PEB handling: 20 -+UBI: max/mean erase counter: 0/0 -+UBI: background thread "ubi_bgt0d" started, PID 241 -+ -+Now, create two UBI volumes, one is called ubifs and size is 200MB, the -+other is called vfat and size is 298MB. -+ -+# ubimkvol /dev/ubi0 -s 200MiB -N ubifs -+Volume ID 0, size 813 LEBs (209793024 bytes, 200.1 MiB), LEB size 258048 bytes (252.0 KiB), dynamic, name "ubifs", alignment 1 -+# ubimkvol /dev/ubi0 -s 298MiB -N vfat -+Volume ID 1, size 1211 LEBs (312496128 bytes, 298.0 MiB), LEB size 258048 bytes (252.0 KiB), dynamic, name "vfat", alignment 1 -+ -+Then you can use 'ubinfo' to query the UBI volume info: -+ -+# ubinfo -a -+UBI version: 1 -+Count of UBI devices: 1 -+UBI control device major/minor: 10:63 -+Present UBI devices: ubi0 -+ -+ubi0: -+Volumes count: 2 -+Logical eraseblock size: 258048 -+Total amount of logical eraseblocks: 2048 (528482304 bytes, 504.0 MiB) -+Amount of available logical eraseblocks: 0 (0 bytes) -+Maximum count of volumes 128 -+Count of bad physical eraseblocks: 0 -+Count of reserved physical eraseblocks: 20 -+Current maximum erase counter value: 3 -+Minimum input/output unit size: 2048 bytes -+Character device major/minor: 252:0 -+Present volumes: 0, 1 -+ -+Volume ID: 0 (on ubi0) -+Type: dynamic -+Alignment: 1 -+Size: 813 LEBs (209793024 bytes, 200.1 MiB) -+State: OK -+Name: ubifs -+Character device major/minor: 252:1 -+----------------------------------- -+Volume ID: 1 (on ubi0) -+Type: dynamic -+Alignment: 1 -+Size: 1211 LEBs (312496128 bytes, 298.0 MiB) -+State: OK -+Name: vfat -+Character device major/minor: 252:2 -+ -+ -+It shows that we have successfully created two UBI volumes (Volume ID 0 and 1) -+on ubi0. -+ -+Now you can install the UBIFS and 'UBI Block Layer' modules and create -+UBIFS and FAT on UBI volume 0 and 1 respectively. -+ -+# modprobe ubifs -+# modprobe ubiblk -+ -+# lsmod -+Module Size Used by Not tainted -+ubiblk 7696 0 -+bdev 10016 1 ubiblk -+deflate 4256 1 -+zlib_deflate 22256 1 deflate -+zlib_inflate 16992 1 deflate -+lzo 2400 1 -+lzo_decompress 2816 1 lzo -+lzo_compress 2848 1 lzo -+ubifs 208560 0 -+crc16 2048 1 ubifs -+ubi 103664 4 ubiblk,bdev,ubifs -+ -+Mount UBI volume 0 (the name is "ubifs") on ubi0 with type ubifs: -+ -+# mount -t ubifs ubi0:ubifs /mnt/ubifs/ -+UBIFS: mounted UBI device 0, volume 0 -+UBIFS: minimal I/O unit size: 2048 bytes -+UBIFS: logical eraseblock size: 258048 bytes (252 KiB) -+UBIFS: file system size: 207212544 bytes (202356 KiB, 197 MiB, 803 LEBs) -+UBIFS: journal size: 9420800 bytes (9200 KiB, 8 MiB, 37 LEBs) -+UBIFS: data journal heads: 1 -+UBIFS: default compressor: LZO -+ -+It shows that we have mounted it sucessfully. -+ -+Format /dev/ubiblock1 (the block device for UBI volume 1) and mount it with -+type vfat: -+ -+# mkfs.vfat /dev/ubiblock1 -+# mount -t vfat /dev/ubiblock1 /mnt/ubiblock1 -+ -+Please refer to the linux26_developer_guide.pdf for more details about -+the UBI and UBIFS. -+ -+ -+-------------------------- -+** UBI and UBIFS images ** -+-------------------------- -+ -+Generally, you want to create UBIFS and VFAT images respectively and combine -+these two images into one single image, and then use the nandwrite command -+to write this image to the MTD partition. -+ -+First of all, you need to compile the mkfs.ubifs utility. We use mkfs.ubifs -+to create the UBIFS image, like this: -+ -+Note: download the linux-nand-utils.tar.gz package from www.ingenic.cn and -+follows the guide to compile and run the mkfs.ubifs. -+ -+On the PC host: -+ -+$ mkfs.ubifs -h -+Usage: mkfs.ubifs [OPTIONS] -+Make a UBIFS file system image from an existing directory tree -+ -+Options: -+ -r, -d, --root=DIR Build file system from directory DIR -+ -m, --min-io-size=SIZE Minimum I/O size SIZE -+ -e, --leb-size=SIZE Use logical erase block size SIZE -+ -c, --max-leb-cnt=COUNT Use maximum logical erase block count COUNT -+ -o, --output=FILE Output to FILE -+ -j, --jrn-size=SIZE Use journal size SIZE bytes -+ -x, --compr=TYPE Use compression type TYPE (lzo, zlib or none) (default: lzo) -+ -f, --fanout=NUM Use fanout NUM (default: 8) -+ -k, --keyhash=TYPE Use key hash type TYPE (r5 or test) (default: r5) -+ -l, --log-lebs=COUNT Use COUNT erase blocks for the log -+ -p, --orph-lebs=COUNT Use COUNT erase blocks for orphans (default: 1) -+ -v, --verbose Verbose operation -+ -V, --version Display version information -+ -g, --debug=LEVEL Display debug information -+ -h, --help Display this help text -+ -+$ mkfs.ubifs -r /nfsroot/root26 -m 2048 -e 258048 -c 813 -o ubifs.img -+ -+This will create an UBIFS image called ubifs.img. The argument values -+can be obtained from the 'ubinfo -a' command. -+ -+Follow next steps to create a 30MB FAT32 image called vfat.img: -+ -+# dd if=/dev/zero of=vfat.img bs=1M count=30 -+# losetup /dev/loop0 vfat.img -+# mkfs.vfat /dev/loop0 -+# mount -t vfat /dev/loop0 /mnt/vfat -+# cp * /mnt/vfat -+# umount /mnt/vfat -+# losetup -d /dev/loop0 -+ -+Now the two images ubifs.img and vfat.img are ready, and we want to -+create two UBI volumes and write these two images to the two UBI volumes -+respectively. We can do like this: -+ -+First, use 'ubinize' command to combine ubifs.img and vfat.img into one -+UBI image called ubi.img. -+ -+Second, use 'nandwrite_mlc_ubi' command to write the ubi.img to the -+MTD partition. -+ -+To use 'ubinize' command, you should prepare an INI file for it. The -+content of the INI file are as below: -+ -+# cat ubinize.cfg -+[ubifs] -+mode=ubi -+image=ubifs.img -+vol_id=0 -+vol_size=200MiB -+vol_type=dynamic -+vol_name=ubifs -+vol_alignment=1 -+vol_flag=autoresize -+ -+[vfat] -+mode=ubi -+image=vfat.img -+vol_id=1 -+vol_size=298MiB -+vol_type=dynamic -+vol_name=vfat -+vol_alignment=1 -+vol_flag=autoresize -+ -+ -+Now you can boot your board and follow next guides to create the UBI -+image and burn the UBI image. -+ -+On the target board side: -+ -+# ubinize -o ubi.img ubinize.cfg -p 262144 -m 2048 -+ -+If things go well, you can get the UBI image ubi.img. -+ -+Then use 'nandwrite_ubi' command to write it to the MTD partition. -+ -+# flash_eraseall /dev/mtd5 -+# nandwrite_ubi -a -q -m /dev/mtd5 ubi.img -+ -+Now the UBI image has been written to the NAND mtd5 partition. -+ -+Use next commands to test it. -+ -+# modprobe ubi mtd=5 -+ -+# ubinfo -a -+UBI version: 1 -+Count of UBI devices: 1 -+UBI control device major/minor: 10:63 -+Present UBI devices: ubi0 -+ -+ubi0: -+Volumes count: 2 -+Logical eraseblock size: 258048 -+Total amount of logical eraseblocks: 2048 (528482304 bytes, 504.0 MiB) -+Amount of available logical eraseblocks: 0 (0 bytes) -+Maximum count of volumes 128 -+Count of bad physical eraseblocks: 0 -+Count of reserved physical eraseblocks: 20 -+Current maximum erase counter value: 1 -+Minimum input/output unit size: 2048 bytes -+Character device major/minor: 252:0 -+Present volumes: 0, 1 -+ -+Volume ID: 0 (on ubi0) -+Type: dynamic -+Alignment: 1 -+Size: 813 LEBs (209793024 bytes, 200.1 MiB) -+State: OK -+Name: ubifs -+Character device major/minor: 252:1 -+----------------------------------- -+Volume ID: 1 (on ubi0) -+Type: dynamic -+Alignment: 1 -+Size: 1211 LEBs (312496128 bytes, 298.0 MiB) -+State: OK -+Name: vfat -+Character device major/minor: 252:2 -+ -+ -+This shows that two UBI volumes are present on ubi0. -+ -+# modprobe ubifs -+# mount -t ubifs ubi0:ubifs /mnt/ubifs/ -+UBIFS: mounted UBI device 0, volume 0 -+UBIFS: minimal I/O unit size: 2048 bytes -+UBIFS: logical eraseblock size: 258048 bytes (252 KiB) -+UBIFS: file system size: 207212544 bytes (202356 KiB, 197 MiB, 803 LEBs) -+UBIFS: journal size: 9420800 bytes (9200 KiB, 8 MiB, 37 LEBs) -+UBIFS: data journal heads: 1 -+UBIFS: default compressor: LZO -+ -+# modprobe ubiblk -+# mount -t vfat /dev/ubiblock1 /mnt/ubiblock1 -+ -+# df -+Filesystem 1k-blocks Used Available Use% Mounted on -+tmpfs 30196 56 30140 0% /dev -+ubi0:ubifs 197536 48228 149308 24% /mnt/ubifs -+/dev/ubiblock1 30642 5762 24880 19% /mnt/ubiblock1 -+ -+It shows that the UBIFS and VFAT are all mounted successfully. -+ -+ -+------------ -+** YAFFS2 ** -+------------ -+ -+YAFFS (Yet Another Flash File System) was written to satisfy the -+special needs of NAND flash. The second release of YAFFS especially -+points to supporting newer NAND flash chips with 2k page size and -+up to 128MB capacity. -+ -+YAFFS2 is supported in this kernel. It's built on top of MTD directly. -+Go to fs/yaffs2 for more details. -+ -+To build the utility of YAFFS2, change to directory fs/yaffs2/utils/ -+and type 'make'. -+ -+To create a YAFFS2 image, mkyaffs2image command is used On PC host: -+ -+ usage: mkyaffs2image layout# dir image_file [convert] -+ -+ layout# NAND OOB layout: -+ 0 - nand_oob_raw, no used, -+ 1 - nand_oob_64, for 2KB pagesize, -+ 2 - nand_oob_128, for 2KB pagesize using multiple planes or 4KB pagesize, -+ 3 - nand_oob_256, for 4KB pagesize using multiple planes -+ dir the directory tree to be converted -+ image_file the output file to hold the image -+ -+ e.g., for 2KB page size NAND not using multi-plane: -+ -+ $ mkyaffs2image 1 /nfsroot/root26 root26.yaffs2 -+ -+To burn the yaffs2 image to the NAND, use next command (On target board): -+ -+ # nandwrite -a -o /dev/mtd2 root26.yaffs2 -+ -+To format and mount YAFFS2 (On target board): -+ -+ # flash_eraseall /dev/mtd2 -+ # mount -t yaffs2 /dev/mtdblock2 /mnt/mtdblock2 -+ -+ -+--------------------- -+** MTD Block Layer ** -+--------------------- -+ -+Ingenic implement the 'MTD Block Layer' by ourself. This gives you a choice -+to implement a general filesystem such as FAT and ext2 on NAND flash. -+ -+Which partition used for VFAT should be set in bootargs of u-boot for kernel cmdline, -+so the kernel kowns other partitions aren't base on MTD Block Layer, and their mounting -+speed will be faster. For example, if mtdblock5 is used for VFAT, you can -+ -+set bootargs mem=64M console=ttyS1,57600n8 ip=dhcp root=/dev/mtdblock2 rw mtdblk=5 -+ -+and the mounting speed of mtdblock2 which is not based on MTD Block Layer will be faster. -+ -+ -+Features of the 'MTD Block Layer' include: -+ -+1. Block unit management (address mapping & block cache operations) -+2. Wear-leveling -+3. Bad block management -+4. Write verify enable -+5. mutiple choice of ECC algorithms (hardware Hamming ECC & Reed Solomon ECC, -+software Hamming ECC) -+ -+Kernel configurations related to the 'MTD Block Layer': -+ -+* CONFIG_MTD_OOB_COPIES: defines how many copies of the critical oob data for -+ each block. Since the page data can be corrected by the ECC algorithm but -+ the oob data can't, we want to ensure the correction of the oob data by this -+ way. The mtdblock-jz translation layer driver uses block mode to manipulate -+ the NAND flash. It makes several copies of the oobinfo data for each block, -+ so that it can get a correct copy even there is an error in one of them. -+ -+* CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE: defines this to enable the write -+ verification function, which will read back data to verify during a write -+ operation. -+ -+Take following steps to use the 'MTD Block Layer': -+ -+ # flash_eraseall /dev/mtd3 -+ # mkfs.vfat /dev/mtdblock3 -+ # mount -t vfat /dev/mtdblock3 /mnt/vfat -+ -+ -+NOTICE: -+ -+You can define mutiple VFAT partitions, all the VFAT partitions share -+the same above configurations. -+ -+Each VFAT partition have its own block cache which resides only in RAM. -+Generally, the block cache flush operation is triggered when the access -+address exceeds block boundary. The last block cache usually will be -+flushed to NAND device when the device is closed (eg: umount /mnt/vfat; -+use system call close(fd)). -+ -+Abrupt poweroff without flushing the last block cache will cause the -+VFAT partition to lose the most significant data which records the -+information of the file system management such as FAT table, inodes ... -+ -+To avoid this bad thing, you have to flush block cache as soon as possible. -+Please do remember to flush block cache manually when you finish -+a write operation. -+ -+The MTD block layer driver supplys an ioctl for triggering flush block cache -+operation. The code attached behind is a reference for you to use. -+ -+eg: -+ -+ # cp * /mnt/vfat -+ # sync ; this step is necessary to flush the FS cache -+ # flushcache /dev/mtdblock3 ; this step is necessary to flush the NFTL block cache -+ -+ -+/* flushcache.c */ -+#include -+#include -+#include -+#include -+ -+int main(int argc,char **argv) -+{ -+ int fd; -+ -+ if( argc != 2 ){ -+ printf( "Usage:%s device name(full path)\n", argv[0] ); -+ return -1; -+ } -+ -+ if( (fd = open( argv[1], O_RDONLY ) ) == -1) { -+ printf( "Open %s failed\n", argv[1] ); -+ return -1; -+ } -+ -+ if( ioctl( fd, BLKFLSBUF) == -1) -+ printf("flush catche failed\n"); -+ -+ close(fd); -+ return 0; -+} -+ -+ -+------------------------------ -+** About Bad Blocks of NAND ** -+------------------------------ -+ -+NAND is a special flash type which there are new bad blocks generated during -+the whole period of using it. So the NAND driver should know how to detect -+a bad block and how to mark a new block bad. -+ -+Some types of NAND flash mark the bad block in the spare area of the first -+page but others in the last page. So we define a kernel configuration called -+CONFIG_MTD_BADBLOCK_FLAG_PAGE and use it to decide the bad block. -+ -+CONFIG_MTD_BADBLOCK_FLAG_PAGE: page in a block to store the badblock mark -+ -+Following functions should be cared: -+ -+nand_base.c: -+ -+ - nand_block_bad() -+ - nand_default_block_markbad() -+ -+nand_bbt.c: -+ -+ - create_bbt() -+ -+--------------------------------------- -+** Multiple plane operation for NAND ** -+--------------------------------------- -+ -+NAND multiple plane is a feature enabling support of simultaneous write/erase -+operations for NAND devices with multiplane architecture. This feature -+significantly increases write performance. It could give performance benefits -+if NAND device supports ultiple plane architecture only. If NAND device does -+not support multiple plane and CONFIG_MTD_NAND_MULTI_PLANE was set to yes when -+compiling kernel, code will parse device capabilities and NAND device will work -+in single plane mode. For safe, you'd better set CONFIG_MTD_NAND_MULTI_PLANE to -+no if NAND device does not support multiple plane. -+ -+If the NAND device support multiple plane, you could determine which partitions -+use multiple plane and which use single plane by setting the value of -+partition_info[] in driver/mtd/nand/jz47xx_nand.c, if the value of use_planes -+for a partition is 0, then the partition uses single plane, or else it uses -+multiple plane. e.g. -+ -+static struct mtd_partition partition_info[] = { -+ {name:"NAND BOOT partition", -+ offset:0 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND KERNEL partition", -+ offset:4 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND ROOTFS partition", -+ offset:8 * 0x100000, -+ size:120 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA1 partition", -+ offset:128 * 0x100000, -+ size:128 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA2 partition", -+ offset:256 * 0x100000, -+ size:256 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND VFAT partition", -+ offset:512 * 0x100000, -+ size:512 * 0x100000, -+ use_planes: 1}, -+}; -+ -+--------------------------------------- -+** Multiple chip selecting for NAND ** -+--------------------------------------- -+ -+CS1_N pin on Jz4740 or Jz4750 will be used for NAND defaultly; besides CS2_N, -+CS3_N, and CS4_N pins could be used for NAND, too. You can configure the kernel -+and select the configuration at: -+ -+ [Memory Technology Devices (MTD)] --> [NAND Device Support] -+ -+ --> [ECC Type] --> [Use NAND on CS2_N of JZSOC] -+ [Use NAND on CS3_N of JZSOC] -+ [Use NAND on CS4_N of JZSOC] -+ -+ -+---------------------------- -+** SLC and MLC NAND Flash ** -+---------------------------- -+ -+Single-Level Cell (SLC) and Multi-Level Cell (MLC) are both NAND-based -+non-volatile memory technologies. MLC NAND Flash allows each memory cell -+to store two bits of information, compared to the one bit-per-cell SLC -+NAND Flash allows. As a result, 90 nanometer (nm) MLC NAND offers a -+larger capacity (typically twice the density of SLC) and at a cost point -+appropriate for consumer products. -+ -+Though SLC NAND offers a lower density, it also provides an enhanced -+level of performance in the form of faster write speeds. Because SLC -+stores only one bit per cell, the likelihood for error is reduced. -+At 90 nanometer process, it is recommended to implement a 1 to 2-bit -+ECC for SLC, whereas 4-bit ECC is recommended on the MLC architecture. -+ -+The linux kernel from ingenic provides MLC NAND support through Hardware -+ECC algorithm. Jz4740 supports Reed-Solomon (RS) ECC algorithm, which can -+detect and correct 4-bit errors per 512 bytes at least. Jz4750 supports -+4-bit and 8-bit BCH ECC algorithm, 4-bit BCH ECC can detect and correct -+4 bits for up to 1010 bytes and 8-bit BCH ECC can detect and correct -+8 bits errors for up to 1016 bytes. -+ -+To include MLC NAND support, you are required to configure the kernel -+and select the configuration CONFIG_MTD_HW_RS_ECC for Jz4740, and -+CONFIG_MTD_HW_BCH_ECC for Jz4750, which can be found at: -+ -+ [Memory Technology Devices (MTD)] --> [NAND Device Support] -+ -+ --> [ECC Type] --> [Select hardware RS ECC] -+ [Select hardware BCH ECC] -+ -+ -+--------------- -+** Initramfs ** -+--------------- -+ -+Please read Documentation/filesystems/ramfs-rootfs-initramfs.txt for -+more information about how to use initramfs. -+ -+Following are some steps to help you to create root fs by using initramfs: -+ -+# cd /rootfs/ -+# find . | cpio -c -o | gzip -9 > ../rootfs.cpio.gz -+ -+Reconfigure the Linux kernel and select next configurations: -+ -+CONFIG_BLK_DEV_INITRD=y -+CONFIG_INITRAMFS_SOURCE="/rootfs.cpio.gz" -+CONFIG_INITRAMFS_ROOT_UID=0 -+CONFIG_INITRAMFS_ROOT_GID=0 -+ -+Rebuild the kernel and boot the kernel with next command lines: -+ -+"root=/dev/ram0 rw rdinit=/sbin/init" -+ -+ -+---------------------------- -+** Audio full duplex mode ** -+---------------------------- -+ -+OSS audio driver supports full duplex mode, that is to say, you can -+record while replaying. -+ -+The user application want to do some jobs to enable the full duplex mode -+of the OSS driver. The following are two examples: -+ -+ -+One is: -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define AUDIO_FILE "/dev/dsp" -+#define FREQS 48000 -+#define CHANNELS 2 -+#define TEST_TIME 10 -+#define SAMPLES 16 -+#define BUF_SIZE 8192 -+#define MAX_LEN (FREQS * CHANNELS * TEST_TIME * SAMPLES / 8) -+ -+int main(int argc, char *argv[]) -+{ -+ FILE *fp; -+ pid_t pid; -+ int audio_fd, i; -+ char *play_name; -+ char *rec_name; -+ -+ int play_count, play_cnt, played; -+ int rec_count, rec_cnt, recorded; -+ -+ u_char play_arr[MAX_LEN]; -+ u_char rec_arr[MAX_LEN]; -+ int err = 0; -+ -+ play_name = argv[1]; -+ rec_name = argv[2]; -+ -+ if ((audio_fd = open("/dev/dsp", O_RDWR)) < 0) { -+ printf(" Can't open sound device!\n"); -+ exit(-1); -+ } -+ -+ i = BUF_SIZE; -+ ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i); -+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL); -+ -+ i = CHANNELS; -+ ioctl(audio_fd, SNDCTL_DSP_STEREO, (u_char *) &i); -+ -+ i = SAMPLES; -+ ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, (u_char *) &i); -+ -+ i = FREQS; -+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i); -+ -+ fp=fopen(play_name, "r"); -+ fread(play_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ -+ -+ play_count = MAX_LEN; -+ played = 0; -+ -+ rec_count = MAX_LEN; -+ recorded = 0; -+ -+ switch(pid = fork()) { -+ case -1: -+ printf("error\n"); -+ break; -+ case 0: -+ printf(" playing\n"); -+ while (play_count) { -+ play_cnt = play_count; -+ if (play_cnt > BUF_SIZE) -+ play_cnt = BUF_SIZE; -+ -+ write (audio_fd, (char *)play_arr+played, play_cnt); -+ played += play_cnt; -+ play_count -= play_cnt; -+ }/* while (count) */ -+ exit(0); -+ break; -+ default: -+ printf(" recording\n"); -+ while (rec_count) { -+ rec_cnt = rec_count; -+ if (rec_cnt > BUF_SIZE) -+ rec_cnt = BUF_SIZE; -+ -+ read (audio_fd, (char *)rec_arr+recorded, rec_cnt); -+ recorded += rec_cnt; -+ rec_count -= rec_cnt; -+ }/* while (count) */ -+ break; -+ } -+ close(audio_fd); -+ -+ printf("write data to file, waiting for a while\n"); -+ fp=fopen(rec_name, "w"); -+ fwrite(rec_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ -+ return err; -+} -+ -+The other is : -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define AUDIO_FILE "/dev/dsp" -+#define FREQS_PLAY 22050 -+#define FREQS_REC 8000 -+#define FREQS 22050 -+#define CHANNELS 1 -+#define TEST_TIME 10 -+#define SAMPLES 16 -+#define BUF_SIZE 8192 -+#define MAX_LEN (FREQS * CHANNELS * TEST_TIME * SAMPLES / 8) -+ -+int main(int argc, char *argv[]) -+{ -+ FILE *fp; -+ pid_t pid; -+ int audio_fd, i; -+ char *play_name; -+ char *rec_name1, *rec_name2, *rec_name3; -+ int mixerfd, vol, savevol; -+ -+ int count; -+ int play_count, play_cnt, played; -+ int rec_count, rec_cnt, recorded; -+ -+ u_char play_arr[MAX_LEN]; -+ u_char rec_arr[MAX_LEN]; -+ int err = 0; -+ -+ play_name = argv[1]; -+ rec_name1 = argv[2]; -+ rec_name2 = argv[3]; -+ rec_name3 = argv[4]; -+ -+ if ((mixerfd = open("/dev/mixer", O_RDWR)) < 0) { -+ perror("/dev/mixer"); -+ exit(1); -+ } -+ -+ if ((audio_fd = open("/dev/dsp", O_RDWR)) < 0) { -+ printf(" Can't open sound device!\n"); -+ exit(-1); -+ } -+ -+ i = BUF_SIZE; -+ ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);// midify buffer lenth -+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL); -+ -+ i = CHANNELS; -+ ioctl(audio_fd, SNDCTL_DSP_CHANNELS, (u_char *) &i); -+ -+ i = SAMPLES; -+ ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE, (u_char *) &i); -+ -+ fp=fopen(play_name, "r"); -+ fread(play_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ -+ if (ioctl(mixerfd, SOUND_MIXER_READ_MIC, &savevol) == -1) { -+ perror("SOUND_MIXER_READ_DEVMASK mic"); -+ exit(-1); -+ } -+ -+ savevol = savevol & 0xff; -+ -+ for (count = 1; count <= 3; count++) { -+ -+ play_count = MAX_LEN; -+ played = 0; -+ -+ rec_count = MAX_LEN; -+ recorded = 0; -+ -+ -+ i = FREQS_PLAY; -+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i); -+ -+ printf(" playing %d\n", i); -+ while (play_count) { -+ play_cnt = play_count; -+ if (play_cnt > BUF_SIZE) -+ play_cnt = BUF_SIZE; -+ -+ write (audio_fd, (char *)play_arr+played, play_cnt); -+ played += play_cnt; -+ play_count -= play_cnt; -+ }/* while (count) */ -+ -+ /* wait for sync */ -+ ioctl(audio_fd, SNDCTL_DSP_SYNC, NULL); -+ -+ /* set mic gain 0 */ -+ vol = 0; -+ if (ioctl(mixerfd, SOUND_MIXER_WRITE_MIC, &vol) == -1) { -+ perror("SOUND_MIXER_WRITE_DEVMASK mic"); -+ exit(-1); -+ } -+ i = FREQS_REC; -+ ioctl(audio_fd, SNDCTL_DSP_SPEED, (u_char *) &i); -+ /* set mic gain orgin */ -+ vol = savevol; -+ if (ioctl(mixerfd, SOUND_MIXER_WRITE_MIC, &vol) == -1) { -+ perror("SOUND_MIXER_READ_DEVMASK mic"); -+ exit(-1); -+ } -+ -+ printf(" recording %d\n", i); -+ while (rec_count) { -+ rec_cnt = rec_count; -+ if (rec_cnt > BUF_SIZE) -+ rec_cnt = BUF_SIZE; -+ -+ read (audio_fd, (char *)rec_arr+recorded, rec_cnt); -+ recorded += rec_cnt; -+ rec_count -= rec_cnt; -+ }/* while (count) */ -+ -+ switch (count) { -+ case 1: -+ printf(" write to %s\n",rec_name1); -+ fp=fopen(rec_name1, "w"); -+ fwrite(rec_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ break; -+ case 2: -+ printf(" write to %s\n",rec_name2); -+ fp=fopen(rec_name2, "w"); -+ fwrite(rec_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ break; -+ case 3: -+ printf(" write to %s\n",rec_name3); -+ fp=fopen(rec_name3, "w"); -+ fwrite(rec_arr, 1, MAX_LEN, fp); -+ fclose(fp); -+ break; -+ } -+ sleep(1); -+ } -+ -+ close(audio_fd); -+ -+ return err; -+} -+ -+------------- -+** Support ** -+------------- -+ -+Welcome to Ingenic website: -+ -+More details, please refer to linux26_developer_guide.pdf. -diff -urN linux-2.6.24.7.old/arch/mips/Kconfig linux-2.6.24.7/arch/mips/Kconfig ---- linux-2.6.24.7.old/arch/mips/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -16,6 +16,82 @@ - prompt "System type" - default SGI_IP22 - -+config JZ4730_PMP -+ bool "Ingenic JZ4730 PMP board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4730 -+ -+config JZ4740_PAVO -+ bool "Ingenic JZ4740 PAVO board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4740 -+ -+config JZ4740_LEO -+ bool "Ingenic JZ4740 LEO board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4740 -+ -+config JZ4740_LYRA -+ bool "Ingenic JZ4740 LYRA board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4740 -+ -+config JZ4725_DIPPER -+ bool "Ingenic JZ4725 DIPPER board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4740 -+ select SOC_JZ4725 -+ -+config JZ4720_VIRGO -+ bool "Ingenic JZ4720 VIRGO board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4740 -+ select SOC_JZ4720 -+ -+config JZ4750_FUWA -+ bool "Ingenic JZ4750 FUWA board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4750 -+ select JZ_FPGA -+ -+config JZ4750D_FUWA1 -+ bool "Ingenic JZ4750d FUWA1 board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4750D -+ select JZ_FPGA -+ -+config JZ4750_APUS -+ bool "Ingenic JZ4750 APUS board" -+ select DMA_NONCOHERENT -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_LITTLE_ENDIAN -+ select SOC_JZ4750 -+ - config MACH_ALCHEMY - bool "Alchemy processor based machines" - -@@ -701,6 +777,48 @@ - - endmenu - -+##################################################### -+# Ingenic SOC series -+##################################################### -+ -+config SOC_JZ4730 -+ bool -+ select JZSOC -+ -+config SOC_JZ4740 -+ bool -+ select JZSOC -+ -+config SOC_JZ4725 -+ bool -+ select JZSOC -+ -+config SOC_JZ4720 -+ bool -+ select JZSOC -+ -+config SOC_JZ4750 -+ bool -+ select JZSOC -+ -+config SOC_JZ4750D -+ bool -+ select JZSOC -+ -+config JZ_FPGA -+ bool -+ -+config JZSOC -+ bool -+ select JZRISC -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_SUPPORTS_32BIT_KERNEL -+ -+config JZRISC -+ bool -+ -+#################################################### -+ - config RWSEM_GENERIC_SPINLOCK - bool - default y -@@ -1770,6 +1888,14 @@ - - source "kernel/time/Kconfig" - -+# the value of (max order + 1) -+config FORCE_MAX_ZONEORDER -+ prompt "MAX_ZONEORDER" -+ int -+ default "12" -+ help -+ The max memory that can be allocated = 4KB * 2^(CONFIG_FORCE_MAX_ZONEORDER - 1) -+ - # - # Timer Interrupt Frequency Configuration - # -@@ -2046,6 +2172,23 @@ - - endmenu - -+menu "CPU Frequency scaling" -+ -+config CPU_FREQ_JZ -+ tristate "CPUfreq driver for JZ CPUs" -+ depends on JZSOC -+ default n -+ help -+ This enables the CPUfreq driver for JZ CPUs. -+ -+ If in doubt, say N. -+ -+if (CPU_FREQ_JZ) -+source "drivers/cpufreq/Kconfig" -+endif -+ -+endmenu -+ - menu "Power management options" - - source "kernel/power/Kconfig" -diff -urN linux-2.6.24.7.old/arch/mips/Makefile linux-2.6.24.7/arch/mips/Makefile ---- linux-2.6.24.7.old/arch/mips/Makefile 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -159,6 +159,37 @@ - # - - # -+# Commond Ingenic JZ4730 series -+# -+core-$(CONFIG_SOC_JZ4730) += arch/mips/jz4730/ -+cflags-$(CONFIG_SOC_JZ4730) += -Iinclude/asm-mips/mach-jz4730 -+load-$(CONFIG_SOC_JZ4730) += 0xffffffff80010000 -+ -+# -+# Commond Ingenic JZ4740 series -+# -+ -+core-$(CONFIG_SOC_JZ4740) += arch/mips/jz4740/ -+cflags-$(CONFIG_SOC_JZ4740) += -Iinclude/asm-mips/mach-jz4740 -+load-$(CONFIG_SOC_JZ4740) += 0xffffffff80010000 -+ -+# -+# Commond Ingenic JZ4750 series -+# -+ -+core-$(CONFIG_SOC_JZ4750) += arch/mips/jz4750/ -+cflags-$(CONFIG_SOC_JZ4750) += -Iinclude/asm-mips/mach-jz4750 -+load-$(CONFIG_SOC_JZ4750) += 0xffffffff80010000 -+ -+# -+# Commond Ingenic JZ4750d series -+# -+ -+core-$(CONFIG_SOC_JZ4750D) += arch/mips/jz4750d/ -+cflags-$(CONFIG_SOC_JZ4750D) += -Iinclude/asm-mips/mach-jz4750d -+load-$(CONFIG_SOC_JZ4750D) += 0xffffffff80010000 -+ -+# - # Acer PICA 61, Mips Magnum 4000 and Olivetti M700. - # - core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/ -@@ -673,6 +704,12 @@ - - all: $(all-y) - -+uImage: $(vmlinux-32) -+ +@$(call makeboot,$@) -+ -+zImage: $(vmlinux-32) -+ +@$(call makeboot,$@) -+ - vmlinux.bin: $(vmlinux-32) - +@$(call makeboot,$@) - -@@ -697,12 +734,13 @@ - - archclean: - @$(MAKE) $(clean)=arch/mips/boot -+ @$(MAKE) $(clean)=arch/mips/boot/compressed - @$(MAKE) $(clean)=arch/mips/lasat - - define archhelp -- echo ' vmlinux.ecoff - ECOFF boot image' -- echo ' vmlinux.bin - Raw binary boot image' -- echo ' vmlinux.srec - SREC boot image' -+ echo ' uImage - u-boot format image (arch/$(ARCH)/boot/uImage)' -+ echo ' zImage - Compressed binary image (arch/$(ARCH)/boot/compressed/zImage)' -+ echo ' vmlinux.bin - Uncompressed binary image (arch/$(ARCH)/boot/vmlinux.bin)' - echo - echo ' These will be default as apropriate for a configured platform.' - endef -diff -urN linux-2.6.24.7.old/arch/mips/Makefile.orig linux-2.6.24.7/arch/mips/Makefile.orig ---- linux-2.6.24.7.old/arch/mips/Makefile.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/Makefile.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,712 @@ -+# -+# This file is subject to the terms and conditions of the GNU General Public -+# License. See the file "COPYING" in the main directory of this archive -+# for more details. -+# -+# Copyright (C) 1994, 95, 96, 2003 by Ralf Baechle -+# DECStation modifications by Paul M. Antoine, 1996 -+# Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki -+# -+# This file is included by the global makefile so that you can add your own -+# architecture-specific flags and dependencies. Remember to do have actions -+# for "archclean" cleaning up for this architecture. -+# -+ -+cflags-y := -+ -+# -+# Select the object file format to substitute into the linker script. -+# -+ifdef CONFIG_CPU_LITTLE_ENDIAN -+32bit-tool-archpref = mipsel -+64bit-tool-archpref = mips64el -+32bit-bfd = elf32-tradlittlemips -+64bit-bfd = elf64-tradlittlemips -+32bit-emul = elf32ltsmip -+64bit-emul = elf64ltsmip -+else -+32bit-tool-archpref = mips -+64bit-tool-archpref = mips64 -+32bit-bfd = elf32-tradbigmips -+64bit-bfd = elf64-tradbigmips -+32bit-emul = elf32btsmip -+64bit-emul = elf64btsmip -+endif -+ -+ifdef CONFIG_32BIT -+tool-archpref = $(32bit-tool-archpref) -+UTS_MACHINE := mips -+endif -+ifdef CONFIG_64BIT -+tool-archpref = $(64bit-tool-archpref) -+UTS_MACHINE := mips64 -+endif -+ -+ifneq ($(SUBARCH),$(ARCH)) -+ ifeq ($(CROSS_COMPILE),) -+ CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux- $(tool-archpref)-linux-gnu- $(tool-archpref)-unknown-linux-gnu-) -+ endif -+endif -+ -+ifdef CONFIG_32BIT -+ld-emul = $(32bit-emul) -+vmlinux-32 = vmlinux -+vmlinux-64 = vmlinux.64 -+ -+cflags-y += -mabi=32 -+endif -+ -+ifdef CONFIG_64BIT -+ld-emul = $(64bit-emul) -+vmlinux-32 = vmlinux.32 -+vmlinux-64 = vmlinux -+ -+cflags-y += -mabi=64 -+endif -+ -+all-$(CONFIG_BOOT_ELF32) := $(vmlinux-32) -+all-$(CONFIG_BOOT_ELF64) := $(vmlinux-64) -+ -+# -+# GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel -+# code since it only slows down the whole thing. At some point we might make -+# use of global pointer optimizations but their use of $28 conflicts with -+# the current pointer optimization. -+# -+# The DECStation requires an ECOFF kernel for remote booting, other MIPS -+# machines may also. Since BFD is incredibly buggy with respect to -+# crossformat linking we rely on the elf2ecoff tool for format conversion. -+# -+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -+cflags-y += -msoft-float -+LDFLAGS_vmlinux += -G 0 -static -n -nostdlib -+MODFLAGS += -mlong-calls -+ -+cflags-y += -ffreestanding -+ -+# -+# We explicitly add the endianness specifier if needed, this allows -+# to compile kernels with a toolchain for the other endianness. We -+# carefully avoid to add it redundantly because gcc 3.3/3.4 complains -+# when fed the toolchain default! -+# -+# Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of -+# 2006-10-10 don't properly change the predefined symbols if -EB / -EL -+# are used, so we kludge that here. A bug has been filed at -+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413. -+# -+undef-all += -UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__ -+undef-all += -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__ -+predef-be += -DMIPSEB -D_MIPSEB -D__MIPSEB -D__MIPSEB__ -+predef-le += -DMIPSEL -D_MIPSEL -D__MIPSEL -D__MIPSEL__ -+cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB $(undef-all) $(predef-be)) -+cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le)) -+ -+cflags-$(CONFIG_CPU_HAS_SMARTMIPS) += $(call cc-option,-msmartmips) -+ -+cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \ -+ -fno-omit-frame-pointer -+ -+# -+# CPU-dependent compiler/assembler options for optimization. -+# -+cflags-$(CONFIG_CPU_R3000) += -march=r3000 -+cflags-$(CONFIG_CPU_TX39XX) += -march=r3900 -+cflags-$(CONFIG_CPU_R6000) += -march=r6000 -Wa,--trap -+cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap -+cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap -+cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap -+cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap -+cflags-$(CONFIG_CPU_LOONGSON2) += -march=r4600 -Wa,--trap -+cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ -+ -Wa,-mips32 -Wa,--trap -+cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ -+ -Wa,-mips32r2 -Wa,--trap -+cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ -+ -Wa,-mips64 -Wa,--trap -+cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ -+ -Wa,-mips64r2 -Wa,--trap -+cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap -+cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \ -+ -Wa,--trap -+cflags-$(CONFIG_CPU_NEVADA) += $(call cc-option,-march=rm5200,-march=r5000) \ -+ -Wa,--trap -+cflags-$(CONFIG_CPU_RM7000) += $(call cc-option,-march=rm7000,-march=r5000) \ -+ -Wa,--trap -+cflags-$(CONFIG_CPU_RM9000) += $(call cc-option,-march=rm9000,-march=r5000) \ -+ -Wa,--trap -+cflags-$(CONFIG_CPU_SB1) += $(call cc-option,-march=sb1,-march=r5000) \ -+ -Wa,--trap -+cflags-$(CONFIG_CPU_R8000) += -march=r8000 -Wa,--trap -+cflags-$(CONFIG_CPU_R10000) += $(call cc-option,-march=r10000,-march=r8000) \ -+ -Wa,--trap -+ -+ifdef CONFIG_CPU_SB1 -+ifdef CONFIG_SB1_PASS_1_WORKAROUNDS -+MODFLAGS += -msb1-pass1-workarounds -+endif -+endif -+ -+# -+# Firmware support -+# -+libs-$(CONFIG_ARC) += arch/mips/fw/arc/ -+libs-$(CONFIG_CFE) += arch/mips/fw/cfe/ -+libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/ -+ -+# -+# Board-dependent options and extra files -+# -+ -+# -+# Acer PICA 61, Mips Magnum 4000 and Olivetti M700. -+# -+core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/ -+cflags-$(CONFIG_MACH_JAZZ) += -Iinclude/asm-mips/mach-jazz -+load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000 -+ -+# -+# Common Alchemy Au1x00 stuff -+# -+core-$(CONFIG_SOC_AU1X00) += arch/mips/au1000/common/ -+cflags-$(CONFIG_SOC_AU1X00) += -Iinclude/asm-mips/mach-au1x00 -+ -+# -+# AMD Alchemy Pb1000 eval board -+# -+libs-$(CONFIG_MIPS_PB1000) += arch/mips/au1000/pb1000/ -+cflags-$(CONFIG_MIPS_PB1000) += -Iinclude/asm-mips/mach-pb1x00 -+load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Pb1100 eval board -+# -+libs-$(CONFIG_MIPS_PB1100) += arch/mips/au1000/pb1100/ -+cflags-$(CONFIG_MIPS_PB1100) += -Iinclude/asm-mips/mach-pb1x00 -+load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Pb1500 eval board -+# -+libs-$(CONFIG_MIPS_PB1500) += arch/mips/au1000/pb1500/ -+cflags-$(CONFIG_MIPS_PB1500) += -Iinclude/asm-mips/mach-pb1x00 -+load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Pb1550 eval board -+# -+libs-$(CONFIG_MIPS_PB1550) += arch/mips/au1000/pb1550/ -+cflags-$(CONFIG_MIPS_PB1550) += -Iinclude/asm-mips/mach-pb1x00 -+load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Pb1200 eval board -+# -+libs-$(CONFIG_MIPS_PB1200) += arch/mips/au1000/pb1200/ -+cflags-$(CONFIG_MIPS_PB1200) += -Iinclude/asm-mips/mach-pb1x00 -+load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Db1000 eval board -+# -+libs-$(CONFIG_MIPS_DB1000) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_DB1000) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Db1100 eval board -+# -+libs-$(CONFIG_MIPS_DB1100) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_DB1100) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Db1500 eval board -+# -+libs-$(CONFIG_MIPS_DB1500) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_DB1500) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Db1550 eval board -+# -+libs-$(CONFIG_MIPS_DB1550) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_DB1550) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Db1200 eval board -+# -+libs-$(CONFIG_MIPS_DB1200) += arch/mips/au1000/pb1200/ -+cflags-$(CONFIG_MIPS_DB1200) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Bosporus eval board -+# -+libs-$(CONFIG_MIPS_BOSPORUS) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_BOSPORUS) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000 -+ -+# -+# AMD Alchemy Mirage eval board -+# -+libs-$(CONFIG_MIPS_MIRAGE) += arch/mips/au1000/db1x00/ -+cflags-$(CONFIG_MIPS_MIRAGE) += -Iinclude/asm-mips/mach-db1x00 -+load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000 -+ -+# -+# 4G-Systems eval board -+# -+libs-$(CONFIG_MIPS_MTX1) += arch/mips/au1000/mtx-1/ -+load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000 -+ -+# -+# MyCable eval board -+# -+libs-$(CONFIG_MIPS_XXS1500) += arch/mips/au1000/xxs1500/ -+load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 -+ -+# -+# Cobalt Server -+# -+core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/ -+cflags-$(CONFIG_MIPS_COBALT) += -Iinclude/asm-mips/mach-cobalt -+load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000 -+ -+# -+# DECstation family -+# -+core-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/ -+cflags-$(CONFIG_MACH_DECSTATION)+= -Iinclude/asm-mips/mach-dec -+libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/ -+load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000 -+ -+# -+# Wind River PPMC Board (4KC + GT64120) -+# -+core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/ -+cflags-$(CONFIG_WR_PPMC) += -Iinclude/asm-mips/mach-wrppmc -+load-$(CONFIG_WR_PPMC) += 0xffffffff80100000 -+ -+# -+# lemote fulong mini-PC board -+# -+core-$(CONFIG_LEMOTE_FULONG) +=arch/mips/lemote/lm2e/ -+load-$(CONFIG_LEMOTE_FULONG) +=0xffffffff80100000 -+cflags-$(CONFIG_LEMOTE_FULONG) += -Iinclude/asm-mips/mach-lemote -+ -+# -+# For all MIPS, Inc. eval boards -+# -+core-$(CONFIG_MIPS_BOARDS_GEN) += arch/mips/mips-boards/generic/ -+ -+# -+# MIPS Atlas board -+# -+core-$(CONFIG_MIPS_ATLAS) += arch/mips/mips-boards/atlas/ -+cflags-$(CONFIG_MIPS_ATLAS) += -Iinclude/asm-mips/mach-atlas -+cflags-$(CONFIG_MIPS_ATLAS) += -Iinclude/asm-mips/mach-mips -+load-$(CONFIG_MIPS_ATLAS) += 0xffffffff80100000 -+all-$(CONFIG_MIPS_ATLAS) := vmlinux.srec -+ -+# -+# MIPS Malta board -+# -+core-$(CONFIG_MIPS_MALTA) += arch/mips/mips-boards/malta/ -+cflags-$(CONFIG_MIPS_MALTA) += -Iinclude/asm-mips/mach-mips -+load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000 -+all-$(CONFIG_MIPS_MALTA) := vmlinux.srec -+ -+# -+# MIPS SEAD board -+# -+core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/ -+cflags-$(CONFIG_MIPS_SEAD) += -Iinclude/asm-mips/mach-mips -+load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000 -+all-$(CONFIG_MIPS_SEAD) := vmlinux.srec -+ -+# -+# MIPS SIM -+# -+core-$(CONFIG_MIPS_SIM) += arch/mips/mipssim/ -+cflags-$(CONFIG_MIPS_SIM) += -Iinclude/asm-mips/mach-mipssim -+load-$(CONFIG_MIPS_SIM) += 0x80100000 -+ -+# -+# PMC-Sierra MSP SOCs -+# -+core-$(CONFIG_PMC_MSP) += arch/mips/pmc-sierra/msp71xx/ -+cflags-$(CONFIG_PMC_MSP) += -Iinclude/asm-mips/pmc-sierra/msp71xx \ -+ -mno-branch-likely -+load-$(CONFIG_PMC_MSP) += 0xffffffff80100000 -+ -+# -+# PMC-Sierra Yosemite -+# -+core-$(CONFIG_PMC_YOSEMITE) += arch/mips/pmc-sierra/yosemite/ -+cflags-$(CONFIG_PMC_YOSEMITE) += -Iinclude/asm-mips/mach-yosemite -+load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000 -+ -+# -+# Qemu simulating MIPS32 4Kc -+# -+core-$(CONFIG_QEMU) += arch/mips/qemu/ -+cflags-$(CONFIG_QEMU) += -Iinclude/asm-mips/mach-qemu -+load-$(CONFIG_QEMU) += 0xffffffff80010000 -+all-$(CONFIG_QEMU) := vmlinux.bin -+ -+# -+# Basler eXcite -+# -+core-$(CONFIG_BASLER_EXCITE) += arch/mips/basler/excite/ -+cflags-$(CONFIG_BASLER_EXCITE) += -Iinclude/asm-mips/mach-excite -+load-$(CONFIG_BASLER_EXCITE) += 0x80100000 -+ -+# -+# LASAT platforms -+# -+core-$(CONFIG_LASAT) += arch/mips/lasat/ -+cflags-$(CONFIG_LASAT) += -Iinclude/asm-mips/mach-lasat -+load-$(CONFIG_LASAT) += 0xffffffff80000000 -+ -+# -+# Common VR41xx -+# -+core-$(CONFIG_MACH_VR41XX) += arch/mips/vr41xx/common/ -+cflags-$(CONFIG_MACH_VR41XX) += -Iinclude/asm-mips/mach-vr41xx -+ -+# -+# NEC VR4133 -+# -+core-$(CONFIG_NEC_CMBVR4133) += arch/mips/vr41xx/nec-cmbvr4133/ -+load-$(CONFIG_NEC_CMBVR4133) += 0xffffffff80100000 -+ -+# -+# ZAO Networks Capcella (VR4131) -+# -+load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000 -+ -+# -+# Victor MP-C303/304 (VR4122) -+# -+load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000 -+ -+# -+# IBM WorkPad z50 (VR4121) -+# -+core-$(CONFIG_IBM_WORKPAD) += arch/mips/vr41xx/ibm-workpad/ -+load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000 -+ -+# -+# CASIO CASSIPEIA E-55/65 (VR4111) -+# -+core-$(CONFIG_CASIO_E55) += arch/mips/vr41xx/casio-e55/ -+load-$(CONFIG_CASIO_E55) += 0xffffffff80004000 -+ -+# -+# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131) -+# -+load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000 -+ -+# -+# Common Philips PNX8550 -+# -+core-$(CONFIG_SOC_PNX8550) += arch/mips/philips/pnx8550/common/ -+cflags-$(CONFIG_SOC_PNX8550) += -Iinclude/asm-mips/mach-pnx8550 -+ -+# -+# Philips PNX8550 JBS board -+# -+libs-$(CONFIG_PNX8550_JBS) += arch/mips/philips/pnx8550/jbs/ -+#cflags-$(CONFIG_PNX8550_JBS) += -Iinclude/asm-mips/mach-pnx8550 -+load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000 -+ -+# Philips PNX8550 STB810 board -+# -+libs-$(CONFIG_PNX8550_STB810) += arch/mips/philips/pnx8550/stb810/ -+load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000 -+ -+# NEC EMMA2RH boards -+# -+core-$(CONFIG_EMMA2RH) += arch/mips/emma2rh/common/ -+cflags-$(CONFIG_EMMA2RH) += -Iinclude/asm-mips/mach-emma2rh -+ -+# NEC EMMA2RH Mark-eins -+core-$(CONFIG_MARKEINS) += arch/mips/emma2rh/markeins/ -+load-$(CONFIG_MARKEINS) += 0xffffffff88100000 -+ -+# -+# SGI IP22 (Indy/Indigo2) -+# -+# Set the load address to >= 0xffffffff88069000 if you want to leave space for -+# symmon, 0xffffffff80002000 for production kernels. Note that the value must -+# be aligned to a multiple of the kernel stack size or the handling of the -+# current variable will break so for 64-bit kernels we have to raise the start -+# address by 8kb. -+# -+core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/ -+cflags-$(CONFIG_SGI_IP22) += -Iinclude/asm-mips/mach-ip22 -+ifdef CONFIG_32BIT -+load-$(CONFIG_SGI_IP22) += 0xffffffff88002000 -+endif -+ifdef CONFIG_64BIT -+load-$(CONFIG_SGI_IP22) += 0xffffffff88004000 -+endif -+ -+# -+# SGI-IP27 (Origin200/2000) -+# -+# Set the load address to >= 0xc000000000300000 if you want to leave space for -+# symmon, 0xc00000000001c000 for production kernels. Note that the value must -+# be 16kb aligned or the handling of the current variable will break. -+# -+ifdef CONFIG_SGI_IP27 -+core-$(CONFIG_SGI_IP27) += arch/mips/sgi-ip27/ -+cflags-$(CONFIG_SGI_IP27) += -Iinclude/asm-mips/mach-ip27 -+ifdef CONFIG_MAPPED_KERNEL -+load-$(CONFIG_SGI_IP27) += 0xc00000004001c000 -+OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000 -+dataoffset-$(CONFIG_SGI_IP27) += 0x01000000 -+else -+load-$(CONFIG_SGI_IP27) += 0xa80000000001c000 -+OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000 -+endif -+endif -+ -+# -+# SGI-IP32 (O2) -+# -+# Set the load address to >= 80069000 if you want to leave space for symmon, -+# 0xffffffff80004000 for production kernels. Note that the value must be aligned to -+# a multiple of the kernel stack size or the handling of the current variable -+# will break. -+# -+core-$(CONFIG_SGI_IP32) += arch/mips/sgi-ip32/ -+cflags-$(CONFIG_SGI_IP32) += -Iinclude/asm-mips/mach-ip32 -+load-$(CONFIG_SGI_IP32) += 0xffffffff80004000 -+ -+# -+# Sibyte SB1250/BCM1480 SOC -+# -+# This is a LIB so that it links at the end, and initcalls are later -+# the sequence; but it is built as an object so that modules don't get -+# removed (as happens, even if they have __initcall/module_init) -+# -+core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/sb1250/ -+core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/common/ -+cflags-$(CONFIG_SIBYTE_BCM112X) += -Iinclude/asm-mips/mach-sibyte \ -+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL -+ -+core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/ -+core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/common/ -+cflags-$(CONFIG_SIBYTE_SB1250) += -Iinclude/asm-mips/mach-sibyte \ -+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL -+ -+core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/bcm1480/ -+core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/common/ -+cflags-$(CONFIG_SIBYTE_BCM1x55) += -Iinclude/asm-mips/mach-sibyte \ -+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL -+ -+core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/bcm1480/ -+core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/common/ -+cflags-$(CONFIG_SIBYTE_BCM1x80) += -Iinclude/asm-mips/mach-sibyte \ -+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL -+ -+# -+# Sibyte BCM91120x (Carmel) board -+# Sibyte BCM91120C (CRhine) board -+# Sibyte BCM91125C (CRhone) board -+# Sibyte BCM91125E (Rhone) board -+# Sibyte SWARM board -+# Sibyte BCM91x80 (BigSur) board -+# -+libs-$(CONFIG_SIBYTE_CARMEL) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_CRHINE) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_CRHONE) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_RHONE) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_SENTOSA) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_SWARM) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000 -+libs-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/ -+load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000 -+ -+# -+# Broadcom BCM47XX boards -+# -+core-$(CONFIG_BCM47XX) += arch/mips/bcm47xx/ -+cflags-$(CONFIG_BCM47XX) += -Iinclude/asm-mips/mach-bcm47xx -+load-$(CONFIG_BCM47XX) := 0xffffffff80001000 -+ -+# -+# SNI RM -+# -+core-$(CONFIG_SNI_RM) += arch/mips/sni/ -+cflags-$(CONFIG_SNI_RM) += -Iinclude/asm-mips/mach-rm -+load-$(CONFIG_SNI_RM) += 0xffffffff80600000 -+all-$(CONFIG_SNI_RM) := vmlinux.ecoff -+ -+# -+# Toshiba JMR-TX3927 board -+# -+core-$(CONFIG_TOSHIBA_JMR3927) += arch/mips/jmr3927/rbhma3100/ \ -+ arch/mips/jmr3927/common/ -+cflags-$(CONFIG_TOSHIBA_JMR3927) += -Iinclude/asm-mips/mach-jmr3927 -+load-$(CONFIG_TOSHIBA_JMR3927) += 0xffffffff80050000 -+ -+# -+# Toshiba RBTX4927 board or -+# Toshiba RBTX4937 board -+# -+core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/toshiba_rbtx4927/ -+core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/tx4927/common/ -+cflags-$(CONFIG_TOSHIBA_RBTX4927) += -Iinclude/asm-mips/mach-tx49xx -+load-$(CONFIG_TOSHIBA_RBTX4927) += 0xffffffff80020000 -+ -+# -+# Toshiba RBTX4938 board -+# -+core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/tx4938/toshiba_rbtx4938/ -+core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/tx4938/common/ -+cflags-$(CONFIG_TOSHIBA_RBTX4938) += -Iinclude/asm-mips/mach-tx49xx -+load-$(CONFIG_TOSHIBA_RBTX4938) += 0xffffffff80100000 -+ -+# temporary until string.h is fixed -+cflags-y += -ffreestanding -+ -+cflags-y += -Iinclude/asm-mips/mach-generic -+drivers-$(CONFIG_PCI) += arch/mips/pci/ -+ -+ifdef CONFIG_32BIT -+ifdef CONFIG_CPU_LITTLE_ENDIAN -+JIFFIES = jiffies_64 -+else -+JIFFIES = jiffies_64 + 4 -+endif -+else -+JIFFIES = jiffies_64 -+endif -+ -+# -+# Automatically detect the build format. By default we choose -+# the elf format according to the load address. -+# We can always force a build with a 64-bits symbol format by -+# passing 'KBUILD_SYM32=no' option to the make's command line. -+# -+ifdef CONFIG_64BIT -+ ifndef KBUILD_SYM32 -+ ifeq ($(shell expr $(load-y) \< 0xffffffff80000000), 0) -+ KBUILD_SYM32 = y -+ endif -+ endif -+ -+ ifeq ($(KBUILD_SYM32), y) -+ ifeq ($(call cc-option-yn,-msym32), y) -+ cflags-y += -msym32 -DKBUILD_64BIT_SYM32 -+ endif -+ endif -+endif -+ -+KBUILD_AFLAGS += $(cflags-y) -+KBUILD_CFLAGS += $(cflags-y) \ -+ -D"VMLINUX_LOAD_ADDRESS=$(load-y)" -+ -+LDFLAGS += -m $(ld-emul) -+ -+ifdef CONFIG_MIPS -+CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -xc /dev/null | \ -+ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ -+ sed -e 's/^\#define /-D/' -e "s/ /='/" -e "s/$$/'/") -+ifdef CONFIG_64BIT -+CHECKFLAGS += -m64 -+endif -+endif -+ -+OBJCOPYFLAGS += --remove-section=.reginfo -+ -+# -+# Choosing incompatible machines durings configuration will result in -+# error messages during linking. Select a default linkscript if -+# none has been choosen above. -+# -+ -+CPPFLAGS_vmlinux.lds := \ -+ $(KBUILD_CFLAGS) \ -+ -D"LOADADDR=$(load-y)" \ -+ -D"JIFFIES=$(JIFFIES)" \ -+ -D"DATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)" -+ -+head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o -+ -+libs-y += arch/mips/lib/ -+ -+core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/ -+ -+drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/ -+ -+ifdef CONFIG_LASAT -+rom.bin rom.sw: vmlinux -+ $(Q)$(MAKE) $(build)=arch/mips/lasat/image $@ -+endif -+ -+# -+# Some machines like the Indy need 32-bit ELF binaries for booting purposes. -+# Other need ECOFF, so we build a 32-bit ELF binary for them which we then -+# convert to ECOFF using elf2ecoff. -+# -+vmlinux.32: vmlinux -+ $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@ -+ -+# -+# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit -+# ELF files from 32-bit files by conversion. -+# -+vmlinux.64: vmlinux -+ $(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@ -+ -+makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1) -+ -+all: $(all-y) -+ -+vmlinux.bin: $(vmlinux-32) -+ +@$(call makeboot,$@) -+ -+vmlinux.ecoff: $(vmlinux-32) -+ +@$(call makeboot,$@) -+ -+vmlinux.srec: $(vmlinux-32) -+ +@$(call makeboot,$@) -+ -+CLEAN_FILES += vmlinux.ecoff \ -+ vmlinux.srec -+ -+archprepare: -+ifdef CONFIG_MIPS32_N32 -+ @echo ' Checking missing-syscalls for N32' -+ $(Q)$(MAKE) $(build)=. missing-syscalls EXTRA_CFLAGS="-mabi=n32" -+endif -+ifdef CONFIG_MIPS32_O32 -+ @echo ' Checking missing-syscalls for O32' -+ $(Q)$(MAKE) $(build)=. missing-syscalls EXTRA_CFLAGS="-mabi=32" -+endif -+ -+archclean: -+ @$(MAKE) $(clean)=arch/mips/boot -+ @$(MAKE) $(clean)=arch/mips/lasat -+ -+define archhelp -+ echo ' vmlinux.ecoff - ECOFF boot image' -+ echo ' vmlinux.bin - Raw binary boot image' -+ echo ' vmlinux.srec - SREC boot image' -+ echo -+ echo ' These will be default as apropriate for a configured platform.' -+endef -+ -+CLEAN_FILES += vmlinux.32 \ -+ vmlinux.64 \ -+ vmlinux.ecoff -diff -urN linux-2.6.24.7.old/arch/mips/boot/Makefile linux-2.6.24.7/arch/mips/boot/Makefile ---- linux-2.6.24.7.old/arch/mips/boot/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/boot/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -7,6 +7,9 @@ - # Copyright (C) 2004 Maciej W. Rozycki - # - -+# This one must match the LOADADDR in arch/mips/Makefile! -+LOADADDR=0x80010000 -+ - # - # Some DECstations need all possible sections of an ECOFF executable - # -@@ -25,7 +28,7 @@ - - VMLINUX = vmlinux - --all: vmlinux.ecoff vmlinux.srec addinitrd -+all: vmlinux.ecoff vmlinux.srec addinitrd uImage zImage - - vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX) - $(obj)/elf2ecoff $(VMLINUX) vmlinux.ecoff $(E2EFLAGS) -@@ -42,8 +45,24 @@ - $(obj)/addinitrd: $(obj)/addinitrd.c - $(HOSTCC) -o $@ $^ - -+uImage: $(VMLINUX) vmlinux.bin -+ rm -f $(obj)/vmlinux.bin.gz -+ gzip -9 $(obj)/vmlinux.bin -+ mkimage -A mips -O linux -T kernel -C gzip \ -+ -a $(LOADADDR) -e $(shell sh ./$(obj)/tools/entry $(NM) $(VMLINUX) ) \ -+ -n 'Linux-$(KERNELRELEASE)' \ -+ -d $(obj)/vmlinux.bin.gz $(obj)/uImage -+ @echo ' Kernel: arch/mips/boot/$@ is ready' -+ -+zImage: -+ $(Q)$(MAKE) $(build)=$(obj)/compressed loadaddr=$(LOADADDR) $@ -+ @echo ' Kernel: arch/mips/boot/compressed/$@ is ready' -+ - clean-files += addinitrd \ - elf2ecoff \ - vmlinux.bin \ - vmlinux.ecoff \ -- vmlinux.srec -+ vmlinux.srec \ -+ vmlinux.bin.gz \ -+ uImage \ -+ zImage -diff -urN linux-2.6.24.7.old/arch/mips/boot/compressed/Makefile linux-2.6.24.7/arch/mips/boot/compressed/Makefile ---- linux-2.6.24.7.old/arch/mips/boot/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/compressed/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,42 @@ -+# -+# linux/arch/mips/boot/compressed/Makefile -+# -+# create a compressed zImage from the original vmlinux -+# -+ -+targets := zImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o -+ -+OBJS := $(obj)/head.o $(obj)/misc.o -+ -+LD_ARGS := -T $(obj)/ld.script -Ttext 0x80600000 -Bstatic -+OBJCOPY_ARGS := -O elf32-tradlittlemips -+ -+ENTRY := $(obj)/../tools/entry -+FILESIZE := $(obj)/../tools/filesize -+ -+drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options -+strip-flags = $(addprefix --remove-section=,$(drop-sections)) -+ -+ -+$(obj)/vmlinux.bin.gz: vmlinux -+ rm -f $(obj)/vmlinux.bin.gz -+ $(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin -+ gzip -v9f $(obj)/vmlinux.bin -+ -+$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux -+ $(CC) $(KBUILD_AFLAGS) \ -+ -DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \ -+ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \ -+ -DLOADADDR=$(loadaddr) \ -+ -c -o $(obj)/head.o $< -+ -+$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o -+ $(OBJCOPY) \ -+ --add-section=.image=$(obj)/vmlinux.bin.gz \ -+ --set-section-flags=.image=contents,alloc,load,readonly,data \ -+ $(obj)/dummy.o $(obj)/piggy.o -+ $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o -+ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap -+ -+zImage: $(obj)/vmlinuz -+ $(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage -diff -urN linux-2.6.24.7.old/arch/mips/boot/compressed/dummy.c linux-2.6.24.7/arch/mips/boot/compressed/dummy.c ---- linux-2.6.24.7.old/arch/mips/boot/compressed/dummy.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/compressed/dummy.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,4 @@ -+int main(void) -+{ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/arch/mips/boot/compressed/head.S linux-2.6.24.7/arch/mips/boot/compressed/head.S ---- linux-2.6.24.7.old/arch/mips/boot/compressed/head.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/compressed/head.S 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+/* -+ * linux/arch/mips/boot/compressed/head.S -+ * -+ * Copyright (C) 2005-2008 Ingenic Semiconductor Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#define IndexInvalidate_I 0x00 -+#define IndexWriteBack_D 0x01 -+ -+ .set noreorder -+ LEAF(startup) -+startup: -+ move s0, a0 /* Save the boot loader transfered args */ -+ move s1, a1 -+ move s2, a2 -+ move s3, a3 -+ -+ la a0, _edata -+ la a1, _end -+1: sw zero, 0(a0) /* Clear BSS section */ -+ bne a1, a0, 1b -+ addu a0, 4 -+ -+ la sp, (.stack + 8192) -+ -+ la a0, __image_begin -+ la a1, IMAGESIZE -+ la a2, LOADADDR -+ la ra, 1f -+ la k0, decompress_kernel -+ jr k0 -+ nop -+1: -+ -+ move a0, s0 -+ move a1, s1 -+ move a2, s2 -+ move a3, s3 -+ li k0, KERNEL_ENTRY -+ jr k0 -+ nop -+2: -+ b 32 -+ END(startup) -+ -+ -+ LEAF(flushcaches) -+ la t0, 1f -+ la t1, 0xa0000000 -+ or t0, t0, t1 -+ jr t0 -+ nop -+1: -+ li k0, 0x80000000 # start address -+ li k1, 0x80004000 # end address (16KB I-Cache) -+ subu k1, 128 -+ -+2: -+ .set mips3 -+ cache IndexWriteBack_D, 0(k0) -+ cache IndexWriteBack_D, 32(k0) -+ cache IndexWriteBack_D, 64(k0) -+ cache IndexWriteBack_D, 96(k0) -+ cache IndexInvalidate_I, 0(k0) -+ cache IndexInvalidate_I, 32(k0) -+ cache IndexInvalidate_I, 64(k0) -+ cache IndexInvalidate_I, 96(k0) -+ .set mips0 -+ -+ bne k0, k1, 2b -+ addu k0, k0, 128 -+ la t0, 3f -+ jr t0 -+ nop -+3: -+ jr ra -+ nop -+ END(flushcaches) -+ -+ .comm .stack,4096*2,4 -diff -urN linux-2.6.24.7.old/arch/mips/boot/compressed/ld.script linux-2.6.24.7/arch/mips/boot/compressed/ld.script ---- linux-2.6.24.7.old/arch/mips/boot/compressed/ld.script 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/compressed/ld.script 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,151 @@ -+OUTPUT_ARCH(mips) -+ENTRY(startup) -+SECTIONS -+{ -+ /* Read-only sections, merged into text segment: */ -+ -+ .init : { *(.init) } =0 -+ .text : -+ { -+ _ftext = . ; -+ *(.text) -+ *(.rodata) -+ *(.rodata1) -+ /* .gnu.warning sections are handled specially by elf32.em. */ -+ *(.gnu.warning) -+ } =0 -+ .kstrtab : { *(.kstrtab) } -+ -+ . = ALIGN(16); /* Exception table */ -+ __start___ex_table = .; -+ __ex_table : { *(__ex_table) } -+ __stop___ex_table = .; -+ -+ __start___dbe_table = .; /* Exception table for data bus errors */ -+ __dbe_table : { *(__dbe_table) } -+ __stop___dbe_table = .; -+ -+ __start___ksymtab = .; /* Kernel symbol table */ -+ __ksymtab : { *(__ksymtab) } -+ __stop___ksymtab = .; -+ -+ _etext = .; -+ -+ . = ALIGN(8192); -+ .data.init_task : { *(.data.init_task) } -+ -+ /* Startup code */ -+ . = ALIGN(4096); -+ __init_begin = .; -+ .text.init : { *(.text.init) } -+ .data.init : { *(.data.init) } -+ . = ALIGN(16); -+ __setup_start = .; -+ .setup.init : { *(.setup.init) } -+ __setup_end = .; -+ __initcall_start = .; -+ .initcall.init : { *(.initcall.init) } -+ __initcall_end = .; -+ . = ALIGN(4096); /* Align double page for init_task_union */ -+ __init_end = .; -+ -+ . = ALIGN(4096); -+ .data.page_aligned : { *(.data.idt) } -+ -+ . = ALIGN(32); -+ .data.cacheline_aligned : { *(.data.cacheline_aligned) } -+ -+ .fini : { *(.fini) } =0 -+ .reginfo : { *(.reginfo) } -+ /* Adjust the address for the data segment. We want to adjust up to -+ the same address within the page on the next page up. It would -+ be more correct to do this: -+ . = .; -+ The current expression does not correctly handle the case of a -+ text segment ending precisely at the end of a page; it causes the -+ data segment to skip a page. The above expression does not have -+ this problem, but it will currently (2/95) cause BFD to allocate -+ a single segment, combining both text and data, for this case. -+ This will prevent the text segment from being shared among -+ multiple executions of the program; I think that is more -+ important than losing a page of the virtual address space (note -+ that no actual memory is lost; the page which is skipped can not -+ be referenced). */ -+ . = .; -+ .data : -+ { -+ _fdata = . ; -+ *(.data) -+ -+ /* Put the compressed image here, so bss is on the end. */ -+ __image_begin = .; -+ *(.image) -+ __image_end = .; -+ /* Align the initial ramdisk image (INITRD) on page boundaries. */ -+ . = ALIGN(4096); -+ __ramdisk_begin = .; -+ *(.initrd) -+ __ramdisk_end = .; -+ . = ALIGN(4096); -+ -+ CONSTRUCTORS -+ } -+ .data1 : { *(.data1) } -+ _gp = . + 0x8000; -+ .lit8 : { *(.lit8) } -+ .lit4 : { *(.lit4) } -+ .ctors : { *(.ctors) } -+ .dtors : { *(.dtors) } -+ .got : { *(.got.plt) *(.got) } -+ .dynamic : { *(.dynamic) } -+ /* We want the small data sections together, so single-instruction offsets -+ can access them all, and initialized data all before uninitialized, so -+ we can shorten the on-disk segment size. */ -+ .sdata : { *(.sdata) } -+ . = ALIGN(4); -+ _edata = .; -+ PROVIDE (edata = .); -+ -+ __bss_start = .; -+ _fbss = .; -+ .sbss : { *(.sbss) *(.scommon) } -+ .bss : -+ { -+ *(.dynbss) -+ *(.bss) -+ *(COMMON) -+ . = ALIGN(4); -+ _end = . ; -+ PROVIDE (end = .); -+ } -+ -+ /* Sections to be discarded */ -+ /DISCARD/ : -+ { -+ *(.text.exit) -+ *(.data.exit) -+ *(.exitcall.exit) -+ } -+ -+ /* This is the MIPS specific mdebug section. */ -+ .mdebug : { *(.mdebug) } -+ /* These are needed for ELF backends which have not yet been -+ converted to the new style linker. */ -+ .stab 0 : { *(.stab) } -+ .stabstr 0 : { *(.stabstr) } -+ /* DWARF debug sections. -+ Symbols in the .debug DWARF section are relative to the beginning of the -+ section so we begin .debug at 0. It's not clear yet what needs to happen -+ for the others. */ -+ .debug 0 : { *(.debug) } -+ .debug_srcinfo 0 : { *(.debug_srcinfo) } -+ .debug_aranges 0 : { *(.debug_aranges) } -+ .debug_pubnames 0 : { *(.debug_pubnames) } -+ .debug_sfnames 0 : { *(.debug_sfnames) } -+ .line 0 : { *(.line) } -+ /* These must appear regardless of . */ -+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } -+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } -+ .comment : { *(.comment) } -+ .note : { *(.note) } -+} -diff -urN linux-2.6.24.7.old/arch/mips/boot/compressed/misc.c linux-2.6.24.7/arch/mips/boot/compressed/misc.c ---- linux-2.6.24.7.old/arch/mips/boot/compressed/misc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/compressed/misc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,242 @@ -+/* -+ * linux/arch/mips/boot/compressed/misc.c -+ * -+ * This is a collection of several routines from gzip-1.0.3 -+ * adapted for Linux. -+ * -+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 -+ * -+ * Adapted for JZSOC by Peter Wei, 2008 -+ * -+ */ -+ -+#define size_t int -+#define NULL 0 -+ -+/* -+ * gzip declarations -+ */ -+ -+#define OF(args) args -+#define STATIC static -+ -+#undef memset -+#undef memcpy -+#define memzero(s, n) memset ((s), 0, (n)) -+ -+typedef unsigned char uch; -+typedef unsigned short ush; -+typedef unsigned long ulg; -+ -+#define WSIZE 0x8000 /* Window size must be at least 32k, */ -+ /* and a power of two */ -+ -+static uch *inbuf; /* input buffer */ -+static uch window[WSIZE]; /* Sliding window buffer */ -+ -+static unsigned insize = 0; /* valid bytes in inbuf */ -+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ -+static unsigned outcnt = 0; /* bytes in output buffer */ -+ -+/* gzip flag byte */ -+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ -+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ -+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -+#define COMMENT 0x10 /* bit 4 set: file comment present */ -+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ -+#define RESERVED 0xC0 /* bit 6,7: reserved */ -+ -+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) -+ -+/* Diagnostic functions */ -+#ifdef DEBUG -+# define Assert(cond,msg) {if(!(cond)) error(msg);} -+# define Trace(x) fprintf x -+# define Tracev(x) {if (verbose) fprintf x ;} -+# define Tracevv(x) {if (verbose>1) fprintf x ;} -+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -+#else -+# define Assert(cond,msg) -+# define Trace(x) -+# define Tracev(x) -+# define Tracevv(x) -+# define Tracec(c,x) -+# define Tracecv(c,x) -+#endif -+ -+static int fill_inbuf(void); -+static void flush_window(void); -+static void error(char *m); -+static void gzip_mark(void **); -+static void gzip_release(void **); -+ -+void* memset(void* s, int c, size_t n); -+void* memcpy(void* __dest, __const void* __src, size_t __n); -+ -+extern void flushcaches(void); /* defined in head.S */ -+ -+char *input_data; -+int input_len; -+ -+static long bytes_out = 0; -+static uch *output_data; -+static unsigned long output_ptr = 0; -+ -+ -+static void *malloc(int size); -+static void free(void *where); -+static void error(char *m); -+static void gzip_mark(void **); -+static void gzip_release(void **); -+ -+static void puts(const char *str) -+{ -+} -+ -+extern unsigned char _end[]; -+static unsigned long free_mem_ptr; -+static unsigned long free_mem_end_ptr; -+ -+#define HEAP_SIZE 0x10000 -+ -+#include "../../../../lib/inflate.c" -+ -+static void *malloc(int size) -+{ -+ void *p; -+ -+ if (size <0) error("Malloc error\n"); -+ if (free_mem_ptr == 0) error("Memory error\n"); -+ -+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ -+ -+ p = (void *)free_mem_ptr; -+ free_mem_ptr += size; -+ -+ if (free_mem_ptr >= free_mem_end_ptr) -+ error("\nOut of memory\n"); -+ -+ return p; -+} -+ -+static void free(void *where) -+{ /* Don't care */ -+} -+ -+static void gzip_mark(void **ptr) -+{ -+ *ptr = (void *) free_mem_ptr; -+} -+ -+static void gzip_release(void **ptr) -+{ -+ free_mem_ptr = (long) *ptr; -+} -+ -+void* memset(void* s, int c, size_t n) -+{ -+ int i; -+ char *ss = (char*)s; -+ -+ for (i=0;i> 3; i > 0; i--) { -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ } -+ -+ if (__n & 1 << 2) { -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ *d++ = *s++; -+ } -+ -+ if (__n & 1 << 1) { -+ *d++ = *s++; -+ *d++ = *s++; -+ } -+ -+ if (__n & 1) -+ *d++ = *s++; -+ -+ return __dest; -+} -+ -+/* =========================================================================== -+ * Fill the input buffer. This is called only when the buffer is empty -+ * and at least one byte is really needed. -+ */ -+static int fill_inbuf(void) -+{ -+ if (insize != 0) { -+ error("ran out of input data\n"); -+ } -+ -+ inbuf = input_data; -+ insize = input_len; -+ inptr = 1; -+ return inbuf[0]; -+} -+ -+/* =========================================================================== -+ * Write the output window window[0..outcnt-1] and update crc and bytes_out. -+ * (Used for the decompressed data only.) -+ */ -+static void flush_window(void) -+{ -+ ulg c = crc; /* temporary variable */ -+ unsigned n; -+ uch *in, *out, ch; -+ -+ in = window; -+ out = &output_data[output_ptr]; -+ for (n = 0; n < outcnt; n++) { -+ ch = *out++ = *in++; -+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); -+ } -+ crc = c; -+ bytes_out += (ulg)outcnt; -+ output_ptr += (ulg)outcnt; -+ outcnt = 0; -+} -+ -+static void error(char *x) -+{ -+ puts("\n\n"); -+ puts(x); -+ puts("\n\n -- System halted"); -+ -+ while(1); /* Halt */ -+} -+ -+void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr) -+{ -+ input_data = (char *)imageaddr; -+ input_len = imagesize; -+ output_ptr = 0; -+ output_data = (uch *)loadaddr; -+ free_mem_ptr = (unsigned long)_end; -+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; -+ -+ makecrc(); -+ puts("Uncompressing Linux..."); -+ gunzip(); -+ flushcaches(); -+ puts("Ok, booting the kernel."); -+} -diff -urN linux-2.6.24.7.old/arch/mips/boot/tools/entry linux-2.6.24.7/arch/mips/boot/tools/entry ---- linux-2.6.24.7.old/arch/mips/boot/tools/entry 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/tools/entry 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,12 @@ -+#!/bin/sh -+ -+# grab the kernel_entry address from the vmlinux elf image -+entry=`$1 $2 | grep kernel_entry` -+ -+fs=`echo $entry | grep ffffffff` # check toolchain output -+ -+if [ -n "$fs" ]; then -+ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'` -+else -+ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'` -+fi -diff -urN linux-2.6.24.7.old/arch/mips/boot/tools/filesize linux-2.6.24.7/arch/mips/boot/tools/filesize ---- linux-2.6.24.7.old/arch/mips/boot/tools/filesize 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/boot/tools/filesize 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,7 @@ -+#!/bin/sh -+HOSTNAME=`uname` -+if [ "$HOSTNAME" = "Linux" ]; then -+echo `ls -l $1 | awk '{print $5}'` -+else -+echo `ls -l $1 | awk '{print $6}'` -+fi -diff -urN linux-2.6.24.7.old/arch/mips/configs/apus_defconfig linux-2.6.24.7/arch/mips/configs/apus_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/apus_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/apus_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1205 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Fri Dec 12 17:16:48 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+CONFIG_JZ4750_APUS=y -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4750=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+CONFIG_FORCE_MAX_ZONEORDER=12 -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+# CONFIG_SUSPEND is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+CONFIG_INET_DIAG=m -+CONFIG_INET_TCP_DIAG=m -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4750=y -+# CONFIG_MTD_NAND_CS2 is not set -+# CONFIG_MTD_NAND_CS3 is not set -+# CONFIG_MTD_NAND_CS4 is not set -+CONFIG_MTD_NAND_MULTI_PLANE=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+# CONFIG_MTD_HW_RS_ECC is not set -+CONFIG_MTD_HW_BCH_ECC=y -+CONFIG_MTD_HW_BCH_4BIT=y -+# CONFIG_MTD_HW_BCH_8BIT is not set -+CONFIG_MTD_NAND_DMA=y -+# CONFIG_MTD_NAND_DMABUF is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+# CONFIG_MTD_UBI is not set -+# CONFIG_MTD_UBI_BLKDEVS is not set -+# CONFIG_PARPORT is not set -+# CONFIG_PNP is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZCS8900=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+# CONFIG_NETDEV_1000 is not set -+# CONFIG_NETDEV_10000 is not set -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_CATC is not set -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_RTL8150 is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+CONFIG_KEYBOARD_ATKBD=y -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+# CONFIG_KEYBOARD_JZ is not set -+# CONFIG_KEYBOARD_GPIO is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+CONFIG_SERIO_LIBPS2=y -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_NR_UARTS=4 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+# CONFIG_RTC_JZ is not set -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+CONFIG_JZ_SADC=y -+# CONFIG_JZ_TPANEL_AK4182 is not set -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+# CONFIG_JZ_UDC_HOTPLUG is not set -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+CONFIG_JZ_TCSM=y -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_WATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+CONFIG_FB_JZ4750_TVE=y -+# CONFIG_IPU_JZ4750 is not set -+CONFIG_FB_JZ4750_LCD=y -+# CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER is not set -+# CONFIG_FB_JZ4750_SLCD is not set -+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF01 is not set -+# CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02 is not set -+CONFIG_JZ4750_LCD_AUO_A043FL01V2=y -+# CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set -+# CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT is not set -+# CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W is not set -+# CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+# CONFIG_SND is not set -+ -+# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=y -+CONFIG_OSS_OBSOLETE=y -+# CONFIG_SOUND_JZ_AC97 is not set -+CONFIG_SOUND_JZ_I2S=y -+# CONFIG_SOUND_JZ_PCM is not set -+# CONFIG_I2S_AK4642EN is not set -+# CONFIG_I2S_ICODEC is not set -+CONFIG_I2S_DLV=y -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+CONFIG_USB_HIDDEV=y -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+# CONFIG_USB_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MSC0_JZ4750=y -+# CONFIG_JZ4750_MSC0_BUS_1 is not set -+CONFIG_JZ4750_MSC0_BUS_4=y -+# CONFIG_JZ4750_MSC0_BUS_8 is not set -+# CONFIG_MSC1_JZ4750 is not set -+# CONFIG_JZ4750_BOOT_FROM_MSC0 is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_LZO is not set -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+# CONFIG_CRC16 is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/dipper_defconfig linux-2.6.24.7/arch/mips/configs/dipper_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/dipper_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/dipper_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1281 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Thu Jun 12 13:55:45 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+CONFIG_JZ4725_DIPPER=y -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4740=y -+CONFIG_SOC_JZ4725=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+# CONFIG_SUSPEND is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4740=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+CONFIG_MTD_HW_RS_ECC=y -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=256 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+# CONFIG_MTD_UBI_GLUEBI is not set -+ -+# -+# UBI debugging options -+# -+# CONFIG_MTD_UBI_DEBUG is not set -+CONFIG_MTD_UBI_BLKDEVS=m -+CONFIG_MTD_UBI_BLOCK=m -+# CONFIG_PARPORT is not set -+CONFIG_PNP=y -+# CONFIG_PNP_DEBUG is not set -+ -+# -+# Protocols -+# -+# CONFIG_PNPACPI is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=2 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_NET_SB1000 is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZCS8900=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+# CONFIG_NETDEV_1000 is not set -+# CONFIG_NETDEV_10000 is not set -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_CATC is not set -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_RTL8150 is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_PNP=y -+CONFIG_SERIAL_8250_NR_UARTS=2 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+CONFIG_RTC_JZ=y -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+CONFIG_JZ_SADC=y -+# CONFIG_JZ_TPANEL_AK4182 is not set -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L1=y -+CONFIG_VIDEO_V4L1_COMPAT=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -+# CONFIG_VIDEO_VIVI is not set -+# CONFIG_VIDEO_CPIA is not set -+# CONFIG_VIDEO_CPIA2 is not set -+CONFIG_VIDEO_JZ_CIM=y -+CONFIG_VIDEO_JZ_SENSOR=y -+CONFIG_V4L_USB_DRIVERS=y -+# CONFIG_USB_VICAM is not set -+# CONFIG_USB_IBMCAM is not set -+# CONFIG_USB_KONICAWC is not set -+# CONFIG_USB_QUICKCAM_MESSENGER is not set -+# CONFIG_USB_ET61X251 is not set -+# CONFIG_USB_OV511 is not set -+# CONFIG_USB_SE401 is not set -+# CONFIG_USB_SN9C102 is not set -+# CONFIG_USB_STV680 is not set -+# CONFIG_USB_ZC0301 is not set -+# CONFIG_USB_PWC is not set -+# CONFIG_USB_ZR364XX is not set -+CONFIG_RADIO_ADAPTERS=y -+# CONFIG_USB_DSBR is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+# CONFIG_FB_JZ4740_SLCD is not set -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set -+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y -+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+# CONFIG_SND is not set -+ -+# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=y -+CONFIG_OSS_OBSOLETE=y -+# CONFIG_SOUND_JZ_AC97 is not set -+CONFIG_SOUND_JZ_I2S=y -+# CONFIG_SOUND_JZ_PCM is not set -+# CONFIG_I2S_AK4642EN is not set -+CONFIG_I2S_ICODEC=y -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+# CONFIG_USB_HIDDEV is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+CONFIG_USB_GADGET_JZ4740=y -+CONFIG_USB_JZ4740=m -+# CONFIG_USB_GADGET_JZ4730 is not set -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_JZ=y -+# CONFIG_JZ_MMC_BUS_4 is not set -+CONFIG_JZ_MMC_BUS_1=y -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+CONFIG_UBIFS_FS=m -+# CONFIG_UBIFS_FS_XATTR is not set -+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -+CONFIG_UBIFS_FS_LZO=y -+CONFIG_UBIFS_FS_ZLIB=y -+# CONFIG_UBIFS_FS_DEBUG is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_LZO=m -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=m -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=m -+CONFIG_ZLIB_DEFLATE=m -+CONFIG_LZO_COMPRESS=m -+CONFIG_LZO_DECOMPRESS=m -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/fuwa_defconfig linux-2.6.24.7/arch/mips/configs/fuwa_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/fuwa_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/fuwa_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,928 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Fri Jul 4 19:20:22 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+CONFIG_JZ4750_FUWA=y -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4750=y -+CONFIG_JZ_FPGA=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ_JZ is not set -+ -+# -+# Power management options -+# -+# CONFIG_PM is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+CONFIG_INET_DIAG=m -+CONFIG_INET_TCP_DIAG=m -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+# CONFIG_WIRELESS_EXT is not set -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+CONFIG_MTD_NAND_JZ4750=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+# CONFIG_MTD_HW_RS_ECC is not set -+CONFIG_MTD_HW_BCH_ECC=y -+CONFIG_MTD_NAND_DMA=y -+# CONFIG_MTD_NAND_NO_DMA is not set -+CONFIG_MTD_HW_BCH_4BIT=y -+# CONFIG_MTD_HW_BCH_8BIT is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=0 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+# CONFIG_MTD_UBI is not set -+# CONFIG_MTD_UBI_BLKDEVS is not set -+# CONFIG_PARPORT is not set -+# CONFIG_PNP is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+# CONFIG_SCSI is not set -+# CONFIG_SCSI_DMA is not set -+# CONFIG_SCSI_NETLINK is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZ_ETH=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+CONFIG_NETDEV_1000=y -+CONFIG_NETDEV_10000=y -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_NR_UARTS=4 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+# CONFIG_RTC_JZ is not set -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+# CONFIG_JZCHAR is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_WATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+ -+# -+# Sound -+# -+# CONFIG_SOUND is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# USB Gadget Support -+# -+# CONFIG_USB_GADGET is not set -+# CONFIG_MMC is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_LZO is not set -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+# CONFIG_CRC16 is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/leo_defconfig linux-2.6.24.7/arch/mips/configs/leo_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/leo_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/leo_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1256 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Thu Jun 12 13:59:18 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+CONFIG_JZ4740_LEO=y -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4740=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+CONFIG_KALLSYMS_ALL=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+# CONFIG_SUSPEND is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+CONFIG_MTD_CONCAT=y -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+CONFIG_MTD_BLOCK2MTD=y -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4740=y -+# CONFIG_MTD_HW_HM_ECC is not set -+CONFIG_MTD_SW_HM_ECC=y -+# CONFIG_MTD_HW_RS_ECC is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=4096 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+# CONFIG_MTD_UBI_GLUEBI is not set -+ -+# -+# UBI debugging options -+# -+# CONFIG_MTD_UBI_DEBUG is not set -+CONFIG_MTD_UBI_BLKDEVS=m -+CONFIG_MTD_UBI_BLOCK=m -+# CONFIG_PARPORT is not set -+CONFIG_PNP=y -+# CONFIG_PNP_DEBUG is not set -+ -+# -+# Protocols -+# -+# CONFIG_PNPACPI is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=2 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_NETDEVICES is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_PNP=y -+CONFIG_SERIAL_8250_NR_UARTS=2 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+CONFIG_RTC_JZ=y -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+CONFIG_JZ_SADC=y -+# CONFIG_JZ_TPANEL_AK4182 is not set -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L1=y -+CONFIG_VIDEO_V4L1_COMPAT=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -+# CONFIG_VIDEO_VIVI is not set -+# CONFIG_VIDEO_CPIA is not set -+# CONFIG_VIDEO_CPIA2 is not set -+CONFIG_VIDEO_JZ_CIM=y -+CONFIG_VIDEO_JZ_SENSOR=y -+CONFIG_V4L_USB_DRIVERS=y -+# CONFIG_USB_VICAM is not set -+# CONFIG_USB_IBMCAM is not set -+# CONFIG_USB_KONICAWC is not set -+# CONFIG_USB_QUICKCAM_MESSENGER is not set -+# CONFIG_USB_ET61X251 is not set -+# CONFIG_USB_OV511 is not set -+# CONFIG_USB_SE401 is not set -+# CONFIG_USB_SN9C102 is not set -+# CONFIG_USB_STV680 is not set -+# CONFIG_USB_ZC0301 is not set -+# CONFIG_USB_PWC is not set -+# CONFIG_USB_ZR364XX is not set -+CONFIG_RADIO_ADAPTERS=y -+# CONFIG_USB_DSBR is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+# CONFIG_FB_JZ4740_SLCD is not set -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set -+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y -+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+CONFIG_SND=y -+CONFIG_SND_TIMER=y -+CONFIG_SND_PCM=y -+# CONFIG_SND_SEQUENCER is not set -+CONFIG_SND_OSSEMUL=y -+CONFIG_SND_MIXER_OSS=y -+CONFIG_SND_PCM_OSS=y -+CONFIG_SND_PCM_OSS_PLUGINS=y -+# CONFIG_SND_DYNAMIC_MINORS is not set -+CONFIG_SND_SUPPORT_OLD_API=y -+CONFIG_SND_VERBOSE_PROCFS=y -+# CONFIG_SND_VERBOSE_PRINTK is not set -+# CONFIG_SND_DEBUG is not set -+ -+# -+# Generic devices -+# -+# CONFIG_SND_DUMMY is not set -+# CONFIG_SND_MTPAV is not set -+# CONFIG_SND_SERIAL_U16550 is not set -+# CONFIG_SND_MPU401 is not set -+ -+# -+# ALSA MIPS devices -+# -+ -+# -+# USB devices -+# -+# CONFIG_SND_USB_AUDIO is not set -+# CONFIG_SND_USB_CAIAQ is not set -+ -+# -+# System on Chip audio support -+# -+CONFIG_SND_SOC=y -+ -+# -+# SoC Audio support for SuperH -+# -+ -+# -+# Open Sound System -+# -+# CONFIG_SOUND_PRIME is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+# CONFIG_USB_HIDDEV is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+CONFIG_USB_GADGET_JZ4740=y -+CONFIG_USB_JZ4740=m -+# CONFIG_USB_GADGET_JZ4730 is not set -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+CONFIG_USB_FILE_STORAGE_TEST=y -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_JZ=y -+CONFIG_JZ_MMC_BUS_4=y -+# CONFIG_JZ_MMC_BUS_1 is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+CONFIG_UBIFS_FS=m -+# CONFIG_UBIFS_FS_XATTR is not set -+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -+CONFIG_UBIFS_FS_LZO=y -+CONFIG_UBIFS_FS_ZLIB=y -+CONFIG_UBIFS_FS_DEBUG=y -+CONFIG_UBIFS_FS_DEBUG_MSG_LVL=0 -+# CONFIG_UBIFS_FS_DEBUG_CHKS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_LZO=m -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=m -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=m -+CONFIG_ZLIB_DEFLATE=m -+CONFIG_LZO_COMPRESS=m -+CONFIG_LZO_DECOMPRESS=m -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/lyra_defconfig linux-2.6.24.7/arch/mips/configs/lyra_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/lyra_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/lyra_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,981 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Thu Jun 12 13:53:57 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+CONFIG_JZ4740_LYRA=y -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4740=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+CONFIG_KALLSYMS_ALL=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_PM_SLEEP=y -+CONFIG_SUSPEND_UP_POSSIBLE=y -+CONFIG_SUSPEND=y -+ -+# -+# Networking -+# -+# CONFIG_NET is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+CONFIG_MTD_CONCAT=y -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+CONFIG_MTD_BLOCK2MTD=y -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+CONFIG_MTD_NAND_JZ4740=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+CONFIG_MTD_HW_RS_ECC=y -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=4096 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+CONFIG_MTD_UBI_GLUEBI=y -+ -+# -+# UBI debugging options -+# -+# CONFIG_MTD_UBI_DEBUG is not set -+# CONFIG_MTD_UBI_BLKDEVS is not set -+# CONFIG_PARPORT is not set -+# CONFIG_PNP is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_NR_UARTS=4 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=256 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+CONFIG_RTC_JZ=y -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+CONFIG_JZ_TPANEL_ATA2508=y -+# CONFIG_JZ_TPANEL is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+# CONFIG_FB_JZ4740_SLCD is not set -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set -+CONFIG_JZLCD_AUO_A030FL01_V1=y -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+# CONFIG_SND is not set -+ -+# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=y -+CONFIG_OSS_OBSOLETE=y -+# CONFIG_SOUND_JZ_AC97 is not set -+CONFIG_SOUND_JZ_I2S=y -+# CONFIG_SOUND_JZ_PCM is not set -+# CONFIG_I2S_AK4642EN is not set -+CONFIG_I2S_ICODEC=y -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+# CONFIG_USB is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+CONFIG_USB_GADGET_DEBUG_FILES=y -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+CONFIG_USB_GADGET_JZ4740=y -+CONFIG_USB_JZ4740=m -+# CONFIG_USB_GADGET_JZ4730 is not set -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+CONFIG_USB_G_SERIAL=m -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+# CONFIG_MMC_JZ is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+CONFIG_EXT3_FS=y -+CONFIG_EXT3_FS_XATTR=y -+# CONFIG_EXT3_FS_POSIX_ACL is not set -+# CONFIG_EXT3_FS_SECURITY is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_JBD=y -+# CONFIG_JBD_DEBUG is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+CONFIG_UBIFS_FS=m -+# CONFIG_UBIFS_FS_XATTR is not set -+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -+CONFIG_UBIFS_FS_LZO=y -+CONFIG_UBIFS_FS_ZLIB=y -+CONFIG_UBIFS_FS_DEBUG=y -+CONFIG_UBIFS_FS_DEBUG_MSG_LVL=0 -+# CONFIG_UBIFS_FS_DEBUG_CHKS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_LZO=m -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=m -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=m -+CONFIG_ZLIB_DEFLATE=m -+CONFIG_LZO_COMPRESS=m -+CONFIG_LZO_DECOMPRESS=m -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/pavo_defconfig linux-2.6.24.7/arch/mips/configs/pavo_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/pavo_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/pavo_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1293 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Sat Nov 15 16:15:17 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+CONFIG_JZ4740_PAVO=y -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_JZ4750_APUS is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4740=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+# CONFIG_SUSPEND is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4740=y -+# CONFIG_MTD_NAND_CS2 is not set -+# CONFIG_MTD_NAND_CS3 is not set -+# CONFIG_MTD_NAND_CS4 is not set -+CONFIG_MTD_NAND_MULTI_PLANE=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+CONFIG_MTD_HW_RS_ECC=y -+# CONFIG_MTD_HW_BCH_ECC is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=256 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+# CONFIG_MTD_UBI_GLUEBI is not set -+ -+# -+# UBI debugging options -+# -+# CONFIG_MTD_UBI_DEBUG is not set -+CONFIG_MTD_UBI_BLKDEVS=m -+CONFIG_MTD_UBI_BLOCK=m -+# CONFIG_PARPORT is not set -+CONFIG_PNP=y -+# CONFIG_PNP_DEBUG is not set -+ -+# -+# Protocols -+# -+# CONFIG_PNPACPI is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=2 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_NET_SB1000 is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZCS8900=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+# CONFIG_NETDEV_1000 is not set -+# CONFIG_NETDEV_10000 is not set -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_CATC is not set -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_RTL8150 is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_PNP=y -+CONFIG_SERIAL_8250_NR_UARTS=2 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+CONFIG_RTC_JZ=y -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+CONFIG_JZ_SADC=y -+# CONFIG_JZ_TPANEL_AK4182 is not set -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L1=y -+CONFIG_VIDEO_V4L1_COMPAT=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -+# CONFIG_VIDEO_VIVI is not set -+# CONFIG_VIDEO_CPIA is not set -+# CONFIG_VIDEO_CPIA2 is not set -+CONFIG_VIDEO_JZ_CIM=y -+CONFIG_VIDEO_JZ_SENSOR=y -+CONFIG_V4L_USB_DRIVERS=y -+# CONFIG_USB_VICAM is not set -+# CONFIG_USB_IBMCAM is not set -+# CONFIG_USB_KONICAWC is not set -+# CONFIG_USB_QUICKCAM_MESSENGER is not set -+# CONFIG_USB_ET61X251 is not set -+# CONFIG_USB_OV511 is not set -+# CONFIG_USB_SE401 is not set -+# CONFIG_USB_SN9C102 is not set -+# CONFIG_USB_STV680 is not set -+# CONFIG_USB_ZC0301 is not set -+# CONFIG_USB_PWC is not set -+# CONFIG_USB_ZR364XX is not set -+CONFIG_RADIO_ADAPTERS=y -+# CONFIG_USB_DSBR is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+# CONFIG_FB_JZ4740_SLCD is not set -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set -+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y -+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+# CONFIG_SND is not set -+ -+# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=y -+CONFIG_OSS_OBSOLETE=y -+# CONFIG_SOUND_JZ_AC97 is not set -+CONFIG_SOUND_JZ_I2S=y -+# CONFIG_SOUND_JZ_PCM is not set -+# CONFIG_I2S_AK4642EN is not set -+CONFIG_I2S_ICODEC=y -+# CONFIG_I2S_DLV is not set -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+# CONFIG_USB_HIDDEV is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+CONFIG_USB_GADGET_JZ4740=y -+CONFIG_USB_JZ4740=m -+# CONFIG_USB_GADGET_JZ4730 is not set -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_JZ=y -+# CONFIG_JZ_MMC_BUS_1 is not set -+CONFIG_JZ_MMC_BUS_4=y -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+CONFIG_UBIFS_FS=m -+# CONFIG_UBIFS_FS_XATTR is not set -+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -+CONFIG_UBIFS_FS_LZO=y -+CONFIG_UBIFS_FS_ZLIB=y -+# CONFIG_UBIFS_FS_DEBUG is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+# CONFIG_YAFFS_ECC_BCH is not set -+CONFIG_YAFFS_ECC_RS=y -+# CONFIG_YAFFS_ECC_HAMMING is not set -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_LZO=m -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=m -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=m -+CONFIG_ZLIB_DEFLATE=m -+CONFIG_LZO_COMPRESS=m -+CONFIG_LZO_DECOMPRESS=m -+CONFIG_REED_SOLOMON=y -+CONFIG_REED_SOLOMON_ENC8=y -+CONFIG_REED_SOLOMON_DEC8=y -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/pmp_defconfig linux-2.6.24.7/arch/mips/configs/pmp_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/pmp_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/pmp_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1212 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Thu Jun 12 13:37:10 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+CONFIG_JZ4730_PMP=y -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4730=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_PM_SLEEP=y -+CONFIG_SUSPEND_UP_POSSIBLE=y -+CONFIG_SUSPEND=y -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+# CONFIG_WIRELESS_EXT is not set -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+CONFIG_MTD_CONCAT=y -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4730=y -+CONFIG_MTD_HW_HM_ECC=y -+# CONFIG_MTD_SW_HM_ECC is not set -+# CONFIG_MTD_HW_RS_ECC is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=0 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+# CONFIG_MTD_UBI is not set -+# CONFIG_MTD_UBI_BLKDEVS is not set -+# CONFIG_PARPORT is not set -+# CONFIG_PNP is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZ_ETH=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+# CONFIG_NETDEV_1000 is not set -+# CONFIG_NETDEV_10000 is not set -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_CATC is not set -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_RTL8150 is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_NR_UARTS=4 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=256 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+CONFIG_RTC_PCF8563=y -+# CONFIG_RTC_JZ is not set -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+# CONFIG_JZ_SADC is not set -+CONFIG_JZ_TPANEL_AK4182=y -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+# CONFIG_JZ_UDC_HOTPLUG is not set -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+CONFIG_VIDEO_DEV=y -+# CONFIG_VIDEO_V4L1 is not set -+# CONFIG_VIDEO_V4L1_COMPAT is not set -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set -+ -+# -+# Encoders/decoders and other helper chips -+# -+ -+# -+# Audio decoders -+# -+ -+# -+# Video decoders -+# -+ -+# -+# Video and audio decoders -+# -+ -+# -+# MPEG video encoders -+# -+# CONFIG_VIDEO_CX2341X is not set -+ -+# -+# Video encoders -+# -+ -+# -+# Video improvement chips -+# -+# CONFIG_VIDEO_VIVI is not set -+CONFIG_VIDEO_JZ_CIM=m -+CONFIG_VIDEO_JZ_SENSOR=m -+# CONFIG_V4L_USB_DRIVERS is not set -+CONFIG_RADIO_ADAPTERS=y -+# CONFIG_USB_DSBR is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+CONFIG_JZLCD_SAMSUNG_LTP400WQF01=y -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF02 is not set -+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+# CONFIG_SOUND is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+CONFIG_USB_HIDDEV=y -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+CONFIG_USB_DEVICEFS=y -+# CONFIG_USB_DEVICE_CLASS is not set -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+# CONFIG_USB_MON is not set -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+# CONFIG_USB_TEST is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+CONFIG_USB_GADGET_SELECTED=y -+# CONFIG_USB_GADGET_JZ4740 is not set -+CONFIG_USB_GADGET_JZ4730=y -+CONFIG_USB_JZ4730=m -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+# CONFIG_USB_GADGET_DUALSPEED is not set -+# CONFIG_USB_ZERO is not set -+CONFIG_USB_ETH=m -+CONFIG_USB_ETH_RNDIS=y -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+CONFIG_USB_G_SERIAL=m -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_JZ=y -+CONFIG_JZ_MMC_BUS_4=y -+# CONFIG_JZ_MMC_BUS_1 is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+CONFIG_EXT3_FS=y -+CONFIG_EXT3_FS_XATTR=y -+# CONFIG_EXT3_FS_POSIX_ACL is not set -+# CONFIG_EXT3_FS_SECURITY is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_JBD=y -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_FS_POSIX_ACL is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+# CONFIG_NFS_V3_ACL is not set -+# CONFIG_NFS_V4 is not set -+# CONFIG_NFS_DIRECTIO is not set -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+# CONFIG_SUNRPC_BIND34 is not set -+# CONFIG_RPCSEC_GSS_KRB5 is not set -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+CONFIG_BSD_DISKLABEL=y -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+# CONFIG_CRYPTO is not set -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+# CONFIG_CRC16 is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/slt50_defconfig linux-2.6.24.7/arch/mips/configs/slt50_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/slt50_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/slt50_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1036 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Tue Nov 25 09:38:56 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+# CONFIG_JZ4720_VIRGO is not set -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_JZ4750_APUS is not set -+CONFIG_JZ4750_SLT50=y -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4750=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ_JZ is not set -+ -+# -+# Power management options -+# -+# CONFIG_PM is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+CONFIG_INET_DIAG=m -+CONFIG_INET_TCP_DIAG=m -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4750=y -+# CONFIG_MTD_NAND_CS2 is not set -+# CONFIG_MTD_NAND_CS3 is not set -+# CONFIG_MTD_NAND_CS4 is not set -+# CONFIG_MTD_NAND_MULTI_PLANE is not set -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+# CONFIG_MTD_HW_RS_ECC is not set -+CONFIG_MTD_HW_BCH_ECC=y -+CONFIG_MTD_HW_BCH_4BIT=y -+# CONFIG_MTD_HW_BCH_8BIT is not set -+CONFIG_MTD_NAND_DMA=y -+# CONFIG_MTD_NAND_DMABUF is not set -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+# CONFIG_MTD_UBI is not set -+# CONFIG_MTD_UBI_BLKDEVS is not set -+# CONFIG_PARPORT is not set -+# CONFIG_PNP is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=16 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+# CONFIG_NETDEVICES is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+CONFIG_INPUT_KEYBOARD=y -+CONFIG_KEYBOARD_ATKBD=y -+# CONFIG_KEYBOARD_SUNKBD is not set -+# CONFIG_KEYBOARD_LKKBD is not set -+# CONFIG_KEYBOARD_XTKBD is not set -+# CONFIG_KEYBOARD_NEWTON is not set -+# CONFIG_KEYBOARD_STOWAWAY is not set -+# CONFIG_KEYBOARD_JZ is not set -+# CONFIG_KEYBOARD_GPIO is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+CONFIG_SERIO_LIBPS2=y -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_NR_UARTS=4 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=4 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+# CONFIG_RTC_JZ is not set -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+# CONFIG_JZ_TPANEL is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+# CONFIG_JZ_POWEROFF is not set -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+# CONFIG_WATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+# CONFIG_FB is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+ -+# -+# Sound -+# -+# CONFIG_SOUND is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+CONFIG_USB_HIDDEV=y -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+# CONFIG_USB_GADGET is not set -+# CONFIG_MMC is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+# CONFIG_YAFFS_ECC_BCH is not set -+CONFIG_YAFFS_ECC_RS=y -+# CONFIG_YAFFS_ECC_HAMMING is not set -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+# CONFIG_DEBUG_FS is not set -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+# CONFIG_CRYPTO_DEFLATE is not set -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+# CONFIG_CRYPTO_LZO is not set -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+# CONFIG_CRC16 is not set -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_REED_SOLOMON=y -+CONFIG_REED_SOLOMON_ENC8=y -+CONFIG_REED_SOLOMON_DEC8=y -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/configs/virgo_defconfig linux-2.6.24.7/arch/mips/configs/virgo_defconfig ---- linux-2.6.24.7.old/arch/mips/configs/virgo_defconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/configs/virgo_defconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1281 @@ -+# -+# Automatically generated make config: don't edit -+# Linux kernel version: 2.6.24.3 -+# Thu Jun 12 13:52:15 2008 -+# -+CONFIG_MIPS=y -+ -+# -+# Machine selection -+# -+# CONFIG_JZ4730_PMP is not set -+# CONFIG_JZ4740_PAVO is not set -+# CONFIG_JZ4740_LEO is not set -+# CONFIG_JZ4740_LYRA is not set -+# CONFIG_JZ4725_DIPPER is not set -+CONFIG_JZ4720_VIRGO=y -+# CONFIG_JZ4750_FUWA is not set -+# CONFIG_MACH_ALCHEMY is not set -+# CONFIG_BASLER_EXCITE is not set -+# CONFIG_BCM47XX is not set -+# CONFIG_MIPS_COBALT is not set -+# CONFIG_MACH_DECSTATION is not set -+# CONFIG_MACH_JAZZ is not set -+# CONFIG_LASAT is not set -+# CONFIG_LEMOTE_FULONG is not set -+# CONFIG_MIPS_ATLAS is not set -+# CONFIG_MIPS_MALTA is not set -+# CONFIG_MIPS_SEAD is not set -+# CONFIG_MIPS_SIM is not set -+# CONFIG_MARKEINS is not set -+# CONFIG_MACH_VR41XX is not set -+# CONFIG_PNX8550_JBS is not set -+# CONFIG_PNX8550_STB810 is not set -+# CONFIG_PMC_MSP is not set -+# CONFIG_PMC_YOSEMITE is not set -+# CONFIG_QEMU is not set -+# CONFIG_SGI_IP22 is not set -+# CONFIG_SGI_IP27 is not set -+# CONFIG_SGI_IP32 is not set -+# CONFIG_SIBYTE_CRHINE is not set -+# CONFIG_SIBYTE_CARMEL is not set -+# CONFIG_SIBYTE_CRHONE is not set -+# CONFIG_SIBYTE_RHONE is not set -+# CONFIG_SIBYTE_SWARM is not set -+# CONFIG_SIBYTE_LITTLESUR is not set -+# CONFIG_SIBYTE_SENTOSA is not set -+# CONFIG_SIBYTE_PTSWARM is not set -+# CONFIG_SIBYTE_BIGSUR is not set -+# CONFIG_SNI_RM is not set -+# CONFIG_TOSHIBA_JMR3927 is not set -+# CONFIG_TOSHIBA_RBTX4927 is not set -+# CONFIG_TOSHIBA_RBTX4938 is not set -+# CONFIG_WR_PPMC is not set -+CONFIG_SOC_JZ4740=y -+CONFIG_SOC_JZ4720=y -+CONFIG_JZSOC=y -+CONFIG_JZRISC=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_ARCH_HAS_ILOG2_U32 is not set -+# CONFIG_ARCH_HAS_ILOG2_U64 is not set -+CONFIG_ARCH_SUPPORTS_OPROFILE=y -+CONFIG_GENERIC_FIND_NEXT_BIT=y -+CONFIG_GENERIC_HWEIGHT=y -+CONFIG_GENERIC_CALIBRATE_DELAY=y -+CONFIG_GENERIC_CLOCKEVENTS=y -+CONFIG_GENERIC_TIME=y -+CONFIG_GENERIC_CMOS_UPDATE=y -+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y -+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set -+CONFIG_DMA_NONCOHERENT=y -+CONFIG_DMA_NEED_PCI_MAP_STATE=y -+# CONFIG_HOTPLUG_CPU is not set -+# CONFIG_NO_IOPORT is not set -+# CONFIG_CPU_BIG_ENDIAN is not set -+CONFIG_CPU_LITTLE_ENDIAN=y -+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y -+CONFIG_MIPS_L1_CACHE_SHIFT=5 -+ -+# -+# CPU selection -+# -+# CONFIG_CPU_LOONGSON2 is not set -+CONFIG_CPU_MIPS32_R1=y -+# CONFIG_CPU_MIPS32_R2 is not set -+# CONFIG_CPU_MIPS64_R1 is not set -+# CONFIG_CPU_MIPS64_R2 is not set -+# CONFIG_CPU_R3000 is not set -+# CONFIG_CPU_TX39XX is not set -+# CONFIG_CPU_VR41XX is not set -+# CONFIG_CPU_R4300 is not set -+# CONFIG_CPU_R4X00 is not set -+# CONFIG_CPU_TX49XX is not set -+# CONFIG_CPU_R5000 is not set -+# CONFIG_CPU_R5432 is not set -+# CONFIG_CPU_R6000 is not set -+# CONFIG_CPU_NEVADA is not set -+# CONFIG_CPU_R8000 is not set -+# CONFIG_CPU_R10000 is not set -+# CONFIG_CPU_RM7000 is not set -+# CONFIG_CPU_RM9000 is not set -+# CONFIG_CPU_SB1 is not set -+CONFIG_SYS_HAS_CPU_MIPS32_R1=y -+CONFIG_CPU_MIPS32=y -+CONFIG_CPU_MIPSR1=y -+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y -+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -+ -+# -+# Kernel type -+# -+CONFIG_32BIT=y -+# CONFIG_64BIT is not set -+CONFIG_PAGE_SIZE_4KB=y -+# CONFIG_PAGE_SIZE_8KB is not set -+# CONFIG_PAGE_SIZE_16KB is not set -+# CONFIG_PAGE_SIZE_64KB is not set -+CONFIG_CPU_HAS_PREFETCH=y -+CONFIG_MIPS_MT_DISABLED=y -+# CONFIG_MIPS_MT_SMP is not set -+# CONFIG_MIPS_MT_SMTC is not set -+CONFIG_CPU_HAS_LLSC=y -+CONFIG_CPU_HAS_SYNC=y -+CONFIG_GENERIC_HARDIRQS=y -+CONFIG_GENERIC_IRQ_PROBE=y -+CONFIG_CPU_SUPPORTS_HIGHMEM=y -+CONFIG_ARCH_FLATMEM_ENABLE=y -+CONFIG_ARCH_POPULATES_NODE_MAP=y -+CONFIG_SELECT_MEMORY_MODEL=y -+CONFIG_FLATMEM_MANUAL=y -+# CONFIG_DISCONTIGMEM_MANUAL is not set -+# CONFIG_SPARSEMEM_MANUAL is not set -+CONFIG_FLATMEM=y -+CONFIG_FLAT_NODE_MEM_MAP=y -+# CONFIG_SPARSEMEM_STATIC is not set -+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set -+CONFIG_SPLIT_PTLOCK_CPUS=4 -+# CONFIG_RESOURCES_64BIT is not set -+CONFIG_ZONE_DMA_FLAG=0 -+CONFIG_VIRT_TO_BUS=y -+# CONFIG_TICK_ONESHOT is not set -+# CONFIG_NO_HZ is not set -+# CONFIG_HIGH_RES_TIMERS is not set -+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -+# CONFIG_HZ_48 is not set -+CONFIG_HZ_100=y -+# CONFIG_HZ_128 is not set -+# CONFIG_HZ_250 is not set -+# CONFIG_HZ_256 is not set -+# CONFIG_HZ_1000 is not set -+# CONFIG_HZ_1024 is not set -+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y -+CONFIG_HZ=100 -+# CONFIG_PREEMPT_NONE is not set -+# CONFIG_PREEMPT_VOLUNTARY is not set -+CONFIG_PREEMPT=y -+CONFIG_PREEMPT_BKL=y -+# CONFIG_KEXEC is not set -+CONFIG_SECCOMP=y -+CONFIG_LOCKDEP_SUPPORT=y -+CONFIG_STACKTRACE_SUPPORT=y -+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" -+ -+# -+# General setup -+# -+CONFIG_EXPERIMENTAL=y -+CONFIG_BROKEN_ON_SMP=y -+CONFIG_LOCK_KERNEL=y -+CONFIG_INIT_ENV_ARG_LIMIT=32 -+CONFIG_LOCALVERSION="" -+CONFIG_LOCALVERSION_AUTO=y -+CONFIG_SWAP=y -+CONFIG_SYSVIPC=y -+CONFIG_SYSVIPC_SYSCTL=y -+# CONFIG_POSIX_MQUEUE is not set -+# CONFIG_BSD_PROCESS_ACCT is not set -+# CONFIG_TASKSTATS is not set -+# CONFIG_USER_NS is not set -+# CONFIG_PID_NS is not set -+# CONFIG_AUDIT is not set -+# CONFIG_IKCONFIG is not set -+CONFIG_LOG_BUF_SHIFT=14 -+# CONFIG_CGROUPS is not set -+CONFIG_FAIR_GROUP_SCHED=y -+CONFIG_FAIR_USER_SCHED=y -+# CONFIG_FAIR_CGROUP_SCHED is not set -+CONFIG_SYSFS_DEPRECATED=y -+CONFIG_RELAY=y -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set -+CONFIG_SYSCTL=y -+CONFIG_EMBEDDED=y -+CONFIG_SYSCTL_SYSCALL=y -+CONFIG_KALLSYMS=y -+# CONFIG_KALLSYMS_EXTRA_PASS is not set -+CONFIG_HOTPLUG=y -+CONFIG_PRINTK=y -+CONFIG_BUG=y -+CONFIG_ELF_CORE=y -+CONFIG_BASE_FULL=y -+CONFIG_FUTEX=y -+CONFIG_ANON_INODES=y -+CONFIG_EPOLL=y -+CONFIG_SIGNALFD=y -+CONFIG_EVENTFD=y -+CONFIG_SHMEM=y -+CONFIG_VM_EVENT_COUNTERS=y -+CONFIG_SLAB=y -+# CONFIG_SLUB is not set -+# CONFIG_SLOB is not set -+CONFIG_SLABINFO=y -+CONFIG_RT_MUTEXES=y -+# CONFIG_TINY_SHMEM is not set -+CONFIG_BASE_SMALL=0 -+CONFIG_MODULES=y -+CONFIG_MODULE_UNLOAD=y -+# CONFIG_MODULE_FORCE_UNLOAD is not set -+CONFIG_MODVERSIONS=y -+CONFIG_MODULE_SRCVERSION_ALL=y -+CONFIG_KMOD=y -+CONFIG_BLOCK=y -+# CONFIG_LBD is not set -+# CONFIG_BLK_DEV_IO_TRACE is not set -+# CONFIG_LSF is not set -+# CONFIG_BLK_DEV_BSG is not set -+ -+# -+# IO Schedulers -+# -+CONFIG_IOSCHED_NOOP=y -+CONFIG_IOSCHED_AS=y -+CONFIG_IOSCHED_DEADLINE=y -+CONFIG_IOSCHED_CFQ=y -+CONFIG_DEFAULT_AS=y -+# CONFIG_DEFAULT_DEADLINE is not set -+# CONFIG_DEFAULT_CFQ is not set -+# CONFIG_DEFAULT_NOOP is not set -+CONFIG_DEFAULT_IOSCHED="anticipatory" -+ -+# -+# Bus options (PCI, PCMCIA, EISA, ISA, TC) -+# -+# CONFIG_ARCH_SUPPORTS_MSI is not set -+CONFIG_MMU=y -+# CONFIG_PCCARD is not set -+ -+# -+# Executable file formats -+# -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+CONFIG_TRAD_SIGNALS=y -+ -+# -+# CPU Frequency scaling -+# -+CONFIG_CPU_FREQ_JZ=y -+CONFIG_CPU_FREQ=y -+CONFIG_CPU_FREQ_TABLE=y -+# CONFIG_CPU_FREQ_DEBUG is not set -+CONFIG_CPU_FREQ_STAT=y -+# CONFIG_CPU_FREQ_STAT_DETAILS is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set -+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set -+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set -+CONFIG_CPU_FREQ_GOV_USERSPACE=y -+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set -+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set -+ -+# -+# Power management options -+# -+CONFIG_PM=y -+CONFIG_PM_LEGACY=y -+# CONFIG_PM_DEBUG is not set -+CONFIG_SUSPEND_UP_POSSIBLE=y -+# CONFIG_SUSPEND is not set -+ -+# -+# Networking -+# -+CONFIG_NET=y -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+CONFIG_UNIX=y -+# CONFIG_NET_KEY is not set -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_FIB_HASH=y -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_INET_AH is not set -+# CONFIG_INET_ESP is not set -+# CONFIG_INET_IPCOMP is not set -+# CONFIG_INET_XFRM_TUNNEL is not set -+# CONFIG_INET_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -+# CONFIG_INET_XFRM_MODE_TUNNEL is not set -+# CONFIG_INET_XFRM_MODE_BEET is not set -+# CONFIG_INET_LRO is not set -+# CONFIG_INET_DIAG is not set -+# CONFIG_TCP_CONG_ADVANCED is not set -+CONFIG_TCP_CONG_CUBIC=y -+CONFIG_DEFAULT_TCP_CONG="cubic" -+# CONFIG_TCP_MD5SIG is not set -+# CONFIG_IPV6 is not set -+# CONFIG_INET6_XFRM_TUNNEL is not set -+# CONFIG_INET6_TUNNEL is not set -+# CONFIG_NETWORK_SECMARK is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_IP_DCCP is not set -+# CONFIG_IP_SCTP is not set -+# CONFIG_TIPC is not set -+# CONFIG_ATM is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_DECNET is not set -+# CONFIG_LLC2 is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+# CONFIG_HAMRADIO is not set -+# CONFIG_IRDA is not set -+# CONFIG_BT is not set -+# CONFIG_AF_RXRPC is not set -+ -+# -+# Wireless -+# -+# CONFIG_CFG80211 is not set -+CONFIG_WIRELESS_EXT=y -+# CONFIG_MAC80211 is not set -+# CONFIG_IEEE80211 is not set -+# CONFIG_RFKILL is not set -+# CONFIG_NET_9P is not set -+ -+# -+# Device Drivers -+# -+ -+# -+# Generic Driver Options -+# -+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -+CONFIG_STANDALONE=y -+CONFIG_PREVENT_FIRMWARE_BUILD=y -+# CONFIG_FW_LOADER is not set -+# CONFIG_SYS_HYPERVISOR is not set -+# CONFIG_CONNECTOR is not set -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_CONCAT is not set -+CONFIG_MTD_PARTITIONS=y -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+ -+# -+# User Modules And Translation Layers -+# -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLKDEVS=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+# CONFIG_INFTL is not set -+# CONFIG_RFD_FTL is not set -+# CONFIG_SSFDC is not set -+# CONFIG_MTD_OOPS is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+# CONFIG_MTD_CFI is not set -+# CONFIG_MTD_JEDECPROBE is not set -+CONFIG_MTD_MAP_BANK_WIDTH_1=y -+CONFIG_MTD_MAP_BANK_WIDTH_2=y -+CONFIG_MTD_MAP_BANK_WIDTH_4=y -+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set -+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set -+CONFIG_MTD_CFI_I1=y -+CONFIG_MTD_CFI_I2=y -+# CONFIG_MTD_CFI_I4 is not set -+# CONFIG_MTD_CFI_I8 is not set -+# CONFIG_MTD_RAM is not set -+# CONFIG_MTD_ROM is not set -+# CONFIG_MTD_ABSENT is not set -+ -+# -+# Mapping drivers for chip access -+# -+# CONFIG_MTD_COMPLEX_MAPPINGS is not set -+# CONFIG_MTD_PLATRAM is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_SLRAM is not set -+# CONFIG_MTD_PHRAM is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLOCK2MTD is not set -+ -+# -+# Disk-On-Chip Device Drivers -+# -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOC2001PLUS is not set -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+# CONFIG_MTD_NAND_ECC_SMC is not set -+# CONFIG_MTD_NAND_MUSEUM_IDS is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_NAND_DISKONCHIP is not set -+# CONFIG_MTD_NAND_NANDSIM is not set -+# CONFIG_MTD_NAND_PLATFORM is not set -+# CONFIG_MTD_ALAUDA is not set -+CONFIG_MTD_NAND_JZ4740=y -+# CONFIG_MTD_HW_HM_ECC is not set -+# CONFIG_MTD_SW_HM_ECC is not set -+CONFIG_MTD_HW_RS_ECC=y -+# CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE is not set -+CONFIG_MTD_OOB_COPIES=3 -+CONFIG_MTD_BADBLOCK_FLAG_PAGE=127 -+# CONFIG_MTD_ONENAND is not set -+ -+# -+# UBI - Unsorted block images -+# -+CONFIG_MTD_UBI=m -+CONFIG_MTD_UBI_WL_THRESHOLD=256 -+CONFIG_MTD_UBI_BEB_RESERVE=1 -+# CONFIG_MTD_UBI_GLUEBI is not set -+ -+# -+# UBI debugging options -+# -+# CONFIG_MTD_UBI_DEBUG is not set -+CONFIG_MTD_UBI_BLKDEVS=m -+CONFIG_MTD_UBI_BLOCK=m -+# CONFIG_PARPORT is not set -+CONFIG_PNP=y -+# CONFIG_PNP_DEBUG is not set -+ -+# -+# Protocols -+# -+# CONFIG_PNPACPI is not set -+CONFIG_BLK_DEV=y -+# CONFIG_BLK_DEV_COW_COMMON is not set -+CONFIG_BLK_DEV_LOOP=y -+# CONFIG_BLK_DEV_CRYPTOLOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+# CONFIG_BLK_DEV_UB is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_COUNT=2 -+CONFIG_BLK_DEV_RAM_SIZE=4096 -+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 -+# CONFIG_CDROM_PKTCDVD is not set -+# CONFIG_ATA_OVER_ETH is not set -+CONFIG_MISC_DEVICES=y -+# CONFIG_EEPROM_93CX6 is not set -+# CONFIG_IDE is not set -+ -+# -+# SCSI device support -+# -+# CONFIG_RAID_ATTRS is not set -+CONFIG_SCSI=y -+CONFIG_SCSI_DMA=y -+# CONFIG_SCSI_TGT is not set -+# CONFIG_SCSI_NETLINK is not set -+CONFIG_SCSI_PROC_FS=y -+ -+# -+# SCSI support type (disk, tape, CD-ROM) -+# -+CONFIG_BLK_DEV_SD=y -+# CONFIG_CHR_DEV_ST is not set -+# CONFIG_CHR_DEV_OSST is not set -+# CONFIG_BLK_DEV_SR is not set -+# CONFIG_CHR_DEV_SG is not set -+# CONFIG_CHR_DEV_SCH is not set -+ -+# -+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -+# -+# CONFIG_SCSI_MULTI_LUN is not set -+# CONFIG_SCSI_CONSTANTS is not set -+# CONFIG_SCSI_LOGGING is not set -+# CONFIG_SCSI_SCAN_ASYNC is not set -+CONFIG_SCSI_WAIT_SCAN=m -+ -+# -+# SCSI Transports -+# -+# CONFIG_SCSI_SPI_ATTRS is not set -+# CONFIG_SCSI_FC_ATTRS is not set -+# CONFIG_SCSI_ISCSI_ATTRS is not set -+# CONFIG_SCSI_SAS_LIBSAS is not set -+# CONFIG_SCSI_SRP_ATTRS is not set -+CONFIG_SCSI_LOWLEVEL=y -+# CONFIG_ISCSI_TCP is not set -+# CONFIG_SCSI_DEBUG is not set -+# CONFIG_ATA is not set -+# CONFIG_MD is not set -+CONFIG_NETDEVICES=y -+# CONFIG_NETDEVICES_MULTIQUEUE is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_MACVLAN is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_VETH is not set -+# CONFIG_NET_SB1000 is not set -+CONFIG_PHYLIB=y -+ -+# -+# MII PHY device drivers -+# -+# CONFIG_MARVELL_PHY is not set -+# CONFIG_DAVICOM_PHY is not set -+# CONFIG_QSEMI_PHY is not set -+# CONFIG_LXT_PHY is not set -+# CONFIG_CICADA_PHY is not set -+# CONFIG_VITESSE_PHY is not set -+# CONFIG_SMSC_PHY is not set -+# CONFIG_BROADCOM_PHY is not set -+# CONFIG_ICPLUS_PHY is not set -+# CONFIG_FIXED_PHY is not set -+# CONFIG_MDIO_BITBANG is not set -+CONFIG_NET_ETHERNET=y -+CONFIG_MII=y -+CONFIG_JZCS8900=y -+# CONFIG_AX88796 is not set -+# CONFIG_DM9000 is not set -+# CONFIG_IBM_NEW_EMAC_ZMII is not set -+# CONFIG_IBM_NEW_EMAC_RGMII is not set -+# CONFIG_IBM_NEW_EMAC_TAH is not set -+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set -+# CONFIG_B44 is not set -+# CONFIG_NETDEV_1000 is not set -+# CONFIG_NETDEV_10000 is not set -+ -+# -+# Wireless LAN -+# -+# CONFIG_WLAN_PRE80211 is not set -+# CONFIG_WLAN_80211 is not set -+ -+# -+# USB Network Adapters -+# -+# CONFIG_USB_CATC is not set -+# CONFIG_USB_KAWETH is not set -+# CONFIG_USB_PEGASUS is not set -+# CONFIG_USB_RTL8150 is not set -+# CONFIG_USB_USBNET is not set -+# CONFIG_WAN is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+# CONFIG_SHAPER is not set -+# CONFIG_NETCONSOLE is not set -+# CONFIG_NETPOLL is not set -+# CONFIG_NET_POLL_CONTROLLER is not set -+# CONFIG_ISDN is not set -+# CONFIG_PHONE is not set -+ -+# -+# Input device support -+# -+CONFIG_INPUT=y -+# CONFIG_INPUT_FF_MEMLESS is not set -+# CONFIG_INPUT_POLLDEV is not set -+ -+# -+# Userland interfaces -+# -+CONFIG_INPUT_MOUSEDEV=y -+CONFIG_INPUT_MOUSEDEV_PSAUX=y -+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -+# CONFIG_INPUT_JOYDEV is not set -+CONFIG_INPUT_EVDEV=y -+# CONFIG_INPUT_EVBUG is not set -+ -+# -+# Input Device Drivers -+# -+# CONFIG_INPUT_KEYBOARD is not set -+# CONFIG_INPUT_MOUSE is not set -+# CONFIG_INPUT_JOYSTICK is not set -+# CONFIG_INPUT_TABLET is not set -+# CONFIG_INPUT_TOUCHSCREEN is not set -+# CONFIG_INPUT_MISC is not set -+ -+# -+# Hardware I/O ports -+# -+CONFIG_SERIO=y -+# CONFIG_SERIO_I8042 is not set -+CONFIG_SERIO_SERPORT=y -+# CONFIG_SERIO_LIBPS2 is not set -+# CONFIG_SERIO_RAW is not set -+# CONFIG_GAMEPORT is not set -+ -+# -+# Character devices -+# -+CONFIG_VT=y -+CONFIG_VT_CONSOLE=y -+CONFIG_HW_CONSOLE=y -+CONFIG_VT_HW_CONSOLE_BINDING=y -+# CONFIG_SERIAL_NONSTANDARD is not set -+ -+# -+# Serial drivers -+# -+CONFIG_SERIAL_8250=y -+CONFIG_SERIAL_8250_CONSOLE=y -+CONFIG_SERIAL_8250_PNP=y -+CONFIG_SERIAL_8250_NR_UARTS=2 -+CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -+# CONFIG_SERIAL_8250_EXTENDED is not set -+ -+# -+# Non-8250 serial port support -+# -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+CONFIG_UNIX98_PTYS=y -+CONFIG_LEGACY_PTYS=y -+CONFIG_LEGACY_PTY_COUNT=2 -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_HW_RANDOM is not set -+# CONFIG_RTC is not set -+# CONFIG_RTC_PCF8563 is not set -+CONFIG_RTC_JZ=y -+# CONFIG_R3964 is not set -+# CONFIG_RAW_DRIVER is not set -+# CONFIG_TCG_TPM is not set -+ -+# -+# JZSOC char device support -+# -+CONFIG_JZCHAR=y -+# CONFIG_JZ_CIM is not set -+# CONFIG_JZ_TPANEL_ATA2508 is not set -+CONFIG_JZ_TPANEL=y -+CONFIG_JZ_SADC=y -+# CONFIG_JZ_TPANEL_AK4182 is not set -+# CONFIG_JZ_TPANEL_UCB1400 is not set -+# CONFIG_JZ_TPANEL_WM9712 is not set -+CONFIG_JZ_UDC_HOTPLUG=y -+CONFIG_JZ_POWEROFF=y -+# CONFIG_JZ_OW is not set -+# CONFIG_I2C is not set -+ -+# -+# SPI support -+# -+# CONFIG_SPI is not set -+# CONFIG_SPI_MASTER is not set -+# CONFIG_W1 is not set -+# CONFIG_POWER_SUPPLY is not set -+# CONFIG_HWMON is not set -+CONFIG_WATCHDOG=y -+# CONFIG_WATCHDOG_NOWAYOUT is not set -+ -+# -+# Watchdog Device Drivers -+# -+CONFIG_JZ_WDT=y -+# CONFIG_SOFT_WATCHDOG is not set -+ -+# -+# USB-based Watchdog Cards -+# -+# CONFIG_USBPCWATCHDOG is not set -+ -+# -+# Sonics Silicon Backplane -+# -+CONFIG_SSB_POSSIBLE=y -+# CONFIG_SSB is not set -+ -+# -+# Multifunction device drivers -+# -+# CONFIG_MFD_SM501 is not set -+ -+# -+# Multimedia devices -+# -+CONFIG_VIDEO_DEV=y -+CONFIG_VIDEO_V4L1=y -+CONFIG_VIDEO_V4L1_COMPAT=y -+CONFIG_VIDEO_V4L2=y -+CONFIG_VIDEO_CAPTURE_DRIVERS=y -+# CONFIG_VIDEO_ADV_DEBUG is not set -+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y -+# CONFIG_VIDEO_VIVI is not set -+# CONFIG_VIDEO_CPIA is not set -+# CONFIG_VIDEO_CPIA2 is not set -+CONFIG_VIDEO_JZ_CIM=y -+CONFIG_VIDEO_JZ_SENSOR=y -+CONFIG_V4L_USB_DRIVERS=y -+# CONFIG_USB_VICAM is not set -+# CONFIG_USB_IBMCAM is not set -+# CONFIG_USB_KONICAWC is not set -+# CONFIG_USB_QUICKCAM_MESSENGER is not set -+# CONFIG_USB_ET61X251 is not set -+# CONFIG_USB_OV511 is not set -+# CONFIG_USB_SE401 is not set -+# CONFIG_USB_SN9C102 is not set -+# CONFIG_USB_STV680 is not set -+# CONFIG_USB_ZC0301 is not set -+# CONFIG_USB_PWC is not set -+# CONFIG_USB_ZR364XX is not set -+CONFIG_RADIO_ADAPTERS=y -+# CONFIG_USB_DSBR is not set -+# CONFIG_DVB_CORE is not set -+# CONFIG_DAB is not set -+ -+# -+# Graphics support -+# -+# CONFIG_VGASTATE is not set -+# CONFIG_VIDEO_OUTPUT_CONTROL is not set -+CONFIG_FB=y -+# CONFIG_FIRMWARE_EDID is not set -+# CONFIG_FB_DDC is not set -+CONFIG_FB_CFB_FILLRECT=y -+CONFIG_FB_CFB_COPYAREA=y -+CONFIG_FB_CFB_IMAGEBLIT=y -+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set -+# CONFIG_FB_SYS_FILLRECT is not set -+# CONFIG_FB_SYS_COPYAREA is not set -+# CONFIG_FB_SYS_IMAGEBLIT is not set -+# CONFIG_FB_SYS_FOPS is not set -+CONFIG_FB_DEFERRED_IO=y -+# CONFIG_FB_SVGALIB is not set -+# CONFIG_FB_MACMODES is not set -+# CONFIG_FB_BACKLIGHT is not set -+# CONFIG_FB_MODE_HELPERS is not set -+# CONFIG_FB_TILEBLITTING is not set -+ -+# -+# Frame buffer hardware drivers -+# -+CONFIG_FB_JZSOC=y -+# CONFIG_FB_JZ4740_SLCD is not set -+CONFIG_FB_JZLCD_4730_4740=y -+CONFIG_JZLCD_FRAMEBUFFER_MAX=1 -+# CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT is not set -+# CONFIG_JZLCD_SHARP_LQ035Q7 is not set -+# CONFIG_JZLCD_SAMSUNG_LTS350Q1 is not set -+# CONFIG_JZLCD_SAMSUNG_LTV350QVF04 is not set -+# CONFIG_JZLCD_SAMSUNG_LTP400WQF01 is not set -+CONFIG_JZLCD_SAMSUNG_LTP400WQF02=y -+# CONFIG_JZLCD_AUO_A030FL01_V1 is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW is not set -+# CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL is not set -+# CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E is not set -+# CONFIG_JZLCD_FOXCONN_PT035TN01 is not set -+# CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL is not set -+# CONFIG_JZLCD_TOSHIBA_LTM084P363 is not set -+# CONFIG_JZLCD_HYNIX_HT10X21 is not set -+# CONFIG_JZLCD_INNOLUX_AT080TN42 is not set -+# CONFIG_JZLCD_CSTN_800x600 is not set -+# CONFIG_JZLCD_CSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_480x320 is not set -+# CONFIG_JZLCD_MSTN_320x240 is not set -+# CONFIG_JZLCD_MSTN_240x128 is not set -+# CONFIG_FB_S1D13XXX is not set -+# CONFIG_FB_VIRTUAL is not set -+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set -+ -+# -+# Display device support -+# -+# CONFIG_DISPLAY_SUPPORT is not set -+ -+# -+# Console display driver support -+# -+# CONFIG_VGA_CONSOLE is not set -+CONFIG_DUMMY_CONSOLE=y -+CONFIG_FRAMEBUFFER_CONSOLE=y -+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH is not set -+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set -+CONFIG_FONTS=y -+CONFIG_FONT_8x8=y -+CONFIG_FONT_8x16=y -+# CONFIG_FONT_6x11 is not set -+# CONFIG_FONT_7x14 is not set -+# CONFIG_FONT_PEARL_8x8 is not set -+# CONFIG_FONT_ACORN_8x8 is not set -+# CONFIG_FONT_MINI_4x6 is not set -+# CONFIG_FONT_SUN8x16 is not set -+# CONFIG_FONT_SUN12x22 is not set -+# CONFIG_FONT_10x18 is not set -+CONFIG_LOGO=y -+CONFIG_LOGO_LINUX_MONO=y -+CONFIG_LOGO_LINUX_VGA16=y -+CONFIG_LOGO_LINUX_CLUT224=y -+ -+# -+# Sound -+# -+CONFIG_SOUND=y -+ -+# -+# Advanced Linux Sound Architecture -+# -+# CONFIG_SND is not set -+ -+# -+# Open Sound System -+# -+CONFIG_SOUND_PRIME=y -+CONFIG_OSS_OBSOLETE=y -+# CONFIG_SOUND_JZ_AC97 is not set -+CONFIG_SOUND_JZ_I2S=y -+# CONFIG_SOUND_JZ_PCM is not set -+# CONFIG_I2S_AK4642EN is not set -+CONFIG_I2S_ICODEC=y -+# CONFIG_SOUND_MSNDCLAS is not set -+# CONFIG_SOUND_MSNDPIN is not set -+CONFIG_HID_SUPPORT=y -+CONFIG_HID=y -+# CONFIG_HID_DEBUG is not set -+# CONFIG_HIDRAW is not set -+ -+# -+# USB Input Devices -+# -+CONFIG_USB_HID=y -+# CONFIG_USB_HIDINPUT_POWERBOOK is not set -+# CONFIG_HID_FF is not set -+# CONFIG_USB_HIDDEV is not set -+CONFIG_USB_SUPPORT=y -+CONFIG_USB_ARCH_HAS_HCD=y -+CONFIG_USB_ARCH_HAS_OHCI=y -+# CONFIG_USB_ARCH_HAS_EHCI is not set -+CONFIG_USB=y -+# CONFIG_USB_DEBUG is not set -+ -+# -+# Miscellaneous USB options -+# -+# CONFIG_USB_DEVICEFS is not set -+CONFIG_USB_DEVICE_CLASS=y -+# CONFIG_USB_DYNAMIC_MINORS is not set -+# CONFIG_USB_SUSPEND is not set -+# CONFIG_USB_PERSIST is not set -+# CONFIG_USB_OTG is not set -+ -+# -+# USB Host Controller Drivers -+# -+# CONFIG_USB_ISP116X_HCD is not set -+CONFIG_USB_OHCI_HCD=y -+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set -+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set -+CONFIG_USB_OHCI_LITTLE_ENDIAN=y -+# CONFIG_USB_SL811_HCD is not set -+# CONFIG_USB_R8A66597_HCD is not set -+ -+# -+# USB Device Class drivers -+# -+# CONFIG_USB_ACM is not set -+# CONFIG_USB_PRINTER is not set -+ -+# -+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' -+# -+ -+# -+# may also be needed; see USB_STORAGE Help for more information -+# -+CONFIG_USB_STORAGE=y -+# CONFIG_USB_STORAGE_DEBUG is not set -+# CONFIG_USB_STORAGE_DATAFAB is not set -+# CONFIG_USB_STORAGE_FREECOM is not set -+# CONFIG_USB_STORAGE_ISD200 is not set -+# CONFIG_USB_STORAGE_DPCM is not set -+# CONFIG_USB_STORAGE_USBAT is not set -+# CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set -+# CONFIG_USB_STORAGE_JUMPSHOT is not set -+# CONFIG_USB_STORAGE_ALAUDA is not set -+# CONFIG_USB_STORAGE_KARMA is not set -+# CONFIG_USB_LIBUSUAL is not set -+ -+# -+# USB Imaging devices -+# -+# CONFIG_USB_MDC800 is not set -+# CONFIG_USB_MICROTEK is not set -+CONFIG_USB_MON=y -+ -+# -+# USB port drivers -+# -+ -+# -+# USB Serial Converter support -+# -+# CONFIG_USB_SERIAL is not set -+ -+# -+# USB Miscellaneous drivers -+# -+# CONFIG_USB_EMI62 is not set -+# CONFIG_USB_EMI26 is not set -+# CONFIG_USB_ADUTUX is not set -+# CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_RIO500 is not set -+# CONFIG_USB_LEGOTOWER is not set -+# CONFIG_USB_LCD is not set -+# CONFIG_USB_BERRY_CHARGE is not set -+# CONFIG_USB_LED is not set -+# CONFIG_USB_CYPRESS_CY7C63 is not set -+# CONFIG_USB_CYTHERM is not set -+# CONFIG_USB_PHIDGET is not set -+# CONFIG_USB_IDMOUSE is not set -+# CONFIG_USB_FTDI_ELAN is not set -+# CONFIG_USB_APPLEDISPLAY is not set -+# CONFIG_USB_LD is not set -+# CONFIG_USB_TRANCEVIBRATOR is not set -+# CONFIG_USB_IOWARRIOR is not set -+ -+# -+# USB DSL modem support -+# -+ -+# -+# USB Gadget Support -+# -+CONFIG_USB_GADGET=m -+# CONFIG_USB_GADGET_DEBUG_FILES is not set -+# CONFIG_USB_GADGET_DEBUG_FS is not set -+CONFIG_USB_GADGET_SELECTED=y -+CONFIG_USB_GADGET_JZ4740=y -+CONFIG_USB_JZ4740=m -+# CONFIG_USB_GADGET_JZ4730 is not set -+# CONFIG_USB_GADGET_AMD5536UDC is not set -+# CONFIG_USB_GADGET_ATMEL_USBA is not set -+# CONFIG_USB_GADGET_FSL_USB2 is not set -+# CONFIG_USB_GADGET_NET2280 is not set -+# CONFIG_USB_GADGET_PXA2XX is not set -+# CONFIG_USB_GADGET_M66592 is not set -+# CONFIG_USB_GADGET_GOKU is not set -+# CONFIG_USB_GADGET_LH7A40X is not set -+# CONFIG_USB_GADGET_OMAP is not set -+# CONFIG_USB_GADGET_S3C2410 is not set -+# CONFIG_USB_GADGET_AT91 is not set -+# CONFIG_USB_GADGET_DUMMY_HCD is not set -+CONFIG_USB_GADGET_DUALSPEED=y -+# CONFIG_USB_ZERO is not set -+# CONFIG_USB_ETH is not set -+# CONFIG_USB_GADGETFS is not set -+CONFIG_USB_FILE_STORAGE=m -+# CONFIG_USB_FILE_STORAGE_TEST is not set -+# CONFIG_USB_G_SERIAL is not set -+# CONFIG_USB_MIDI_GADGET is not set -+CONFIG_MMC=y -+# CONFIG_MMC_DEBUG is not set -+# CONFIG_MMC_UNSAFE_RESUME is not set -+ -+# -+# MMC/SD Card Drivers -+# -+CONFIG_MMC_BLOCK=y -+CONFIG_MMC_BLOCK_BOUNCE=y -+# CONFIG_SDIO_UART is not set -+ -+# -+# MMC/SD Host Controller Drivers -+# -+CONFIG_MMC_JZ=y -+CONFIG_JZ_MMC_BUS_4=y -+# CONFIG_JZ_MMC_BUS_1 is not set -+# CONFIG_NEW_LEDS is not set -+CONFIG_RTC_LIB=y -+# CONFIG_RTC_CLASS is not set -+ -+# -+# Userspace I/O -+# -+# CONFIG_UIO is not set -+ -+# -+# File systems -+# -+CONFIG_EXT2_FS=y -+CONFIG_EXT2_FS_XATTR=y -+# CONFIG_EXT2_FS_POSIX_ACL is not set -+# CONFIG_EXT2_FS_SECURITY is not set -+# CONFIG_EXT2_FS_XIP is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_EXT4DEV_FS is not set -+CONFIG_FS_MBCACHE=y -+# CONFIG_REISERFS_FS is not set -+# CONFIG_JFS_FS is not set -+CONFIG_FS_POSIX_ACL=y -+# CONFIG_XFS_FS is not set -+# CONFIG_GFS2_FS is not set -+# CONFIG_OCFS2_FS is not set -+CONFIG_MINIX_FS=y -+# CONFIG_ROMFS_FS is not set -+CONFIG_INOTIFY=y -+CONFIG_INOTIFY_USER=y -+# CONFIG_QUOTA is not set -+CONFIG_DNOTIFY=y -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_FUSE_FS is not set -+ -+# -+# CD-ROM/DVD Filesystems -+# -+# CONFIG_ISO9660_FS is not set -+# CONFIG_UDF_FS is not set -+ -+# -+# DOS/FAT/NT Filesystems -+# -+CONFIG_FAT_FS=y -+CONFIG_MSDOS_FS=y -+CONFIG_VFAT_FS=y -+CONFIG_FAT_DEFAULT_CODEPAGE=437 -+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -+# CONFIG_NTFS_FS is not set -+ -+# -+# Pseudo filesystems -+# -+CONFIG_PROC_FS=y -+CONFIG_PROC_KCORE=y -+CONFIG_PROC_SYSCTL=y -+CONFIG_SYSFS=y -+CONFIG_TMPFS=y -+# CONFIG_TMPFS_POSIX_ACL is not set -+# CONFIG_HUGETLB_PAGE is not set -+# CONFIG_CONFIGFS_FS is not set -+ -+# -+# Miscellaneous filesystems -+# -+# CONFIG_ADFS_FS is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+CONFIG_UBIFS_FS=m -+# CONFIG_UBIFS_FS_XATTR is not set -+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set -+CONFIG_UBIFS_FS_LZO=y -+CONFIG_UBIFS_FS_ZLIB=y -+# CONFIG_UBIFS_FS_DEBUG is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_HPFS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_SYSV_FS is not set -+# CONFIG_UFS_FS is not set -+CONFIG_NETWORK_FILESYSTEMS=y -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+CONFIG_NFS_V3_ACL=y -+CONFIG_NFS_V4=y -+CONFIG_NFS_DIRECTIO=y -+# CONFIG_NFSD is not set -+CONFIG_ROOT_NFS=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+CONFIG_NFS_ACL_SUPPORT=y -+CONFIG_NFS_COMMON=y -+CONFIG_SUNRPC=y -+CONFIG_SUNRPC_GSS=y -+# CONFIG_SUNRPC_BIND34 is not set -+CONFIG_RPCSEC_GSS_KRB5=y -+# CONFIG_RPCSEC_GSS_SPKM3 is not set -+# CONFIG_SMB_FS is not set -+# CONFIG_CIFS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_CODA_FS is not set -+# CONFIG_AFS_FS is not set -+ -+# -+# Partition Types -+# -+CONFIG_PARTITION_ADVANCED=y -+# CONFIG_ACORN_PARTITION is not set -+# CONFIG_OSF_PARTITION is not set -+# CONFIG_AMIGA_PARTITION is not set -+# CONFIG_ATARI_PARTITION is not set -+# CONFIG_MAC_PARTITION is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_BSD_DISKLABEL is not set -+# CONFIG_MINIX_SUBPARTITION is not set -+# CONFIG_SOLARIS_X86_PARTITION is not set -+# CONFIG_UNIXWARE_DISKLABEL is not set -+# CONFIG_LDM_PARTITION is not set -+# CONFIG_SGI_PARTITION is not set -+# CONFIG_ULTRIX_PARTITION is not set -+# CONFIG_SUN_PARTITION is not set -+# CONFIG_KARMA_PARTITION is not set -+# CONFIG_EFI_PARTITION is not set -+# CONFIG_SYSV68_PARTITION is not set -+CONFIG_NLS=y -+CONFIG_NLS_DEFAULT="iso8859-1" -+CONFIG_NLS_CODEPAGE_437=y -+# CONFIG_NLS_CODEPAGE_737 is not set -+# CONFIG_NLS_CODEPAGE_775 is not set -+# CONFIG_NLS_CODEPAGE_850 is not set -+# CONFIG_NLS_CODEPAGE_852 is not set -+# CONFIG_NLS_CODEPAGE_855 is not set -+# CONFIG_NLS_CODEPAGE_857 is not set -+# CONFIG_NLS_CODEPAGE_860 is not set -+# CONFIG_NLS_CODEPAGE_861 is not set -+# CONFIG_NLS_CODEPAGE_862 is not set -+# CONFIG_NLS_CODEPAGE_863 is not set -+# CONFIG_NLS_CODEPAGE_864 is not set -+# CONFIG_NLS_CODEPAGE_865 is not set -+# CONFIG_NLS_CODEPAGE_866 is not set -+# CONFIG_NLS_CODEPAGE_869 is not set -+CONFIG_NLS_CODEPAGE_936=y -+# CONFIG_NLS_CODEPAGE_950 is not set -+# CONFIG_NLS_CODEPAGE_932 is not set -+# CONFIG_NLS_CODEPAGE_949 is not set -+# CONFIG_NLS_CODEPAGE_874 is not set -+# CONFIG_NLS_ISO8859_8 is not set -+# CONFIG_NLS_CODEPAGE_1250 is not set -+# CONFIG_NLS_CODEPAGE_1251 is not set -+CONFIG_NLS_ASCII=y -+CONFIG_NLS_ISO8859_1=y -+# CONFIG_NLS_ISO8859_2 is not set -+# CONFIG_NLS_ISO8859_3 is not set -+# CONFIG_NLS_ISO8859_4 is not set -+# CONFIG_NLS_ISO8859_5 is not set -+# CONFIG_NLS_ISO8859_6 is not set -+# CONFIG_NLS_ISO8859_7 is not set -+# CONFIG_NLS_ISO8859_9 is not set -+# CONFIG_NLS_ISO8859_13 is not set -+# CONFIG_NLS_ISO8859_14 is not set -+# CONFIG_NLS_ISO8859_15 is not set -+# CONFIG_NLS_KOI8_R is not set -+# CONFIG_NLS_KOI8_U is not set -+# CONFIG_NLS_UTF8 is not set -+# CONFIG_DLM is not set -+ -+# -+# Yaffs2 Filesystems -+# -+CONFIG_YAFFS_FS=y -+CONFIG_YAFFS_YAFFS1=y -+# CONFIG_YAFFS_DOES_ECC is not set -+CONFIG_YAFFS_YAFFS2=y -+CONFIG_YAFFS_AUTO_YAFFS2=y -+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set -+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set -+CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK=y -+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y -+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10 -+CONFIG_INSTRUMENTATION=y -+# CONFIG_PROFILING is not set -+# CONFIG_MARKERS is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_TRACE_IRQFLAGS_SUPPORT=y -+# CONFIG_PRINTK_TIME is not set -+CONFIG_ENABLE_WARN_DEPRECATED=y -+CONFIG_ENABLE_MUST_CHECK=y -+CONFIG_MAGIC_SYSRQ=y -+# CONFIG_UNUSED_SYMBOLS is not set -+CONFIG_DEBUG_FS=y -+# CONFIG_HEADERS_CHECK is not set -+# CONFIG_DEBUG_KERNEL is not set -+# CONFIG_SAMPLES is not set -+CONFIG_CMDLINE="" -+ -+# -+# Security options -+# -+# CONFIG_KEYS is not set -+# CONFIG_SECURITY is not set -+# CONFIG_SECURITY_FILE_CAPABILITIES is not set -+CONFIG_CRYPTO=y -+CONFIG_CRYPTO_ALGAPI=y -+CONFIG_CRYPTO_BLKCIPHER=y -+CONFIG_CRYPTO_MANAGER=y -+# CONFIG_CRYPTO_HMAC is not set -+# CONFIG_CRYPTO_XCBC is not set -+# CONFIG_CRYPTO_NULL is not set -+# CONFIG_CRYPTO_MD4 is not set -+CONFIG_CRYPTO_MD5=y -+# CONFIG_CRYPTO_SHA1 is not set -+# CONFIG_CRYPTO_SHA256 is not set -+# CONFIG_CRYPTO_SHA512 is not set -+# CONFIG_CRYPTO_WP512 is not set -+# CONFIG_CRYPTO_TGR192 is not set -+# CONFIG_CRYPTO_GF128MUL is not set -+# CONFIG_CRYPTO_ECB is not set -+CONFIG_CRYPTO_CBC=y -+# CONFIG_CRYPTO_PCBC is not set -+# CONFIG_CRYPTO_LRW is not set -+# CONFIG_CRYPTO_XTS is not set -+# CONFIG_CRYPTO_CRYPTD is not set -+CONFIG_CRYPTO_DES=y -+# CONFIG_CRYPTO_FCRYPT is not set -+# CONFIG_CRYPTO_BLOWFISH is not set -+# CONFIG_CRYPTO_TWOFISH is not set -+# CONFIG_CRYPTO_SERPENT is not set -+# CONFIG_CRYPTO_AES is not set -+# CONFIG_CRYPTO_CAST5 is not set -+# CONFIG_CRYPTO_CAST6 is not set -+# CONFIG_CRYPTO_TEA is not set -+# CONFIG_CRYPTO_ARC4 is not set -+# CONFIG_CRYPTO_KHAZAD is not set -+# CONFIG_CRYPTO_ANUBIS is not set -+# CONFIG_CRYPTO_SEED is not set -+CONFIG_CRYPTO_DEFLATE=m -+# CONFIG_CRYPTO_MICHAEL_MIC is not set -+# CONFIG_CRYPTO_CRC32C is not set -+# CONFIG_CRYPTO_CAMELLIA is not set -+# CONFIG_CRYPTO_TEST is not set -+# CONFIG_CRYPTO_AUTHENC is not set -+CONFIG_CRYPTO_LZO=m -+CONFIG_CRYPTO_HW=y -+ -+# -+# Library routines -+# -+CONFIG_BITREVERSE=y -+# CONFIG_CRC_CCITT is not set -+CONFIG_CRC16=m -+# CONFIG_CRC_ITU_T is not set -+CONFIG_CRC32=y -+# CONFIG_CRC7 is not set -+# CONFIG_LIBCRC32C is not set -+CONFIG_ZLIB_INFLATE=m -+CONFIG_ZLIB_DEFLATE=m -+CONFIG_LZO_COMPRESS=m -+CONFIG_LZO_DECOMPRESS=m -+CONFIG_PLIST=y -+CONFIG_HAS_IOMEM=y -+CONFIG_HAS_IOPORT=y -+CONFIG_HAS_DMA=y -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/Makefile linux-2.6.24.7/arch/mips/jz4730/Makefile ---- linux-2.6.24.7.old/arch/mips/jz4730/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,22 @@ -+# -+# Makefile for the Ingenic JZ4730. -+# -+ -+# Object file lists. -+ -+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ -+ platform.o i2c.o -+ -+obj-$(CONFIG_PROC_FS) += proc.o -+ -+# board specific support -+ -+obj-$(CONFIG_JZ4730_PMP) += board-pmp.o -+ -+# CPU Frequency scaling support -+ -+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o -+ -+# PM support -+ -+obj-$(CONFIG_PM_LEGACY) +=pm.o sleep.o -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/board-pmp.c linux-2.6.24.7/arch/mips/jz4730/board-pmp.c ---- linux-2.6.24.7.old/arch/mips/jz4730/board-pmp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/board-pmp.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * linux/arch/mips/jz4730/board-pmp.c -+ * -+ * JZ4730 PMP board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned int count = 0; -+ -+ count ++; -+ count &= 1; -+ if (count) -+ __gpio_set_pin(GPIO_LED_EN); -+ else -+ __gpio_clear_pin(GPIO_LED_EN); -+} -+ -+static void pmp_timer_ack(void) -+{ -+ static unsigned int count = 0; -+ count ++; -+ if (count % 100 == 0) { -+ count = 0; -+ dancing(); -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ __cpm_start_all(); -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Most of the gpios have been setup in the bootloader. -+ */ -+ -+ __harb_usb0_uhc(); -+ __gpio_as_dma(); -+ __gpio_as_eth(); -+ __gpio_as_usb(); -+ __gpio_as_lcd_master(); -+#if defined(CONFIG_I2S_AK4642EN) -+ __gpio_as_scc1(); -+#endif -+#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) -+ __gpio_as_ssi(); -+#endif -+ //__gpio_as_ac97(); -+#if defined(CONFIG_I2S_TSC2301) || defined(CONFIG_I2S_TLC320AIC23) || defined(CONFIG_I2S_CS42L51) -+ __gpio_as_i2s_slave(); -+#endif -+ __gpio_as_cim(); -+ __gpio_as_msc(); -+ -+ __gpio_as_output(GPIO_LED_EN); -+ __gpio_set_pin(GPIO_LED_EN); -+ -+ __gpio_as_output(GPIO_DISP_OFF_N); -+ __gpio_set_pin(GPIO_DISP_OFF_N); -+ __gpio_as_output(GPIO_PWM0); -+ __gpio_set_pin(GPIO_PWM0); -+ -+ __gpio_as_input(GPIO_RTC_IRQ); -+ __gpio_as_output(GPIO_USB_CLK_EN); -+ __gpio_set_pin(GPIO_USB_CLK_EN); -+ -+ __gpio_as_input(GPIO_CHARG_STAT); -+ __gpio_disable_pull(GPIO_CHARG_STAT); -+ -+ __gpio_as_input(GPIO_UDC_HOTPLUG); -+ __gpio_disable_pull(GPIO_UDC_HOTPLUG); -+ __gpio_disable_pull(54); /* fixed ic bug, the pull of gpio pin 86 is as pin 54 */ -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4730 PMP board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = pmp_timer_ack; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/cpufreq.c linux-2.6.24.7/arch/mips/jz4730/cpufreq.c ---- linux-2.6.24.7.old/arch/mips/jz4730/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/cpufreq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,596 @@ -+ -+/* -+ * linux/arch/mips/jz4730/cpufreq.c -+ * -+ * cpufreq driver for JZ4730 -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ -+ "cpufreq-jz4730", msg) -+ -+#undef CHANGE_PLL -+ -+#define PLL_UNCHANGED 0 -+#define PLL_GOES_UP 1 -+#define PLL_GOES_DOWN 2 -+ -+#define PLL_WAIT_500NS (500*(__cpm_get_iclk()/1000000000)) -+ -+/* Saved the boot-time parameters */ -+static struct { -+ /* SDRAM parameters */ -+ unsigned int mclk; /* memory clock, KHz */ -+ unsigned int tras; /* RAS pulse width, cycles of mclk */ -+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ -+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ -+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ -+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ -+ unsigned int rtcor; /* Refresh Time Constant */ -+ unsigned int sdram_initialized; -+ -+ /* LCD parameters */ -+ unsigned int lcd_clk; /* LCD clock, Hz */ -+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ -+ unsigned int lcd_clks_initialized; -+} boot_config; -+ -+struct jz4730_freq_percpu_info { -+ struct cpufreq_frequency_table table[7]; -+}; -+ -+static struct jz4730_freq_percpu_info jz4730_freq_table; -+ -+/* -+ * This contains the registers value for an operating point. -+ * If only part of a register needs to change then there is -+ * a mask value for that register. -+ * When going to a new operating point the current register -+ * value is ANDed with the ~mask and ORed with the new value. -+ */ -+struct dpm_regs { -+ u32 cfcr; /* Clock Freq Control Register */ -+ u32 cfcr_mask; /* Clock Freq Control Register mask */ -+ u32 cfcr2; /* Clock Freq Control Register 2 */ -+ u32 cfcr2_mask; /* Clock Freq Control Register 2 mask */ -+ u32 plcr1; /* PLL1 Control Register */ -+ u32 plcr1_mask; /* PLL1 Control Register mask */ -+ u32 pll_up_flag; /* New PLL freq is higher than current or not */ -+}; -+ -+extern jz_clocks_t jz_clocks; -+ -+static void jz_update_clocks(void) -+{ -+ /* Next clocks must be updated if we have changed -+ * the PLL or divisors. -+ */ -+ jz_clocks.iclk = __cpm_get_iclk(); -+ jz_clocks.sclk = __cpm_get_sclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+} -+ -+static void -+jz_init_boot_config(void) -+{ -+ if (!boot_config.lcd_clks_initialized) { -+ /* the first time to scale pll */ -+ boot_config.lcd_clk = __cpm_get_lcdclk(); -+ boot_config.lcdpix_clk = __cpm_get_pixclk(); -+ boot_config.lcd_clks_initialized = 1; -+ } -+ -+ if (!boot_config.sdram_initialized) { -+ /* the first time to scale frequencies */ -+ unsigned int dmcr, rtcor; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ -+ dmcr = REG_EMC_DMCR; -+ rtcor = REG_EMC_RTCOR; -+ -+ tras = (dmcr >> 13) & 0x7; -+ rcd = (dmcr >> 11) & 0x3; -+ tpc = (dmcr >> 8) & 0x7; -+ trwl = (dmcr >> 5) & 0x3; -+ trc = (dmcr >> 2) & 0x7; -+ -+ boot_config.mclk = __cpm_get_mclk() / 1000; -+ boot_config.tras = tras + 4; -+ boot_config.rcd = rcd + 1; -+ boot_config.tpc = tpc + 1; -+ boot_config.trwl = trwl + 1; -+ boot_config.trc = trc * 2 + 1; -+ boot_config.rtcor = rtcor; -+ -+ boot_config.sdram_initialized = 1; -+ } -+} -+ -+static void jz_update_dram_rtcor(unsigned int new_mclk) -+{ -+ unsigned int rtcor; -+ -+ new_mclk /= 1000; -+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; -+ rtcor--; -+ -+ if (rtcor < 1) rtcor = 1; -+ if (rtcor > 255) rtcor = 255; -+ -+ REG_EMC_RTCOR = rtcor; -+ REG_EMC_RTCNT = rtcor; -+} -+ -+static void jz_update_dram_dmcr(unsigned int new_mclk) -+{ -+ unsigned int dmcr; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ unsigned int valid_time, new_time; /* ns */ -+ -+ new_mclk /= 1000; -+ tras = boot_config.tras * new_mclk / boot_config.mclk; -+ rcd = boot_config.rcd * new_mclk / boot_config.mclk; -+ tpc = boot_config.tpc * new_mclk / boot_config.mclk; -+ trwl = boot_config.trwl * new_mclk / boot_config.mclk; -+ trc = boot_config.trc * new_mclk / boot_config.mclk; -+ -+ /* Validation checking */ -+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; -+ new_time = (tras * 1000000) / new_mclk; -+ if (new_time < valid_time) tras += 1; -+ -+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; -+ new_time = (rcd * 1000000) / new_mclk; -+ if (new_time < valid_time) rcd += 1; -+ -+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; -+ new_time = (tpc * 1000000) / new_mclk; -+ if (new_time < valid_time) tpc += 1; -+ -+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; -+ new_time = (trwl * 1000000) / new_mclk; -+ if (new_time < valid_time) trwl += 1; -+ -+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; -+ new_time = (trc * 1000000) / new_mclk; -+ if (new_time < valid_time) trc += 2; -+ -+ tras = (tras < 4) ? 4: tras; -+ tras = (tras > 11) ? 11: tras; -+ tras -= 4; -+ -+ rcd = (rcd < 1) ? 1: rcd; -+ rcd = (rcd > 4) ? 4: rcd; -+ rcd -= 1; -+ -+ tpc = (tpc < 1) ? 1: tpc; -+ tpc = (tpc > 8) ? 8: tpc; -+ tpc -= 1; -+ -+ trwl = (trwl < 1) ? 1: trwl; -+ trwl = (trwl > 4) ? 4: trwl; -+ trwl -= 1; -+ -+ trc = (trc < 1) ? 1: trc; -+ trc = (trc > 15) ? 15: trc; -+ trc /= 2; -+ -+ dmcr = REG_EMC_DMCR; -+ -+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); -+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); -+ -+ REG_EMC_DMCR = dmcr; -+} -+ -+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR before changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } else { -+ /* We're going SLOWER: first update RTCOR value -+ * before changing the frequency. -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } -+} -+ -+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so update RTCOR -+ * after changing the frequency -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } else { -+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR after changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } -+} -+ -+static void jz_scale_divisors(struct dpm_regs *regs) -+{ -+ unsigned int cfcr; -+ unsigned int cur_mclk, new_mclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ cfcr = REG_CPM_CFCR; -+ cfcr &= ~((unsigned long)regs->cfcr_mask); -+ cfcr |= regs->cfcr; -+ cfcr |= CPM_CFCR_UPE; /* update immediately */ -+ -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = __cpm_get_pllout() / div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT]; -+ -+ /* Update some DRAM parameters before changing frequency */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+ -+#ifdef CHANGE_PLL -+/* Maintain the LCD clock and pixel clock */ -+static void jz_scale_lcd_divisors(struct dpm_regs *regs) -+{ -+ unsigned int new_pll, new_lcd_div, new_lcdpix_div; -+ unsigned int cfcr; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ if (!boot_config.lcd_clks_initialized) return; -+ -+ new_pll = __cpm_get_pllout(); -+ new_lcd_div = new_pll / boot_config.lcd_clk; -+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; -+ -+ if (new_lcd_div < 1) -+ new_lcd_div = 1; -+ if (new_lcd_div > 16) -+ new_lcd_div = 16; -+ -+ if (new_lcdpix_div < 1) -+ new_lcdpix_div = 1; -+ if (new_lcdpix_div > 512) -+ new_lcdpix_div = 512; -+ -+ REG_CPM_CFCR2 = new_lcdpix_div - 1; -+ -+ cfcr = REG_CPM_CFCR; -+ cfcr &= ~CPM_CFCR_LFR_MASK; -+ cfcr |= ((new_lcd_div - 1) << CPM_CFCR_LFR_BIT); -+ cfcr |= CPM_CFCR_UPE; /* update immediately */ -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CFCR), "r" (cfcr), "r" (wait), "r" (tmp)); -+} -+ -+static void jz_scale_pll(struct dpm_regs *regs) -+{ -+ unsigned int plcr1; -+ unsigned int cur_mclk, new_mclk, new_pll; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ int od[] = {1, 2, 2, 4}; -+ -+ plcr1 = REG_CPM_PLCR1; -+ plcr1 &= ~(regs->plcr1_mask | CPM_PLCR1_PLL1S | CPM_PLCR1_PLL1EN | CPM_PLCR1_PLL1ST_MASK); -+ regs->plcr1 &= ~CPM_PLCR1_PLL1EN; -+ plcr1 |= (regs->plcr1 | 0xff); -+ -+ /* Update some DRAM parameters before changing frequency */ -+ new_pll = JZ_EXTAL * ((plcr1>>23)+2) / ((((plcr1>>18)&0x1f)+2) * od[(plcr1>>16)&0x03]); -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = new_pll / div[(REG_CPM_CFCR>>16) & 0xf]; -+ -+ /* -+ * Update some SDRAM parameters -+ */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* -+ * Update PLL, align code to cache line. -+ */ -+ plcr1 |= CPM_PLCR1_PLL1EN; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_PLCR1), "r" (plcr1)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+#endif -+ -+static void jz4730_transition(struct dpm_regs *regs) -+{ -+ /* -+ * Get and save some boot-time conditions. -+ */ -+ jz_init_boot_config(); -+ -+#ifdef CHANGE_PLL -+ /* -+ * Disable LCD before scaling pll. -+ * LCD and LCD pixel clocks should not be changed even if the PLL -+ * output frequency has been changed. -+ */ -+ REG_LCD_CTRL &= ~LCD_CTRL_ENA; -+#endif -+ /* -+ * Stop module clocks before scaling PLL -+ */ -+ __cpm_stop_eth(); -+ __cpm_stop_aic_pclk(); -+ __cpm_stop_aic_bitclk(); -+ -+ /* ... add more as necessary */ -+ -+ if (regs->pll_up_flag == PLL_GOES_UP) { -+ /* the pll frequency is going up, so change dividors first */ -+ jz_scale_divisors(regs); -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ } -+ else if (regs->pll_up_flag == PLL_GOES_DOWN) { -+ /* the pll frequency is going down, so change pll first */ -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ jz_scale_divisors(regs); -+ } -+ else { -+ /* the pll frequency is unchanged, so change divisors only */ -+ jz_scale_divisors(regs); -+ } -+ -+ /* -+ * Restart module clocks before scaling PLL -+ */ -+ __cpm_start_eth(); -+ __cpm_start_aic_pclk(); -+ __cpm_start_aic_bitclk(); -+ -+ /* ... add more as necessary */ -+ -+#ifdef CHANGE_PLL -+ /* Scale the LCD divisors after scaling pll */ -+ if (regs->pll_up_flag != PLL_UNCHANGED) { -+ jz_scale_lcd_divisors(regs); -+ } -+ -+ /* Enable LCD controller */ -+ REG_LCD_CTRL &= ~LCD_CTRL_DIS; -+ REG_LCD_CTRL |= LCD_CTRL_ENA; -+#endif -+ -+ /* Update system clocks */ -+ jz_update_clocks(); -+} -+ -+extern unsigned int idle_times; -+static unsigned int jz4730_freq_get(unsigned int cpu) -+{ -+ return (__cpm_get_iclk() / 1000); -+} -+ -+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) -+{ -+ int n2FR[33] = { -+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, -+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, -+ 9 -+ }; -+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ -+ unsigned int div_of_cclk, new_freq, i; -+ -+ regs->pll_up_flag = PLL_UNCHANGED; -+ regs->cfcr_mask = CPM_CFCR_IFR_MASK | CPM_CFCR_SFR_MASK | CPM_CFCR_PFR_MASK | CPM_CFCR_MFR_MASK; -+ -+ new_freq = jz4730_freq_table.table[index].frequency; -+ -+ do { -+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); -+ } while (div_of_cclk==0); -+ -+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { -+ for(i = 1; i<4; i++) { -+ div[i] = 3; -+ } -+ } else { -+ for(i = 1; i<4; i++) { -+ div[i] = 2; -+ } -+ } -+ -+ for(i = 0; i<4; i++) { -+ div[i] *= div_of_cclk; -+ } -+ -+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); -+ -+ regs->cfcr = (n2FR[div[0]] << CPM_CFCR_IFR_BIT) | -+ (n2FR[div[1]] << CPM_CFCR_SFR_BIT) | -+ (n2FR[div[2]] << CPM_CFCR_PFR_BIT) | -+ (n2FR[div[3]] << CPM_CFCR_MFR_BIT); -+ -+ return div_of_cclk; -+} -+ -+static void jz4730_set_cpu_divider_index(unsigned int cpu, unsigned int index) -+{ -+ unsigned long divisor, old_divisor; -+ struct cpufreq_freqs freqs; -+ struct dpm_regs regs; -+ -+ old_divisor = __cpm_get_pllout() / __cpm_get_iclk(); -+ divisor = index_to_divisor(index, ®s); -+ -+ freqs.old = __cpm_get_iclk() / 1000; -+ freqs.new = __cpm_get_pllout() / (1000 * divisor); -+ freqs.cpu = cpu; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ -+ if (old_divisor != divisor) -+ jz4730_transition(®s); -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+} -+ -+static int jz4730_freq_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ unsigned int new_index = 0; -+ -+ if (cpufreq_frequency_table_target(policy, -+ &jz4730_freq_table.table[0], -+ target_freq, relation, &new_index)) -+ return -EINVAL; -+ -+ jz4730_set_cpu_divider_index(policy->cpu, new_index); -+ -+ dprintk("new frequency is %d KHz (REG_CPM_CFCR:0x%x)\n", __cpm_get_iclk() / 1000, REG_CPM_CFCR); -+ -+ return 0; -+} -+ -+static int jz4730_freq_verify(struct cpufreq_policy *policy) -+{ -+ return cpufreq_frequency_table_verify(policy, -+ &jz4730_freq_table.table[0]); -+} -+ -+static int __init jz4730_cpufreq_driver_init(struct cpufreq_policy *policy) -+{ -+ -+ struct cpufreq_frequency_table *table = &jz4730_freq_table.table[0]; -+ unsigned int MAX_FREQ; -+ -+ dprintk(KERN_INFO "Jz4730 cpufreq driver\n"); -+ -+ if (policy->cpu != 0) -+ return -EINVAL; -+ -+ policy->cur = MAX_FREQ = __cpm_get_iclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ -+ policy->cpuinfo.min_freq = MAX_FREQ/8; -+ policy->cpuinfo.max_freq = MAX_FREQ; -+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ -+ -+ table[0].index = 0; -+ table[0].frequency = MAX_FREQ/8; -+ table[1].index = 1; -+ table[1].frequency = MAX_FREQ/6; -+ table[2].index = 2; -+ table[2].frequency = MAX_FREQ/4; -+ table[3].index = 3; -+ table[3].frequency = MAX_FREQ/3; -+ table[4].index = 4; -+ table[4].frequency = MAX_FREQ/2; -+ table[5].index = 5; -+ table[5].frequency = MAX_FREQ; -+ table[6].index = 6; -+ table[6].frequency = CPUFREQ_TABLE_END; -+ -+ return cpufreq_frequency_table_cpuinfo(policy, table); -+} -+ -+static struct cpufreq_driver cpufreq_jz4730_driver = { -+// .flags = CPUFREQ_STICKY, -+ .init = jz4730_cpufreq_driver_init, -+ .verify = jz4730_freq_verify, -+ .target = jz4730_freq_target, -+ .get = jz4730_freq_get, -+ .name = "jz4730", -+}; -+ -+static int __init jz4730_cpufreq_init(void) -+{ -+ return cpufreq_register_driver(&cpufreq_jz4730_driver); -+} -+ -+static void __exit jz4730_cpufreq_exit(void) -+{ -+ cpufreq_unregister_driver(&cpufreq_jz4730_driver); -+} -+ -+module_init(jz4730_cpufreq_init); -+module_exit(jz4730_cpufreq_exit); -+ -+MODULE_AUTHOR("Regen "); -+MODULE_DESCRIPTION("cpufreq driver for Jz4730"); -+MODULE_LICENSE("GPL"); -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/dma.c linux-2.6.24.7/arch/mips/jz4730/dma.c ---- linux-2.6.24.7.old/arch/mips/jz4730/dma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/dma.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,509 @@ -+/* -+ * linux/arch/mips/jz4730/dma.c -+ * -+ * JZ4730 DMA PC-like APIs. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * A note on resource allocation: -+ * -+ * All drivers needing DMA channels, should allocate and release them -+ * through the public routines `jz_request_dma()' and `jz_free_dma()'. -+ * -+ * In order to avoid problems, all processes should allocate resources in -+ * the same sequence and release them in the reverse order. -+ * -+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. -+ * When releasing them, first release the IRQ, then release the DMA. The -+ * main reason for this order is that, if you are requesting the DMA buffer -+ * done interrupt, you won't know the irq number until the DMA channel is -+ * returned from jz_request_dma(). -+ */ -+ -+struct jz_dma_chan jz_dma_table[NUM_DMA] = { -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+}; -+ -+ -+// Device FIFO addresses and default DMA modes -+static const struct { -+ unsigned int fifo_addr; -+ unsigned int dma_mode; -+ unsigned int dma_source; -+} dma_dev_table[NUM_DMA_DEV] = { -+ {CPHYSADDR(UART0_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, -+ {CPHYSADDR(UART0_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, -+ {CPHYSADDR(UART1_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, -+ {CPHYSADDR(UART1_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, -+ {CPHYSADDR(UART2_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, -+ {CPHYSADDR(UART2_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, -+ {CPHYSADDR(UART3_BASE), DMA_8bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, -+ {CPHYSADDR(UART3_BASE), DMA_8bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, -+ {CPHYSADDR(SSI_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT}, -+ {CPHYSADDR(SSI_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_SSIIN}, -+ {CPHYSADDR(MSC_TXFIFO), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT}, -+ {CPHYSADDR(MSC_RXFIFO), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_MSCIN}, -+ {CPHYSADDR(AIC_DR), DMA_32bit_TX_CONF|DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, -+ {CPHYSADDR(AIC_DR), DMA_32bit_RX_CONF|DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, -+ {0, DMA_AUTOINIT, 0}, -+}; -+ -+ -+int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data) -+{ -+ int i, len = 0; -+ struct jz_dma_chan *chan; -+ -+ for (i = 0; i < NUM_DMA; i++) { -+ if ((chan = get_dma_chan(i)) != NULL) { -+ len += sprintf(buf + len, "%2d: %s\n", -+ i, chan->dev_str); -+ } -+ } -+ -+ if (fpos >= len) { -+ *start = buf; -+ *eof = 1; -+ return 0; -+ } -+ *start = buf + fpos; -+ if ((len -= fpos) > length) -+ return length; -+ *eof = 1; -+ return len; -+} -+ -+ -+void dump_jz_dma_channel(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > NUM_DMA) -+ return; -+ chan = &jz_dma_table[dmanr]; -+ -+ printk(KERN_INFO "DMA%d Register Dump:\n", dmanr); -+ printk(KERN_INFO " DMACR= 0x%08x\n", REG_DMAC_DMACR); -+ printk(KERN_INFO " DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); -+ printk(KERN_INFO " DDAR = 0x%08x\n", REG_DMAC_DDAR(dmanr)); -+ printk(KERN_INFO " DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); -+ printk(KERN_INFO " DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); -+ printk(KERN_INFO " DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); -+} -+ -+ -+/** -+ * jz_request_dma - dynamically allcate an idle DMA channel to return -+ * @dev_id: the specified dma device id or DMA_ID_RAW_REQ -+ * @dev_str: the specified dma device string name -+ * @irqhandler: the irq handler, or NULL -+ * @irqflags: the irq handler flags -+ * @irq_dev_id: the irq handler device id for shared irq -+ * -+ * Finds a free channel, and binds the requested device to it. -+ * Returns the allocated channel number, or negative on error. -+ * Requests the DMA done IRQ if irqhandler != NULL. -+ * -+*/ -+int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+{ -+ struct jz_dma_chan *chan; -+ int i, ret; -+ -+ if (dev_id < 0 || dev_id >= NUM_DMA_DEV) -+ return -EINVAL; -+ -+ for (i = 0; i < NUM_DMA; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == NUM_DMA) -+ return -ENODEV; -+ -+ chan = &jz_dma_table[i]; -+ -+ if (irqhandler) { -+ chan->irq = IRQ_DMA_0 + i; // see intc.h -+ chan->irq_dev = irq_dev_id; -+ if ((ret = request_irq(chan->irq, irqhandler, irqflags, -+ dev_str, chan->irq_dev))) { -+ chan->irq = 0; -+ chan->irq_dev = NULL; -+ return ret; -+ } -+ } else { -+ chan->irq = 0; -+ chan->irq_dev = NULL; -+ } -+ -+ // fill it in -+ chan->io = i; -+ chan->dev_id = dev_id; -+ chan->dev_str = dev_str; -+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; -+ chan->mode = dma_dev_table[dev_id].dma_mode; -+ chan->source = dma_dev_table[dev_id].dma_source; -+ -+ return i; -+} -+ -+void jz_free_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) { -+ printk("Trying to free DMA%d\n", dmanr); -+ return; -+ } -+ -+ disable_dma(dmanr); -+ if (chan->irq) -+ free_irq(chan->irq, chan->irq_dev); -+ -+ chan->irq = 0; -+ chan->irq_dev = NULL; -+ chan->dev_id = -1; -+} -+ -+void jz_set_dma_dest_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ chan->mode &= ~DMAC_DCCSR_DWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCCSR_DWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCCSR_DWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCCSR_DWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_src_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ chan->mode &= ~DMAC_DCCSR_SWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCCSR_SWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCCSR_SWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCCSR_SWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ chan->mode &= ~DMAC_DCCSR_DS_MASK; -+ switch (nbyte) { -+ case 1: -+ chan->mode |= DMAC_DCCSR_DS_8b; -+ break; -+ case 2: -+ chan->mode |= DMAC_DCCSR_DS_16b; -+ break; -+ case 4: -+ chan->mode |= DMAC_DCCSR_DS_32b; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCCSR_DS_16B; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCCSR_DS_32B; -+ break; -+ } -+} -+ -+/** -+ * jz_set_dma_mode - do the raw settings for the specified DMA channel -+ * @dmanr: the specified DMA channel -+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE -+ * @dma_mode: dma raw mode -+ * @dma_source: dma raw request source -+ * @fifo_addr: dma raw device fifo address -+ * -+ * Ensure call jz_request_dma(DMA_ID_RAW_REQ, ...) first, then call -+ * jz_set_dma_mode() rather than set_dma_mode() if you work with -+ * and external request dma device. -+ * -+ * NOTE: Don not dynamically allocate dma channel if one external request -+ * dma device will occupy this channel. -+*/ -+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, -+ unsigned int dma_mode, unsigned int dma_source, -+ unsigned int fifo_addr) -+{ -+ int dev_id, i; -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > NUM_DMA) -+ return -ENODEV; -+ for (i = 0; i < NUM_DMA; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == NUM_DMA) -+ return -ENODEV; -+ -+ chan = &jz_dma_table[dmanr]; -+ dev_id = chan->dev_id; -+ if (dev_id > 0) { -+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", -+ __FUNCTION__, dmanr); -+ return -ENODEV; -+ } -+ -+ /* clone it from the dynamically allocated. */ -+ if (i != dmanr) { -+ chan->irq = jz_dma_table[i].irq; -+ chan->irq_dev = jz_dma_table[i].irq_dev; -+ chan->dev_str = jz_dma_table[i].dev_str; -+ jz_dma_table[i].irq = 0; -+ jz_dma_table[i].irq_dev = NULL; -+ jz_dma_table[i].dev_id = -1; -+ } -+ chan->dev_id = DMA_ID_RAW_SET; -+ chan->io = dmanr; -+ chan->fifo_addr = fifo_addr; -+ chan->mode = dma_mode; -+ chan->source = dma_source; -+ -+ set_dma_mode(dmanr, dma_mode); -+ -+ return dmanr; -+} -+ -+void enable_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ __dmac_enable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_enable_irq(dmanr); -+} -+ -+#define DMA_DISABLE_POLL 0x5000 -+ -+void disable_dma(unsigned int dmanr) -+{ -+ int i; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ if (!__dmac_channel_enabled(dmanr)) -+ return; -+ -+ for (i = 0; i < DMA_DISABLE_POLL; i++) -+ if (__dmac_channel_transmit_end_detected(dmanr)) -+ break; -+#if 0 -+ if (i == DMA_DISABLE_POLL) -+ printk(KERN_INFO "disable_dma: poll expired!\n"); -+#endif -+ -+ __dmac_disable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_disable_irq(dmanr); -+} -+ -+/* note: DMA_MODE_MASK is simulated by sw, DCCSR_MODE_MASK mask hw bits */ -+void set_dma_mode(unsigned int dmanr, unsigned int mode) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); -+ mode &= DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ chan->mode |= DMAC_DCCSR_DAM; -+ chan->mode &= ~DMAC_DCCSR_SAM; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; -+ chan->mode &= ~DMAC_DCCSR_DAM; -+ } else { -+ printk(KERN_DEBUG "set_dma_mode() support DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ } -+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+} -+ -+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case AFMT_U8: -+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ -+ break; -+ case AFMT_S16_LE: -+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCCSR_DAM; -+ chan->mode &= ~DMAC_DCCSR_SAM; -+ } else if (mode == DMA_MODE_WRITE) { -+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM |DMAC_DCCSR_DAM); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; -+ chan->mode &= ~DMAC_DCCSR_DAM; -+ } else -+ printk("jz_set_oss_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case 8: -+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ -+ break; -+ case 16: -+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCCSR_DAM; -+ chan->mode &= ~DMAC_DCCSR_SAM; -+ } else if (mode == DMA_MODE_WRITE) { -+ mode &= ~(DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM | DMAC_DCCSR_DAM); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCCSR_SAM | DMAC_DCCSR_EACKM; -+ chan->mode &= ~DMAC_DCCSR_DAM; -+ } else -+ printk("jz_set_alsa_dma() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCCSR(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+void set_dma_addr(unsigned int dmanr, unsigned int a) -+{ -+ unsigned int mode; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ mode = chan->mode & DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; -+ REG_DMAC_DDAR(chan->io) = a; -+ } else if (mode == DMA_MODE_WRITE) { -+ REG_DMAC_DSAR(chan->io) = a; -+ REG_DMAC_DDAR(chan->io) = chan->fifo_addr; -+ } else -+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); -+} -+ -+void set_dma_count(unsigned int dmanr, unsigned int count) -+{ -+ unsigned int mode; -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT; -+ count = count / dma_ds[mode]; -+ REG_DMAC_DTCR(chan->io) = count; -+} -+ -+int get_dma_residue(unsigned int dmanr) -+{ -+ int count; -+ unsigned int mode; -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ -+ mode = (chan->mode & DMAC_DCCSR_DS_MASK) >> DMAC_DCCSR_DS_BIT; -+ count = REG_DMAC_DTCR(chan->io); -+ count = count * dma_ds[mode]; -+ -+ return count; -+} -+ -+EXPORT_SYMBOL(jz_dma_table); -+EXPORT_SYMBOL(jz_request_dma); -+EXPORT_SYMBOL(jz_free_dma); -+EXPORT_SYMBOL(jz_set_dma_src_width); -+EXPORT_SYMBOL(jz_set_dma_dest_width); -+EXPORT_SYMBOL(jz_set_dma_block_size); -+EXPORT_SYMBOL(jz_set_dma_mode); -+EXPORT_SYMBOL(set_dma_mode); -+EXPORT_SYMBOL(jz_set_oss_dma); -+EXPORT_SYMBOL(jz_set_alsa_dma); -+EXPORT_SYMBOL(set_dma_addr); -+EXPORT_SYMBOL(set_dma_count); -+EXPORT_SYMBOL(get_dma_residue); -+EXPORT_SYMBOL(enable_dma); -+EXPORT_SYMBOL(disable_dma); -+EXPORT_SYMBOL(dump_jz_dma_channel); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/i2c.c linux-2.6.24.7/arch/mips/jz4730/i2c.c ---- linux-2.6.24.7.old/arch/mips/jz4730/i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/i2c.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,214 @@ -+/* -+ * linux/arch/mips/jz4730/i2c.c -+ * -+ * JZ4730 I2C APIs. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* I2C protocol */ -+#define I2C_READ 1 -+#define I2C_WRITE 0 -+ -+#define TIMEOUT 1000 -+ -+/* -+ * I2C bus protocol basic routines -+ */ -+static int i2c_put_data(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT * 10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (!__i2c_received_ack() && timeout) -+ timeout--; -+ -+ if (timeout) -+ return 0; -+ else -+ return -ETIMEDOUT; -+} -+ -+static int i2c_get_data(unsigned char *data, int ack) -+{ -+ int timeout = TIMEOUT*10; -+ -+ if (!ack) -+ __i2c_send_nack(); -+ else -+ __i2c_send_ack(); -+ -+ while (__i2c_check_drf() == 0 && timeout) -+ timeout--; -+ -+ if (timeout) { -+ if (!ack) -+ __i2c_send_stop(); -+ *data = __i2c_read(); -+ __i2c_clear_drf(); -+ return 0; -+ } else -+ return -ETIMEDOUT; -+} -+ -+/* -+ * I2C interface -+ */ -+void i2c_open(void) -+{ -+ __i2c_set_clk(jz_clocks.devclk, 10000); /* default 10 KHz */ -+ __i2c_enable(); -+} -+ -+void i2c_close(void) -+{ -+ udelay(300); /* wait for STOP goes over. */ -+ __i2c_disable(); -+} -+ -+void i2c_setclk(unsigned int i2cclk) -+{ -+ __i2c_set_clk(jz_clocks.devclk, i2cclk); -+} -+ -+int i2c_lseek(unsigned char device, unsigned char offset) -+{ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (i2c_put_data(offset) < 0) -+ goto address_err; -+ return 0; -+ device_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+ address_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); -+ __i2c_send_stop(); -+ return -EREMOTEIO; -+} -+ -+int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int timeout = 5; -+ -+L_try_again: -+ -+ if (timeout < 0) -+ goto L_timeout; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_werr; -+ if (i2c_put_data(address) < 0) -+ goto address_err; -+ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) -+ goto device_rerr; -+ __i2c_send_ack(); /* Master sends ACK for continue reading */ -+ while (cnt) { -+ if (cnt == 1) { -+ if (i2c_get_data(buf, 0) < 0) -+ break; -+ } else { -+ if (i2c_get_data(buf, 1) < 0) -+ break; -+ } -+ cnt--; -+ buf++; -+ } -+ -+ __i2c_send_stop(); -+ return count - cnt; -+ device_rerr: -+ device_werr: -+ address_err: -+ timeout --; -+ __i2c_send_stop(); -+ goto L_try_again; -+ -+L_timeout: -+ __i2c_send_stop(); -+ printk("Read I2C device 0x%2x failed.\n", device); -+ return -ENODEV; -+} -+ -+int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int cnt_in_pg; -+ int timeout = 5; -+ unsigned char *tmpbuf; -+ unsigned char tmpaddr; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ W_try_again: -+ if (timeout < 0) -+ goto W_timeout; -+ -+ cnt = count; -+ tmpbuf = (unsigned char *)buf; -+ tmpaddr = address; -+ -+ start_write_page: -+ cnt_in_pg = 0; -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ __i2c_send_stop(); -+ return count - cnt; -+ device_err: -+ address_err: -+ timeout--; -+ __i2c_send_stop(); -+ goto W_try_again; -+ -+ W_timeout: -+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+} -+ -+EXPORT_SYMBOL(i2c_open); -+EXPORT_SYMBOL(i2c_close); -+EXPORT_SYMBOL(i2c_setclk); -+EXPORT_SYMBOL(i2c_read); -+EXPORT_SYMBOL(i2c_write); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/irq.c linux-2.6.24.7/arch/mips/jz4730/irq.c ---- linux-2.6.24.7.old/arch/mips/jz4730/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/irq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,266 @@ -+/* -+ * linux/arch/mips/jz4730/irq.c -+ * -+ * JZ4730 interrupt routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * INTC irq type -+ */ -+ -+static void enable_intc_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(irq); -+} -+ -+static void disable_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+} -+ -+static void mask_and_ack_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+ __intc_ack_irq(irq); -+} -+ -+static void end_intc_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_intc_irq(irq); -+ } -+} -+ -+static unsigned int startup_intc_irq(unsigned int irq) -+{ -+ enable_intc_irq(irq); -+ return 0; -+} -+ -+static void shutdown_intc_irq(unsigned int irq) -+{ -+ disable_intc_irq(irq); -+} -+ -+static struct irq_chip intc_irq_type = { -+ .typename = "INTC", -+ .startup = startup_intc_irq, -+ .shutdown = shutdown_intc_irq, -+ .enable = enable_intc_irq, -+ .disable = disable_intc_irq, -+ .ack = mask_and_ack_intc_irq, -+ .end = end_intc_irq, -+}; -+ -+/* -+ * GPIO irq type -+ */ -+ -+static void enable_gpio_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if (irq < (IRQ_GPIO_0 + 32)) { -+ intc_irq = IRQ_GPIO0; -+ } -+ else if (irq < (IRQ_GPIO_0 + 64)) { -+ intc_irq = IRQ_GPIO1; -+ } -+ else if (irq < (IRQ_GPIO_0 + 96)) { -+ intc_irq = IRQ_GPIO2; -+ } -+ else { -+ intc_irq = IRQ_GPIO3; -+ } -+ -+ enable_intc_irq(intc_irq); -+ __gpio_unmask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void disable_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void mask_and_ack_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+ __gpio_ack_irq(irq - IRQ_GPIO_0); -+} -+ -+static void end_gpio_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_gpio_irq(irq); -+ } -+} -+ -+static unsigned int startup_gpio_irq(unsigned int irq) -+{ -+ enable_gpio_irq(irq); -+ return 0; -+} -+ -+static void shutdown_gpio_irq(unsigned int irq) -+{ -+ disable_gpio_irq(irq); -+} -+ -+static struct irq_chip gpio_irq_type = { -+ .typename = "GPIO", -+ .startup = startup_gpio_irq, -+ .shutdown = shutdown_gpio_irq, -+ .enable = enable_gpio_irq, -+ .disable = disable_gpio_irq, -+ .ack = mask_and_ack_gpio_irq, -+ .end = end_gpio_irq, -+}; -+ -+/* -+ * DMA irq type -+ */ -+ -+static void enable_dma_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(IRQ_DMAC); -+ __dmac_channel_enable_irq(irq - IRQ_DMA_0); -+} -+ -+static void disable_dma_irq(unsigned int irq) -+{ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void mask_and_ack_dma_irq(unsigned int irq) -+{ -+ __intc_ack_irq(IRQ_DMAC); -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void end_dma_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_dma_irq(irq); -+ } -+} -+ -+static unsigned int startup_dma_irq(unsigned int irq) -+{ -+ enable_dma_irq(irq); -+ return 0; -+} -+ -+static void shutdown_dma_irq(unsigned int irq) -+{ -+ disable_dma_irq(irq); -+} -+ -+static struct irq_chip dma_irq_type = { -+ .typename = "DMA", -+ .startup = startup_dma_irq, -+ .shutdown = shutdown_dma_irq, -+ .enable = enable_dma_irq, -+ .disable = disable_dma_irq, -+ .ack = mask_and_ack_dma_irq, -+ .end = end_dma_irq, -+}; -+ -+//---------------------------------------------------------------------- -+ -+void __init arch_init_irq(void) -+{ -+ int i; -+ -+ clear_c0_status(0xff04); /* clear ERL */ -+ set_c0_status(0x0400); /* set IP2 */ -+ -+ /* Set up INTC irq -+ */ -+ for (i = 0; i < 32; i++) { -+ disable_intc_irq(i); -+ irq_desc[i].chip = &intc_irq_type; -+ } -+ -+ /* Set up DMAC irq -+ */ -+ for (i = 0; i < NUM_DMA; i++) { -+ disable_dma_irq(IRQ_DMA_0 + i); -+ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; -+ } -+ -+ /* Set up GPIO irq -+ */ -+ for (i = 0; i < NUM_GPIO; i++) { -+ disable_gpio_irq(IRQ_GPIO_0 + i); -+ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; -+ } -+} -+ -+static int plat_real_irq(int irq) -+{ -+ switch (irq) { -+ case IRQ_GPIO0: -+ irq = __gpio_group_irq(0) + IRQ_GPIO_0; -+ break; -+ case IRQ_GPIO1: -+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; -+ break; -+ case IRQ_GPIO2: -+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; -+ break; -+ case IRQ_GPIO3: -+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; -+ break; -+ case IRQ_DMAC: -+ irq = __dmac_get_irq() + IRQ_DMA_0; -+ break; -+ } -+ -+ return irq; -+} -+ -+asmlinkage void plat_irq_dispatch(void) -+{ -+ int irq = 0; -+ static unsigned long intc_ipr = 0; -+ -+ intc_ipr |= REG_INTC_IPR; -+ -+ if (!intc_ipr) return; -+ -+ irq = ffs(intc_ipr) - 1; -+ intc_ipr &= ~(1< -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* OHCI (USB full speed host controller) */ -+static struct resource jz_usb_ohci_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap -+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UHC, -+ .end = IRQ_UHC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+/* The dmamask must be set for OHCI to work */ -+static u64 ohci_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_ohci_device = { -+ .name = "jz-ohci", -+ .id = 0, -+ .dev = { -+ .dma_mask = &ohci_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), -+ .resource = jz_usb_ohci_resources, -+}; -+ -+/*** LCD controller ***/ -+static struct resource jz_lcd_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(LCD_BASE), -+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_LCD, -+ .end = IRQ_LCD, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_lcd_dmamask = ~(u32)0; -+ -+static struct platform_device jz_lcd_device = { -+ .name = "jz-lcd", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_lcd_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_lcd_resources), -+ .resource = jz_lcd_resources, -+}; -+ -+/* UDC (USB gadget controller) */ -+static struct resource jz_usb_gdt_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UDC_BASE), -+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UDC, -+ .end = IRQ_UDC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static u64 udc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_gdt_device = { -+ .name = "jz-udc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &udc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), -+ .resource = jz_usb_gdt_resources, -+}; -+ -+/** MMC/SD controller **/ -+static struct resource jz_mmc_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(MSC_BASE), -+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_MSC, -+ .end = IRQ_MSC, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_mmc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_mmc_device = { -+ .name = "jz-mmc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_mmc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_mmc_resources), -+ .resource = jz_mmc_resources, -+}; -+ -+/* All */ -+static struct platform_device *jz_platform_devices[] __initdata = { -+ &jz_usb_ohci_device, -+ &jz_lcd_device, -+ &jz_usb_gdt_device, -+ &jz_mmc_device, -+}; -+ -+static int __init jz_platform_init(void) -+{ -+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); -+} -+ -+arch_initcall(jz_platform_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/pm.c linux-2.6.24.7/arch/mips/jz4730/pm.c ---- linux-2.6.24.7.old/arch/mips/jz4730/pm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/pm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1098 @@ -+/* -+ * linux/arch/mips/jz4730/pm.c -+ * -+ * Jz4730 Power Management Routines -+ * -+ * Copyright 2005 Ingenic Semiconductor -+ * Wei Jianli -+ * Huang Lihong -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+extern void jz_cpu_suspend(void); -+extern void jz_cpu_resume(void); -+ -+static void jz_board_pm_suspend(void); -+ -+#define SAVE(x,s) sleep_save[SLEEP_SAVE_##x] = REG##s(x) -+#define RESTORE(x,s) REG##s(x) = sleep_save[SLEEP_SAVE_##x] -+ -+/* -+ * List of global jz4730 peripheral registers to preserve. -+ * More ones like core register and general purpose register values -+ * are preserved with the stack pointer in sleep.S. -+ */ -+enum { SLEEP_SAVE_START = 0, -+ -+ /* CPM */ -+ SLEEP_SAVE_CPM_MSCR, SLEEP_SAVE_CPM_PLCR1, -+ -+ /* WDT */ -+ SLEEP_SAVE_WDT_WTCNT, SLEEP_SAVE_WDT_WTCSR, -+ -+ /* OST */ -+ SLEEP_SAVE_OST_TER, -+ SLEEP_SAVE_OST_TCSR0, SLEEP_SAVE_OST_TCSR1, SLEEP_SAVE_OST_TCSR2, -+ SLEEP_SAVE_OST_TRDR0, SLEEP_SAVE_OST_TRDR1, SLEEP_SAVE_OST_TRDR2, -+ SLEEP_SAVE_OST_TCNT0, SLEEP_SAVE_OST_TCNT1, SLEEP_SAVE_OST_TCNT2, -+ -+ /* HARB */ -+ SLEEP_SAVE_HARB_HAPOR, SLEEP_SAVE_HARB_HMCTR, SLEEP_SAVE_HARB_HMLTR, -+ -+ /* EMC */ -+ SLEEP_SAVE_EMC_SMCR0, SLEEP_SAVE_EMC_SMCR1, SLEEP_SAVE_EMC_SMCR2, SLEEP_SAVE_EMC_SMCR3, -+ SLEEP_SAVE_EMC_SMCR4, SLEEP_SAVE_EMC_SMCR5, -+ -+ /* GPIO */ -+ SLEEP_SAVE_GPIO_GPDR0, SLEEP_SAVE_GPIO_GPDR1, SLEEP_SAVE_GPIO_GPDR2, SLEEP_SAVE_GPIO_GPDR3, -+ SLEEP_SAVE_GPIO_GPDIR0, SLEEP_SAVE_GPIO_GPDIR1, SLEEP_SAVE_GPIO_GPDIR2, SLEEP_SAVE_GPIO_GPDIR3, -+ SLEEP_SAVE_GPIO_GPODR0, SLEEP_SAVE_GPIO_GPODR1, SLEEP_SAVE_GPIO_GPODR2, SLEEP_SAVE_GPIO_GPODR3, -+ SLEEP_SAVE_GPIO_GPPUR0, SLEEP_SAVE_GPIO_GPPUR1, SLEEP_SAVE_GPIO_GPPUR2, SLEEP_SAVE_GPIO_GPPUR3, -+ SLEEP_SAVE_GPIO_GPALR0, SLEEP_SAVE_GPIO_GPALR1, SLEEP_SAVE_GPIO_GPALR2, SLEEP_SAVE_GPIO_GPALR3, -+ SLEEP_SAVE_GPIO_GPAUR0, SLEEP_SAVE_GPIO_GPAUR1, SLEEP_SAVE_GPIO_GPAUR2, SLEEP_SAVE_GPIO_GPAUR3, -+ SLEEP_SAVE_GPIO_GPIDLR0, SLEEP_SAVE_GPIO_GPIDLR1, SLEEP_SAVE_GPIO_GPIDLR2, SLEEP_SAVE_GPIO_GPIDLR3, -+ SLEEP_SAVE_GPIO_GPIDUR0, SLEEP_SAVE_GPIO_GPIDUR1, SLEEP_SAVE_GPIO_GPIDUR2, SLEEP_SAVE_GPIO_GPIDUR3, -+ SLEEP_SAVE_GPIO_GPIER0, SLEEP_SAVE_GPIO_GPIER1, SLEEP_SAVE_GPIO_GPIER2, SLEEP_SAVE_GPIO_GPIER3, -+ SLEEP_SAVE_GPIO_GPIMR0, SLEEP_SAVE_GPIO_GPIMR1, SLEEP_SAVE_GPIO_GPIMR2, SLEEP_SAVE_GPIO_GPIMR3, -+ SLEEP_SAVE_GPIO_GPFR0, SLEEP_SAVE_GPIO_GPFR1, SLEEP_SAVE_GPIO_GPFR2, SLEEP_SAVE_GPIO_GPFR3, -+ -+ /* UART(0-3) */ -+ SLEEP_SAVE_UART0_IER, SLEEP_SAVE_UART0_LCR, SLEEP_SAVE_UART0_MCR, SLEEP_SAVE_UART0_SPR, SLEEP_SAVE_UART0_DLLR, SLEEP_SAVE_UART0_DLHR, -+ SLEEP_SAVE_UART1_IER, SLEEP_SAVE_UART1_LCR, SLEEP_SAVE_UART1_MCR, SLEEP_SAVE_UART1_SPR, SLEEP_SAVE_UART1_DLLR, SLEEP_SAVE_UART1_DLHR, -+ SLEEP_SAVE_UART2_IER, SLEEP_SAVE_UART2_LCR, SLEEP_SAVE_UART2_MCR, SLEEP_SAVE_UART2_SPR, SLEEP_SAVE_UART2_DLLR, SLEEP_SAVE_UART2_DLHR, -+ SLEEP_SAVE_UART3_IER, SLEEP_SAVE_UART3_LCR, SLEEP_SAVE_UART3_MCR, SLEEP_SAVE_UART3_SPR, SLEEP_SAVE_UART3_DLLR, SLEEP_SAVE_UART3_DLHR, -+ -+ /* DMAC */ -+ SLEEP_SAVE_DMAC_DMACR, -+ SLEEP_SAVE_DMAC_DSAR0, SLEEP_SAVE_DMAC_DSAR1, SLEEP_SAVE_DMAC_DSAR2, SLEEP_SAVE_DMAC_DSAR3, SLEEP_SAVE_DMAC_DSAR4, SLEEP_SAVE_DMAC_DSAR5, SLEEP_SAVE_DMAC_DSAR6, SLEEP_SAVE_DMAC_DSAR7, -+ SLEEP_SAVE_DMAC_DDAR0, SLEEP_SAVE_DMAC_DDAR1, SLEEP_SAVE_DMAC_DDAR2, SLEEP_SAVE_DMAC_DDAR3, SLEEP_SAVE_DMAC_DDAR4, SLEEP_SAVE_DMAC_DDAR5, SLEEP_SAVE_DMAC_DDAR6, SLEEP_SAVE_DMAC_DDAR7, -+ SLEEP_SAVE_DMAC_DTCR0, SLEEP_SAVE_DMAC_DTCR1, SLEEP_SAVE_DMAC_DTCR2, SLEEP_SAVE_DMAC_DTCR3, SLEEP_SAVE_DMAC_DTCR4, SLEEP_SAVE_DMAC_DTCR5, SLEEP_SAVE_DMAC_DTCR6, SLEEP_SAVE_DMAC_DTCR7, -+ SLEEP_SAVE_DMAC_DRSR0, SLEEP_SAVE_DMAC_DRSR1, SLEEP_SAVE_DMAC_DRSR2, SLEEP_SAVE_DMAC_DRSR3, SLEEP_SAVE_DMAC_DRSR4, SLEEP_SAVE_DMAC_DRSR5, SLEEP_SAVE_DMAC_DRSR6, SLEEP_SAVE_DMAC_DRSR7, -+ SLEEP_SAVE_DMAC_DCCSR0, SLEEP_SAVE_DMAC_DCCSR1, SLEEP_SAVE_DMAC_DCCSR2, SLEEP_SAVE_DMAC_DCCSR3, SLEEP_SAVE_DMAC_DCCSR4, SLEEP_SAVE_DMAC_DCCSR5, SLEEP_SAVE_DMAC_DCCSR6, SLEEP_SAVE_DMAC_DCCSR7, -+ -+ /* INTC */ -+ SLEEP_SAVE_INTC_IPR, SLEEP_SAVE_INTC_ISR, SLEEP_SAVE_INTC_IMR, -+ -+ /* Checksum */ -+ SLEEP_SAVE_CKSUM, -+ -+ SLEEP_SAVE_SIZE -+}; -+ -+static unsigned long sleep_save[SLEEP_SAVE_SIZE]; -+ -+static int jz_pm_do_suspend(void) -+{ -+ unsigned long checksum = 0; -+ unsigned long imr = REG_INTC_IMR; -+ int i; -+ -+ printk("Put cpu into suspend mode.\n"); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* Preserve current time */ -+ REG_RTC_RSR = xtime.tv_sec; -+ -+ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY0; /* suspend USB PHY 0 */ -+ REG_CPM_OCR |= CPM_OCR_SUSPEND_PHY1; /* suspend USB PHY 1 */ -+ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* select the external RTC clock (32.768KHz) */ -+ -+ /* Disable NAND ctroller */ -+ REG_EMC_NFCSR &= ~(EMC_NFCSR_NFE | EMC_NFCSR_FCE); -+ -+ /* -+ * Temporary solution. This won't be necessary once -+ * we move this support into the device drivers. -+ * Save the on-chip modules -+ */ -+ SAVE(UART0_LCR, 8); SAVE(UART0_MCR, 8); SAVE(UART0_SPR, 8); -+ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ SAVE(UART0_DLLR, 8); SAVE(UART0_DLHR, 8); -+ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ SAVE(UART0_IER, 8); -+ -+ SAVE(UART1_LCR, 8); SAVE(UART1_MCR, 8); SAVE(UART1_SPR, 8); -+ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ SAVE(UART1_DLLR, 8); SAVE(UART1_DLHR, 8); -+ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ SAVE(UART1_IER, 8); -+ -+ SAVE(UART2_LCR, 8); SAVE(UART2_MCR, 8); SAVE(UART2_SPR, 8); -+ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ SAVE(UART2_DLLR, 8); SAVE(UART2_DLHR, 8); -+ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ SAVE(UART2_IER, 8); -+ -+ SAVE(UART3_LCR, 8); SAVE(UART3_MCR, 8); SAVE(UART3_SPR, 8); -+ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ SAVE(UART3_DLLR, 8); SAVE(UART3_DLHR, 8); -+ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ SAVE(UART3_IER, 8); -+ -+ /* Save vital registers */ -+ -+ SAVE(OST_TER, 8); -+ SAVE(OST_TCSR0, 16); SAVE(OST_TCSR1, 16); SAVE(OST_TCSR2, 16); -+ SAVE(OST_TRDR0, 32); SAVE(OST_TRDR1, 32); SAVE(OST_TRDR2, 32); -+ SAVE(OST_TCNT0, 32); SAVE(OST_TCNT1, 32); SAVE(OST_TCNT2, 32); -+ -+ SAVE(HARB_HAPOR, 32); SAVE(HARB_HMCTR, 32); SAVE(HARB_HMLTR, 32); -+ -+ SAVE(EMC_SMCR0, 32); SAVE(EMC_SMCR1, 32); SAVE(EMC_SMCR2, 32); SAVE(EMC_SMCR3, 32); -+ SAVE(EMC_SMCR4, 32); SAVE(EMC_SMCR5, 32); -+ -+ SAVE(GPIO_GPDR0, 32); SAVE(GPIO_GPDR1, 32); SAVE(GPIO_GPDR2, 32); -+ SAVE(GPIO_GPDR3, 32); -+ SAVE(GPIO_GPDIR0, 32); SAVE(GPIO_GPDIR1, 32); SAVE(GPIO_GPDIR2, 32); -+ SAVE(GPIO_GPDIR3, 32); -+ SAVE(GPIO_GPODR0, 32); SAVE(GPIO_GPODR1, 32); SAVE(GPIO_GPODR2, 32); -+ SAVE(GPIO_GPODR3, 32); -+ SAVE(GPIO_GPPUR0, 32); SAVE(GPIO_GPPUR1, 32); SAVE(GPIO_GPPUR2, 32); -+ SAVE(GPIO_GPPUR3, 32); -+ SAVE(GPIO_GPALR0, 32); SAVE(GPIO_GPALR1, 32); SAVE(GPIO_GPALR2, 32); -+ SAVE(GPIO_GPALR3, 32); -+ SAVE(GPIO_GPAUR0, 32); SAVE(GPIO_GPAUR1, 32); SAVE(GPIO_GPAUR2, 32); -+ SAVE(GPIO_GPAUR3, 32); -+ SAVE(GPIO_GPIDLR0, 32); SAVE(GPIO_GPIDLR1, 32); SAVE(GPIO_GPIDLR2, 32); -+ SAVE(GPIO_GPIDLR3, 32); -+ SAVE(GPIO_GPIDUR0, 32); SAVE(GPIO_GPIDUR1, 32); SAVE(GPIO_GPIDUR2, 32); -+ SAVE(GPIO_GPIDUR3, 32); -+ SAVE(GPIO_GPIER0, 32); SAVE(GPIO_GPIER1, 32); SAVE(GPIO_GPIER2, 32); -+ SAVE(GPIO_GPIER3, 32); -+ SAVE(GPIO_GPIMR0, 32); SAVE(GPIO_GPIMR1, 32); SAVE(GPIO_GPIMR2, 32); -+ SAVE(GPIO_GPIMR3, 32); -+ SAVE(GPIO_GPFR0, 32); SAVE(GPIO_GPFR1, 32); SAVE(GPIO_GPFR2, 32); -+ SAVE(GPIO_GPFR3, 32); -+ -+ SAVE(DMAC_DMACR, 32); -+ SAVE(DMAC_DSAR0, 32); SAVE(DMAC_DSAR1, 32); SAVE(DMAC_DSAR2, 32); SAVE(DMAC_DSAR3, 32); SAVE(DMAC_DSAR4, 32); SAVE(DMAC_DSAR5, 32); SAVE(DMAC_DSAR6, 32); SAVE(DMAC_DSAR7, 32); -+ SAVE(DMAC_DDAR0, 32); SAVE(DMAC_DDAR1, 32); SAVE(DMAC_DDAR2, 32); SAVE(DMAC_DDAR3, 32); SAVE(DMAC_DDAR4, 32); SAVE(DMAC_DDAR5, 32); SAVE(DMAC_DDAR6, 32); SAVE(DMAC_DDAR7, 32); -+ SAVE(DMAC_DTCR0, 32); SAVE(DMAC_DTCR1, 32); SAVE(DMAC_DTCR2, 32); SAVE(DMAC_DTCR3, 32); SAVE(DMAC_DTCR4, 32); SAVE(DMAC_DTCR5, 32); SAVE(DMAC_DTCR6, 32); SAVE(DMAC_DTCR7, 32); -+ SAVE(DMAC_DRSR0, 32); SAVE(DMAC_DRSR1, 32); SAVE(DMAC_DRSR2, 32); SAVE(DMAC_DRSR3, 32); SAVE(DMAC_DRSR4, 32); SAVE(DMAC_DRSR5, 32); SAVE(DMAC_DRSR6, 32); SAVE(DMAC_DRSR7, 32); -+ SAVE(DMAC_DCCSR0, 32); SAVE(DMAC_DCCSR1, 32); SAVE(DMAC_DCCSR2, 32); SAVE(DMAC_DCCSR3, 32); SAVE(DMAC_DCCSR4, 32); SAVE(DMAC_DCCSR5, 32); SAVE(DMAC_DCCSR6, 32); SAVE(DMAC_DCCSR7, 32); -+ -+ SAVE(INTC_IPR, 32);SAVE(INTC_ISR, 32);SAVE(INTC_IMR, 32); -+ -+ SAVE(WDT_WTCNT, 32);SAVE(WDT_WTCSR, 8); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* Save module clocks */ -+ SAVE(CPM_MSCR, 32); -+ -+ /* Save PLL */ -+ SAVE(CPM_PLCR1, 32); -+ -+ /* Stop module clocks */ -+ __cpm_stop_uart0(); -+ __cpm_stop_uart1(); -+ __cpm_stop_uart2(); -+ __cpm_stop_uart3(); -+ __cpm_stop_uhc(); -+ __cpm_stop_udc(); -+ __cpm_stop_eth(); -+ __cpm_stop_cim(); -+ __cpm_stop_kbc(); -+ __cpm_stop_scc(); -+ __cpm_stop_ssi(); -+ __cpm_stop_ost(); -+ -+ /* platform-specific pm routine */ -+ jz_board_pm_suspend(); -+ -+ /* Clear previous reset status */ -+ REG_CPM_RSTR &= ~(CPM_RSTR_HR | CPM_RSTR_WR | CPM_RSTR_SR); -+ -+ /* Set resume return address */ -+ REG_CPM_SPR = virt_to_phys(jz_cpu_resume); -+ -+ /* Before sleeping, calculate and save a checksum */ -+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) -+ checksum += sleep_save[i]; -+ sleep_save[SLEEP_SAVE_CKSUM] = checksum; -+ -+ /* *** go zzz *** */ -+ jz_cpu_suspend(); -+#if 0 -+ /* after sleeping, validate the checksum */ -+ checksum = 0; -+ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) -+ checksum += sleep_save[i]; -+ -+ /* if invalid, display message and wait for a hardware reset */ -+ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { -+ /** Add platform-specific message display codes here **/ -+ while (1); -+ } -+#endif -+ /* Restore PLL */ -+ RESTORE(CPM_PLCR1, 32); -+ -+ /* Restore module clocks */ -+ RESTORE(CPM_MSCR, 32); -+ -+ /* Ensure not to come back here if it wasn't intended */ -+ REG_CPM_SPR = 0; -+ -+ /* Restore registers */ -+ -+ RESTORE(GPIO_GPDR0, 32); RESTORE(GPIO_GPDR1, 32); RESTORE(GPIO_GPDR2, 32); -+ RESTORE(GPIO_GPDR3, 32); -+ RESTORE(GPIO_GPDIR0, 32); RESTORE(GPIO_GPDIR1, 32); RESTORE(GPIO_GPDIR2, 32); -+ RESTORE(GPIO_GPDIR3, 32); -+ RESTORE(GPIO_GPODR0, 32); RESTORE(GPIO_GPODR1, 32); RESTORE(GPIO_GPODR2, 32); -+ RESTORE(GPIO_GPODR3, 32); -+ RESTORE(GPIO_GPPUR0, 32); RESTORE(GPIO_GPPUR1, 32); RESTORE(GPIO_GPPUR2, 32); -+ RESTORE(GPIO_GPPUR3, 32); -+ RESTORE(GPIO_GPALR0, 32); RESTORE(GPIO_GPALR1, 32); RESTORE(GPIO_GPALR2, 32); -+ RESTORE(GPIO_GPALR3, 32); -+ RESTORE(GPIO_GPAUR0, 32); RESTORE(GPIO_GPAUR1, 32); RESTORE(GPIO_GPAUR2, 32); -+ RESTORE(GPIO_GPAUR3, 32); -+ RESTORE(GPIO_GPIDLR0, 32);RESTORE(GPIO_GPIDLR1, 32);RESTORE(GPIO_GPIDLR2, 32); -+ RESTORE(GPIO_GPIDLR3, 32); -+ RESTORE(GPIO_GPIDUR0, 32);RESTORE(GPIO_GPIDUR1, 32);RESTORE(GPIO_GPIDUR2, 32); -+ RESTORE(GPIO_GPIDUR3, 32); -+ RESTORE(GPIO_GPIER0, 32); RESTORE(GPIO_GPIER1, 32); RESTORE(GPIO_GPIER2, 32); -+ RESTORE(GPIO_GPIER3, 32); -+ RESTORE(GPIO_GPIMR0, 32); RESTORE(GPIO_GPIMR1, 32); RESTORE(GPIO_GPIMR2, 32); -+ RESTORE(GPIO_GPIMR3, 32); -+ RESTORE(GPIO_GPFR0, 32); RESTORE(GPIO_GPFR1, 32); RESTORE(GPIO_GPFR2, 32); -+ RESTORE(GPIO_GPFR3, 32); -+ -+ RESTORE(EMC_SMCR0, 32); RESTORE(EMC_SMCR1, 32); RESTORE(EMC_SMCR2, 32); RESTORE(EMC_SMCR3, 32); -+ RESTORE(EMC_SMCR4, 32); RESTORE(EMC_SMCR5, 32); -+ -+ RESTORE(HARB_HAPOR, 32); RESTORE(HARB_HMCTR, 32); RESTORE(HARB_HMLTR, 32); -+ -+ RESTORE(OST_TCNT0, 32); RESTORE(OST_TCNT1, 32); RESTORE(OST_TCNT2, 32); -+ RESTORE(OST_TRDR0, 32); RESTORE(OST_TRDR1, 32); RESTORE(OST_TRDR2, 32); -+ RESTORE(OST_TCSR0, 16); RESTORE(OST_TCSR1, 16); RESTORE(OST_TCSR2, 16); -+ RESTORE(OST_TER, 8); -+ -+ RESTORE(DMAC_DMACR, 32); -+ RESTORE(DMAC_DSAR0, 32); RESTORE(DMAC_DSAR1, 32); RESTORE(DMAC_DSAR2, 32); RESTORE(DMAC_DSAR3, 32); RESTORE(DMAC_DSAR4, 32); RESTORE(DMAC_DSAR5, 32); RESTORE(DMAC_DSAR6, 32); RESTORE(DMAC_DSAR7, 32); -+ RESTORE(DMAC_DDAR0, 32); RESTORE(DMAC_DDAR1, 32); RESTORE(DMAC_DDAR2, 32); RESTORE(DMAC_DDAR3, 32); RESTORE(DMAC_DDAR4, 32); RESTORE(DMAC_DDAR5, 32); RESTORE(DMAC_DDAR6, 32); RESTORE(DMAC_DDAR7, 32); -+ RESTORE(DMAC_DTCR0, 32); RESTORE(DMAC_DTCR1, 32); RESTORE(DMAC_DTCR2, 32); RESTORE(DMAC_DTCR3, 32); RESTORE(DMAC_DTCR4, 32); RESTORE(DMAC_DTCR5, 32); RESTORE(DMAC_DTCR6, 32); RESTORE(DMAC_DTCR7, 32); -+ RESTORE(DMAC_DRSR0, 32); RESTORE(DMAC_DRSR1, 32); RESTORE(DMAC_DRSR2, 32); RESTORE(DMAC_DRSR3, 32); RESTORE(DMAC_DRSR4, 32); RESTORE(DMAC_DRSR5, 32); RESTORE(DMAC_DRSR6, 32); RESTORE(DMAC_DRSR7, 32); -+ RESTORE(DMAC_DCCSR0, 32); RESTORE(DMAC_DCCSR1, 32); RESTORE(DMAC_DCCSR2, 32); RESTORE(DMAC_DCCSR3, 32); RESTORE(DMAC_DCCSR4, 32); RESTORE(DMAC_DCCSR5, 32); RESTORE(DMAC_DCCSR6, 32); RESTORE(DMAC_DCCSR7, 32); -+ -+ RESTORE(INTC_IPR, 32);RESTORE(INTC_ISR, 32);RESTORE(INTC_IMR, 32); -+ -+ REG_WDT_WTCNT = 0; RESTORE(WDT_WTCSR, 8); -+ -+ /* -+ * Temporary solution. This won't be necessary once -+ * we move this support into the device drivers. -+ * Restore the on-chip modules. -+ */ -+ -+ /* FIFO control reg, write-only */ -+ REG8(UART0_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; -+ REG8(UART1_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; -+ REG8(UART2_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; -+ REG8(UART3_FCR) = UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS | UARTFCR_UUE; -+ -+ REG8(UART0_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ RESTORE(UART0_DLLR, 8); RESTORE(UART0_DLHR, 8); -+ REG8(UART0_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ RESTORE(UART0_IER, 8); -+ RESTORE(UART0_MCR, 8); RESTORE(UART0_SPR, 8); RESTORE(UART0_LCR, 8); -+ -+ REG8(UART1_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ RESTORE(UART1_DLLR, 8); RESTORE(UART1_DLHR, 8); -+ REG8(UART1_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ RESTORE(UART1_IER, 8); -+ RESTORE(UART1_MCR, 8); RESTORE(UART1_SPR, 8); RESTORE(UART1_LCR, 8); -+ -+ REG8(UART2_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ RESTORE(UART2_DLLR, 8); RESTORE(UART2_DLHR, 8); -+ REG8(UART2_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ RESTORE(UART2_IER, 8); -+ RESTORE(UART2_MCR, 8); RESTORE(UART2_SPR, 8); RESTORE(UART2_LCR, 8); -+ -+ REG8(UART3_LCR) |= UARTLCR_DLAB; /* Access to DLLR/DLHR */ -+ RESTORE(UART3_DLLR, 8); RESTORE(UART3_DLHR, 8); -+ REG8(UART3_LCR) &= ~UARTLCR_DLAB; /* Access to IER */ -+ RESTORE(UART3_IER, 8); -+ RESTORE(UART3_MCR, 8); RESTORE(UART3_SPR, 8); RESTORE(UART3_LCR, 8); -+ -+ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY0; /* resume USB PHY 0 */ -+ REG_CPM_OCR &= ~CPM_OCR_SUSPEND_PHY1; /* resume USB PHY 1 */ -+#if 0 -+ REG_CPM_OCR &= ~CPM_OCR_EXT_RTC_CLK; /* use internal RTC clock (JZ_EXTAL/128 Hz) */ -+#else -+ REG_CPM_OCR |= CPM_OCR_EXT_RTC_CLK; /* use external RTC clock (32.768 KHz) */ -+#endif -+ -+ /* Enable NAND ctroller */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE; -+ -+ /* Restore current time */ -+ xtime.tv_sec = REG_RTC_RSR; -+ -+ /* Restore interrupts */ -+ REG_INTC_IMSR = imr; -+ REG_INTC_IMCR = ~imr; -+ -+ return 0; -+} -+ -+/* NOTES: -+ * 1: Pins that are floated (NC) should be set as input and pull-enable. -+ * 2: Pins that are pull-up or pull-down by outside should be set as input -+ * and pull-disable. -+ * 3: Pins that are connected to a chipset should be set as pull-disable. -+ */ -+static void jz_board_pm_gpio_setup(void) -+{ -+ /* CIM_D0(IN)/PULL-UP/GP0 */ -+ __gpio_as_input(0); -+ __gpio_enable_pull(0); -+ -+ /* CIM_D1(IN)/PULL-UP/GP1 */ -+ __gpio_as_input(1); -+ __gpio_enable_pull(1); -+ -+ /* CIM_D2(IN)/PULL-UP/GP2 */ -+ __gpio_as_input(2); -+ __gpio_enable_pull(2); -+ -+ /* CIM_D3(IN)/PULL-UP/GP3 */ -+ __gpio_as_input(3); -+ __gpio_enable_pull(3); -+ -+ /* CIM_D4(IN)/PULL-DOWN/GP4 */ -+ __gpio_as_input(4); -+ __gpio_enable_pull(4); -+ -+ /* CIM_D5(IN)/PULL-DOWN/GP5 */ -+ __gpio_as_input(5); -+ __gpio_enable_pull(5); -+ -+ /* CIM_D6(IN)/PULL-DOWN/GP6 */ -+ __gpio_as_input(6); -+ __gpio_enable_pull(6); -+ -+ /* CIM_D7(IN)/PULL-DOWN/GP7 */ -+ __gpio_as_input(7); -+ __gpio_enable_pull(7); -+ -+ /* CIM_VSYNC(IN)/PULL-DOWN/GP8 */ -+ __gpio_as_input(8); -+ __gpio_enable_pull(8); -+ -+ /* CIM_HSYNC(IN)/PULL-UP/GP9 */ -+ __gpio_as_input(9); -+ __gpio_enable_pull(9); -+ -+ /* CIM_PCLK(IN)/PULL-DOWN/GP10 */ -+ __gpio_as_input(10); -+ __gpio_enable_pull(10); -+ -+ /* CIM_MCLK(OUT)/PULL-DOWN/GP11 */ -+ __gpio_as_input(11); -+ __gpio_enable_pull(11); -+ -+ /* DMA_DREQ0(IN)/CHIP_MODE/PULL-UP/GP12 */ -+ __gpio_as_input(12); -+ __gpio_enable_pull(12); -+ -+ /* DMA_DACK0(OUT)/PULL-UP/GP13 */ /* GPIO13 */ -+ __gpio_as_input(13); -+ __gpio_disable_pull(13); -+ -+ /* GP14 */ -+ /* GP15 */ -+ -+ /* RXD3(IN)/PULL-UP/GP16 */ -+ __gpio_as_input(16); -+ __gpio_enable_pull(16); -+ -+ /* CTS3(IN)/PULL-UP/GP17 */ -+ __gpio_as_input(17); -+ __gpio_enable_pull(17); -+ -+ /* GP18 */ -+ /* GP19 */ -+ /* GP20 */ -+ -+ /* TXD3(OUT)/PULL-UP/GP21 */ -+ __gpio_as_input(21); -+ __gpio_enable_pull(21); -+ -+ /* GP22 */ -+ -+ /* RTS3(OUT)/PULL-UP/GP23 */ -+ __gpio_as_input(23); -+ __gpio_enable_pull(23); -+ -+ /* RXD1(IN)/PULL-UP/GP24 */ /* IR_RXD */ -+ __gpio_as_input(24); -+ __gpio_enable_pull(24); -+ -+ /* TXD1(OUT)/PULL-UP/GP25 */ /* IR_TXD */ -+ __gpio_disable_pull(25); -+ __gpio_as_output(25); -+ __cpm_set_pin(25); -+ -+ /* DMA_AEN(OUT)/PULL-UP/GP26 */ /* CIM_PWD_N */ -+ __gpio_as_input(26); -+ __gpio_disable_pull(26); -+ -+ /* DMA_EOP(OUT)/PULL-UP/GP27 */ /* SW4 */ -+ __gpio_as_input(27); -+ __gpio_disable_pull(27); -+ -+ /* USB_CLK(IN)/PULL-UP/GP28 */ -+ __gpio_as_input(28); -+ __gpio_disable_pull(28); -+ -+ /* USB_PPWR0(OUT)/PULL-UP/GP29 */ /* USB_CLK_EN */ -+ __gpio_disable_pull(29); -+ __gpio_as_output(29); -+ __cpm_clear_pin(29); /* disable USB 48MHz clock */ -+ -+ /* GP30 */ -+ /* GP31 */ -+ -+ /* PS2_KCLK(IO)/PULL-UP/GP32 */ -+ __gpio_as_input(32); -+ __gpio_enable_pull(32); -+ -+ /* PS2_KDATA(IO)/PULL-UP/GP33 */ /* CIM_RST */ -+ __gpio_as_input(33); -+ __gpio_enable_pull(33); -+ -+ /* MSC_D0(IO)/PULL-UP/GP34 */ -+ __gpio_as_input(34); -+ __gpio_disable_pull(34); -+ -+ /* MSC_D1(IO)/PULL-UP/GP35 */ -+ __gpio_as_input(35); -+ __gpio_disable_pull(35); -+ -+ /* MSC_D2(IO)/PULL-UP/GP36 */ -+ __gpio_as_input(36); -+ __gpio_disable_pull(36); -+ -+ /* MSC_D3(IO)/PULL-UP/GP37 */ -+ __gpio_as_input(37); -+ __gpio_disable_pull(37); -+ -+ /* MSC_CMD(IO)/PULL-UP/GP38 */ -+ __gpio_as_input(38); -+ __gpio_disable_pull(38); -+ -+ /* MSC_CLK(OUT)/PULL-UP/GP39 */ -+ __gpio_as_input(39); -+ __gpio_enable_pull(39); -+ -+ /* LCD_D0(OUT)/PULL-UP/GP40 */ -+ __gpio_as_input(40); -+ __gpio_enable_pull(40); -+ -+ /* LCD_D1(OUT)/PULL-UP/GP41 */ -+ __gpio_as_input(41); -+ __gpio_enable_pull(41); -+ -+ /* LCD_D2(OUT)/PULL-UP/GP42 */ -+ __gpio_as_input(42); -+ __gpio_enable_pull(42); -+ -+ /* LCD_D3(OUT)/PULL-UP/GP43 */ -+ __gpio_as_input(43); -+ __gpio_enable_pull(43); -+ -+ /* LCD_D4(OUT)/PULL-UP/GP44 */ -+ __gpio_as_input(44); -+ __gpio_enable_pull(44); -+ -+ /* LCD_D5(OUT)/PULL-UP/GP45 */ -+ __gpio_as_input(45); -+ __gpio_enable_pull(45); -+ -+ /* LCD_D6(OUT)/PULL-UP/GP46 */ -+ __gpio_as_input(46); -+ __gpio_enable_pull(46); -+ -+ /* LCD_D7(OUT)/PULL-UP/GP47 */ -+ __gpio_as_input(47); -+ __gpio_enable_pull(47); -+ -+ /* LCD_D8(OUT)/PULL-DOWN/GP48 */ -+ __gpio_as_input(48); -+ __gpio_enable_pull(48); -+ -+ /* LCD_D9(OUT)/PULL-DOWN/GP49 */ -+ __gpio_as_input(49); -+ __gpio_enable_pull(49); -+ -+ /* LCD_D10(OUT)/PULL-DOWN/GP50 */ -+ __gpio_as_input(50); -+ __gpio_enable_pull(50); -+ -+ /* LCD_D11(OUT)/PULL-DOWN/GP51 */ -+ __gpio_as_input(51); -+ __gpio_enable_pull(51); -+ -+ /* LCD_D12(OUT)/PULL-DOWN/GP52 */ -+ __gpio_as_input(52); -+ __gpio_enable_pull(52); -+ -+ /* LCD_D13(OUT)/PULL-DOWN/GP53 */ -+ __gpio_as_input(53); -+ __gpio_enable_pull(53); -+ -+ /* LCD_D14(OUT)/PULL-DOWN/GP54 */ -+ __gpio_as_input(54); -+ __gpio_enable_pull(54); -+ -+ /* LCD_D15(OUT)/PULL-DOWN/GP55 */ -+ __gpio_as_input(55); -+ __gpio_enable_pull(55); -+ -+ /* LCD_VSYNC(IN)/PULL-DOWN/GP56 */ -+ __gpio_as_input(56); -+ __gpio_enable_pull(56); -+ -+ /* LCD_HSYNC(IN)/PULL-UP/GP57 */ -+ __gpio_as_input(57); -+ __gpio_enable_pull(57); -+ -+ /* LCD_PCLK(IN)/PULL-DOWN/GP58 */ -+ __gpio_as_input(58); -+ __gpio_enable_pull(58); -+ -+ /* LCD_DE(OUT)/PULL-DOWN/GP59 */ -+ __gpio_as_input(59); -+ __gpio_enable_pull(59); -+ -+ /* LCD_SPL(OUT)/PULL-UP/GP60 */ -+ __gpio_as_input(60); -+ __gpio_disable_pull(60); -+ -+ /* LCD_CLS(OUT)/PULL-UP/GP61 */ -+ __gpio_as_input(61); -+ __gpio_disable_pull(61); -+ -+ /* LCD_PS(OUT)/PULL-UP/GP62 */ -+ __gpio_as_input(62); -+ __gpio_disable_pull(62); -+ -+ /* LCD_REV(OUT)/PULL-UP/GP63 */ -+ __gpio_as_input(63); -+ __gpio_enable_pull(63); -+ -+ /* SCC0_DAT(IO)/PULL-UP/GP64 */ /* Keypad */ -+ __gpio_as_input(64); -+ __gpio_enable_pull(64); -+ -+ /* SCC1_DAT(IO)/PULL-UP/GP65 */ /* SW5 */ -+ __gpio_as_input(65); -+ __gpio_disable_pull(65); -+ -+ /* SCC0_CLK(OUT)/PULL-UP/GP66 */ /* PW_O */ -+ __gpio_disable_pull(66); -+ __gpio_as_output(66); -+ __cpm_set_pin(66); -+ -+ /* SCC1_CLK(OUT)/PULL-UP/GP67 */ /* SW6 */ -+ __gpio_as_input(67); -+ __gpio_disable_pull(67); -+ -+ /* SYS_CLK(OUT)/PULL-UP/GP68 */ /* I2S_CLK */ -+ __gpio_disable_pull(68); -+ -+ /* ACRESET_N(OUT)/PULL-UP/GP69 */ /* AK4642 PDN */ -+ __gpio_disable_pull(69); -+ __gpio_as_output(69); -+ __cpm_clear_pin(69); -+ -+ /* SDATA_OUT(OUT)/PULL-UP/GP70 */ /* I2S_DIN */ -+ __gpio_disable_pull(70); -+ -+ /* SDATA_IN(IN)/PULL-UP/GP71 */ /* I2S_DOUT */ -+ __gpio_disable_pull(71); -+ -+ /* SSI_CLK(OUT)/PULL-UP/GP72 */ /* SSI_CLK */ -+ __gpio_as_input(72); -+ __gpio_enable_pull(72); -+ -+ /* SSI_CE1_N(OUT)/PULL-UP/GP73 */ /* SSI_CE1_N */ -+ __gpio_as_input(73); -+ __gpio_enable_pull(73); -+ -+ /* SSI_DT(OUT)/PULL-UP/GP74 */ /* SSI_DT */ -+ __gpio_as_input(74); -+ __gpio_enable_pull(74); -+ -+ /* SSI_DR(IN)/PULL-UP/GP75 */ /* SSI_DR */ -+ __gpio_as_input(75); -+ __gpio_enable_pull(75); -+ -+ /* SSI_CE2_N(OUT)/SSI_GPC/PULL-UP/GP76 */ -+ __gpio_as_input(76); -+ __gpio_enable_pull(76); -+ -+ /* BITCLK_IN(IN)/PULL-UP/GP77 */ /* I2S_BITCLK */ -+ __gpio_disable_pull(77); -+ -+ /* SYNC_IN(IN)/PULL-UP/GP78 */ /* I2S_LRCIN */ -+ __gpio_disable_pull(78); -+ -+ /* FRE_N(OUT)/PULL-UP/GP79 */ -+ __gpio_enable_pull(79); -+ __gpio_as_input(79); -+ -+ /* FWE_N(OUT)/PULL-UP/GP80 */ -+ __gpio_enable_pull(80); -+ __gpio_as_input(80); -+ -+ /* FRB_N(IN)/PULL-UP/GP81 */ -+ __gpio_enable_pull(81); -+ __gpio_as_input(81); -+ -+ /* DCS1_N(OUT)/PULL-UP/GP82 */ /* SD_WP */ -+ __gpio_as_input(82); -+ __gpio_enable_pull(82); -+ -+ /* CS1_N(OUT)/PULL-UP/GP83 */ /* JACK_PLUG */ -+ __gpio_as_input(83); -+ __gpio_disable_pull(83); -+ -+ /* CS2_N(OUT)/PULL-UP/GP84 */ /* DC_DETE */ -+ __gpio_as_input(84); -+ __gpio_disable_pull(84); -+ -+ /* CS3_N(OUT)/PULL-UP/GP85 */ /* NAND CS# */ -+ __gpio_enable_pull(85); -+ __gpio_as_input(85); -+ -+ /* CS4_N/(OUT)PULL-UP/GP86 */ /* PULL_OFF */ -+ __gpio_disable_pull(86); -+ __gpio_as_output(86); -+// __cpm_set_pin(86); -+ __cpm_clear_pin(86); -+ -+ /* CS5_N(OUT)/PULL-UP/GP87 */ /* IR_SD */ -+ __gpio_as_input(87); -+ __gpio_disable_pull(87); -+ -+ /* INPACK_N(IN)/PULL-UP/GP88 */ /* SW7 */ -+ __gpio_as_input(88); -+ __gpio_disable_pull(88); -+ -+ /* BVD2(IN)/PULL-UP/GP89 */ /* SW8 */ -+ __gpio_as_input(89); -+ __gpio_disable_pull(89); -+ -+ /* PCE1_N(OUT)/PULL-UP/GP90 */ /* SD_CD_N */ -+ __gpio_as_input(90); -+ __gpio_enable_pull(90); -+ -+ /* PSKTSEL_N(OUT)/PULL-UP/GP91 */ /* SD_VCC_3V_EN_N */ -+ __gpio_disable_pull(91); -+ __gpio_as_output(91); -+ __cpm_clear_pin(91); -+ -+ /* IOIS16_N(IN)/PULL-UP/GP92 */ /* LED_EN */ -+ __gpio_disable_pull(92); -+ __gpio_as_output(92); -+ __cpm_clear_pin(92); -+ -+ /* PCE2_N(OUT)/PULL-UP/GP93 */ /* LCD_DISP_OFF_N */ -+ __gpio_disable_pull(93); -+ __gpio_as_input(93); -+ -+ /* PWM0(OUT)/PULL-UP/GP94 */ /* LCD backlight off */ -+ __gpio_disable_pull(94); -+ __gpio_as_output(94); -+ __cpm_clear_pin(94); -+ -+ /* PWM1(OUT)/PULL-UP/GP95 */ -+ __gpio_disable_pull(95); -+ __gpio_as_output(95); -+ __cpm_clear_pin(95); -+ -+ /* PRT(OUT)/PULL-UP/GP96 */ /* RTC_IRQ */ -+ __gpio_as_input(96); -+ __gpio_disable_pull(96); -+ -+ /* PRT(OUT)/PULL-UP/GP97 */ /* PW_I */ -+ __gpio_as_input(97); -+ __gpio_disable_pull(97); -+ -+ /* PRT(OUT)/PULL-UP/GP98 */ /* Keypad */ -+ __gpio_as_input(98); -+ __gpio_disable_pull(98); -+ -+ /* PRT(OUT)/PULL-UP/GP99 */ /* Keypad */ -+ __gpio_as_input(99); -+ __gpio_disable_pull(99); -+ -+ /* PRT(OUT)/PULL-UP/GP100 */ /* Keypad */ -+ __gpio_as_input(100); -+ __gpio_disable_pull(100); -+ -+ /* PRT(OUT)/PULL-UP/GP101 */ /* Keypad */ -+ __gpio_as_input(101); -+ __gpio_disable_pull(101); -+ -+ /* PRT(OUT)/PULL-UP/GP102 */ /* Keypad */ -+ __gpio_as_input(102); -+ __gpio_disable_pull(102); -+ -+ /* PRT(OUT)/PULL-UP/GP103 */ /* Keypad */ -+ __gpio_as_input(103); -+ __gpio_enable_pull(103); -+ -+ /* PRT(OUT)/PULL-UP/GP104 */ /* Keypad */ -+ __gpio_as_input(104); -+ __gpio_enable_pull(104); -+ -+ /* PRT(OUT)/PULL-UP/GP105 */ /* Keypad */ -+ __gpio_as_input(105); -+ __gpio_enable_pull(105); -+ -+ /* PRT(OUT)/PULL-UP/GP106 */ /* 5V_ON */ -+ __gpio_disable_pull(106); -+ __gpio_as_output(106); -+ __cpm_clear_pin(106); -+ -+ /* PRT(IN)/PULL-UP/GP107 */ /* GSM_BOOT */ -+ __gpio_as_input(107); -+ __gpio_enable_pull(107); -+ -+ /* PRT(IN)/PULL-UP/GP108 */ /* GSM_RESET */ -+ __gpio_as_input(108); -+ __gpio_enable_pull(108); -+ -+ /* PRT(IN)/PULL-UP/GP109 */ /* GSM_EN */ -+ __gpio_as_input(109); -+ __gpio_enable_pull(109); -+ -+ /* PRT(IN)/PULL-UP/GP110 */ /* GSM_RING */ -+ __gpio_as_input(110); -+ __gpio_enable_pull(110); -+ -+ /* PRT(IN)/UART2_RXD/PULL-UP/GP111 */ /* Keypad */ -+ __gpio_as_input(111); -+ __gpio_enable_pull(111); -+ -+ /* MII_TX_EN(OUT)/PULL-UP/GP112 */ -+ __gpio_as_input(112); -+ __gpio_enable_pull(112); -+ -+ /* MII_RX_DV(IN)/PULL-UP/GP113 */ -+ __gpio_as_input(113); -+ __gpio_enable_pull(113); -+ -+ /* MII_RX_ER(IN)/PULL-UP/GP114 */ -+ __gpio_as_input(114); -+ __gpio_enable_pull(114); -+ -+ /* MII_COL(IN)/PULL-UP/GP115 */ -+ __gpio_as_input(115); -+ __gpio_enable_pull(115); -+ -+ /* MII_CRS(IN)/PULL-UP/GP116 */ -+ __gpio_as_input(116); -+ __gpio_enable_pull(116); -+ -+ /* MII_TXD0(OUT)/PULL-UP/GP117 */ -+ __gpio_as_input(117); -+ __gpio_enable_pull(117); -+ -+ /* MII_TXD1(OUT)/PULL-UP/GP118 */ -+ __gpio_as_input(118); -+ __gpio_enable_pull(118); -+ -+ /* MII_TXD2(OUT)/PULL-UP/GP119 */ -+ __gpio_as_input(119); -+ __gpio_enable_pull(119); -+ -+ /* MII_TXD3(OUT)/PULL-UP/GP120 */ -+ __gpio_as_input(120); -+ __gpio_enable_pull(120); -+ -+ /* MII_RXD0(IN)/PULL-UP/GP121 */ -+ __gpio_as_input(121); -+ __gpio_enable_pull(121); -+ -+ /* MII_RXD1(IN)/PULL-UP/GP122 */ -+ __gpio_as_input(122); -+ __gpio_enable_pull(122); -+ -+ /* MII_RXD2(IN)/PULL-UP/GP123 */ -+ __gpio_as_input(123); -+ __gpio_enable_pull(123); -+ -+ /* MII_RXD3(IN)/PULL-UP/GP124 */ -+ __gpio_as_input(124); -+ __gpio_enable_pull(124); -+ -+ /* UART2_TXD(OUT)/PULL-UP/GP125 */ /* CHARG_STAT */ -+ __gpio_as_output(125); -+ __gpio_disable_pull(125); -+ __cpm_clear_pin(125); -+ -+ /* UART0_RXD(IN)/PULL-UP/GP126 */ -+ __gpio_as_input(126); -+ __gpio_enable_pull(126); -+ -+ /* UART0_TXD(OUT)/PULL-UP/GP127 */ -+ __gpio_as_input(127); -+ __gpio_enable_pull(127); -+} -+ -+/* -+ * In order to save power most, all gpio pins should be put to their -+ * proper states during low power mode. -+ */ -+static void jz_board_pm_suspend(void) -+{ -+ /* Setup the state of all the GPIO pins during low-power mode */ -+ jz_board_pm_gpio_setup(); -+ -+ /* Allow next interrupts to wakeup the system. -+ */ -+ REG_CPM_WER = 0; /* Clear all first */ -+ -+ /* RTC alarm */ -+ REG_CPM_WER |= 1 << 0; -+ REG_CPM_WRER |= 1 << 0; -+ REG_CPM_WFER |= 1 << 0; -+ __gpio_as_irq_rise_edge(96); -+ -+ /* Power_I key */ -+ REG_CPM_WER |= 1 << 1; -+ REG_CPM_WRER |= 1 << 1; -+ REG_CPM_WFER |= 1 << 1; -+ __gpio_as_irq_rise_edge(97); -+ -+ /* enable INTC irq */ -+ __intc_unmask_irq(IRQ_GPIO3); -+ -+#if 0 -+ /* Enable RTC alarm */ -+ REG_CPM_WER |= CPM_WER_WERTC; -+ REG_RTC_RGR = 32767; -+ REG_RTC_RCR &= ~RTC_RCR_AE; -+ REG_RTC_RSR = 0; -+ REG_RTC_RSAR = 30; -+ REG_RTC_RCR = RTC_RCR_AE | RTC_RCR_AIE | RTC_RCR_START; -+#endif -+} -+ -+/* -+ * We don't use sleep mode of jz4730 for it has bug, the suspend mode -+ * implemented by hibernate mode is used instead of it. -+ */ -+static int jz_pm_do_sleep(void) -+{ -+ printk("It was deprecated, please use /proc/sys/pm/suspend.\n"); -+#if 0 -+ unsigned long imr = REG_INTC_IMR; -+ -+ /* Preserve current time */ -+ REG_RTC_RSR = xtime.tv_sec; -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* Just allow next interrupts to wakeup the system. -+ * Note: modify this according to your system. -+ */ -+ /* RTC alarm */ -+ __gpio_as_irq_fall_edge(96); /* GPIO 96 */ -+ -+ /* POWER_I key */ -+ __gpio_as_irq_rise_edge(97); /* GPIO 97 */ -+ -+ /* Enable INTC */ -+ __intc_unmask_irq(IRQ_GPIO3); -+ -+ /* Disable modules e.g. LCD backlight */ -+ -+ /* Stop module clocks */ -+ __cpm_stop_uhc(); -+ -+ /* Enter SLEEP mode -+ * Put SDRAM into self-refresh mode. -+ */ -+ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK; -+ REG_CPM_LPCR |= CPM_LPCR_LPM_SLEEP; -+ -+ __asm__(".set\tmips3\n\t" -+ ".set noreorder\n\t" -+ ".align 5\n\t" -+ "wait\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ ".set\tmips0"); -+ -+ /* Restore to IDLE mode */ -+ REG_CPM_LPCR &= ~CPM_LPCR_LPM_MASK; -+ REG_CPM_LPCR |= CPM_LPCR_LPM_IDLE; -+ -+ /* Restore clock of usb host */ -+ __cpm_start_uhc(); -+ -+ /* Restore interrupts */ -+ REG_INTC_IMSR = imr; -+ REG_INTC_IMCR = ~imr; -+ -+ /* Restore current time */ -+ xtime.tv_sec = REG_RTC_RSR; -+#endif -+ return 0; -+} -+ -+#define K0BASE KSEG0 -+void jz_flush_cache_all(void) -+{ -+ unsigned long addr; -+ -+ /* Clear CP0 TagLo */ -+ asm volatile ("mtc0 $0, $28\n\t"::); -+ -+ for (addr = K0BASE; addr < (K0BASE + 0x4000); addr += 32) { -+ asm volatile ( -+ ".set mips3\n\t" -+ " cache %0, 0(%1)\n\t" -+ ".set mips2\n\t" -+ : -+ : "I" (Index_Writeback_Inv_D), "r"(addr)); -+ -+ asm volatile ( -+ ".set mips3\n\t" -+ " cache %0, 0(%1)\n\t" -+ ".set mips2\n\t" -+ : -+ : "I" (Index_Store_Tag_I), "r"(addr)); -+ } -+ -+ asm volatile ("sync\n\t"::); -+ -+ /* invalidate BTB */ -+ asm volatile ( -+ ".set mips32\n\t" -+ " mfc0 %0, $16, 7\n\t" -+ " nop\n\t" -+ " ori $0, 2\n\t" -+ " mtc0 %0, $16, 7\n\t" -+ " nop\n\t" -+ ".set mips2\n\t" -+ : -+ : "r"(addr)); -+} -+ -+/* Put CPU to HIBERNATE mode */ -+int jz_pm_suspend(void) -+{ -+ int retval; -+ -+ pm_send_all(PM_SUSPEND, (void *)3); -+ -+ retval = jz_pm_do_suspend(); -+ -+ pm_send_all(PM_RESUME, (void *)0); -+ -+ return retval; -+} -+ -+#if 0 -+/* Put CPU to SLEEP mode */ -+int jz_pm_sleep(void) -+{ -+ return jz_pm_do_sleep(); -+} -+ -+/* Put CPU to IDLE mode, used for dpm in linux 2.4 */ -+void jz_pm_idle(void) -+{ -+ local_irq_disable(); -+ if (!need_resched()) { -+ local_irq_enable(); -+ cpu_wait(); -+ } -+} -+#endif -+ -+#ifdef CONFIG_SYSCTL -+ -+/* -+ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 -+ * when all the PM interfaces exist nicely. -+ */ -+#define CTL_PM_SUSPEND 1 -+#define CTL_PM_HIBERNATE 2 -+ -+/*---------------------------------------------------------------------------- -+ * Power Management sleep sysctl proc interface -+ * -+ * A write to /proc/sys/pm/suspend invokes this function -+ * which initiates a sleep. -+ *--------------------------------------------------------------------------*/ -+static int sysctl_jz_pm_sleep(void) -+{ -+ return jz_pm_suspend(); -+} -+ -+static struct ctl_table pm_table[] = -+{ -+ { -+ .ctl_name = CTL_UNNUMBERED, -+ .procname = "suspend", -+ .data = NULL, -+ .maxlen = 0, -+ .mode = 0600, -+ .proc_handler = &sysctl_jz_pm_sleep, -+ }, -+ { .ctl_name = 0} -+}; -+ -+static struct ctl_table pm_dir_table[] = -+{ -+ { -+ .ctl_name = CTL_UNNUMBERED, -+ .procname = "pm", -+ .mode = 0555, -+ .child = pm_table, -+ }, -+ { .ctl_name = 0} -+}; -+ -+#endif /* CONFIG_SYSCTL */ -+ -+/* -+ * Initialize power interface -+ */ -+static int __init jz_pm_init(void) -+{ -+ printk("Power Management for JZ\n"); -+ -+#ifdef CONFIG_SYSCTL -+ register_sysctl_table(pm_dir_table); -+#endif -+ -+ return 0; -+} -+ -+module_init(jz_pm_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/proc.c linux-2.6.24.7/arch/mips/jz4730/proc.c ---- linux-2.6.24.7.old/arch/mips/jz4730/proc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/proc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,292 @@ -+/* -+ * linux/arch/mips/jz4730/proc.c -+ * -+ * /proc/jz/ procfs for on-chip peripherals. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+struct proc_dir_entry *proc_jz_root; -+ -+/* -+ * EMC Module -+ */ -+static int emc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += sprintf (page+len, "BCR: 0x%08x\n", REG_EMC_BCR); -+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4, REG_EMC_SMCR5); -+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4, REG_EMC_SACR5); -+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); -+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); -+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); -+ len += sprintf (page+len, "DMAR(0-1): 0x%08x 0x%08x\n", REG_EMC_DMAR1, REG_EMC_DMAR2); -+ return len; -+} -+ -+/* -+ * Power Manager Module -+ */ -+static int pmc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned long lpcr = REG_CPM_LPCR; -+ unsigned long mscr = REG_CPM_MSCR; -+ -+ len += sprintf (page+len, "LPCR : 0x%08lx\n", lpcr); -+ len += sprintf (page+len, "Low Power Mode : %s\n", -+ ((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_IDLE)) ? -+ "idle" : (((lpcr & CPM_LPCR_LPM_MASK) == (CPM_LPCR_LPM_SLEEP)) ? "sleep" : "hibernate")); -+ len += sprintf (page+len, "Doze Mode : %s\n", -+ (lpcr & CPM_LPCR_DOZE) ? "on" : "off"); -+ if (lpcr & CPM_LPCR_DOZE) -+ len += sprintf (page+len, " duty : %d\n", (int)((lpcr & CPM_LPCR_DUTY_MASK) >> CPM_LPCR_DUTY_BIT)); -+ len += sprintf (page+len, "CKO1 : %s\n", -+ (REG_CPM_CFCR & CPM_CFCR_CKOEN1) ? "enable" : "disable"); -+ len += sprintf (page+len, "UART0 : %s\n", -+ (mscr & CPM_MSCR_MSTP_UART0) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART1 : %s\n", -+ (mscr & CPM_MSCR_MSTP_UART1) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART2 : %s\n", -+ (mscr & CPM_MSCR_MSTP_UART2) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART3 : %s\n", -+ (mscr & CPM_MSCR_MSTP_UART3) ? "stopped" : "running"); -+ len += sprintf (page+len, "OST : %s\n", -+ (mscr & CPM_MSCR_MSTP_OST) ? "stopped" : "running"); -+ len += sprintf (page+len, "DMAC : %s\n", -+ (mscr & CPM_MSCR_MSTP_DMAC) ? "stopped" : "running"); -+ len += sprintf (page+len, "ETH : %s\n", -+ (mscr & CPM_MSCR_MSTP_ETH) ? "stopped" : "running"); -+ len += sprintf (page+len, "UHC/UDC : %s\n", -+ (mscr & CPM_MSCR_MSTP_UHC) ? "stopped" : "running"); -+ len += sprintf (page+len, "PWM0 : %s\n", -+ (mscr & CPM_MSCR_MSTP_PWM0) ? "stopped" : "running"); -+ len += sprintf (page+len, "PWM1 : %s\n", -+ (mscr & CPM_MSCR_MSTP_PWM1) ? "stopped" : "running"); -+ len += sprintf (page+len, "I2C : %s\n", -+ (mscr & CPM_MSCR_MSTP_I2C) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI : %s\n", -+ (mscr & CPM_MSCR_MSTP_SSI) ? "stopped" : "running"); -+ len += sprintf (page+len, "SCC : %s\n", -+ (mscr & CPM_MSCR_MSTP_SCC) ? "stopped" : "running"); -+ return len; -+} -+ -+static int pmc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_MSCR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+/* -+ * Clock Generation Module -+ */ -+static int cgm_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int cfcr = REG_CPM_CFCR; -+ unsigned int plcr1 = REG_CPM_PLCR1; -+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int od[4] = {1, 2, 2, 4}; -+ -+ -+ len += sprintf (page+len, "PLCR1 : 0x%08x\n", plcr1); -+ len += sprintf (page+len, "CFCR : 0x%08x\n", cfcr); -+ len += sprintf (page+len, "PLL : %s\n", -+ (plcr1 & CPM_PLCR1_PLL1EN) ? "ON" : "OFF"); -+ len += sprintf (page+len, "NF:NR:NO : %d:%d:%d\n", -+ __cpm_plcr1_fd() + 2, -+ __cpm_plcr1_rd() + 2, -+ od[__cpm_plcr1_od()] -+ ); -+ len += sprintf (page+len, "I:S:M:P : %d:%d:%d:%d\n", -+ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT], -+ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT], -+ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT], -+ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT] -+ ); -+ len += sprintf (page+len, "PLL Freq : %d MHz\n", __cpm_get_pllout()/1000000); -+ len += sprintf (page+len, "ICLK : %d MHz\n", __cpm_get_iclk()/1000000); -+ len += sprintf (page+len, "SCLK : %d MHz\n", __cpm_get_sclk()/1000000); -+ len += sprintf (page+len, "MCLK : %d MHz\n", __cpm_get_mclk()/1000000); -+ len += sprintf (page+len, "PCLK : %d MHz\n", __cpm_get_pclk()/1000000); -+ len += sprintf (page+len, "DEVCLK : %d MHz\n", __cpm_get_devclk()/1000000); -+ len += sprintf (page+len, "RTCCLK : %d KHz\n", __cpm_get_rtcclk()/1000); -+ len += sprintf (page+len, "USBCLK : %d MHz\n", __cpm_get_usbclk()/1000000); -+#if defined(CONFIG_FB_JZ) -+ len += sprintf (page+len, "LCDCLK : %d MHz\n", __cpm_get_lcdclk()/1000000); -+ len += sprintf (page+len, "PIXCLK : %d MHz\n", __cpm_get_pixclk()/1000000); -+#endif -+ return len; -+} -+ -+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CFCR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+/* -+ * WDT -+ */ -+static int wdt_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += sprintf (page+len, "WDT_WTCSR : 0x%08x\n", REG_WDT_WTCSR); -+ len += sprintf (page+len, "WDT_WTCNT : 0x%08x\n", REG_WDT_WTCNT); -+ -+ return len; -+} -+ -+static int wdt_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned long cnt = simple_strtoul(buffer, 0, 16); -+ -+ REG_WDT_WTCNT = cnt; -+ REG_WDT_WTCSR = WDT_WTCSR_START; -+ -+ return count; -+} -+ -+/* -+ * PWM -+ */ -+ -+static int proc_jz_pwm_read_byte(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ return sprintf (page, "0x%02x\n", REG8(data)); -+} -+ -+static int proc_jz_pwm_read_word(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ return sprintf (page, "0x%04x\n", REG16(data)); -+} -+ -+static int proc_jz_pwm_write_byte(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG8(data) = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+static int proc_jz_pwm_write_word(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG16(data) = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+#define PWM_NUM 2 -+ -+static int jz_pwm_proc_init(void) -+{ -+ struct proc_dir_entry *proc_jz_pwm, *res; -+ char name[16]; -+ unsigned char i; -+ -+ for (i = 0; i < PWM_NUM; i++) { -+ sprintf(name, "pwm%d", i); -+ proc_jz_pwm = proc_mkdir(name, proc_jz_root); -+ res = create_proc_entry("control", 0600, proc_jz_pwm); -+ if ( res) { -+ res->read_proc = proc_jz_pwm_read_byte; -+ res->write_proc = proc_jz_pwm_write_byte; -+ if (i) -+ res->data = (void * )PWM_CTR(1); -+ else -+ res->data = (void * )PWM_CTR(0); -+ } -+ res = create_proc_entry("period", 0600, proc_jz_pwm); -+ if ( res) { -+ res->read_proc = proc_jz_pwm_read_word; -+ res->write_proc = proc_jz_pwm_write_word; -+ if (i) -+ res->data = (void *)PWM_PER(1); -+ else -+ res->data = (void *)PWM_PER(0); -+ } -+ res = create_proc_entry("duty", 0600, proc_jz_pwm); -+ if ( res) { -+ res->read_proc = proc_jz_pwm_read_word; -+ res->write_proc = proc_jz_pwm_write_word; -+ if (i) -+ res->data = (void * )PWM_DUT(1); -+ else -+ res->data = (void * )PWM_DUT(0); -+ } -+ } -+ return 0; -+} -+ -+/* -+ * /proc/jz/xxx entry -+ * -+ */ -+static int __init jz_proc_init(void) -+{ -+ struct proc_dir_entry *entry; -+ -+ /* create /proc/jz */ -+ proc_jz_root = proc_mkdir("jz", 0); -+ -+ /* create /proc/jz/emc */ -+ entry = create_proc_entry("emc", 0644, proc_jz_root); -+ if (entry) { -+ entry->read_proc = emc_read_proc; -+ entry->write_proc = NULL; -+ entry->data = NULL; -+ } -+ -+ /* create /proc/jz/pmc */ -+ entry = create_proc_entry("pmc", 0644, proc_jz_root); -+ if (entry) { -+ entry->read_proc = pmc_read_proc; -+ entry->write_proc = pmc_write_proc; -+ entry->data = NULL; -+ } -+ -+ /* create /proc/jz/cgm */ -+ entry = create_proc_entry("cgm", 0644, proc_jz_root); -+ if (entry) { -+ entry->read_proc = cgm_read_proc; -+ entry->write_proc = cgm_write_proc; -+ entry->data = NULL; -+ } -+ -+ /* create /proc/jz/wdt */ -+ entry = create_proc_entry("wdt", 0644, proc_jz_root); -+ if (entry) { -+ entry->read_proc = wdt_read_proc; -+ entry->write_proc = wdt_write_proc; -+ entry->data = NULL; -+ } -+ -+ /* PWM */ -+ jz_pwm_proc_init(); -+ -+ return 0; -+} -+ -+__initcall(jz_proc_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/prom.c linux-2.6.24.7/arch/mips/jz4730/prom.c ---- linux-2.6.24.7.old/arch/mips/jz4730/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/prom.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,198 @@ -+/* -+ * -+ * BRIEF MODULE DESCRIPTION -+ * PROM library initialisation code, supports YAMON and U-Boot. -+ * -+ * Copyright 2000, 2001, 2006 MontaVista Software Inc. -+ * Author: MontaVista Software, Inc. -+ * ppopov@mvista.com or source@mvista.com -+ * -+ * This file was derived from Carsten Langgaard's -+ * arch/mips/mips-boards/xx files. -+ * -+ * Carsten Langgaard, carstenl@mips.com -+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* #define DEBUG_CMDLINE */ -+ -+int prom_argc; -+char **prom_argv, **prom_envp; -+ -+char * prom_getcmdline(void) -+{ -+ return &(arcs_cmdline[0]); -+} -+ -+void prom_init_cmdline(void) -+{ -+ char *cp; -+ int actr; -+ -+ actr = 1; /* Always ignore argv[0] */ -+ -+ cp = &(arcs_cmdline[0]); -+ while(actr < prom_argc) { -+ strcpy(cp, prom_argv[actr]); -+ cp += strlen(prom_argv[actr]); -+ *cp++ = ' '; -+ actr++; -+ } -+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ -+ --cp; -+ if (prom_argc > 1) -+ *cp = '\0'; -+ -+} -+ -+ -+char *prom_getenv(char *envname) -+{ -+#if 0 -+ /* -+ * Return a pointer to the given environment variable. -+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". -+ */ -+ -+ char **env = prom_envp; -+ int i = strlen(envname); -+ int yamon = (*env && strchr(*env, '=') == NULL); -+ -+ while (*env) { -+ if (yamon) { -+ if (strcmp(envname, *env++) == 0) -+ return *env; -+ } else { -+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') -+ return *env + i + 1; -+ } -+ env++; -+ } -+#endif -+ return NULL; -+} -+ -+inline unsigned char str2hexnum(unsigned char c) -+{ -+ if(c >= '0' && c <= '9') -+ return c - '0'; -+ if(c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if(c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for(i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+int get_ethernet_addr(char *ethernet_addr) -+{ -+ char *ethaddr_str; -+ -+ ethaddr_str = prom_getenv("ethaddr"); -+ if (!ethaddr_str) { -+ printk("ethaddr not set in boot prom\n"); -+ return -1; -+ } -+ str2eaddr(ethernet_addr, ethaddr_str); -+ -+#if 0 -+ { -+ int i; -+ -+ printk("get_ethernet_addr: "); -+ for (i=0; i<5; i++) -+ printk("%02x:", (unsigned char)*(ethernet_addr+i)); -+ printk("%02x\n", *(ethernet_addr+i)); -+ } -+#endif -+ -+ return 0; -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+} -+ -+void __init prom_init(void) -+{ -+ unsigned char *memsize_str; -+ unsigned long memsize; -+ -+ prom_argc = (int) fw_arg0; -+ prom_argv = (char **) fw_arg1; -+ prom_envp = (char **) fw_arg2; -+ -+ mips_machtype = MACH_INGENIC_JZ4730; -+ -+ prom_init_cmdline(); -+ memsize_str = prom_getenv("memsize"); -+ if (!memsize_str) { -+ memsize = 0x04000000; -+ } else { -+ memsize = simple_strtol(memsize_str, NULL, 0); -+ } -+ add_memory_region(0, memsize, BOOT_MEM_RAM); -+} -+ -+/* used by early printk */ -+void prom_putchar(char c) -+{ -+ volatile u8 *uart_lsr = (volatile u8 *)(UART3_BASE + OFF_LSR); -+ volatile u8 *uart_tdr = (volatile u8 *)(UART3_BASE + OFF_TDR); -+ -+ /* Wait for fifo to shift out some bytes */ -+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); -+ -+ *uart_tdr = (u8)c; -+} -+ -+const char *get_system_type(void) -+{ -+ return "JZ4730"; -+} -+ -+EXPORT_SYMBOL(prom_getcmdline); -+EXPORT_SYMBOL(get_ethernet_addr); -+EXPORT_SYMBOL(str2eaddr); -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/reset.c linux-2.6.24.7/arch/mips/jz4730/reset.c ---- linux-2.6.24.7.old/arch/mips/jz4730/reset.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/reset.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * linux/arch/mips/jz4730/reset.c -+ * -+ * JZ4730 reset routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+void jz_restart(char *command) -+{ -+ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */ -+ __wdt_start(); -+ while (1); -+} -+ -+void jz_halt(void) -+{ -+ __wdt_set_count(0xffffffff-32); /* reset after 1/1024 s */ -+ __wdt_start(); -+ while (1); -+} -+ -+void jz_power_off(void) -+{ -+ jz_halt(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/setup.c linux-2.6.24.7/arch/mips/jz4730/setup.c ---- linux-2.6.24.7.old/arch/mips/jz4730/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/setup.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,182 @@ -+/* -+ * linux/arch/mips/jz4730/setup.c -+ * -+ * JZ4730 CPU common setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PC_KEYB -+#include -+#endif -+ -+jz_clocks_t jz_clocks; -+ -+extern char * __init prom_getcmdline(void); -+extern void __init jz_board_setup(void); -+extern void jz_restart(char *); -+extern void jz_halt(void); -+extern void jz_power_off(void); -+extern void jz_time_init(void); -+ -+static void __init sysclocks_setup(void) -+{ -+#ifndef CONFIG_JZ4730_URANUS -+ jz_clocks.iclk = __cpm_get_iclk(); -+ jz_clocks.sclk = __cpm_get_sclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.devclk = __cpm_get_devclk(); -+ jz_clocks.rtcclk = __cpm_get_rtcclk(); -+ jz_clocks.uartclk = __cpm_get_uartclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(); -+#else /* URANUS FPGA */ -+ -+#define FPGACLK 8000000 -+ -+ jz_clocks.iclk = FPGACLK; -+ jz_clocks.sclk = FPGACLK; -+ jz_clocks.mclk = FPGACLK; -+ jz_clocks.devclk = FPGACLK; -+ jz_clocks.rtcclk = FPGACLK; -+ jz_clocks.uartclk = FPGACLK; -+ jz_clocks.pixclk = FPGACLK; -+ jz_clocks.lcdclk = FPGACLK; -+ jz_clocks.usbclk = FPGACLK; -+ jz_clocks.i2sclk = FPGACLK; -+ jz_clocks.mscclk = FPGACLK; -+#endif -+ -+ printk("CPU clock: %dMHz, System clock: %dMHz, Memory clock: %dMHz, Peripheral clock: %dMHz\n", -+ (jz_clocks.iclk + 500000) / 1000000, -+ (jz_clocks.sclk + 500000) / 1000000, -+ (jz_clocks.mclk + 500000) / 1000000, -+ (jz_clocks.pclk + 500000) / 1000000); -+} -+ -+static void __init soc_cpm_setup(void) -+{ -+ __cpm_idle_mode(); -+ __cpm_enable_cko1(); -+ __cpm_start_all(); -+ -+ /* get system clocks */ -+ sysclocks_setup(); -+} -+ -+static void __init soc_harb_setup(void) -+{ -+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ -+ __harb_set_priority(0x08); /* DMAC>LCD>CIM>ETH>USB>CIM */ -+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ -+} -+ -+static void __init soc_emc_setup(void) -+{ -+} -+ -+static void __init soc_dmac_setup(void) -+{ -+ __dmac_enable_all_channels(); -+} -+ -+static void __init jz_soc_setup(void) -+{ -+ soc_cpm_setup(); -+ soc_harb_setup(); -+ soc_emc_setup(); -+ soc_dmac_setup(); -+} -+ -+static void __init jz_serial_setup(void) -+{ -+#ifdef CONFIG_SERIAL_8250 -+ struct uart_port s; -+ -+ memset(&s, 0, sizeof(s)); -+ -+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; -+ s.iotype = UPIO_MEM; -+ s.regshift = 2; -+ s.uartclk = jz_clocks.uartclk; -+ -+ s.line = 0; -+ s.membase = (u8 *)UART0_BASE; -+ s.irq = IRQ_UART0; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); -+ } -+ -+ s.line = 1; -+ s.membase = (u8 *)UART1_BASE; -+ s.irq = IRQ_UART1; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); -+ } -+ -+ s.line = 2; -+ s.membase = (u8 *)UART2_BASE; -+ s.irq = IRQ_UART2; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); -+ } -+ -+ s.line = 3; -+ s.membase = (u8 *)UART3_BASE; -+ s.irq = IRQ_UART3; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); -+ } -+#endif -+} -+ -+void __init plat_mem_setup(void) -+{ -+ char *argptr; -+ -+ argptr = prom_getcmdline(); -+ -+ /* IO/MEM resources. */ -+ set_io_port_base(0); -+ ioport_resource.start = 0x00000000; -+ ioport_resource.end = 0xffffffff; -+ iomem_resource.start = 0x00000000; -+ iomem_resource.end = 0xffffffff; -+ -+ _machine_restart = jz_restart; -+ _machine_halt = jz_halt; -+ pm_power_off = jz_power_off; -+ -+ jz_soc_setup(); /* soc specific setup */ -+ jz_serial_setup(); /* serial port setup */ -+ jz_board_setup(); /* board specific setup */ -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/sleep.S linux-2.6.24.7/arch/mips/jz4730/sleep.S ---- linux-2.6.24.7.old/arch/mips/jz4730/sleep.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/sleep.S 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,307 @@ -+/* -+ * linux/arch/mips/jz4730/sleep.S -+ * -+ * jz4730 Assembler Sleep/WakeUp Management Routines -+ * -+ * Copyright (C) 2005 Ingenic Semiconductor -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+ -+ .text -+ .set noreorder -+ .set noat -+ -+ .extern jz_flush_cache_all -+ -+/* -+ * jz_cpu_suspend() -+ * -+ * Forces CPU into hibernate mode -+ */ -+ -+ .globl jz_cpu_suspend -+jz_cpu_suspend: -+ -+ /* save hi, lo and general registers except k0($26) and k1($27) (total 32) */ -+ move k0, sp -+ addiu k0, k0, -(32*4) -+ mfhi k1 -+ sw $0, 0(k0) -+ sw $1, 4(k0) -+ sw k1, 120(k0) /* hi */ -+ mflo k1 -+ sw $2, 8(k0) -+ sw $3, 12(k0) -+ sw k1, 124(k0) /* lo */ -+ sw $4, 16(k0) -+ sw $5, 20(k0) -+ sw $6, 24(k0) -+ sw $7, 28(k0) -+ sw $8, 32(k0) -+ sw $9, 36(k0) -+ sw $10, 40(k0) -+ sw $11, 44(k0) -+ sw $12, 48(k0) -+ sw $13, 52(k0) -+ sw $14, 56(k0) -+ sw $15, 60(k0) -+ sw $16, 64(k0) -+ sw $17, 68(k0) -+ sw $18, 72(k0) -+ sw $19, 76(k0) -+ sw $20, 80(k0) -+ sw $21, 84(k0) -+ sw $22, 88(k0) -+ sw $23, 92(k0) -+ sw $24, 96(k0) -+ sw $25, 100(k0) -+ sw $28, 104(k0) -+ sw $29, 108(k0) /* saved sp */ -+ sw $30, 112(k0) -+ sw $31, 116(k0) /* saved ra */ -+ move sp, k0 -+ -+ /* save CP0 registers and sp (total 26) */ -+ move k0, sp -+ addiu k0, k0, -(26*4) -+ -+ mfc0 $1, CP0_INDEX -+ mfc0 $2, CP0_RANDOM -+ mfc0 $3, CP0_ENTRYLO0 -+ mfc0 $4, CP0_ENTRYLO1 -+ mfc0 $5, CP0_CONTEXT -+ mfc0 $6, CP0_PAGEMASK -+ mfc0 $7, CP0_WIRED -+ mfc0 $8, CP0_BADVADDR -+ mfc0 $9, CP0_ENTRYHI -+ mfc0 $10, CP0_STATUS -+/* mfc0 $11, $12, 1*/ /* IntCtl */ -+ mfc0 $12, CP0_CAUSE -+ mfc0 $13, CP0_EPC -+/* mfc0 $14, $15, 1*/ /* EBase */ -+ mfc0 $15, CP0_CONFIG -+/* mfc0 $16, CP0_CONFIG, 7*/ /* Config 7 */ -+ mfc0 $17, CP0_LLADDR -+ mfc0 $18, CP0_WATCHLO -+ mfc0 $19, CP0_WATCHHI -+ mfc0 $20, CP0_DEBUG -+ mfc0 $21, CP0_DEPC -+ mfc0 $22, CP0_ECC -+ mfc0 $23, CP0_TAGLO -+ mfc0 $24, CP0_ERROREPC -+ mfc0 $25, CP0_DESAVE -+ -+ sw $1, 0(k0) -+ sw $2, 4(k0) -+ sw $3, 8(k0) -+ sw $4, 12(k0) -+ sw $5, 16(k0) -+ sw $6, 20(k0) -+ sw $7, 24(k0) -+ sw $8, 28(k0) -+ sw $9, 32(k0) -+ sw $10, 36(k0) -+ sw $11, 40(k0) -+ sw $12, 44(k0) -+ sw $13, 48(k0) -+ sw $14, 52(k0) -+ sw $15, 56(k0) -+ sw $16, 60(k0) -+ sw $17, 64(k0) -+ sw $18, 68(k0) -+ sw $19, 72(k0) -+ sw $20, 76(k0) -+ sw $21, 80(k0) -+ sw $22, 84(k0) -+ sw $23, 88(k0) -+ sw $24, 92(k0) -+ sw $25, 96(k0) -+ sw $29, 100(k0) /* saved sp */ -+ move sp, k0 -+ -+ /* preserve virtual address of stack */ -+ la k0, suspend_save_sp -+ sw sp, 0(k0) -+ -+ /* flush caches and write buffers */ -+ jal jz_flush_cache_all -+ nop -+ -+ /* set new sdram refresh constant */ -+ li t0, 1 -+ la t1, EMC_RTCOR -+ sh t0, 0(t1) -+ -+ /* disable PLL */ -+ la t0, CPM_PLCR1 -+ sw $0, 0(t0) -+ -+ /* put CPU to hibernate mode */ -+ la t0, CPM_LPCR -+ lw t1, 0(t0) -+ li t2, ~CPM_LPCR_LPM_MASK -+ and t1, t2 -+ ori t1, CPM_LPCR_LPM_HIBERNATE -+ -+ .align 5 -+ /* align execution to a cache line */ -+ j 1f -+ -+ .align 5 -+1: -+ /* all needed values are now in registers. -+ * These last instructions should be in cache -+ */ -+ nop -+ nop -+ -+ /* set hibernate mode */ -+ sw t1, 0(t0) -+ nop -+ -+ /* enter hibernate mode */ -+ .set mips3 -+ wait -+ nop -+ .set mips2 -+ -+2: j 2b /* loop waiting for suspended */ -+ nop -+ -+/* -+ * jz_cpu_resume() -+ * -+ * entry point from bootloader into kernel during resume -+ */ -+ -+ .align 5 -+ .globl jz_cpu_resume -+jz_cpu_resume: -+ /* clear SCR.HGP */ -+ la t0, CPM_SCR -+ lw t1, 0(t0) -+ li t2, ~CPM_SCR_HGP -+ and t1, t2 -+ sw t1, 0(t0) -+ -+ /* restore LPCR.LPM to IDLE mode */ -+ la t0, CPM_LPCR -+ lw t1, 0(t0) -+ li t2, ~CPM_LPCR_LPM_MASK -+ and t1, t2 -+ ori t1, CPM_LPCR_LPM_IDLE -+ sw t1, 0(t0) -+ -+ /* restore saved sp */ -+ la t0, suspend_save_sp -+ lw sp, 0(t0) -+ -+ /* restore CP0 registers */ -+ move k0, sp -+ lw $1, 0(k0) -+ lw $2, 4(k0) -+ lw $3, 8(k0) -+ lw $4, 12(k0) -+ lw $5, 16(k0) -+ lw $6, 20(k0) -+ lw $7, 24(k0) -+ lw $8, 28(k0) -+ lw $9, 32(k0) -+ lw $10, 36(k0) -+ lw $11, 40(k0) -+ lw $12, 44(k0) -+ lw $13, 48(k0) -+ lw $14, 52(k0) -+ lw $15, 56(k0) -+ lw $16, 60(k0) -+ lw $17, 64(k0) -+ lw $18, 68(k0) -+ lw $19, 72(k0) -+ lw $20, 76(k0) -+ lw $21, 80(k0) -+ lw $22, 84(k0) -+ lw $23, 88(k0) -+ lw $24, 92(k0) -+ lw $25, 96(k0) -+ lw $29, 100(k0) /* saved sp */ -+ -+ mtc0 $1, CP0_INDEX -+ mtc0 $2, CP0_RANDOM -+ mtc0 $3, CP0_ENTRYLO0 -+ mtc0 $4, CP0_ENTRYLO1 -+ mtc0 $5, CP0_CONTEXT -+ mtc0 $6, CP0_PAGEMASK -+ mtc0 $7, CP0_WIRED -+ mtc0 $8, CP0_BADVADDR -+ mtc0 $9, CP0_ENTRYHI -+ mtc0 $10, CP0_STATUS -+/* mtc0 $11, $12, 1*/ /* IntCtl */ -+ mtc0 $12, CP0_CAUSE -+ mtc0 $13, CP0_EPC -+/* mtc0 $14, $15, 1*/ /* EBase */ -+ mtc0 $15, CP0_CONFIG -+/* mtc0 $16, CP0_CONFIG, 7*/ /* Config 7 */ -+ mtc0 $17, CP0_LLADDR -+ mtc0 $18, CP0_WATCHLO -+ mtc0 $19, CP0_WATCHHI -+ mtc0 $20, CP0_DEBUG -+ mtc0 $21, CP0_DEPC -+ mtc0 $22, CP0_ECC -+ mtc0 $23, CP0_TAGLO -+ mtc0 $24, CP0_ERROREPC -+ mtc0 $25, CP0_DESAVE -+ -+ /* restore general registers */ -+ move k0, sp -+ lw k1, 120(k0) /* hi */ -+ lw $0, 0(k0) -+ lw $1, 4(k0) -+ mthi k1 -+ lw k1, 124(k0) /* lo */ -+ lw $2, 8(k0) -+ lw $3, 12(k0) -+ mtlo k1 -+ lw $4, 16(k0) -+ lw $5, 20(k0) -+ lw $6, 24(k0) -+ lw $7, 28(k0) -+ lw $8, 32(k0) -+ lw $9, 36(k0) -+ lw $10, 40(k0) -+ lw $11, 44(k0) -+ lw $12, 48(k0) -+ lw $13, 52(k0) -+ lw $14, 56(k0) -+ lw $15, 60(k0) -+ lw $16, 64(k0) -+ lw $17, 68(k0) -+ lw $18, 72(k0) -+ lw $19, 76(k0) -+ lw $20, 80(k0) -+ lw $21, 84(k0) -+ lw $22, 88(k0) -+ lw $23, 92(k0) -+ lw $24, 96(k0) -+ lw $25, 100(k0) -+ lw $28, 104(k0) -+ lw $29, 108(k0) /* saved sp */ -+ lw $30, 112(k0) -+ lw $31, 116(k0) /* saved ra */ -+ -+ /* return to caller */ -+ jr ra -+ nop -+ -+suspend_save_sp: -+ .word 0 /* preserve sp here */ -+ -+ .set reorder -diff -urN linux-2.6.24.7.old/arch/mips/jz4730/time.c linux-2.6.24.7/arch/mips/jz4730/time.c ---- linux-2.6.24.7.old/arch/mips/jz4730/time.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4730/time.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,129 @@ -+/* -+ * linux/arch/mips/jz4730/time.c -+ * -+ * Setting up the clock on the JZ4730 boards. -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define JZ_TIMER_CHAN 0 -+#define JZ_TIMER_IRQ IRQ_OST0 -+#define JZ_TIMER_CLOCK JZ_EXTAL -+ -+static unsigned int timer_latch; -+ -+void (*jz_timer_callback)(void); -+ -+static void jz_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ switch (mode) { -+ case CLOCK_EVT_MODE_PERIODIC: -+ break; -+ case CLOCK_EVT_MODE_ONESHOT: -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ break; -+ case CLOCK_EVT_MODE_RESUME: -+ break; -+ } -+} -+ -+static struct clock_event_device jz_clockevent_device = { -+ .name = "jz-timer", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+ -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ -+ .rating = 300, -+ .irq = JZ_TIMER_IRQ, -+ .set_mode = jz_set_mode, -+}; -+ -+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ -+ __ost_clear_uf(JZ_TIMER_CHAN); /* ACK timer */ -+ -+ if (jz_timer_callback) -+ jz_timer_callback(); -+ -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct irqaction jz_irqaction = { -+ .handler = jz_timer_interrupt, -+ .flags = IRQF_DISABLED | IRQF_PERCPU, -+ .name = "jz-timer", -+}; -+ -+cycle_t jz_get_cycles(void) -+{ -+ unsigned int jz_timer_cnt; -+#if 0 /* clock source use pll, read directly */ -+ jz_timer_cnt = timer_latch - REG_OST_TCNT(JZ_TIMER_CHAN); -+#else /* clock source use RTCClock or Extall Clock, wait read ready */ -+ jz_timer_cnt = REG_OST_TCNT(JZ_TIMER_CHAN); /* dummy read */ -+ while ( __ost_is_busy(JZ_TIMER_CHAN) ) ; /* wait read ready */ -+ jz_timer_cnt = timer_latch - REG_OST_TCRB(JZ_TIMER_CHAN); -+#endif -+ -+ /* convert jiffes to jz timer cycles */ -+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + jz_timer_cnt); -+} -+ -+static struct clocksource clocksource_jz = { -+ .name = "jz_clocksource", -+ .rating = 300, -+ .read = jz_get_cycles, -+ .mask = 0xFFFFFFFF, -+ .shift = 10, /* control clocksource.mult's accuracy */ -+ .flags = CLOCK_SOURCE_WATCHDOG, -+}; -+ -+static int __init jz_clocksource_init(void) -+{ -+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); -+ clocksource_register(&clocksource_jz); -+ return 0; -+} -+ -+static void __init jz_timer_setup(void) -+{ -+ struct clock_event_device *cd = &jz_clockevent_device; -+ struct irqaction *action = &jz_irqaction; -+ unsigned int cpu = smp_processor_id(); -+ -+ jz_clocksource_init(); -+ cd->cpumask = cpumask_of_cpu(cpu); -+ clockevents_register_device(cd); -+ action->dev_id = cd; -+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); -+} -+ -+void __init plat_time_init(void) -+{ -+ /* Init timer, timer clock soure use extal clock */ -+ timer_latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; -+ __ost_set_mode(JZ_TIMER_CHAN, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL); -+ __ost_set_reload(JZ_TIMER_CHAN, timer_latch); -+ __ost_set_count(JZ_TIMER_CHAN, timer_latch); -+ __ost_enable_channel(JZ_TIMER_CHAN); -+ -+ jz_timer_setup(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/Makefile linux-2.6.24.7/arch/mips/jz4740/Makefile ---- linux-2.6.24.7.old/arch/mips/jz4740/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,26 @@ -+# -+# Makefile for the Ingenic JZ4740. -+# -+ -+# Object file lists. -+ -+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ -+ platform.o i2c.o -+ -+obj-$(CONFIG_PROC_FS) += proc.o -+ -+# board specific support -+ -+obj-$(CONFIG_JZ4740_PAVO) += board-pavo.o -+obj-$(CONFIG_JZ4740_LEO) += board-leo.o -+obj-$(CONFIG_JZ4740_LYRA) += board-lyra.o -+obj-$(CONFIG_JZ4725_DIPPER) += board-dipper.o -+obj-$(CONFIG_JZ4720_VIRGO) += board-virgo.o -+ -+# PM support -+ -+obj-$(CONFIG_PM_LEGACY) +=pm.o -+ -+# CPU Frequency scaling support -+ -+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/board-dipper.c linux-2.6.24.7/arch/mips/jz4740/board-dipper.c ---- linux-2.6.24.7.old/arch/mips/jz4740/board-dipper.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/board-dipper.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,117 @@ -+/* -+ * linux/arch/mips/jz4740/board-dipper.c -+ * -+ * JZ4725 Dipper board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+#if 0 -+static void dancing(void) -+{ -+ static unsigned int count = 0; -+ -+ count ++; -+ count &= 1; -+ -+ if (count) -+ __gpio_set_pin(GPIO_LED_EN); -+ else -+ __gpio_clear_pin(GPIO_LED_EN); -+} -+#endif -+ -+static void dipper_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+// dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4740/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Most of the GPIO pins should have been initialized by the boot-loader -+ */ -+ -+ /* -+ * Initialize MSC pins -+ */ -+ __gpio_as_msc(); -+ -+ /* -+ * Initialize Smart LCD pins -+ */ -+// __gpio_as_slcd_18bit(); -+ -+ /* -+ * Initialize SSI pins -+ */ -+ __gpio_as_ssi(); -+ -+ /* -+ * Initialize I2C pins -+ */ -+ __gpio_as_i2c(); -+ -+ /* -+ * Initialize Other pins -+ */ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); -+ -+ __gpio_as_input(GPIO_SD_CD_N); -+ __gpio_disable_pull(GPIO_SD_CD_N); -+ -+ __gpio_as_input(GPIO_SD_WP); -+ __gpio_disable_pull(GPIO_SD_WP); -+ -+ __gpio_as_input(GPIO_DC_DETE_N); -+ __gpio_as_input(GPIO_CHARG_STAT_N); -+ __gpio_as_input(GPIO_USB_DETE); -+ -+ __gpio_as_output(GPIO_DISP_OFF_N); -+ -+// __gpio_as_output(GPIO_LED_EN); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4725 DIPPER board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = dipper_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/board-leo.c linux-2.6.24.7/arch/mips/jz4740/board-leo.c ---- linux-2.6.24.7.old/arch/mips/jz4740/board-leo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/board-leo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,67 @@ -+/* -+ * linux/arch/mips/jz4740/board-leo.c -+ * -+ * JZ4740 LEO board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned char slash[] = "\\|/-"; -+ static volatile unsigned char *p = (unsigned char *)0xb6000016; -+ static unsigned int count = 0; -+ *p = slash[count++]; -+ count &= 3; -+} -+ -+static void leo_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 10 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4740/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* All GPIO pins should have been initialized by the boot-loader */ -+} -+ -+void __init jz_board_setup(void) -+{ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ printk(" BOARD SETUP"); -+ jz_timer_callback = leo_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/board-lyra.c linux-2.6.24.7/arch/mips/jz4740/board-lyra.c ---- linux-2.6.24.7.old/arch/mips/jz4740/board-lyra.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/board-lyra.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,114 @@ -+/* -+ * linux/arch/mips/jz4740/board-lyra.c -+ * -+ * JZ4740 LYRA board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned int count = 0; -+ -+ count ++; -+ count &= 1; -+ if (count) -+ __gpio_set_pin(GPIO_LED_EN); -+ else -+ __gpio_clear_pin(GPIO_LED_EN); -+} -+ -+static void lyra_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4740/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Most of the GPIO pins should have been initialized by the boot-loader -+ */ -+ -+ /* -+ * Initialize MSC pins -+ */ -+ __gpio_as_msc(); -+ -+ /* -+ * Initialize LCD pins -+ */ -+ __gpio_as_lcd_18bit(); -+ -+ /* -+ * Initialize SSI pins -+ */ -+ __gpio_as_ssi(); -+ -+ /* -+ * Initialize I2C pins -+ */ -+ __gpio_as_i2c(); -+ -+ /* -+ * Initialize Other pins -+ */ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); -+ -+ __gpio_as_input(GPIO_SD_CD_N); -+ __gpio_disable_pull(GPIO_SD_CD_N); -+ -+ __gpio_as_input(GPIO_SD_WP); -+ __gpio_disable_pull(GPIO_SD_WP); -+ -+ __gpio_as_input(GPIO_DC_DETE_N); -+ __gpio_as_input(GPIO_CHARG_STAT_N); -+ __gpio_as_input(GPIO_USB_DETE); -+ -+ __gpio_as_output(GPIO_DISP_OFF_N); -+ -+ __gpio_as_output(GPIO_LED_EN); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4740 LYRA board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = lyra_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/board-pavo.c linux-2.6.24.7/arch/mips/jz4740/board-pavo.c ---- linux-2.6.24.7.old/arch/mips/jz4740/board-pavo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/board-pavo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,114 @@ -+/* -+ * linux/arch/mips/jz4740/board-pavo.c -+ * -+ * JZ4740 PAVO board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned int count = 0; -+ -+ count ++; -+ count &= 1; -+ if (count) -+ __gpio_set_pin(GPIO_LED_EN); -+ else -+ __gpio_clear_pin(GPIO_LED_EN); -+} -+ -+static void pavo_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4740/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Most of the GPIO pins should have been initialized by the boot-loader -+ */ -+ -+ /* -+ * Initialize MSC pins -+ */ -+ __gpio_as_msc(); -+ -+ /* -+ * Initialize LCD pins -+ */ -+ __gpio_as_lcd_18bit(); -+ -+ /* -+ * Initialize SSI pins -+ */ -+ __gpio_as_ssi(); -+ -+ /* -+ * Initialize I2C pins -+ */ -+ __gpio_as_i2c(); -+ -+ /* -+ * Initialize Other pins -+ */ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); -+ -+ __gpio_as_input(GPIO_SD_CD_N); -+ __gpio_disable_pull(GPIO_SD_CD_N); -+ -+ __gpio_as_input(GPIO_SD_WP); -+ __gpio_disable_pull(GPIO_SD_WP); -+ -+ __gpio_as_input(GPIO_DC_DETE_N); -+ __gpio_as_input(GPIO_CHARG_STAT_N); -+ __gpio_as_input(GPIO_USB_DETE); -+ -+ __gpio_as_output(GPIO_DISP_OFF_N); -+ -+ __gpio_as_output(GPIO_LED_EN); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4740 PAVO board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = pavo_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/board-virgo.c linux-2.6.24.7/arch/mips/jz4740/board-virgo.c ---- linux-2.6.24.7.old/arch/mips/jz4740/board-virgo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/board-virgo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,114 @@ -+/* -+ * linux/arch/mips/jz4740/board-virgo.c -+ * -+ * JZ4720 VIRGO board setup routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned int count = 0; -+ -+ count ++; -+ count &= 1; -+ if (count) -+ __gpio_set_pin(GPIO_LED_EN); -+ else -+ __gpio_clear_pin(GPIO_LED_EN); -+} -+ -+static void virgo_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4740/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Most of the GPIO pins should have been initialized by the boot-loader -+ */ -+ -+ /* -+ * Initialize MSC pins -+ */ -+ __gpio_as_msc(); -+ -+ /* -+ * Initialize LCD pins -+ */ -+// __gpio_as_lcd_18bit(); -+ -+ /* -+ * Initialize SSI pins -+ */ -+ __gpio_as_ssi(); -+ -+ /* -+ * Initialize I2C pins -+ */ -+ __gpio_as_i2c(); -+ -+ /* -+ * Initialize Other pins -+ */ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); -+ -+ __gpio_as_input(GPIO_SD_CD_N); -+ __gpio_disable_pull(GPIO_SD_CD_N); -+ -+// __gpio_as_input(GPIO_SD_WP); -+// __gpio_disable_pull(GPIO_SD_WP); -+ -+ __gpio_as_input(GPIO_DC_DETE_N); -+// __gpio_as_input(GPIO_CHARG_STAT_N); -+ __gpio_as_input(GPIO_USB_DETE); -+ -+ __gpio_as_output(GPIO_DISP_OFF_N); -+ -+// __gpio_as_output(GPIO_LED_EN); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4720 VIRGO board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = virgo_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/cpufreq.c linux-2.6.24.7/arch/mips/jz4740/cpufreq.c ---- linux-2.6.24.7.old/arch/mips/jz4740/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/cpufreq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,602 @@ -+/* -+ * linux/arch/mips/jz4740/cpufreq.c -+ * -+ * cpufreq driver for JZ4740 -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ -+ "cpufreq-jz4740", msg) -+ -+#undef CHANGE_PLL -+ -+#define PLL_UNCHANGED 0 -+#define PLL_GOES_UP 1 -+#define PLL_GOES_DOWN 2 -+ -+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) -+ -+/* Saved the boot-time parameters */ -+static struct { -+ /* SDRAM parameters */ -+ unsigned int mclk; /* memory clock, KHz */ -+ unsigned int tras; /* RAS pulse width, cycles of mclk */ -+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ -+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ -+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ -+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ -+ unsigned int rtcor; /* Refresh Time Constant */ -+ unsigned int sdram_initialized; -+ -+ /* LCD parameters */ -+ unsigned int lcd_clk; /* LCD clock, Hz */ -+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ -+ unsigned int lcd_clks_initialized; -+} boot_config; -+ -+struct jz4740_freq_percpu_info { -+ struct cpufreq_frequency_table table[7]; -+}; -+ -+static struct jz4740_freq_percpu_info jz4740_freq_table; -+ -+/* -+ * This contains the registers value for an operating point. -+ * If only part of a register needs to change then there is -+ * a mask value for that register. -+ * When going to a new operating point the current register -+ * value is ANDed with the ~mask and ORed with the new value. -+ */ -+struct dpm_regs { -+ u32 cpccr; /* Clock Freq Control Register */ -+ u32 cpccr_mask; /* Clock Freq Control Register mask */ -+ u32 cppcr; /* PLL1 Control Register */ -+ u32 cppcr_mask; /* PLL1 Control Register mask */ -+ u32 pll_up_flag; /* New PLL freq is higher than current or not */ -+}; -+ -+extern jz_clocks_t jz_clocks; -+ -+static void jz_update_clocks(void) -+{ -+ /* Next clocks must be updated if we have changed -+ * the PLL or divisors. -+ */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(); -+} -+ -+static void -+jz_init_boot_config(void) -+{ -+ if (!boot_config.lcd_clks_initialized) { -+ /* the first time to scale pll */ -+ boot_config.lcd_clk = __cpm_get_lcdclk(); -+ boot_config.lcdpix_clk = __cpm_get_pixclk(); -+ boot_config.lcd_clks_initialized = 1; -+ } -+ -+ if (!boot_config.sdram_initialized) { -+ /* the first time to scale frequencies */ -+ unsigned int dmcr, rtcor; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ -+ dmcr = REG_EMC_DMCR; -+ rtcor = REG_EMC_RTCOR; -+ -+ tras = (dmcr >> 13) & 0x7; -+ rcd = (dmcr >> 11) & 0x3; -+ tpc = (dmcr >> 8) & 0x7; -+ trwl = (dmcr >> 5) & 0x3; -+ trc = (dmcr >> 2) & 0x7; -+ -+ boot_config.mclk = __cpm_get_mclk() / 1000; -+ boot_config.tras = tras + 4; -+ boot_config.rcd = rcd + 1; -+ boot_config.tpc = tpc + 1; -+ boot_config.trwl = trwl + 1; -+ boot_config.trc = trc * 2 + 1; -+ boot_config.rtcor = rtcor; -+ -+ boot_config.sdram_initialized = 1; -+ } -+} -+ -+static void jz_update_dram_rtcor(unsigned int new_mclk) -+{ -+ unsigned int rtcor; -+ -+ new_mclk /= 1000; -+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; -+ rtcor--; -+ -+ if (rtcor < 1) rtcor = 1; -+ if (rtcor > 255) rtcor = 255; -+ -+ REG_EMC_RTCOR = rtcor; -+ REG_EMC_RTCNT = rtcor; -+} -+ -+static void jz_update_dram_dmcr(unsigned int new_mclk) -+{ -+ unsigned int dmcr; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ unsigned int valid_time, new_time; /* ns */ -+ -+ new_mclk /= 1000; -+ tras = boot_config.tras * new_mclk / boot_config.mclk; -+ rcd = boot_config.rcd * new_mclk / boot_config.mclk; -+ tpc = boot_config.tpc * new_mclk / boot_config.mclk; -+ trwl = boot_config.trwl * new_mclk / boot_config.mclk; -+ trc = boot_config.trc * new_mclk / boot_config.mclk; -+ -+ /* Validation checking */ -+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; -+ new_time = (tras * 1000000) / new_mclk; -+ if (new_time < valid_time) tras += 1; -+ -+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; -+ new_time = (rcd * 1000000) / new_mclk; -+ if (new_time < valid_time) rcd += 1; -+ -+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; -+ new_time = (tpc * 1000000) / new_mclk; -+ if (new_time < valid_time) tpc += 1; -+ -+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; -+ new_time = (trwl * 1000000) / new_mclk; -+ if (new_time < valid_time) trwl += 1; -+ -+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; -+ new_time = (trc * 1000000) / new_mclk; -+ if (new_time < valid_time) trc += 2; -+ -+ tras = (tras < 4) ? 4: tras; -+ tras = (tras > 11) ? 11: tras; -+ tras -= 4; -+ -+ rcd = (rcd < 1) ? 1: rcd; -+ rcd = (rcd > 4) ? 4: rcd; -+ rcd -= 1; -+ -+ tpc = (tpc < 1) ? 1: tpc; -+ tpc = (tpc > 8) ? 8: tpc; -+ tpc -= 1; -+ -+ trwl = (trwl < 1) ? 1: trwl; -+ trwl = (trwl > 4) ? 4: trwl; -+ trwl -= 1; -+ -+ trc = (trc < 1) ? 1: trc; -+ trc = (trc > 15) ? 15: trc; -+ trc /= 2; -+ -+ dmcr = REG_EMC_DMCR; -+ -+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); -+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); -+ -+ REG_EMC_DMCR = dmcr; -+} -+ -+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR before changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } else { -+ /* We're going SLOWER: first update RTCOR value -+ * before changing the frequency. -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } -+} -+ -+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so update RTCOR -+ * after changing the frequency -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } else { -+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR after changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } -+} -+ -+static void jz_scale_divisors(struct dpm_regs *regs) -+{ -+ unsigned int cpccr; -+ unsigned int cur_mclk, new_mclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~((unsigned long)regs->cpccr_mask); -+ cpccr |= regs->cpccr; -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; -+ -+ /* Update some DRAM parameters before changing frequency */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+ -+#ifdef CHANGE_PLL -+/* Maintain the LCD clock and pixel clock */ -+static void jz_scale_lcd_divisors(struct dpm_regs *regs) -+{ -+ unsigned int new_pll, new_lcd_div, new_lcdpix_div; -+ unsigned int cpccr; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ if (!boot_config.lcd_clks_initialized) return; -+ -+ new_pll = __cpm_get_pllout(); -+ new_lcd_div = new_pll / boot_config.lcd_clk; -+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; -+ -+ if (new_lcd_div < 1) -+ new_lcd_div = 1; -+ if (new_lcd_div > 16) -+ new_lcd_div = 16; -+ -+ if (new_lcdpix_div < 1) -+ new_lcdpix_div = 1; -+ if (new_lcdpix_div > 512) -+ new_lcdpix_div = 512; -+ -+// REG_CPM_CPCCR2 = new_lcdpix_div - 1; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~CPM_CPCCR_LDIV_MASK; -+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+} -+ -+static void jz_scale_pll(struct dpm_regs *regs) -+{ -+ unsigned int cppcr; -+ unsigned int cur_mclk, new_mclk, new_pll; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ int od[] = {1, 2, 2, 4}; -+ -+ cppcr = REG_CPM_CPPCR; -+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); -+ regs->cppcr &= ~CPM_CPPCR_PLLEN; -+ cppcr |= (regs->cppcr | 0xff); -+ -+ /* Update some DRAM parameters before changing frequency */ -+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf]; -+ -+ /* -+ * Update some SDRAM parameters -+ */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* -+ * Update PLL, align code to cache line. -+ */ -+ cppcr |= CPM_CPPCR_PLLEN; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPPCR), "r" (cppcr)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+#endif -+ -+static void jz4740_transition(struct dpm_regs *regs) -+{ -+ /* -+ * Get and save some boot-time conditions. -+ */ -+ jz_init_boot_config(); -+ -+#ifdef CHANGE_PLL -+ /* -+ * Disable LCD before scaling pll. -+ * LCD and LCD pixel clocks should not be changed even if the PLL -+ * output frequency has been changed. -+ */ -+ REG_LCD_CTRL &= ~LCD_CTRL_ENA; -+ -+ /* -+ * Stop module clocks before scaling PLL -+ */ -+ __cpm_stop_eth(); -+ __cpm_stop_aic(1); -+ __cpm_stop_aic(2); -+#endif -+ -+ /* ... add more as necessary */ -+ -+ if (regs->pll_up_flag == PLL_GOES_UP) { -+ /* the pll frequency is going up, so change dividors first */ -+ jz_scale_divisors(regs); -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ } -+ else if (regs->pll_up_flag == PLL_GOES_DOWN) { -+ /* the pll frequency is going down, so change pll first */ -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ jz_scale_divisors(regs); -+ } -+ else { -+ /* the pll frequency is unchanged, so change divisors only */ -+ jz_scale_divisors(regs); -+ } -+ -+#ifdef CHANGE_PLL -+ /* -+ * Restart module clocks before scaling PLL -+ */ -+ __cpm_start_eth(); -+ __cpm_start_aic(1); -+ __cpm_start_aic(2); -+ -+ /* ... add more as necessary */ -+ -+ /* Scale the LCD divisors after scaling pll */ -+ if (regs->pll_up_flag != PLL_UNCHANGED) { -+ jz_scale_lcd_divisors(regs); -+ } -+ -+ /* Enable LCD controller */ -+ REG_LCD_CTRL &= ~LCD_CTRL_DIS; -+ REG_LCD_CTRL |= LCD_CTRL_ENA; -+#endif -+ -+ /* Update system clocks */ -+ jz_update_clocks(); -+} -+ -+extern unsigned int idle_times; -+static unsigned int jz4740_freq_get(unsigned int cpu) -+{ -+ return (__cpm_get_cclk() / 1000); -+} -+ -+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) -+{ -+ int n2FR[33] = { -+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, -+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, -+ 9 -+ }; -+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ -+ unsigned int div_of_cclk, new_freq, i; -+ -+ regs->pll_up_flag = PLL_UNCHANGED; -+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; -+ -+ new_freq = jz4740_freq_table.table[index].frequency; -+ -+ do { -+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); -+ } while (div_of_cclk==0); -+ -+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { -+ for(i = 1; i<4; i++) { -+ div[i] = 3; -+ } -+ } else { -+ for(i = 1; i<4; i++) { -+ div[i] = 2; -+ } -+ } -+ -+ for(i = 0; i<4; i++) { -+ div[i] *= div_of_cclk; -+ } -+ -+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); -+ -+ regs->cpccr = -+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | -+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | -+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | -+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); -+ -+ return div_of_cclk; -+} -+ -+static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index) -+{ -+ unsigned long divisor, old_divisor; -+ struct cpufreq_freqs freqs; -+ struct dpm_regs regs; -+ -+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); -+ divisor = index_to_divisor(index, ®s); -+ -+ freqs.old = __cpm_get_cclk() / 1000; -+ freqs.new = __cpm_get_pllout() / (1000 * divisor); -+ freqs.cpu = cpu; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ -+ if (old_divisor != divisor) -+ jz4740_transition(®s); -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+} -+ -+static int jz4740_freq_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ unsigned int new_index = 0; -+ -+ if (cpufreq_frequency_table_target(policy, -+ &jz4740_freq_table.table[0], -+ target_freq, relation, &new_index)) -+ return -EINVAL; -+ -+ jz4740_set_cpu_divider_index(policy->cpu, new_index); -+ -+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); -+ -+ return 0; -+} -+ -+static int jz4740_freq_verify(struct cpufreq_policy *policy) -+{ -+ return cpufreq_frequency_table_verify(policy, -+ &jz4740_freq_table.table[0]); -+} -+ -+static int __init jz4740_cpufreq_driver_init(struct cpufreq_policy *policy) -+{ -+ -+ struct cpufreq_frequency_table *table = &jz4740_freq_table.table[0]; -+ unsigned int MAX_FREQ; -+ -+ dprintk(KERN_INFO "Jz4740 cpufreq driver\n"); -+ -+ if (policy->cpu != 0) -+ return -EINVAL; -+ -+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ -+ policy->cpuinfo.min_freq = MAX_FREQ/8; -+ policy->cpuinfo.max_freq = MAX_FREQ; -+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ -+ -+ table[0].index = 0; -+ table[0].frequency = MAX_FREQ/8; -+ table[1].index = 1; -+ table[1].frequency = MAX_FREQ/6; -+ table[2].index = 2; -+ table[2].frequency = MAX_FREQ/4; -+ table[3].index = 3; -+ table[3].frequency = MAX_FREQ/3; -+ table[4].index = 4; -+ table[4].frequency = MAX_FREQ/2; -+ table[5].index = 5; -+ table[5].frequency = MAX_FREQ; -+ table[6].index = 6; -+ table[6].frequency = CPUFREQ_TABLE_END; -+ -+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS -+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ -+#endif -+ -+ return cpufreq_frequency_table_cpuinfo(policy, table); -+} -+ -+static struct cpufreq_driver cpufreq_jz4740_driver = { -+// .flags = CPUFREQ_STICKY, -+ .init = jz4740_cpufreq_driver_init, -+ .verify = jz4740_freq_verify, -+ .target = jz4740_freq_target, -+ .get = jz4740_freq_get, -+ .name = "jz4740", -+}; -+ -+static int __init jz4740_cpufreq_init(void) -+{ -+ return cpufreq_register_driver(&cpufreq_jz4740_driver); -+} -+ -+static void __exit jz4740_cpufreq_exit(void) -+{ -+ cpufreq_unregister_driver(&cpufreq_jz4740_driver); -+} -+ -+module_init(jz4740_cpufreq_init); -+module_exit(jz4740_cpufreq_exit); -+ -+MODULE_AUTHOR("Regen "); -+MODULE_DESCRIPTION("cpufreq driver for Jz4740"); -+MODULE_LICENSE("GPL"); -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/dma.c linux-2.6.24.7/arch/mips/jz4740/dma.c ---- linux-2.6.24.7.old/arch/mips/jz4740/dma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/dma.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,768 @@ -+/* -+ * linux/arch/mips/jz4740/dma.c -+ * -+ * Support functions for the JZ4740 internal DMA channels. -+ * No-descriptor transfer only. -+ * Descriptor transfer should also call jz_request_dma() to get a free -+ * channel and call jz_free_dma() to free the channel. And driver should -+ * build the DMA descriptor and setup the DMA channel by itself. -+ * -+ * Copyright (C) 2006 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * A note on resource allocation: -+ * -+ * All drivers needing DMA channels, should allocate and release them -+ * through the public routines `jz_request_dma()' and `jz_free_dma()'. -+ * -+ * In order to avoid problems, all processes should allocate resources in -+ * the same sequence and release them in the reverse order. -+ * -+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. -+ * When releasing them, first release the IRQ, then release the DMA. The -+ * main reason for this order is that, if you are requesting the DMA buffer -+ * done interrupt, you won't know the irq number until the DMA channel is -+ * returned from jz_request_dma(). -+ */ -+ -+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+ {dev_id:-1,}, -+}; -+ -+// Device FIFO addresses and default DMA modes -+static const struct { -+ unsigned int fifo_addr; -+ unsigned int dma_mode; -+ unsigned int dma_source; -+} dma_dev_table[DMA_ID_MAX] = { -+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, -+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, -+ {CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT}, -+ {CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, -+ {CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT}, -+ {CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, -+ {}, -+}; -+ -+ -+int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data) -+{ -+ int i, len = 0; -+ struct jz_dma_chan *chan; -+ -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if ((chan = get_dma_chan(i)) != NULL) { -+ len += sprintf(buf + len, "%2d: %s\n", -+ i, chan->dev_str); -+ } -+ } -+ -+ if (fpos >= len) { -+ *start = buf; -+ *eof = 1; -+ return 0; -+ } -+ *start = buf + fpos; -+ if ((len -= fpos) > length) -+ return length; -+ *eof = 1; -+ return len; -+} -+ -+ -+void dump_jz_dma_channel(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return; -+ chan = &jz_dma_table[dmanr]; -+ -+ printk("DMA%d Registers:\n", dmanr); -+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR); -+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); -+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); -+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); -+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); -+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); -+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); -+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); -+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR); -+} -+ -+ -+/** -+ * jz_request_dma - dynamically allcate an idle DMA channel to return -+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET -+ * @dev_str: the specified dma device string name -+ * @irqhandler: the irq handler, or NULL -+ * @irqflags: the irq handler flags -+ * @irq_dev_id: the irq handler device id for shared irq -+ * -+ * Finds a free channel, and binds the requested device to it. -+ * Returns the allocated channel number, or negative on error. -+ * Requests the DMA done IRQ if irqhandler != NULL. -+ * -+*/ -+/*int jz_request_dma(int dev_id, const char *dev_str, -+ void (*irqhandler)(int, void *, struct pt_regs *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+*/ -+ -+int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+{ -+ struct jz_dma_chan *chan; -+ int i, ret; -+ -+ if (dev_id < 0 || dev_id >= DMA_ID_MAX) -+ return -EINVAL; -+ -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) /* no free channel */ -+ return -ENODEV; -+ -+ /* we got a free channel */ -+ chan = &jz_dma_table[i]; -+ -+ if (irqhandler) { -+ chan->irq = IRQ_DMA_0 + i; // allocate irq number -+ chan->irq_dev = irq_dev_id; -+ if ((ret = request_irq(chan->irq, irqhandler, irqflags, -+ dev_str, chan->irq_dev))) { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ return ret; -+ } -+ } else { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ } -+ -+ // fill it in -+ chan->io = i; -+ chan->dev_id = dev_id; -+ chan->dev_str = dev_str; -+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; -+ chan->mode = dma_dev_table[dev_id].dma_mode; -+ chan->source = dma_dev_table[dev_id].dma_source; -+ -+ return i; -+} -+ -+void jz_free_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) { -+ printk("Trying to free DMA%d\n", dmanr); -+ return; -+ } -+ -+ disable_dma(dmanr); -+ if (chan->irq) -+ free_irq(chan->irq, chan->irq_dev); -+ -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ chan->dev_id = -1; -+} -+ -+void jz_set_dma_dest_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_DWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_src_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_SWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_SWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_SWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_SWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DS_MASK; -+ switch (nbyte) { -+ case 1: -+ chan->mode |= DMAC_DCMD_DS_8BIT; -+ break; -+ case 2: -+ chan->mode |= DMAC_DCMD_DS_16BIT; -+ break; -+ case 4: -+ chan->mode |= DMAC_DCMD_DS_32BIT; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DS_16BYTE; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DS_32BYTE; -+ break; -+ } -+} -+ -+unsigned int jz_get_dma_command(int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ return chan->mode; -+} -+ -+/** -+ * jz_set_dma_mode - do the raw settings for the specified DMA channel -+ * @dmanr: the specified DMA channel -+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE -+ * @dma_mode: dma raw mode -+ * @dma_source: dma raw request source -+ * @fifo_addr: dma raw device fifo address -+ * -+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call -+ * jz_set_dma_mode() rather than set_dma_mode() if you work with -+ * and external request dma device. -+ * -+ * NOTE: Don not dynamically allocate dma channel if one external request -+ * dma device will occupy this channel. -+*/ -+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, -+ unsigned int dma_mode, unsigned int dma_source, -+ unsigned int fifo_addr) -+{ -+ int dev_id, i; -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return -ENODEV; -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) -+ return -ENODEV; -+ -+ chan = &jz_dma_table[dmanr]; -+ dev_id = chan->dev_id; -+ if (dev_id > 0) { -+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", -+ __FUNCTION__, dmanr); -+ return -ENODEV; -+ } -+ -+ /* clone it from the dynamically allocated. */ -+ if (i != dmanr) { -+ chan->irq = jz_dma_table[i].irq; -+ chan->irq_dev = jz_dma_table[i].irq_dev; -+ chan->dev_str = jz_dma_table[i].dev_str; -+ jz_dma_table[i].irq = 0; -+ jz_dma_table[i].irq_dev = NULL; -+ jz_dma_table[i].dev_id = -1; -+ } -+ chan->dev_id = DMA_ID_RAW_SET; -+ chan->io = dmanr; -+ chan->fifo_addr = fifo_addr; -+ chan->mode = dma_mode; -+ chan->source = dma_source; -+ -+ set_dma_mode(dmanr, dma_mode); -+ -+ return dmanr; -+} -+ -+void enable_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ -+ __dmac_enable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_enable_irq(dmanr); -+} -+ -+#define DMA_DISABLE_POLL 0x10000 -+ -+void disable_dma(unsigned int dmanr) -+{ -+ int i; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ if (!__dmac_channel_enabled(dmanr)) -+ return; -+ -+ for (i = 0; i < DMA_DISABLE_POLL; i++) -+ if (__dmac_channel_transmit_end_detected(dmanr)) -+ break; -+#if 0 -+ if (i == DMA_DISABLE_POLL) -+ printk(KERN_INFO "disable_dma: poll expired!\n"); -+#endif -+ -+ __dmac_disable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_disable_irq(dmanr); -+} -+ -+/* Note: DMA_MODE_MASK is simulated by sw */ -+void set_dma_mode(unsigned int dmanr, unsigned int mode) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else { -+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ } -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+} -+ -+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) -+{ -+ unsigned int mode; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ mode = chan->mode & DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; -+ REG_DMAC_DTAR(chan->io) = phyaddr; -+ } else if (mode == DMA_MODE_WRITE) { -+ REG_DMAC_DSAR(chan->io) = phyaddr; -+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; -+ } else -+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); -+} -+ -+void set_dma_count(unsigned int dmanr, unsigned int bytecnt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ unsigned int ds; -+ -+ if (!chan) -+ return; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count -+} -+ -+unsigned int get_dma_residue(unsigned int dmanr) -+{ -+ unsigned int count, ds; -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ count = REG_DMAC_DTCR(chan->io); -+ count = count * dma_ds[ds]; -+ -+ return count; -+} -+ -+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case AFMT_U8: -+ /* burst mode : 32BIT */ -+ break; -+ case AFMT_S16_LE: -+ /* burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case 8: -+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ -+ break; -+ case 16: -+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+#undef JZ4740_DMAC_TEST_ENABLE -+ -+#ifdef JZ4740_DMAC_TEST_ENABLE -+ -+/* -+ * DMA test: external address <--> external address -+ */ -+#define TEST_DMA_SIZE 16*1024 -+ -+static jz_dma_desc *dma_desc; -+ -+static int dma_chan; -+static dma_addr_t dma_desc_phys_addr; -+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; -+ -+static int dma_check_result(void *src, void *dst, int size) -+{ -+ unsigned int addr1, addr2, i, err = 0; -+ -+ addr1 = (unsigned int)src; -+ addr2 = (unsigned int)dst; -+ -+ for (i = 0; i < size; i += 4) { -+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { -+ err++; -+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); -+ } -+ addr1 += 4; -+ addr2 += 4; -+ } -+ printk("check DMA result err=%d\n", err); -+ return err; -+} -+ -+static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ printk("jz4740_dma_irq %d\n", irq); -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ printk("DMA HALT\n"); -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ printk("DMA ADDR ERROR\n"); -+ __dmac_channel_clear_address_error(dma_chan); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ printk("DMA DESC INVALID\n"); -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ } -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ printk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ } -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ printk("DMA TT\n"); -+ __dmac_channel_clear_transmit_end(dma_chan); -+ dump_jz_dma_channel(dma_chan); -+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); -+ } -+ -+ /* free buffers */ -+ printk("free DMA buffers\n"); -+ free_pages(dma_src_addr, 2); -+ free_pages(dma_dst_addr, 2); -+ -+ if (dma_desc) -+ free_pages((unsigned int)dma_desc, 0); -+ -+ /* free dma */ -+ jz_free_dma(dma_chan); -+} -+ -+void dma_nodesc_test(void) -+{ -+ unsigned int addr, i; -+ -+ printk("dma_nodesc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, -+ SA_INTERRUPT, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Init DMA module */ -+ printk("Starting DMA\n"); -+ REG_DMAC_DMACR = 0; -+ REG_DMAC_DCCSR(dma_chan) = 0; -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = 512; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+} -+ -+void dma_desc_test(void) -+{ -+ unsigned int next, addr, i; -+ static jz_dma_desc *desc; -+ -+ printk("dma_desc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, -+ SA_INTERRUPT, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Allocate DMA descriptors */ -+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); -+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); -+ -+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); -+ -+ /* Setup DMA descriptors */ -+ desc = dma_desc; -+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ -+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; -+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ -+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ -+ -+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ REG_DMAC_DMADBSR = 1 << dma_chan; -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+} -+ -+#endif -+ -+//EXPORT_SYMBOL_NOVERS(jz_dma_table); -+EXPORT_SYMBOL(jz_dma_table); -+EXPORT_SYMBOL(jz_request_dma); -+EXPORT_SYMBOL(jz_free_dma); -+EXPORT_SYMBOL(jz_set_dma_src_width); -+EXPORT_SYMBOL(jz_set_dma_dest_width); -+EXPORT_SYMBOL(jz_set_dma_block_size); -+EXPORT_SYMBOL(jz_set_dma_mode); -+EXPORT_SYMBOL(set_dma_mode); -+EXPORT_SYMBOL(jz_set_oss_dma); -+EXPORT_SYMBOL(jz_set_alsa_dma); -+EXPORT_SYMBOL(set_dma_addr); -+EXPORT_SYMBOL(set_dma_count); -+EXPORT_SYMBOL(get_dma_residue); -+EXPORT_SYMBOL(enable_dma); -+EXPORT_SYMBOL(disable_dma); -+EXPORT_SYMBOL(dump_jz_dma_channel); -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/i2c.c linux-2.6.24.7/arch/mips/jz4740/i2c.c ---- linux-2.6.24.7.old/arch/mips/jz4740/i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/i2c.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,273 @@ -+/* -+ * linux/arch/mips/jz4740/i2c.c -+ * -+ * Jz4740 I2C routines. -+ * -+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* I2C protocol */ -+#define I2C_READ 1 -+#define I2C_WRITE 0 -+ -+#define TIMEOUT 1000 -+ -+/* -+ * I2C bus protocol basic routines -+ */ -+static int i2c_put_data(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (!__i2c_received_ack() && timeout) -+ timeout--; -+ -+ if (timeout) -+ return 0; -+ else -+ return -ETIMEDOUT; -+} -+ -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+static int i2c_put_data_nack(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (timeout--); -+ return 0; -+} -+#endif -+ -+static int i2c_get_data(unsigned char *data, int ack) -+{ -+ int timeout = TIMEOUT*10; -+ -+ if (!ack) -+ __i2c_send_nack(); -+ else -+ __i2c_send_ack(); -+ -+ while (__i2c_check_drf() == 0 && timeout) -+ timeout--; -+ -+ if (timeout) { -+ if (!ack) -+ __i2c_send_stop(); -+ *data = __i2c_read(); -+ __i2c_clear_drf(); -+ return 0; -+ } else -+ return -ETIMEDOUT; -+} -+ -+/* -+ * I2C interface -+ */ -+void i2c_open(void) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ -+ __i2c_enable(); -+} -+ -+void i2c_close(void) -+{ -+ udelay(300); /* wait for STOP goes over. */ -+ __i2c_disable(); -+} -+ -+void i2c_setclk(unsigned int i2cclk) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, i2cclk); -+} -+ -+int i2c_lseek(unsigned char device, unsigned char offset) -+{ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (i2c_put_data(offset) < 0) -+ goto address_err; -+ return 0; -+ device_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+ address_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); -+ __i2c_send_stop(); -+ return -EREMOTEIO; -+} -+ -+int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int timeout = 5; -+ -+L_try_again: -+ -+ if (timeout < 0) -+ goto L_timeout; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_werr; -+ if (i2c_put_data(address) < 0) -+ goto address_err; -+ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) -+ goto device_rerr; -+ __i2c_send_ack(); /* Master sends ACK for continue reading */ -+ while (cnt) { -+ if (cnt == 1) { -+ if (i2c_get_data(buf, 0) < 0) -+ break; -+ } else { -+ if (i2c_get_data(buf, 1) < 0) -+ break; -+ } -+ cnt--; -+ buf++; -+ } -+ -+ __i2c_send_stop(); -+ return count - cnt; -+ device_rerr: -+ device_werr: -+ address_err: -+ timeout --; -+ __i2c_send_stop(); -+ goto L_try_again; -+ -+L_timeout: -+ __i2c_send_stop(); -+ printk("Read I2C device 0x%2x failed.\n", device); -+ return -ENODEV; -+} -+ -+int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int cnt_in_pg; -+ int timeout = 5; -+ unsigned char *tmpbuf; -+ unsigned char tmpaddr; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ W_try_again: -+ if (timeout < 0) -+ goto W_timeout; -+ -+ cnt = count; -+ tmpbuf = (unsigned char *)buf; -+ tmpaddr = address; -+ -+ start_write_page: -+ cnt_in_pg = 0; -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+ if (address == 0xff) { -+ if (i2c_put_data_nack(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data_nack(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+ else { -+ -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+#else -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+#endif -+ __i2c_send_stop(); -+ return count - cnt; -+ device_err: -+ address_err: -+ timeout--; -+ __i2c_send_stop(); -+ goto W_try_again; -+ -+ W_timeout: -+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+} -+ -+EXPORT_SYMBOL(i2c_open); -+EXPORT_SYMBOL(i2c_close); -+EXPORT_SYMBOL(i2c_setclk); -+EXPORT_SYMBOL(i2c_read); -+EXPORT_SYMBOL(i2c_write); -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/irq.c linux-2.6.24.7/arch/mips/jz4740/irq.c ---- linux-2.6.24.7.old/arch/mips/jz4740/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/irq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,265 @@ -+/* -+ * linux/arch/mips/jz4740/irq.c -+ * -+ * JZ4740 interrupt routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * INTC irq type -+ */ -+ -+static void enable_intc_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(irq); -+} -+ -+static void disable_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+} -+ -+static void mask_and_ack_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+ __intc_ack_irq(irq); -+} -+ -+static void end_intc_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_intc_irq(irq); -+ } -+} -+ -+static unsigned int startup_intc_irq(unsigned int irq) -+{ -+ enable_intc_irq(irq); -+ return 0; -+} -+ -+static void shutdown_intc_irq(unsigned int irq) -+{ -+ disable_intc_irq(irq); -+} -+ -+static struct irq_chip intc_irq_type = { -+ .typename = "INTC", -+ .startup = startup_intc_irq, -+ .shutdown = shutdown_intc_irq, -+ .enable = enable_intc_irq, -+ .disable = disable_intc_irq, -+ .ack = mask_and_ack_intc_irq, -+ .end = end_intc_irq, -+}; -+ -+/* -+ * GPIO irq type -+ */ -+ -+static void enable_gpio_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if (irq < (IRQ_GPIO_0 + 32)) { -+ intc_irq = IRQ_GPIO0; -+ } -+ else if (irq < (IRQ_GPIO_0 + 64)) { -+ intc_irq = IRQ_GPIO1; -+ } -+ else if (irq < (IRQ_GPIO_0 + 96)) { -+ intc_irq = IRQ_GPIO2; -+ } -+ else { -+ intc_irq = IRQ_GPIO3; -+ } -+ -+ enable_intc_irq(intc_irq); -+ __gpio_unmask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void disable_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void mask_and_ack_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+ __gpio_ack_irq(irq - IRQ_GPIO_0); -+} -+ -+static void end_gpio_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_gpio_irq(irq); -+ } -+} -+ -+static unsigned int startup_gpio_irq(unsigned int irq) -+{ -+ enable_gpio_irq(irq); -+ return 0; -+} -+ -+static void shutdown_gpio_irq(unsigned int irq) -+{ -+ disable_gpio_irq(irq); -+} -+ -+static struct irq_chip gpio_irq_type = { -+ .typename = "GPIO", -+ .startup = startup_gpio_irq, -+ .shutdown = shutdown_gpio_irq, -+ .enable = enable_gpio_irq, -+ .disable = disable_gpio_irq, -+ .ack = mask_and_ack_gpio_irq, -+ .end = end_gpio_irq, -+}; -+ -+/* -+ * DMA irq type -+ */ -+ -+static void enable_dma_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(IRQ_DMAC); -+ __dmac_channel_enable_irq(irq - IRQ_DMA_0); -+} -+ -+static void disable_dma_irq(unsigned int irq) -+{ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void mask_and_ack_dma_irq(unsigned int irq) -+{ -+ __intc_ack_irq(IRQ_DMAC); -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void end_dma_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_dma_irq(irq); -+ } -+} -+ -+static unsigned int startup_dma_irq(unsigned int irq) -+{ -+ enable_dma_irq(irq); -+ return 0; -+} -+ -+static void shutdown_dma_irq(unsigned int irq) -+{ -+ disable_dma_irq(irq); -+} -+ -+static struct irq_chip dma_irq_type = { -+ .typename = "DMA", -+ .startup = startup_dma_irq, -+ .shutdown = shutdown_dma_irq, -+ .enable = enable_dma_irq, -+ .disable = disable_dma_irq, -+ .ack = mask_and_ack_dma_irq, -+ .end = end_dma_irq, -+}; -+ -+//---------------------------------------------------------------------- -+ -+void __init arch_init_irq(void) -+{ -+ int i; -+ -+ clear_c0_status(0xff04); /* clear ERL */ -+ set_c0_status(0x0400); /* set IP2 */ -+ -+ /* Set up INTC irq -+ */ -+ for (i = 0; i < 32; i++) { -+ disable_intc_irq(i); -+ irq_desc[i].chip = &intc_irq_type; -+ } -+ -+ /* Set up DMAC irq -+ */ -+ for (i = 0; i < NUM_DMA; i++) { -+ disable_dma_irq(IRQ_DMA_0 + i); -+ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; -+ } -+ -+ /* Set up GPIO irq -+ */ -+ for (i = 0; i < NUM_GPIO; i++) { -+ disable_gpio_irq(IRQ_GPIO_0 + i); -+ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; -+ } -+} -+ -+static int plat_real_irq(int irq) -+{ -+ switch (irq) { -+ case IRQ_GPIO0: -+ irq = __gpio_group_irq(0) + IRQ_GPIO_0; -+ break; -+ case IRQ_GPIO1: -+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; -+ break; -+ case IRQ_GPIO2: -+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; -+ break; -+ case IRQ_GPIO3: -+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; -+ break; -+ case IRQ_DMAC: -+ irq = __dmac_get_irq() + IRQ_DMA_0; -+ break; -+ } -+ -+ return irq; -+} -+ -+asmlinkage void plat_irq_dispatch(void) -+{ -+ int irq = 0; -+ static unsigned long intc_ipr = 0; -+ -+ intc_ipr |= REG_INTC_IPR; -+ -+ if (!intc_ipr) return; -+ -+ irq = ffs(intc_ipr) - 1; -+ intc_ipr &= ~(1< -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* OHCI (USB full speed host controller) */ -+static struct resource jz_usb_ohci_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap -+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UHC, -+ .end = IRQ_UHC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+/* The dmamask must be set for OHCI to work */ -+static u64 ohci_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_ohci_device = { -+ .name = "jz-ohci", -+ .id = 0, -+ .dev = { -+ .dma_mask = &ohci_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), -+ .resource = jz_usb_ohci_resources, -+}; -+ -+/*** LCD controller ***/ -+static struct resource jz_lcd_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(LCD_BASE), -+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_LCD, -+ .end = IRQ_LCD, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_lcd_dmamask = ~(u32)0; -+ -+static struct platform_device jz_lcd_device = { -+ .name = "jz-lcd", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_lcd_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_lcd_resources), -+ .resource = jz_lcd_resources, -+}; -+ -+/* UDC (USB gadget controller) */ -+static struct resource jz_usb_gdt_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UDC_BASE), -+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UDC, -+ .end = IRQ_UDC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static u64 udc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_gdt_device = { -+ .name = "jz-udc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &udc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), -+ .resource = jz_usb_gdt_resources, -+}; -+ -+/** MMC/SD controller **/ -+static struct resource jz_mmc_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(MSC_BASE), -+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_MSC, -+ .end = IRQ_MSC, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_mmc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_mmc_device = { -+ .name = "jz-mmc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_mmc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_mmc_resources), -+ .resource = jz_mmc_resources, -+}; -+ -+/** I2C controller **/ -+static struct resource jz_i2c_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(I2C_BASE), -+ .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_I2C, -+ .end = IRQ_I2C, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_i2c_dmamask = ~(u32)0; -+ -+static struct platform_device jz_i2c_device = { -+ .name = "jz_i2c", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_i2c_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_i2c_resources), -+ .resource = jz_i2c_resources, -+}; -+ -+/* All */ -+static struct platform_device *jz_platform_devices[] __initdata = { -+ &jz_usb_ohci_device, -+ &jz_lcd_device, -+ &jz_usb_gdt_device, -+ &jz_mmc_device, -+ &jz_i2c_device, -+}; -+ -+static int __init jz_platform_init(void) -+{ -+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); -+} -+ -+arch_initcall(jz_platform_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/pm.c linux-2.6.24.7/arch/mips/jz4740/pm.c ---- linux-2.6.24.7.old/arch/mips/jz4740/pm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/pm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,462 @@ -+/* -+ * linux/arch/mips/jz4740/common/pm.c -+ * -+ * JZ4740 Power Management Routines -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+#define GPIO_WAKEUP 125 /* set SW7(GPIO 125) as WAKEUP key */ -+ -+/* -+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input -+ * except sdram, nand flash pins and the pins which can be used as CS1_N -+ * to CS4_N for chip select. -+ */ -+#define __gpio_as_sleep() \ -+do { \ -+ REG_GPIO_PXFUNC(1) = ~0x9ff9ffff; \ -+ REG_GPIO_PXSELC(1) = ~0x9ff9ffff; \ -+ REG_GPIO_PXDIRC(1) = ~0x9ff9ffff; \ -+ REG_GPIO_PXPES(1) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(2) = ~0x37000000; \ -+ REG_GPIO_PXSELC(2) = ~0x37000000; \ -+ REG_GPIO_PXDIRC(2) = ~0x37000000; \ -+ REG_GPIO_PXPES(2) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(3) = 0xffffffff; \ -+ REG_GPIO_PXSELC(3) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(3) = 0xffffffff; \ -+ REG_GPIO_PXPES(3) = 0xffffffff; \ -+} while (0) -+ -+static int jz_pm_do_hibernate(void) -+{ -+ printk("Put CPU into hibernate mode.\n"); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* -+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled -+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). -+ */ -+ -+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); -+ -+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ -+ -+ /* Scratch pad register to be reserved */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HSPR = 0x12345678; -+ -+ /* clear wakeup status register */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWRSR = 0x0; -+ -+ /* Put CPU to power down mode */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HCR = RTC_HCR_PD; -+ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ while(1); -+ -+ /* We can't get here */ -+ return 0; -+} -+ -+/* NOTES: -+ * 1: Pins that are floated (NC) should be set as input and pull-enable. -+ * 2: Pins that are pull-up or pull-down by outside should be set as input -+ * and pull-disable. -+ * 3: Pins that are connected to a chip except sdram and nand flash -+ * should be set as input and pull-disable, too. -+ */ -+static void jz_board_do_sleep(unsigned long *ptr) -+{ -+ unsigned char i; -+ -+ /* Print messages of GPIO registers for debug */ -+ for(i=0;i<4;i++) { -+ dprintk("run dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ -+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ -+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); -+ } -+ -+ /* Save GPIO registers */ -+ for(i = 1; i < 4; i++) { -+ *ptr++ = REG_GPIO_PXFUN(i); -+ *ptr++ = REG_GPIO_PXSEL(i); -+ *ptr++ = REG_GPIO_PXDIR(i); -+ *ptr++ = REG_GPIO_PXPE(i); -+ *ptr++ = REG_GPIO_PXIM(i); -+ *ptr++ = REG_GPIO_PXDAT(i); -+ *ptr++ = REG_GPIO_PXTRG(i); -+ } -+ -+ /* -+ * Set all pins to pull-disable, and set all pins as input except -+ * sdram, nand flash pins and the pins which can be used as CS1_N -+ * to CS4_N for chip select. -+ */ -+ __gpio_as_sleep(); -+ -+ /* -+ * Set proper status for GPB25 to GPB28 which can be used as CS1_N to CS4_N. -+ * Keep the pins' function used for chip select(CS) here according to your -+ * system to avoid chip select crashing with sdram when resuming from sleep mode. -+ */ -+ -+#if defined(CONFIG_JZ4740_PAVO) -+ /* GPB25/CS1_N is used as chip select for nand flash, shouldn't be change. */ -+ -+ /* GPB26/CS2_N is connected to nand flash, needn't be changed. */ -+ -+ /* GPB27/CS3_N is used as EXT_INT for CS8900 on debug board, it should be set as input.*/ -+ __gpio_as_input(32+27); -+ -+ /* GPB28/CS4_N is used as cs8900's chip select, shouldn't be changed. */ -+#endif -+ -+ /* -+ * Enable pull for NC pins here according to your system -+ */ -+ -+#if defined(CONFIG_JZ4740_PAVO) -+ /* GPB30-27 <-> J1: WE_N RD_N CS4_N EXT_INT */ -+ for(i=27;i<31;i++) { -+ __gpio_enable_pull(32+i); -+ } -+ -+ /* GPC27<-> WAIT_N */ -+ __gpio_enable_pull(32*2+27); -+ -+ /* GPD16<->SD_WP; GPD13-10<->MSC_D0-3; GPD9<->MSC_CMD; GPD8<->MSC_CLK */ -+ __gpio_enable_pull(32*3+16); -+ for(i=8;i<14;i++) { -+ __gpio_enable_pull(32*3+i); -+ } -+#endif -+ -+ /* -+ * If you must set some GPIOs as output to high level or low level, -+ * you can set them here, using: -+ * __gpio_as_output(n); -+ * __gpio_set_pin(n); or __gpio_clear_pin(n); -+ */ -+ -+#if defined(CONFIG_JZ4740_PAVO) -+ /* GPD16 which is used as AMPEN_N should be set to high to disable audio amplifier */ -+ __gpio_set_pin(32*3+4); -+#endif -+ -+#ifdef DEBUG -+ /* Keep uart0 function for printing debug message */ -+ __gpio_as_uart0(); -+ -+ /* Print messages of GPIO registers for debug */ -+ for(i=0;i<4;i++) { -+ dprintk("sleep dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ -+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ -+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); -+ } -+#endif -+} -+ -+static void jz_board_do_resume(unsigned long *ptr) -+{ -+ unsigned char i; -+ -+ /* Restore GPIO registers */ -+ for(i = 1; i < 4; i++) { -+ REG_GPIO_PXFUNS(i) = *ptr; -+ REG_GPIO_PXFUNC(i) = ~(*ptr++); -+ -+ REG_GPIO_PXSELS(i) = *ptr; -+ REG_GPIO_PXSELC(i) = ~(*ptr++); -+ -+ REG_GPIO_PXDIRS(i) = *ptr; -+ REG_GPIO_PXDIRC(i) = ~(*ptr++); -+ -+ REG_GPIO_PXPES(i) = *ptr; -+ REG_GPIO_PXPEC(i) = ~(*ptr++); -+ -+ REG_GPIO_PXIMS(i)=*ptr; -+ REG_GPIO_PXIMC(i)=~(*ptr++); -+ -+ REG_GPIO_PXDATS(i)=*ptr; -+ REG_GPIO_PXDATC(i)=~(*ptr++); -+ -+ REG_GPIO_PXTRGS(i)=*ptr; -+ REG_GPIO_PXTRGC(i)=~(*ptr++); -+ } -+ -+ /* Print messages of GPIO registers for debug */ -+ for(i=0;i<4;i++) { -+ dprintk("resume dat:%x pin:%x fun:%x sel:%x dir:%x pull:%x msk:%x trg:%x\n", \ -+ REG_GPIO_PXDAT(i),REG_GPIO_PXPIN(i),REG_GPIO_PXFUN(i),REG_GPIO_PXSEL(i), \ -+ REG_GPIO_PXDIR(i),REG_GPIO_PXPE(i),REG_GPIO_PXIM(i),REG_GPIO_PXTRG(i)); -+ } -+} -+ -+ -+ -+static int jz_pm_do_sleep(void) -+{ -+ unsigned long delta; -+ unsigned long nfcsr = REG_EMC_NFCSR; -+ unsigned long scr = REG_CPM_SCR; -+ unsigned long imr = REG_INTC_IMR; -+ unsigned long sadc = REG_SADC_ENA; -+ unsigned long sleep_gpio_save[7*3]; -+ -+ printk("Put CPU into sleep mode.\n"); -+ -+ /* Preserve current time */ -+ delta = xtime.tv_sec - REG_RTC_RSR; -+ -+ /* Disable nand flash */ -+ REG_EMC_NFCSR = ~0xff; -+ -+ /* stop sadc */ -+ REG_SADC_ENA &= ~0x7; -+ while((REG_SADC_ENA & 0x7) != 0); -+ udelay(100); -+ -+ /*stop udc and usb*/ -+ REG_CPM_SCR &= ~( 1<<6 | 1<<7); -+ REG_CPM_SCR |= 0<<6 | 1<<7; -+ -+ /* Sleep on-board modules */ -+ jz_board_do_sleep(sleep_gpio_save); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* Just allow following interrupts to wakeup the system. -+ * Note: modify this according to your system. -+ */ -+ -+ /* enable RTC alarm */ -+ __intc_unmask_irq(IRQ_RTC); -+#if 0 -+ /* make system wake up after n seconds by RTC alarm */ -+ unsigned int v, n; -+ n = 10; -+ while (!__rtc_write_ready()); -+ __rtc_enable_alarm(); -+ while (!__rtc_write_ready()); -+ __rtc_enable_alarm_irq(); -+ while (!__rtc_write_ready()); -+ v = __rtc_get_second(); -+ while (!__rtc_write_ready()); -+ __rtc_set_alarm_second(v+n); -+#endif -+ -+ /* WAKEUP key */ -+ __gpio_as_irq_rise_edge(GPIO_WAKEUP); -+ __gpio_unmask_irq(GPIO_WAKEUP); -+ __intc_unmask_irq(IRQ_GPIO3); /* IRQ_GPIOn depends on GPIO_WAKEUP */ -+ -+ /* Enter SLEEP mode */ -+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; -+ REG_CPM_LCR |= CPM_LCR_LPM_SLEEP; -+ __asm__(".set\tmips3\n\t" -+ "wait\n\t" -+ ".set\tmips0"); -+ -+ /* Restore to IDLE mode */ -+ REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; -+ REG_CPM_LCR |= CPM_LCR_LPM_IDLE; -+ -+ /* Restore nand flash control register */ -+ REG_EMC_NFCSR = nfcsr; -+ -+ /* Restore interrupts */ -+ REG_INTC_IMSR = imr; -+ REG_INTC_IMCR = ~imr; -+ -+ /* Restore sadc */ -+ REG_SADC_ENA = sadc; -+ -+ /* Resume on-board modules */ -+ jz_board_do_resume(sleep_gpio_save); -+ -+ /* Restore sleep control register */ -+ REG_CPM_SCR = scr; -+ -+ /* Restore current time */ -+ xtime.tv_sec = REG_RTC_RSR + delta; -+ -+ return 0; -+} -+ -+/* Put CPU to HIBERNATE mode */ -+int jz_pm_hibernate(void) -+{ -+ return jz_pm_do_hibernate(); -+} -+ -+#ifndef CONFIG_JZ_POWEROFF -+static irqreturn_t pm_irq_handler (int irq, void *dev_id) -+{ -+ return IRQ_HANDLED; -+} -+#endif -+ -+/* Put CPU to SLEEP mode */ -+int jz_pm_sleep(void) -+{ -+ int retval; -+ -+#ifndef CONFIG_JZ_POWEROFF -+ if ((retval = request_irq (IRQ_GPIO_0 + GPIO_WAKEUP, pm_irq_handler, IRQF_DISABLED, -+ "PM", NULL))) { -+ printk ("PM could not get IRQ for GPIO_WAKEUP\n"); -+ return retval; -+ } -+#endif -+ -+ pm_send_all(PM_SUSPEND, (void *)3); -+ retval = jz_pm_do_sleep(); -+ pm_send_all(PM_RESUME, (void *)0); -+ -+#ifndef CONFIG_JZ_POWEROFF -+ free_irq (IRQ_GPIO_0 + GPIO_WAKEUP, NULL); -+#endif -+ -+ return retval; -+} -+ -+#if 0 -+/* Deprecated ,was used by dpm */ -+void jz_pm_idle(void) -+{ -+ local_irq_disable(); -+ if (!need_resched()) { -+ local_irq_enable(); -+ cpu_wait(); -+ } -+} -+#endif -+ -+#ifdef CONFIG_SYSCTL -+ -+/* -+ * Use a temporary sysctl number. Horrid, but will be cleaned up in 2.6 -+ * when all the PM interfaces exist nicely. -+ */ -+#define CTL_PM_SUSPEND 1 -+#define CTL_PM_HIBERNATE 2 -+ -+/*---------------------------------------------------------------------------- -+ * Power Management sleep sysctl proc interface -+ * -+ * A write to /proc/sys/pm/suspend invokes this function -+ * which initiates a sleep. -+ *--------------------------------------------------------------------------*/ -+static int sysctl_jz_pm_sleep(struct ctl_table *ctl, int write, struct file * filp, -+ void __user *buffer, size_t *lenp, loff_t *ppos) -+{ -+ return jz_pm_sleep(); -+} -+ -+/*---------------------------------------------------------------------------- -+ * Power Management sleep sysctl proc interface -+ * -+ * A write to /proc/sys/pm/hibernate invokes this function -+ * which initiates a poweroff. -+ *--------------------------------------------------------------------------*/ -+static int sysctl_jz_pm_hibernate(struct ctl_table *ctl, int write, struct file * filp, -+ void __user *buffer, size_t *lenp, loff_t *ppos) -+{ -+ return jz_pm_hibernate(); -+} -+ -+static struct ctl_table pm_table[] = -+{ -+ { -+ .ctl_name = CTL_UNNUMBERED, -+ .procname = "suspend", -+ .data = NULL, -+ .maxlen = 0, -+ .mode = 0600, -+ .proc_handler = &sysctl_jz_pm_sleep, -+ }, -+ { -+ .ctl_name = CTL_UNNUMBERED, -+ .procname = "hibernate", -+ .data = NULL, -+ .maxlen = 0, -+ .mode = 0600, -+ .proc_handler = &sysctl_jz_pm_hibernate, -+ }, -+ { .ctl_name = 0} -+}; -+ -+static struct ctl_table pm_dir_table[] = -+{ -+ { -+ .ctl_name = CTL_UNNUMBERED, -+ .procname = "pm", -+ .mode = 0555, -+ .child = pm_table, -+ }, -+ { .ctl_name = 0} -+}; -+ -+#endif /* CONFIG_SYSCTL */ -+ -+/* -+ * Initialize power interface -+ */ -+static int __init jz_pm_init(void) -+{ -+ printk("Power Management for JZ\n"); -+ -+#ifdef CONFIG_SYSCTL -+ register_sysctl_table(pm_dir_table); -+#endif -+ -+ return 0; -+} -+ -+module_init(jz_pm_init); -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/proc.c linux-2.6.24.7/arch/mips/jz4740/proc.c ---- linux-2.6.24.7.old/arch/mips/jz4740/proc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/proc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,887 @@ -+/* -+ * linux/arch/mips/jz4740/proc.c -+ * -+ * /proc/jz/ procfs for jz4740 on-chip modules. -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+//#define DEBUG 1 -+#undef DEBUG -+ -+/* Define this to reserve total 4MB contineous physical memory for IPU. -+ * MPlayer will use IPU to optimize the decoding process. -+ * -+ * If you do not want to run the MPlayer, you can comment it. -+ */ -+#define CONFIG_RESERVE_IPU_MEM 1 -+ -+struct proc_dir_entry *proc_jz_root; -+ -+ -+/* -+ * EMC Modules -+ */ -+static int emc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); -+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); -+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); -+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); -+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); -+ return len; -+} -+ -+/* -+ * Power Manager Module -+ */ -+static int pmc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned long lcr = REG_CPM_LCR; -+ unsigned long clkgr = REG_CPM_CLKGR; -+ -+ len += sprintf (page+len, "Low Power Mode : %s\n", -+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? -+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? -+ "SLEEP" : "HIBERNATE")); -+ len += sprintf (page+len, "Doze Mode : %s\n", -+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); -+ if (lcr & CPM_LCR_DOZE_ON) -+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); -+ len += sprintf (page+len, "IPU : %s\n", -+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); -+ len += sprintf (page+len, "DMAC : %s\n", -+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UHC : %s\n", -+ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UDC : %s\n", -+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); -+ len += sprintf (page+len, "LCD : %s\n", -+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); -+ len += sprintf (page+len, "CIM : %s\n", -+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); -+ len += sprintf (page+len, "SADC : %s\n", -+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); -+ len += sprintf (page+len, "MSC : %s\n", -+ (clkgr & CPM_CLKGR_MSC) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC1 : %s\n", -+ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC2 : %s\n", -+ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI : %s\n", -+ (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running"); -+ len += sprintf (page+len, "I2C : %s\n", -+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); -+ len += sprintf (page+len, "RTC : %s\n", -+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); -+ len += sprintf (page+len, "TCU : %s\n", -+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART1 : %s\n", -+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART0 : %s\n", -+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); -+ return len; -+} -+ -+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+/* -+ * Clock Generation Module -+ */ -+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 -+#define TO_KHZ(x) (x/1000),(x%1000)/10 -+ -+static int cgm_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ -+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ -+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int od[4] = {1, 2, 2, 4}; -+ -+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); -+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); -+ len += sprintf (page+len, "PLL : %s\n", -+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); -+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", -+ __cpm_get_pllm() + 2, -+ __cpm_get_plln() + 2, -+ od[__cpm_get_pllod()] -+ ); -+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", -+ div[__cpm_get_cdiv()], -+ div[__cpm_get_hdiv()], -+ div[__cpm_get_mdiv()], -+ div[__cpm_get_pdiv()] -+ ); -+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); -+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); -+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); -+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); -+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); -+ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); -+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); -+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); -+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); -+ len += sprintf (page+len, "MSCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk())); -+ len += sprintf (page+len, "EXTALCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); -+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); -+ -+ return len; -+} -+ -+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+ -+/* -+ * UDC hotplug -+ */ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */ -+#endif -+ -+#ifndef GPIO_UDC_HOTPLUG -+#define GPIO_UDC_HOTPLUG 86 -+#endif -+ -+static int udc_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) { -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ -+ /* Cable has connected, wait for disconnection. */ -+ __gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG); -+ -+ if (jz_udc_active) -+ len += sprintf (page+len, "CONNECT_CABLE\n"); -+ else -+ len += sprintf (page+len, "CONNECT_POWER\n"); -+#else -+ len += sprintf (page+len, "CONNECT\n"); -+#endif -+ } -+ else { -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ /* Cable has disconnected, wait for connection. */ -+ __gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG); -+#endif -+ -+ len += sprintf (page+len, "REMOVE\n"); -+ } -+ -+ return len; -+} -+ -+/* -+ * MMC/SD hotplug -+ */ -+ -+#ifndef MSC_HOTPLUG_PIN -+#define MSC_HOTPLUG_PIN 90 -+#endif -+ -+static int mmc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+#if defined(CONFIG_JZ4740_LYRA) -+ if (!(__gpio_get_pin(MSC_HOTPLUG_PIN))) -+#else -+ if (__gpio_get_pin(MSC_HOTPLUG_PIN)) -+#endif -+ len += sprintf (page+len, "REMOVE\n"); -+ else -+ len += sprintf (page+len, "INSERT\n"); -+ -+ return len; -+} -+ -+#ifdef CONFIG_RESERVE_IPU_MEM -+ -+/* USAGE: -+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. -+ * echo FF > /proc/jz/ipu // 255, free all buffer -+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx -+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) -+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf -+ * od -X /proc/jz/ipu // read mem addr -+ */ -+ -+typedef struct _ipu_buf { -+ unsigned int addr; /* phys addr */ -+ unsigned int page_shift; -+} ipu_buf_t; -+ -+#define IPU_BUF_MAX 4 /* 4 buffers */ -+ -+static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; -+static int ipu_buf_cnt = 0; -+static unsigned char g_asid=0; -+ -+extern void local_flush_tlb_all(void); -+ -+/* CP0 hazard avoidance. */ -+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ -+ "nop; nop; nop; nop; nop; nop;\n\t" \ -+ ".set reorder\n\t") -+void show_tlb(void) -+{ -+#define ASID_MASK 0xFF -+ -+ unsigned long flags; -+ unsigned int old_ctx; -+ unsigned int entry; -+ unsigned int entrylo0, entrylo1, entryhi; -+ unsigned int pagemask; -+ -+ local_irq_save(flags); -+ -+ /* Save old context */ -+ old_ctx = (read_c0_entryhi() & 0xff); -+ -+ printk("TLB content:\n"); -+ entry = 0; -+ while(entry < 32) { -+ write_c0_index(entry); -+ BARRIER; -+ tlb_read(); -+ BARRIER; -+ entryhi = read_c0_entryhi(); -+ entrylo0 = read_c0_entrylo0(); -+ entrylo1 = read_c0_entrylo1(); -+ pagemask = read_c0_pagemask(); -+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); -+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); -+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); -+ -+ printk("\t\tpagemask=0x%08x", pagemask); -+ printk("\tentryhi=0x%08x\n", entryhi); -+ printk("\t\tentrylo0=0x%08x", entrylo0); -+ printk("\tentrylo1=0x%08x\n", entrylo1); -+ -+ entry++; -+ } -+ BARRIER; -+ write_c0_entryhi(old_ctx); -+ -+ local_irq_restore(flags); -+} -+ -+static void ipu_add_wired_entry(unsigned long pid, -+ unsigned long entrylo0, unsigned long entrylo1, -+ unsigned long entryhi, unsigned long pagemask) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ unsigned long old_pagemask; -+ unsigned long old_ctx; -+ struct task_struct *g, *p; -+ -+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ -+ wired = read_c0_wired(); -+ if (wired) return; -+ -+ do_each_thread(g, p) { -+ if (p->pid == pid ) -+ g_asid = p->mm->context[0]; -+ } while_each_thread(g, p); -+ -+ local_irq_save(flags); -+ -+ entrylo0 = entrylo0 >> 6; /* PFN */ -+ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */ -+ -+ /* Save old context and create impossible VPN2 value */ -+ old_ctx = read_c0_entryhi() & 0xff; -+ old_pagemask = read_c0_pagemask(); -+ write_c0_wired(wired + 1); -+ write_c0_index(wired); -+ BARRIER; -+ entryhi &= ~0xff; /* new add, 20070906 */ -+ entryhi |= g_asid; /* new add, 20070906 */ -+// entryhi |= old_ctx; /* new add, 20070906 */ -+ write_c0_pagemask(pagemask); -+ write_c0_entryhi(entryhi); -+ write_c0_entrylo0(entrylo0); -+ write_c0_entrylo1(entrylo1); -+ BARRIER; -+ tlb_write_indexed(); -+ BARRIER; -+ -+ write_c0_entryhi(old_ctx); -+ BARRIER; -+ write_c0_pagemask(old_pagemask); -+ local_flush_tlb_all(); -+ local_irq_restore(flags); -+#if defined(DEBUG) -+ printk("\nold_ctx=%03d\n", old_ctx); -+ -+ show_tlb(); -+#endif -+} -+ -+static void ipu_del_wired_entry( void ) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ -+ /* Free all lock entry */ -+ local_irq_save(flags); -+ wired = read_c0_wired(); -+ if (wired) -+ write_c0_wired(0); -+ local_irq_restore(flags); -+} -+ -+static inline void ipu_buf_get( unsigned int page_shift ) -+{ -+ unsigned char * virt_addr; -+ int i; -+ for ( i=0; i< IPU_BUF_MAX; ++i ) { -+ if ( ipu_buf[i].addr == 0 ) { -+ break; -+ } -+ } -+ -+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { -+ printk("Error, no free ipu buffer.\n"); -+ return ; -+ } -+ -+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ -+ if ( virt_addr ) { -+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); -+ ipu_buf[ipu_buf_cnt].page_shift = page_shift; -+ -+ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ -+ printk("no free buffer.\n"); -+ *pint = 0; -+ } -+ else -+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ -+ len += sizeof(unsigned int); -+ -+#if defined(DEBUG) -+ show_tlb(); -+#endif -+ return len; -+ -+} -+ -+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val ; -+ int cnt,i; -+ char buf[12]; -+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; -+#if defined(DEBUG) -+ printk("ipu write count=%u\n", count); -+#endif -+ if (count == (8*5+1)) { -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*0, 8); -+ pid = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*1, 8); -+ entrylo0 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*2, 8); -+ entrylo1 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*3, 8); -+ entryhi = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*4, 8); -+ pagemask = simple_strtoul(buf, 0, 16); -+ -+#if defined(DEBUG) -+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", -+ pid, entrylo0, entrylo1, entryhi, pagemask); -+#endif -+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); -+ return 41; -+ } else if ( count <= 8+1 ) { -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer, 8); -+ val = simple_strtoul(buf, 0, 16); -+ } else if (count == 44) { -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer, 10); -+ pid = simple_strtoul(buf, 0, 16); -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 11, 10); -+ entryhi = simple_strtoul(buf, 0, 16);//vaddr -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 22, 10); -+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 33, 10); -+ pagemask = simple_strtoul(buf, 0, 16); -+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ -+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); -+ return 44; -+ } else { -+ printk("ipu write count error, count=%d\n.", (unsigned int)count); -+ return -1; -+ } -+ -+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ -+ if ( val == 0 ) { /* debug, print ipu_buf info */ -+ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages -+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx -+ * echo FF > /proc/jz/ipu // FF, free all buffers -+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer -+ */ -+ -+//#define DEBUG_IMEM 1 -+ -+#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */ -+ -+static unsigned int jz_imem_base; /* physical base address of ipu memory */ -+ -+static unsigned int allocated_phys_addr = 0; -+ -+/* -+ * Allocated buffer list -+ */ -+typedef struct imem_list { -+ unsigned int phys_start; /* physical start addr */ -+ unsigned int phys_end; /* physical end addr */ -+ struct imem_list *next; -+} imem_list_t; -+ -+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */ -+ -+#ifdef DEBUG_IMEM -+static void dump_imem_list(void) -+{ -+ struct imem_list *imem; -+ -+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head); -+ imem = imem_list_head; -+ while (imem) { -+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next); -+ imem = imem->next; -+ } -+} -+#endif -+ -+/* allocate 2^order pages inside the 4MB memory */ -+static int imem_alloc(unsigned int order) -+{ -+ int alloc_ok = 0; -+ unsigned int start, end; -+ unsigned int size = (1 << order) * PAGE_SIZE; -+ struct imem_list *imem, *imemn, *imemp; -+ -+ allocated_phys_addr = 0; -+ -+ start = jz_imem_base; -+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ imem = imem_list_head; -+ while (imem) { -+ if ((imem->phys_start - start) >= size) { -+ /* we got a valid address range */ -+ alloc_ok = 1; -+ break; -+ } -+ -+ start = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (!alloc_ok) { -+ if ((end - start) >= size) -+ alloc_ok = 1; -+ } -+ -+ if (alloc_ok) { -+ end = start + size - 1; -+ allocated_phys_addr = start; -+ -+ /* add to imem_list, up sorted by phys_start */ -+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL); -+ if (!imemn) { -+ return -ENOMEM; -+ } -+ imemn->phys_start = start; -+ imemn->phys_end = end; -+ imemn->next = NULL; -+ -+ if (!imem_list_head) -+ imem_list_head = imemn; -+ else { -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (start < imem->phys_start) { -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+ if (imem == imem_list_head) { -+ imem_list_head = imemn; -+ imemn->next = imem; -+ } -+ else { -+ imemn->next = imemp->next; -+ imemp->next = imemn; -+ } -+ } -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+ return 0; -+} -+ -+static void imem_free(unsigned int phys_addr) -+{ -+ struct imem_list *imem, *imemp; -+ -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (phys_addr == imem->phys_start) { -+ if (imem == imem_list_head) { -+ imem_list_head = imem->next; -+ } -+ else { -+ imemp->next = imem->next; -+ } -+ -+ kfree(imem); -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+static void imem_free_all(void) -+{ -+ struct imem_list *imem; -+ -+ imem = imem_list_head; -+ while (imem) { -+ kfree(imem); -+ imem = imem->next; -+ } -+ -+ imem_list_head = NULL; -+ -+ allocated_phys_addr = 0; -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+/* -+ * Return the allocated buffer address and the max order of free buffer -+ */ -+static int imem_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int start_addr, end_addr, max_order, max_size; -+ struct imem_list *imem; -+ -+ unsigned int *tmp = (unsigned int *)(page + len); -+ -+ start_addr = jz_imem_base; -+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ if (!imem_list_head) -+ max_size = end_addr - start_addr; -+ else { -+ max_size = 0; -+ imem = imem_list_head; -+ while (imem) { -+ if (max_size < (imem->phys_start - start_addr)) -+ max_size = imem->phys_start - start_addr; -+ -+ start_addr = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (max_size < (end_addr - start_addr)) -+ max_size = end_addr - start_addr; -+ } -+ -+ if (max_size > 0) { -+ max_order = get_order(max_size); -+ if (((1 << max_order) * PAGE_SIZE) > max_size) -+ max_order--; -+ } -+ else { -+ max_order = 0xffffffff; /* No any free buffer */ -+ } -+ -+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */ -+ *tmp = max_order; /* max order of current free buffers */ -+ -+ len += 2 * sizeof(unsigned int); -+ -+ return len; -+} -+ -+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val; -+ -+ val = simple_strtoul(buffer, 0, 16); -+ -+ if (val == 0xff) { -+ /* free all memory */ -+ imem_free_all(); -+ ipu_del_wired_entry(); -+ } -+ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) { -+ /* allocate 2^val pages */ -+ imem_alloc(val); -+ } -+ else { -+ /* free buffer which phys_addr is val */ -+ imem_free(val); -+ } -+ -+ return count; -+} -+ -+#endif /* CONFIG_RESERVE_IPU_MEM */ -+ -+/* -+ * /proc/jz/xxx entry -+ * -+ */ -+static int __init jz_proc_init(void) -+{ -+ struct proc_dir_entry *res; -+#ifdef CONFIG_RESERVE_IPU_MEM -+ unsigned int virt_addr, i; -+#endif -+ -+ proc_jz_root = proc_mkdir("jz", 0); -+ -+ /* External Memory Controller */ -+ res = create_proc_entry("emc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = emc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* Power Management Controller */ -+ res = create_proc_entry("pmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = pmc_read_proc; -+ res->write_proc = pmc_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Clock Generation Module */ -+ res = create_proc_entry("cgm", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = cgm_read_proc; -+ res->write_proc = cgm_write_proc; -+ res->data = NULL; -+ } -+ -+ /* udc hotplug */ -+ res = create_proc_entry("udc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = udc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* mmc hotplug */ -+ res = create_proc_entry("mmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = mmc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+#ifdef CONFIG_RESERVE_IPU_MEM -+ /* Image process unit */ -+ res = create_proc_entry("ipu", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = ipu_read_proc; -+ res->write_proc = ipu_write_proc; -+ res->data = NULL; -+ } -+ -+ /* -+ * Reserve a 4MB memory for IPU on JZ4740. -+ */ -+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); -+ if (jz_imem_base) { -+ /* imem (IPU memory management) */ -+ res = create_proc_entry("imem", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = imem_read_proc; -+ res->write_proc = imem_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Set page reserved */ -+ virt_addr = jz_imem_base; -+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { -+ SetPageReserved(virt_to_page((void *)virt_addr)); -+ virt_addr += PAGE_SIZE; -+ } -+ -+ /* Convert to physical address */ -+ jz_imem_base = virt_to_phys((void *)jz_imem_base); -+ -+ printk("Total %dMB memory at 0x%x was reserved for IPU\n", -+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); -+ } -+#endif -+ -+ return 0; -+} -+ -+__initcall(jz_proc_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/prom.c linux-2.6.24.7/arch/mips/jz4740/prom.c ---- linux-2.6.24.7.old/arch/mips/jz4740/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/prom.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,198 @@ -+/* -+ * -+ * BRIEF MODULE DESCRIPTION -+ * PROM library initialisation code, supports YAMON and U-Boot. -+ * -+ * Copyright 2000, 2001, 2006 MontaVista Software Inc. -+ * Author: MontaVista Software, Inc. -+ * ppopov@mvista.com or source@mvista.com -+ * -+ * This file was derived from Carsten Langgaard's -+ * arch/mips/mips-boards/xx files. -+ * -+ * Carsten Langgaard, carstenl@mips.com -+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* #define DEBUG_CMDLINE */ -+ -+int prom_argc; -+char **prom_argv, **prom_envp; -+ -+char * prom_getcmdline(void) -+{ -+ return &(arcs_cmdline[0]); -+} -+ -+void prom_init_cmdline(void) -+{ -+ char *cp; -+ int actr; -+ -+ actr = 1; /* Always ignore argv[0] */ -+ -+ cp = &(arcs_cmdline[0]); -+ while(actr < prom_argc) { -+ strcpy(cp, prom_argv[actr]); -+ cp += strlen(prom_argv[actr]); -+ *cp++ = ' '; -+ actr++; -+ } -+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ -+ --cp; -+ if (prom_argc > 1) -+ *cp = '\0'; -+ -+} -+ -+ -+char *prom_getenv(char *envname) -+{ -+#if 0 -+ /* -+ * Return a pointer to the given environment variable. -+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". -+ */ -+ -+ char **env = prom_envp; -+ int i = strlen(envname); -+ int yamon = (*env && strchr(*env, '=') == NULL); -+ -+ while (*env) { -+ if (yamon) { -+ if (strcmp(envname, *env++) == 0) -+ return *env; -+ } else { -+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') -+ return *env + i + 1; -+ } -+ env++; -+ } -+#endif -+ return NULL; -+} -+ -+inline unsigned char str2hexnum(unsigned char c) -+{ -+ if(c >= '0' && c <= '9') -+ return c - '0'; -+ if(c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if(c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for(i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+int get_ethernet_addr(char *ethernet_addr) -+{ -+ char *ethaddr_str; -+ -+ ethaddr_str = prom_getenv("ethaddr"); -+ if (!ethaddr_str) { -+ printk("ethaddr not set in boot prom\n"); -+ return -1; -+ } -+ str2eaddr(ethernet_addr, ethaddr_str); -+ -+#if 0 -+ { -+ int i; -+ -+ printk("get_ethernet_addr: "); -+ for (i=0; i<5; i++) -+ printk("%02x:", (unsigned char)*(ethernet_addr+i)); -+ printk("%02x\n", *(ethernet_addr+i)); -+ } -+#endif -+ -+ return 0; -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+} -+ -+void __init prom_init(void) -+{ -+ unsigned char *memsize_str; -+ unsigned long memsize; -+ -+ prom_argc = (int) fw_arg0; -+ prom_argv = (char **) fw_arg1; -+ prom_envp = (char **) fw_arg2; -+ -+ mips_machtype = MACH_INGENIC_JZ4740; -+ -+ prom_init_cmdline(); -+ memsize_str = prom_getenv("memsize"); -+ if (!memsize_str) { -+ memsize = 0x04000000; -+ } else { -+ memsize = simple_strtol(memsize_str, NULL, 0); -+ } -+ add_memory_region(0, memsize, BOOT_MEM_RAM); -+} -+ -+/* used by early printk */ -+void prom_putchar(char c) -+{ -+ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); -+ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); -+ -+ /* Wait for fifo to shift out some bytes */ -+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); -+ -+ *uart_tdr = (u8)c; -+} -+ -+const char *get_system_type(void) -+{ -+ return "JZ4740"; -+} -+ -+EXPORT_SYMBOL(prom_getcmdline); -+EXPORT_SYMBOL(get_ethernet_addr); -+EXPORT_SYMBOL(str2eaddr); -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/reset.c linux-2.6.24.7/arch/mips/jz4740/reset.c ---- linux-2.6.24.7.old/arch/mips/jz4740/reset.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/reset.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,46 @@ -+/* -+ * linux/arch/mips/jz4740/reset.c -+ * -+ * JZ4740 reset routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+void jz_restart(char *command) -+{ -+ printk("Restarting after 4 ms\n"); -+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; -+ REG_WDT_TCNT = 0; -+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ -+ REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */ -+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ -+ while (1); -+} -+ -+void jz_halt(void) -+{ -+ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); -+ -+ while (1) -+ __asm__(".set\tmips3\n\t" -+ "wait\n\t" -+ ".set\tmips0"); -+} -+ -+void jz_power_off(void) -+{ -+ jz_halt(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/setup.c linux-2.6.24.7/arch/mips/jz4740/setup.c ---- linux-2.6.24.7.old/arch/mips/jz4740/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/setup.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,182 @@ -+/* -+ * linux/arch/mips/jz4740/common/setup.c -+ * -+ * JZ4740 common setup routines. -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PC_KEYB -+#include -+#endif -+ -+jz_clocks_t jz_clocks; -+ -+extern char * __init prom_getcmdline(void); -+extern void __init jz_board_setup(void); -+extern void jz_restart(char *); -+extern void jz_halt(void); -+extern void jz_power_off(void); -+extern void jz_time_init(void); -+ -+static void __init sysclocks_setup(void) -+{ -+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(); -+ jz_clocks.extalclk = __cpm_get_extalclk(); -+ jz_clocks.rtcclk = __cpm_get_rtcclk(); -+#else -+ -+#define FPGACLK 8000000 -+ -+ jz_clocks.cclk = FPGACLK; -+ jz_clocks.hclk = FPGACLK; -+ jz_clocks.pclk = FPGACLK; -+ jz_clocks.mclk = FPGACLK; -+ jz_clocks.lcdclk = FPGACLK; -+ jz_clocks.pixclk = FPGACLK; -+ jz_clocks.i2sclk = FPGACLK; -+ jz_clocks.usbclk = FPGACLK; -+ jz_clocks.mscclk = FPGACLK; -+ jz_clocks.extalclk = FPGACLK; -+ jz_clocks.rtcclk = FPGACLK; -+#endif -+ -+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", -+ (jz_clocks.cclk + 500000) / 1000000, -+ (jz_clocks.hclk + 500000) / 1000000, -+ (jz_clocks.pclk + 500000) / 1000000, -+ (jz_clocks.mclk + 500000) / 1000000); -+} -+ -+static void __init soc_cpm_setup(void) -+{ -+ /* Start all module clocks -+ */ -+ __cpm_start_all(); -+ -+ /* Enable CKO to external memory */ -+ __cpm_enable_cko(); -+ -+ /* CPU enters IDLE mode when executing 'wait' instruction */ -+ __cpm_idle_mode(); -+ -+ /* Setup system clocks */ -+ sysclocks_setup(); -+} -+ -+static void __init soc_harb_setup(void) -+{ -+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ -+} -+ -+static void __init soc_emc_setup(void) -+{ -+} -+ -+static void __init soc_dmac_setup(void) -+{ -+ __dmac_enable_module(); -+} -+ -+static void __init jz_soc_setup(void) -+{ -+ soc_cpm_setup(); -+ soc_harb_setup(); -+ soc_emc_setup(); -+ soc_dmac_setup(); -+} -+ -+static void __init jz_serial_setup(void) -+{ -+#ifdef CONFIG_SERIAL_8250 -+ struct uart_port s; -+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ -+ memset(&s, 0, sizeof(s)); -+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; -+ s.iotype = SERIAL_IO_MEM; -+ s.regshift = 2; -+ s.uartclk = jz_clocks.extalclk ; -+ -+ s.line = 0; -+ s.membase = (u8 *)UART0_BASE; -+ s.irq = IRQ_UART0; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); -+ } -+ -+ s.line = 1; -+ s.membase = (u8 *)UART1_BASE; -+ s.irq = IRQ_UART1; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); -+ } -+#endif -+} -+ -+void __init plat_mem_setup(void) -+{ -+ char *argptr; -+ -+ argptr = prom_getcmdline(); -+ -+ /* IO/MEM resources. Which will be the addtion value in `inX' and -+ * `outX' macros defined in asm/io.h */ -+ set_io_port_base(0); -+ ioport_resource.start = 0x00000000; -+ ioport_resource.end = 0xffffffff; -+ iomem_resource.start = 0x00000000; -+ iomem_resource.end = 0xffffffff; -+ -+ _machine_restart = jz_restart; -+ _machine_halt = jz_halt; -+ pm_power_off = jz_power_off; -+ -+ jz_soc_setup(); -+ jz_serial_setup(); -+ jz_board_setup(); -+} -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4740/time.c linux-2.6.24.7/arch/mips/jz4740/time.c ---- linux-2.6.24.7.old/arch/mips/jz4740/time.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4740/time.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,158 @@ -+/* -+ * linux/arch/mips/jz4740/time.c -+ * -+ * Setting up the clock on the JZ4740 boards. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* This is for machines which generate the exact clock. */ -+ -+#define JZ_TIMER_CHAN 0 -+#define JZ_TIMER_IRQ IRQ_TCU0 -+ -+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ -+ -+static struct clocksource clocksource_jz; /* Jz clock source */ -+static struct clock_event_device jz_clockevent_device; /* Jz clock event */ -+ -+void (*jz_timer_callback)(void); -+ -+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ -+ REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */ -+ -+ if (jz_timer_callback) -+ jz_timer_callback(); -+ -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct irqaction jz_irqaction = { -+ .handler = jz_timer_interrupt, -+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, -+ .name = "jz-timerirq", -+}; -+ -+ -+cycle_t jz_get_cycles(void) -+{ -+ /* convert jiffes to jz timer cycles */ -+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN)); -+} -+ -+static struct clocksource clocksource_jz = { -+ .name = "jz_clocksource", -+ .rating = 300, -+ .read = jz_get_cycles, -+ .mask = 0xFFFF, -+ .shift = 10, -+ .flags = CLOCK_SOURCE_WATCHDOG, -+}; -+ -+static int __init jz_clocksource_init(void) -+{ -+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); -+ clocksource_register(&clocksource_jz); -+ return 0; -+} -+ -+static int jz_set_next_event(unsigned long evt, -+ struct clock_event_device *unused) -+{ -+ return 0; -+} -+ -+static void jz_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ switch (mode) { -+ case CLOCK_EVT_MODE_PERIODIC: -+ break; -+ case CLOCK_EVT_MODE_ONESHOT: -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ break; -+ case CLOCK_EVT_MODE_RESUME: -+ break; -+ } -+} -+ -+static struct clock_event_device jz_clockevent_device = { -+ .name = "jz-clockenvent", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ -+ -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 300, -+ .irq = JZ_TIMER_IRQ, -+ .set_mode = jz_set_mode, -+ .set_next_event = jz_set_next_event, -+}; -+ -+static void __init jz_clockevent_init(void) -+{ -+ struct clock_event_device *cd = &jz_clockevent_device; -+ unsigned int cpu = smp_processor_id(); -+ -+ cd->cpumask = cpumask_of_cpu(cpu); -+ clockevents_register_device(cd); -+} -+ -+static void __init jz_timer_setup(void) -+{ -+ jz_clocksource_init(); /* init jz clock source */ -+ jz_clockevent_init(); /* init jz clock event */ -+ -+ /* -+ * Make irqs happen for the system timer -+ */ -+ jz_irqaction.dev_id = &jz_clockevent_device; -+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); -+} -+ -+ -+void __init plat_time_init(void) -+{ -+ unsigned int latch; -+ /* Init timer */ -+ latch = ( JZ_TIMER_CLOCK + (HZ>>1)) / HZ; -+ -+ REG_TCU_TCSR(JZ_TIMER_CHAN) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN; -+ REG_TCU_TCNT(JZ_TIMER_CHAN) = 0; -+ REG_TCU_TDHR(JZ_TIMER_CHAN) = 0; -+ REG_TCU_TDFR(JZ_TIMER_CHAN) = latch; -+ -+ REG_TCU_TMSR = (1 << (JZ_TIMER_CHAN + 16)); /* mask half irq */ -+ REG_TCU_TMCR = (1 << JZ_TIMER_CHAN); /* unmask full irq */ -+ REG_TCU_TSCR = (1 << JZ_TIMER_CHAN); /* enable timer clock */ -+ REG_TCU_TESR = (1 << JZ_TIMER_CHAN); /* start counting up */ -+ -+ jz_timer_setup(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/Makefile linux-2.6.24.7/arch/mips/jz4750/Makefile ---- linux-2.6.24.7.old/arch/mips/jz4750/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,23 @@ -+# -+# Makefile for the Ingenic JZ4750. -+# -+ -+# Object file lists. -+ -+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ -+ platform.o i2c.o -+ -+obj-$(CONFIG_PROC_FS) += proc.o -+ -+# board specific support -+ -+obj-$(CONFIG_JZ4750_FUWA) += board-fuwa.o -+obj-$(CONFIG_JZ4750_APUS) += board-apus.o -+ -+# PM support -+ -+obj-$(CONFIG_PM_LEGACY) +=pm.o -+ -+# CPU Frequency scaling support -+ -+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/board-apus.c linux-2.6.24.7/arch/mips/jz4750/board-apus.c ---- linux-2.6.24.7.old/arch/mips/jz4750/board-apus.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/board-apus.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,64 @@ -+/* -+ * linux/arch/mips/jz4750/board-apus.c -+ * -+ * JZ4750 APUS board setup routines. -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+} -+ -+static void apus_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4750/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ __gpio_as_pcm(); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4750 APUS board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = apus_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/board-fuwa.c linux-2.6.24.7/arch/mips/jz4750/board-fuwa.c ---- linux-2.6.24.7.old/arch/mips/jz4750/board-fuwa.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/board-fuwa.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,105 @@ -+/* -+ * linux/arch/mips/jz4750/board-fuwa.c -+ * -+ * JZ4750 FUWA board setup routines. -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned char slash[] = "\\|/-"; -+// static volatile unsigned char *p = (unsigned char *)0xb6000058; -+ static volatile unsigned char *p = (unsigned char *)0xb6000016; -+ static unsigned int count = 0; -+ *p = slash[count++]; -+ count &= 3; -+} -+ -+static void fuwa_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4750/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Initialize SDRAM pins -+ */ -+ -+ /* PORT A: D0 ~ D31 */ -+ REG_GPIO_PXFUNS(0) = 0xffffffff; -+ REG_GPIO_PXSELC(0) = 0xffffffff; -+ -+ /* PORT B: A0 ~ A16, DCS#, RAS#, CAS#, CKE#, RDWE#, CKO#, WE0# */ -+ REG_GPIO_PXFUNS(1) = 0x81f9ffff; -+ REG_GPIO_PXSELC(1) = 0x81f9ffff; -+ -+ /* PORT C: WE1#, WE2#, WE3# */ -+ REG_GPIO_PXFUNS(2) = 0x07000000; -+ REG_GPIO_PXSELC(2) = 0x07000000; -+ -+ -+ /* -+ * Initialize UART0 pins -+ */ -+ -+ /* PORT D: TXD/RXD */ -+ REG_GPIO_PXFUNS(3) = 0x06000000; -+ REG_GPIO_PXSELS(3) = 0x06000000; -+ -+ -+ /* -+ * Initialize LED pins -+ */ -+ __gpio_as_lcd_18bit(); -+ -+ /* CS2# */ -+ REG_GPIO_PXFUNS(1) = 0x04000000; -+ REG_GPIO_PXSELC(1) = 0x04000000; -+ -+ __gpio_as_pcm(); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4750 FUWA board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = fuwa_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/board-slt50.c linux-2.6.24.7/arch/mips/jz4750/board-slt50.c ---- linux-2.6.24.7.old/arch/mips/jz4750/board-slt50.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/board-slt50.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,64 @@ -+/* -+ * linux/arch/mips/jz4750/board-apus.c -+ * -+ * JZ4750 APUS board setup routines. -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+} -+ -+static void apus_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4750/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ __gpio_as_pcm(); -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4750 SLT_50 board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = apus_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/cpufreq.c linux-2.6.24.7/arch/mips/jz4750/cpufreq.c ---- linux-2.6.24.7.old/arch/mips/jz4750/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/cpufreq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,601 @@ -+/* -+ * linux/arch/mips/jz4750/cpufreq.c -+ * -+ * cpufreq driver for JZ4750 -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ -+ "cpufreq-jz4750", msg) -+ -+#undef CHANGE_PLL -+ -+#define PLL_UNCHANGED 0 -+#define PLL_GOES_UP 1 -+#define PLL_GOES_DOWN 2 -+ -+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) -+ -+/* Saved the boot-time parameters */ -+static struct { -+ /* SDRAM parameters */ -+ unsigned int mclk; /* memory clock, KHz */ -+ unsigned int tras; /* RAS pulse width, cycles of mclk */ -+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ -+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ -+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ -+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ -+ unsigned int rtcor; /* Refresh Time Constant */ -+ unsigned int sdram_initialized; -+ -+ /* LCD parameters */ -+ unsigned int lcd_clk; /* LCD clock, Hz */ -+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ -+ unsigned int lcd_clks_initialized; -+} boot_config; -+ -+struct jz4750_freq_percpu_info { -+ struct cpufreq_frequency_table table[7]; -+}; -+ -+static struct jz4750_freq_percpu_info jz4750_freq_table; -+ -+/* -+ * This contains the registers value for an operating point. -+ * If only part of a register needs to change then there is -+ * a mask value for that register. -+ * When going to a new operating point the current register -+ * value is ANDed with the ~mask and ORed with the new value. -+ */ -+struct dpm_regs { -+ u32 cpccr; /* Clock Freq Control Register */ -+ u32 cpccr_mask; /* Clock Freq Control Register mask */ -+ u32 cppcr; /* PLL1 Control Register */ -+ u32 cppcr_mask; /* PLL1 Control Register mask */ -+ u32 pll_up_flag; /* New PLL freq is higher than current or not */ -+}; -+ -+extern jz_clocks_t jz_clocks; -+ -+static void jz_update_clocks(void) -+{ -+ /* Next clocks must be updated if we have changed -+ * the PLL or divisors. -+ */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(0); -+} -+ -+static void -+jz_init_boot_config(void) -+{ -+ if (!boot_config.lcd_clks_initialized) { -+ /* the first time to scale pll */ -+ boot_config.lcd_clk = __cpm_get_lcdclk(); -+ boot_config.lcdpix_clk = __cpm_get_pixclk(); -+ boot_config.lcd_clks_initialized = 1; -+ } -+ -+ if (!boot_config.sdram_initialized) { -+ /* the first time to scale frequencies */ -+ unsigned int dmcr, rtcor; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ -+ dmcr = REG_EMC_DMCR; -+ rtcor = REG_EMC_RTCOR; -+ -+ tras = (dmcr >> 13) & 0x7; -+ rcd = (dmcr >> 11) & 0x3; -+ tpc = (dmcr >> 8) & 0x7; -+ trwl = (dmcr >> 5) & 0x3; -+ trc = (dmcr >> 2) & 0x7; -+ -+ boot_config.mclk = __cpm_get_mclk() / 1000; -+ boot_config.tras = tras + 4; -+ boot_config.rcd = rcd + 1; -+ boot_config.tpc = tpc + 1; -+ boot_config.trwl = trwl + 1; -+ boot_config.trc = trc * 2 + 1; -+ boot_config.rtcor = rtcor; -+ -+ boot_config.sdram_initialized = 1; -+ } -+} -+ -+static void jz_update_dram_rtcor(unsigned int new_mclk) -+{ -+ unsigned int rtcor; -+ -+ new_mclk /= 1000; -+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; -+ rtcor--; -+ -+ if (rtcor < 1) rtcor = 1; -+ if (rtcor > 255) rtcor = 255; -+ -+ REG_EMC_RTCOR = rtcor; -+ REG_EMC_RTCNT = rtcor; -+} -+ -+static void jz_update_dram_dmcr(unsigned int new_mclk) -+{ -+ unsigned int dmcr; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ unsigned int valid_time, new_time; /* ns */ -+ -+ new_mclk /= 1000; -+ tras = boot_config.tras * new_mclk / boot_config.mclk; -+ rcd = boot_config.rcd * new_mclk / boot_config.mclk; -+ tpc = boot_config.tpc * new_mclk / boot_config.mclk; -+ trwl = boot_config.trwl * new_mclk / boot_config.mclk; -+ trc = boot_config.trc * new_mclk / boot_config.mclk; -+ -+ /* Validation checking */ -+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; -+ new_time = (tras * 1000000) / new_mclk; -+ if (new_time < valid_time) tras += 1; -+ -+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; -+ new_time = (rcd * 1000000) / new_mclk; -+ if (new_time < valid_time) rcd += 1; -+ -+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; -+ new_time = (tpc * 1000000) / new_mclk; -+ if (new_time < valid_time) tpc += 1; -+ -+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; -+ new_time = (trwl * 1000000) / new_mclk; -+ if (new_time < valid_time) trwl += 1; -+ -+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; -+ new_time = (trc * 1000000) / new_mclk; -+ if (new_time < valid_time) trc += 2; -+ -+ tras = (tras < 4) ? 4: tras; -+ tras = (tras > 11) ? 11: tras; -+ tras -= 4; -+ -+ rcd = (rcd < 1) ? 1: rcd; -+ rcd = (rcd > 4) ? 4: rcd; -+ rcd -= 1; -+ -+ tpc = (tpc < 1) ? 1: tpc; -+ tpc = (tpc > 8) ? 8: tpc; -+ tpc -= 1; -+ -+ trwl = (trwl < 1) ? 1: trwl; -+ trwl = (trwl > 4) ? 4: trwl; -+ trwl -= 1; -+ -+ trc = (trc < 1) ? 1: trc; -+ trc = (trc > 15) ? 15: trc; -+ trc /= 2; -+ -+ dmcr = REG_EMC_DMCR; -+ -+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); -+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); -+ -+ REG_EMC_DMCR = dmcr; -+} -+ -+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR before changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } else { -+ /* We're going SLOWER: first update RTCOR value -+ * before changing the frequency. -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } -+} -+ -+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so update RTCOR -+ * after changing the frequency -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } else { -+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR after changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } -+} -+ -+static void jz_scale_divisors(struct dpm_regs *regs) -+{ -+ unsigned int cpccr; -+ unsigned int cur_mclk, new_mclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~((unsigned long)regs->cpccr_mask); -+ cpccr |= regs->cpccr; -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; -+ -+ /* Update some DRAM parameters before changing frequency */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+ -+#ifdef CHANGE_PLL -+/* Maintain the LCD clock and pixel clock */ -+static void jz_scale_lcd_divisors(struct dpm_regs *regs) -+{ -+ unsigned int new_pll, new_lcd_div, new_lcdpix_div; -+ unsigned int cpccr; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ if (!boot_config.lcd_clks_initialized) return; -+ -+ new_pll = __cpm_get_pllout(); -+ new_lcd_div = new_pll / boot_config.lcd_clk; -+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; -+ -+ if (new_lcd_div < 1) -+ new_lcd_div = 1; -+ if (new_lcd_div > 16) -+ new_lcd_div = 16; -+ -+ if (new_lcdpix_div < 1) -+ new_lcdpix_div = 1; -+ if (new_lcdpix_div > 512) -+ new_lcdpix_div = 512; -+ -+// REG_CPM_CPCCR2 = new_lcdpix_div - 1; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~CPM_CPCCR_LDIV_MASK; -+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+} -+ -+static void jz_scale_pll(struct dpm_regs *regs) -+{ -+ unsigned int cppcr; -+ unsigned int cur_mclk, new_mclk, new_pll; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ int od[] = {1, 2, 2, 4}; -+ -+ cppcr = REG_CPM_CPPCR; -+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); -+ regs->cppcr &= ~CPM_CPPCR_PLLEN; -+ cppcr |= (regs->cppcr | 0xff); -+ -+ /* Update some DRAM parameters before changing frequency */ -+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf]; -+ -+ /* -+ * Update some SDRAM parameters -+ */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* -+ * Update PLL, align code to cache line. -+ */ -+ cppcr |= CPM_CPPCR_PLLEN; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPPCR), "r" (cppcr)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+#endif -+ -+static void jz4750_transition(struct dpm_regs *regs) -+{ -+ /* -+ * Get and save some boot-time conditions. -+ */ -+ jz_init_boot_config(); -+ -+#ifdef CHANGE_PLL -+ /* -+ * Disable LCD before scaling pll. -+ * LCD and LCD pixel clocks should not be changed even if the PLL -+ * output frequency has been changed. -+ */ -+ REG_LCD_CTRL &= ~LCD_CTRL_ENA; -+ -+ /* -+ * Stop module clocks before scaling PLL -+ */ -+ __cpm_stop_eth(); -+ __cpm_stop_aic(1); -+ __cpm_stop_aic(2); -+#endif -+ -+ /* ... add more as necessary */ -+ -+ if (regs->pll_up_flag == PLL_GOES_UP) { -+ /* the pll frequency is going up, so change dividors first */ -+ jz_scale_divisors(regs); -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ } -+ else if (regs->pll_up_flag == PLL_GOES_DOWN) { -+ /* the pll frequency is going down, so change pll first */ -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ jz_scale_divisors(regs); -+ } -+ else { -+ /* the pll frequency is unchanged, so change divisors only */ -+ jz_scale_divisors(regs); -+ } -+ -+#ifdef CHANGE_PLL -+ /* -+ * Restart module clocks before scaling PLL -+ */ -+ __cpm_start_eth(); -+ __cpm_start_aic(1); -+ __cpm_start_aic(2); -+ -+ /* ... add more as necessary */ -+ -+ /* Scale the LCD divisors after scaling pll */ -+ if (regs->pll_up_flag != PLL_UNCHANGED) { -+ jz_scale_lcd_divisors(regs); -+ } -+ -+ /* Enable LCD controller */ -+ REG_LCD_CTRL &= ~LCD_CTRL_DIS; -+ REG_LCD_CTRL |= LCD_CTRL_ENA; -+#endif -+ -+ /* Update system clocks */ -+ jz_update_clocks(); -+} -+ -+extern unsigned int idle_times; -+static unsigned int jz4750_freq_get(unsigned int cpu) -+{ -+ return (__cpm_get_cclk() / 1000); -+} -+ -+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) -+{ -+ int n2FR[33] = { -+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, -+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, -+ 9 -+ }; -+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ -+ unsigned int div_of_cclk, new_freq, i; -+ -+ regs->pll_up_flag = PLL_UNCHANGED; -+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; -+ -+ new_freq = jz4750_freq_table.table[index].frequency; -+ -+ do { -+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); -+ } while (div_of_cclk==0); -+ -+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { -+ for(i = 1; i<4; i++) { -+ div[i] = 3; -+ } -+ } else { -+ for(i = 1; i<4; i++) { -+ div[i] = 2; -+ } -+ } -+ -+ for(i = 0; i<4; i++) { -+ div[i] *= div_of_cclk; -+ } -+ -+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); -+ -+ regs->cpccr = -+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | -+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | -+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | -+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); -+ -+ return div_of_cclk; -+} -+ -+static void jz4750_set_cpu_divider_index(unsigned int cpu, unsigned int index) -+{ -+ unsigned long divisor, old_divisor; -+ struct cpufreq_freqs freqs; -+ struct dpm_regs regs; -+ -+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); -+ divisor = index_to_divisor(index, ®s); -+ -+ freqs.old = __cpm_get_cclk() / 1000; -+ freqs.new = __cpm_get_pllout() / (1000 * divisor); -+ freqs.cpu = cpu; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ -+ if (old_divisor != divisor) -+ jz4750_transition(®s); -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+} -+ -+static int jz4750_freq_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ unsigned int new_index = 0; -+ -+ if (cpufreq_frequency_table_target(policy, -+ &jz4750_freq_table.table[0], -+ target_freq, relation, &new_index)) -+ return -EINVAL; -+ -+ jz4750_set_cpu_divider_index(policy->cpu, new_index); -+ -+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); -+ -+ return 0; -+} -+ -+static int jz4750_freq_verify(struct cpufreq_policy *policy) -+{ -+ return cpufreq_frequency_table_verify(policy, -+ &jz4750_freq_table.table[0]); -+} -+ -+static int __init jz4750_cpufreq_driver_init(struct cpufreq_policy *policy) -+{ -+ -+ struct cpufreq_frequency_table *table = &jz4750_freq_table.table[0]; -+ unsigned int MAX_FREQ; -+ -+ dprintk(KERN_INFO "Jz4750 cpufreq driver\n"); -+ -+ if (policy->cpu != 0) -+ return -EINVAL; -+ -+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ -+ policy->cpuinfo.min_freq = MAX_FREQ/8; -+ policy->cpuinfo.max_freq = MAX_FREQ; -+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ -+ -+ table[0].index = 0; -+ table[0].frequency = MAX_FREQ/8; -+ table[1].index = 1; -+ table[1].frequency = MAX_FREQ/6; -+ table[2].index = 2; -+ table[2].frequency = MAX_FREQ/4; -+ table[3].index = 3; -+ table[3].frequency = MAX_FREQ/3; -+ table[4].index = 4; -+ table[4].frequency = MAX_FREQ/2; -+ table[5].index = 5; -+ table[5].frequency = MAX_FREQ; -+ table[6].index = 6; -+ table[6].frequency = CPUFREQ_TABLE_END; -+ -+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS -+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ -+#endif -+ -+ return cpufreq_frequency_table_cpuinfo(policy, table); -+} -+ -+static struct cpufreq_driver cpufreq_jz4750_driver = { -+// .flags = CPUFREQ_STICKY, -+ .init = jz4750_cpufreq_driver_init, -+ .verify = jz4750_freq_verify, -+ .target = jz4750_freq_target, -+ .get = jz4750_freq_get, -+ .name = "jz4750", -+}; -+ -+static int __init jz4750_cpufreq_init(void) -+{ -+ return cpufreq_register_driver(&cpufreq_jz4750_driver); -+} -+ -+static void __exit jz4750_cpufreq_exit(void) -+{ -+ cpufreq_unregister_driver(&cpufreq_jz4750_driver); -+} -+ -+module_init(jz4750_cpufreq_init); -+module_exit(jz4750_cpufreq_exit); -+ -+MODULE_AUTHOR("Regen "); -+MODULE_DESCRIPTION("cpufreq driver for Jz4750"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/dma.c linux-2.6.24.7/arch/mips/jz4750/dma.c ---- linux-2.6.24.7.old/arch/mips/jz4750/dma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/dma.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,836 @@ -+/* -+ * linux/arch/mips/jz4750/dma.c -+ * -+ * Support functions for the JZ4750 internal DMA channels. -+ * No-descriptor transfer only. -+ * Descriptor transfer should also call jz_request_dma() to get a free -+ * channel and call jz_free_dma() to free the channel. And driver should -+ * build the DMA descriptor and setup the DMA channel by itself. -+ * -+ * Copyright (C) 2006 - 2008 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * A note on resource allocation: -+ * -+ * All drivers needing DMA channels, should allocate and release them -+ * through the public routines `jz_request_dma()' and `jz_free_dma()'. -+ * -+ * In order to avoid problems, all processes should allocate resources in -+ * the same sequence and release them in the reverse order. -+ * -+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. -+ * When releasing them, first release the IRQ, then release the DMA. The -+ * main reason for this order is that, if you are requesting the DMA buffer -+ * done interrupt, you won't know the irq number until the DMA channel is -+ * returned from jz_request_dma(). -+ */ -+ -+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { -+ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */ -+ {dev_id:-1,}, /* DMAC0 channel 1 */ -+ {dev_id:-1,}, /* DMAC0 channel 2 */ -+ {dev_id:-1,}, /* DMAC0 channel 3 */ -+ {dev_id:-1,}, /* DMAC0 channel 4 */ -+ {dev_id:-1,}, /* DMAC0 channel 5 */ -+ {dev_id:-1,}, /* DMAC1 channel 0 */ -+ {dev_id:-1,}, /* DMAC1 channel 1 */ -+ {dev_id:-1,}, /* DMAC1 channel 2 */ -+ {dev_id:-1,}, /* DMAC1 channel 3 */ -+ {dev_id:-1,}, /* DMAC1 channel 4 */ -+ {dev_id:-1,}, /* DMAC1 channel 5 */ -+}; -+ -+// Device FIFO addresses and default DMA modes -+static const struct { -+ unsigned int fifo_addr; -+ unsigned int dma_mode; -+ unsigned int dma_source; -+} dma_dev_table[DMA_ID_MAX] = { -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */ -+ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */ -+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC}, -+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, -+// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN}, -+ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, -+ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, -+ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, -+ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, -+ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, -+ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, -+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, -+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, -+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT}, -+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, -+ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT}, -+ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, -+ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */ -+ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */ -+ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */ -+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT}, -+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN}, -+ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT}, -+ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN}, -+ {}, -+}; -+ -+ -+int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data) -+{ -+ int i, len = 0; -+ struct jz_dma_chan *chan; -+ -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if ((chan = get_dma_chan(i)) != NULL) { -+ len += sprintf(buf + len, "%2d: %s\n", -+ i, chan->dev_str); -+ } -+ } -+ -+ if (fpos >= len) { -+ *start = buf; -+ *eof = 1; -+ return 0; -+ } -+ *start = buf + fpos; -+ if ((len -= fpos) > length) -+ return length; -+ *eof = 1; -+ return len; -+} -+ -+ -+void dump_jz_dma_channel(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return; -+ chan = &jz_dma_table[dmanr]; -+ -+ printk("DMA%d Registers:\n", dmanr); -+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM)); -+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); -+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); -+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); -+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); -+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); -+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); -+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); -+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM)); -+} -+ -+ -+/** -+ * jz_request_dma - dynamically allcate an idle DMA channel to return -+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET -+ * @dev_str: the specified dma device string name -+ * @irqhandler: the irq handler, or NULL -+ * @irqflags: the irq handler flags -+ * @irq_dev_id: the irq handler device id for shared irq -+ * -+ * Finds a free channel, and binds the requested device to it. -+ * Returns the allocated channel number, or negative on error. -+ * Requests the DMA done IRQ if irqhandler != NULL. -+ * -+*/ -+/*int jz_request_dma(int dev_id, const char *dev_str, -+ void (*irqhandler)(int, void *, struct pt_regs *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+*/ -+ -+int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+{ -+ struct jz_dma_chan *chan; -+ int i, ret, chan0; -+ -+ if (dev_id < 0 || dev_id >= DMA_ID_MAX) -+ return -EINVAL; -+ -+ /* Because of a bug in DMA controller of jz4750, which causes auto -+ request and device request can't be allocated in a same DMA -+ controller, all device requests should be put in the second DMA -+ controller -+ */ -+ if (dev_id > DMA_ID_AUTO) -+ chan0 = 6; -+ else -+ chan0 = 0; -+ -+ for (i = chan0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) /* no free channel */ -+ return -ENODEV; -+ -+ /* we got a free channel */ -+ chan = &jz_dma_table[i]; -+ -+ if (irqhandler) { -+ chan->irq = IRQ_DMA_0 + i; // allocate irq number -+ chan->irq_dev = irq_dev_id; -+ if ((ret = request_irq(chan->irq, irqhandler, irqflags, -+ dev_str, chan->irq_dev))) { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ return ret; -+ } -+ } else { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ } -+ -+ // fill it in -+ chan->io = i; -+ chan->dev_id = dev_id; -+ chan->dev_str = dev_str; -+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; -+ chan->mode = dma_dev_table[dev_id].dma_mode; -+ chan->source = dma_dev_table[dev_id].dma_source; -+ -+ if (i < 6) -+ REG_DMAC_DMACKE(0) = 1 << i; -+ else -+ REG_DMAC_DMACKE(1) = 1 << (i - 6); -+ -+ return i; -+} -+ -+void jz_free_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) { -+ printk("Trying to free DMA%d\n", dmanr); -+ return; -+ } -+ -+ disable_dma(dmanr); -+ if (chan->irq) -+ free_irq(chan->irq, chan->irq_dev); -+ -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ chan->dev_id = -1; -+} -+ -+void jz_set_dma_dest_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_DWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_src_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_SWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_SWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_SWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_SWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DS_MASK; -+ switch (nbyte) { -+ case 1: -+ chan->mode |= DMAC_DCMD_DS_8BIT; -+ break; -+ case 2: -+ chan->mode |= DMAC_DCMD_DS_16BIT; -+ break; -+ case 4: -+ chan->mode |= DMAC_DCMD_DS_32BIT; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DS_16BYTE; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DS_32BYTE; -+ break; -+ } -+} -+ -+unsigned int jz_get_dma_command(int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ return chan->mode; -+} -+ -+/** -+ * jz_set_dma_mode - do the raw settings for the specified DMA channel -+ * @dmanr: the specified DMA channel -+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE -+ * @dma_mode: dma raw mode -+ * @dma_source: dma raw request source -+ * @fifo_addr: dma raw device fifo address -+ * -+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call -+ * jz_set_dma_mode() rather than set_dma_mode() if you work with -+ * and external request dma device. -+ * -+ * NOTE: Don not dynamically allocate dma channel if one external request -+ * dma device will occupy this channel. -+*/ -+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, -+ unsigned int dma_mode, unsigned int dma_source, -+ unsigned int fifo_addr) -+{ -+ int dev_id, i; -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return -ENODEV; -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) -+ return -ENODEV; -+ -+ chan = &jz_dma_table[dmanr]; -+ dev_id = chan->dev_id; -+ if (dev_id > 0) { -+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", -+ __FUNCTION__, dmanr); -+ return -ENODEV; -+ } -+ -+ /* clone it from the dynamically allocated. */ -+ if (i != dmanr) { -+ chan->irq = jz_dma_table[i].irq; -+ chan->irq_dev = jz_dma_table[i].irq_dev; -+ chan->dev_str = jz_dma_table[i].dev_str; -+ jz_dma_table[i].irq = 0; -+ jz_dma_table[i].irq_dev = NULL; -+ jz_dma_table[i].dev_id = -1; -+ } -+ chan->dev_id = DMA_ID_RAW_SET; -+ chan->io = dmanr; -+ chan->fifo_addr = fifo_addr; -+ chan->mode = dma_mode; -+ chan->source = dma_source; -+ -+ set_dma_mode(dmanr, dma_mode); -+ -+ return dmanr; -+} -+ -+void enable_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ -+ __dmac_enable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_enable_irq(dmanr); -+} -+ -+#define DMA_DISABLE_POLL 0x10000 -+ -+void disable_dma(unsigned int dmanr) -+{ -+ int i; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ if (!__dmac_channel_enabled(dmanr)) -+ return; -+ -+ for (i = 0; i < DMA_DISABLE_POLL; i++) -+ if (__dmac_channel_transmit_end_detected(dmanr)) -+ break; -+#if 0 -+ if (i == DMA_DISABLE_POLL) -+ printk(KERN_INFO "disable_dma: poll expired!\n"); -+#endif -+ -+ __dmac_disable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_disable_irq(dmanr); -+} -+ -+/* Note: DMA_MODE_MASK is simulated by sw */ -+void set_dma_mode(unsigned int dmanr, unsigned int mode) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else { -+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ } -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+} -+ -+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) -+{ -+ unsigned int mode; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ mode = chan->mode & DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; -+ REG_DMAC_DTAR(chan->io) = phyaddr; -+ } else if (mode == DMA_MODE_WRITE) { -+ REG_DMAC_DSAR(chan->io) = phyaddr; -+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; -+ } else -+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); -+} -+ -+void set_dma_count(unsigned int dmanr, unsigned int bytecnt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ unsigned int ds; -+ -+ if (!chan) -+ return; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count -+} -+ -+unsigned int get_dma_residue(unsigned int dmanr) -+{ -+ unsigned int count, ds; -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ count = REG_DMAC_DTCR(chan->io); -+ count = count * dma_ds[ds]; -+ -+ return count; -+} -+ -+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case AFMT_U8: -+ /* burst mode : 32BIT */ -+ break; -+ case AFMT_S16_LE: -+ /* burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case 8: -+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ -+ break; -+ case 16: -+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+//#define JZ4750_DMAC_TEST_ENABLE -+#undef JZ4750_DMAC_TEST_ENABLE -+ -+#ifdef JZ4750_DMAC_TEST_ENABLE -+ -+/* -+ * DMA test: external address <--> external address -+ */ -+#define TEST_DMA_SIZE 16*1024 -+ -+static jz_dma_desc *dma_desc; -+ -+static int dma_chan; -+static dma_addr_t dma_desc_phys_addr; -+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; -+ -+static int dma_check_result(void *src, void *dst, int size) -+{ -+ unsigned int addr1, addr2, i, err = 0; -+ -+ addr1 = (unsigned int)src; -+ addr2 = (unsigned int)dst; -+ -+ for (i = 0; i < size; i += 4) { -+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { -+ err++; -+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); -+ } -+ addr1 += 4; -+ addr2 += 4; -+ } -+ printk("check DMA result err=%d\n", err); -+ return err; -+} -+ -+static irqreturn_t jz4750_dma_irq(int irq, void *dev_id) -+{ -+ printk("jz4750_dma_irq %d\n", irq); -+ -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ printk("DMA HALT\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ printk("DMA ADDR ERROR\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */ -+ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */ -+ __dmac_channel_clear_address_error(dma_chan); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ printk("DMA DESC INVALID\n"); -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ } -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ printk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ } -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ printk("DMA TT\n"); -+ __dmac_channel_clear_transmit_end(dma_chan); -+ dump_jz_dma_channel(dma_chan); -+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+void dma_nodesc_test(void) -+{ -+ unsigned int addr, i; -+ -+ printk("dma_nodesc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq, -+ IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Init DMA module */ -+ printk("Starting DMA\n"); -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; -+ REG_DMAC_DCCSR(dma_chan) = 0; -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = 512; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+ -+ /* wait a long time, ensure transfer end */ -+ printk("wait 3s...\n"); -+ mdelay(3000); /* wait 3s */ -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ /* free buffers */ -+ printk("free DMA buffers\n"); -+ free_pages(dma_src_addr, 2); -+ free_pages(dma_dst_addr, 2); -+ -+ if (dma_desc) -+ free_pages((unsigned int)dma_desc, 0); -+ -+ /* free dma */ -+ jz_free_dma(dma_chan); -+} -+ -+void dma_desc_test(void) -+{ -+ unsigned int next, addr, i; -+ static jz_dma_desc *desc; -+ -+ printk("dma_desc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750_dma_irq, -+ IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Allocate DMA descriptors */ -+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); -+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); -+ -+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); -+ -+ /* Setup DMA descriptors */ -+ desc = dma_desc; -+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ -+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; -+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ -+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ -+ -+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan; -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+ /* wait a long time, ensure transfer end */ -+ printk("wait 3s...\n"); -+ mdelay(3000); /* wait 3s */ -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ /* free buffers */ -+ printk("free DMA buffers\n"); -+ free_pages(dma_src_addr, 2); -+ free_pages(dma_dst_addr, 2); -+ -+ if (dma_desc) -+ free_pages((unsigned int)dma_desc, 0); -+ -+ /* free dma */ -+ jz_free_dma(dma_chan); -+} -+ -+#endif -+ -+//EXPORT_SYMBOL_NOVERS(jz_dma_table); -+EXPORT_SYMBOL(jz_dma_table); -+EXPORT_SYMBOL(jz_request_dma); -+EXPORT_SYMBOL(jz_free_dma); -+EXPORT_SYMBOL(jz_set_dma_src_width); -+EXPORT_SYMBOL(jz_set_dma_dest_width); -+EXPORT_SYMBOL(jz_set_dma_block_size); -+EXPORT_SYMBOL(jz_set_dma_mode); -+EXPORT_SYMBOL(set_dma_mode); -+EXPORT_SYMBOL(jz_set_oss_dma); -+EXPORT_SYMBOL(jz_set_alsa_dma); -+EXPORT_SYMBOL(set_dma_addr); -+EXPORT_SYMBOL(set_dma_count); -+EXPORT_SYMBOL(get_dma_residue); -+EXPORT_SYMBOL(enable_dma); -+EXPORT_SYMBOL(disable_dma); -+EXPORT_SYMBOL(dump_jz_dma_channel); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/i2c.c linux-2.6.24.7/arch/mips/jz4750/i2c.c ---- linux-2.6.24.7.old/arch/mips/jz4750/i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/i2c.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,273 @@ -+/* -+ * linux/arch/mips/jz4750/i2c.c -+ * -+ * Jz4750 I2C routines. -+ * -+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* I2C protocol */ -+#define I2C_READ 1 -+#define I2C_WRITE 0 -+ -+#define TIMEOUT 1000 -+ -+/* -+ * I2C bus protocol basic routines -+ */ -+static int i2c_put_data(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (!__i2c_received_ack() && timeout) -+ timeout--; -+ -+ if (timeout) -+ return 0; -+ else -+ return -ETIMEDOUT; -+} -+ -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+static int i2c_put_data_nack(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (timeout--); -+ return 0; -+} -+#endif -+ -+static int i2c_get_data(unsigned char *data, int ack) -+{ -+ int timeout = TIMEOUT*10; -+ -+ if (!ack) -+ __i2c_send_nack(); -+ else -+ __i2c_send_ack(); -+ -+ while (__i2c_check_drf() == 0 && timeout) -+ timeout--; -+ -+ if (timeout) { -+ if (!ack) -+ __i2c_send_stop(); -+ *data = __i2c_read(); -+ __i2c_clear_drf(); -+ return 0; -+ } else -+ return -ETIMEDOUT; -+} -+ -+/* -+ * I2C interface -+ */ -+void i2c_open(void) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ -+ __i2c_enable(); -+} -+ -+void i2c_close(void) -+{ -+ udelay(300); /* wait for STOP goes over. */ -+ __i2c_disable(); -+} -+ -+void i2c_setclk(unsigned int i2cclk) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, i2cclk); -+} -+ -+int i2c_lseek(unsigned char device, unsigned char offset) -+{ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (i2c_put_data(offset) < 0) -+ goto address_err; -+ return 0; -+ device_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+ address_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); -+ __i2c_send_stop(); -+ return -EREMOTEIO; -+} -+ -+int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int timeout = 5; -+ -+L_try_again: -+ -+ if (timeout < 0) -+ goto L_timeout; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_werr; -+ if (i2c_put_data(address) < 0) -+ goto address_err; -+ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) -+ goto device_rerr; -+ __i2c_send_ack(); /* Master sends ACK for continue reading */ -+ while (cnt) { -+ if (cnt == 1) { -+ if (i2c_get_data(buf, 0) < 0) -+ break; -+ } else { -+ if (i2c_get_data(buf, 1) < 0) -+ break; -+ } -+ cnt--; -+ buf++; -+ } -+ -+ __i2c_send_stop(); -+ return count - cnt; -+ device_rerr: -+ device_werr: -+ address_err: -+ timeout --; -+ __i2c_send_stop(); -+ goto L_try_again; -+ -+L_timeout: -+ __i2c_send_stop(); -+ printk("Read I2C device 0x%2x failed.\n", device); -+ return -ENODEV; -+} -+ -+int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int cnt_in_pg; -+ int timeout = 5; -+ unsigned char *tmpbuf; -+ unsigned char tmpaddr; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ W_try_again: -+ if (timeout < 0) -+ goto W_timeout; -+ -+ cnt = count; -+ tmpbuf = (unsigned char *)buf; -+ tmpaddr = address; -+ -+ start_write_page: -+ cnt_in_pg = 0; -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+ if (address == 0xff) { -+ if (i2c_put_data_nack(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data_nack(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+ else { -+ -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+#else -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+#endif -+ __i2c_send_stop(); -+ return count - cnt; -+ device_err: -+ address_err: -+ timeout--; -+ __i2c_send_stop(); -+ goto W_try_again; -+ -+ W_timeout: -+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+} -+ -+EXPORT_SYMBOL(i2c_open); -+EXPORT_SYMBOL(i2c_close); -+EXPORT_SYMBOL(i2c_setclk); -+EXPORT_SYMBOL(i2c_read); -+EXPORT_SYMBOL(i2c_write); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/irq.c linux-2.6.24.7/arch/mips/jz4750/irq.c ---- linux-2.6.24.7.old/arch/mips/jz4750/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/irq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,299 @@ -+/* -+ * linux/arch/mips/jz4750/irq.c -+ * -+ * JZ4750 interrupt routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * INTC irq type -+ */ -+ -+static void enable_intc_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(irq); -+} -+ -+static void disable_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+} -+ -+static void mask_and_ack_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+ __intc_ack_irq(irq); -+} -+ -+static void end_intc_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_intc_irq(irq); -+ } -+} -+ -+static unsigned int startup_intc_irq(unsigned int irq) -+{ -+ enable_intc_irq(irq); -+ return 0; -+} -+ -+static void shutdown_intc_irq(unsigned int irq) -+{ -+ disable_intc_irq(irq); -+} -+ -+static struct irq_chip intc_irq_type = { -+ .typename = "INTC", -+ .startup = startup_intc_irq, -+ .shutdown = shutdown_intc_irq, -+ .enable = enable_intc_irq, -+ .disable = disable_intc_irq, -+ .ack = mask_and_ack_intc_irq, -+ .end = end_intc_irq, -+}; -+ -+/* -+ * GPIO irq type -+ */ -+ -+static void enable_gpio_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if (irq < (IRQ_GPIO_0 + 32)) { -+ intc_irq = IRQ_GPIO0; -+ } -+ else if (irq < (IRQ_GPIO_0 + 64)) { -+ intc_irq = IRQ_GPIO1; -+ } -+ else if (irq < (IRQ_GPIO_0 + 96)) { -+ intc_irq = IRQ_GPIO2; -+ } -+ else if (irq < (IRQ_GPIO_0 + 128)) { -+ intc_irq = IRQ_GPIO3; -+ } -+ else if (irq < (IRQ_GPIO_0 + 160)) { -+ intc_irq = IRQ_GPIO4; -+ } -+ else { -+ intc_irq = IRQ_GPIO5; -+ } -+ -+ enable_intc_irq(intc_irq); -+ __gpio_unmask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void disable_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void mask_and_ack_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+ __gpio_ack_irq(irq - IRQ_GPIO_0); -+} -+ -+static void end_gpio_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_gpio_irq(irq); -+ } -+} -+ -+static unsigned int startup_gpio_irq(unsigned int irq) -+{ -+ enable_gpio_irq(irq); -+ return 0; -+} -+ -+static void shutdown_gpio_irq(unsigned int irq) -+{ -+ disable_gpio_irq(irq); -+} -+ -+static struct irq_chip gpio_irq_type = { -+ .typename = "GPIO", -+ .startup = startup_gpio_irq, -+ .shutdown = shutdown_gpio_irq, -+ .enable = enable_gpio_irq, -+ .disable = disable_gpio_irq, -+ .ack = mask_and_ack_gpio_irq, -+ .end = end_gpio_irq, -+}; -+ -+/* -+ * DMA irq type -+ */ -+ -+static void enable_dma_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ -+ intc_irq = IRQ_DMAC0; -+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ -+ intc_irq = IRQ_DMAC1; -+ else { -+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); -+ return; -+ } -+ __intc_unmask_irq(intc_irq); -+ __dmac_channel_enable_irq(irq - IRQ_DMA_0); -+} -+ -+static void disable_dma_irq(unsigned int irq) -+{ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void mask_and_ack_dma_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ -+ intc_irq = IRQ_DMAC0; -+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ -+ intc_irq = IRQ_DMAC1; -+ else { -+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); -+ return ; -+ } -+ __intc_ack_irq(intc_irq); -+ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void end_dma_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_dma_irq(irq); -+ } -+} -+ -+static unsigned int startup_dma_irq(unsigned int irq) -+{ -+ enable_dma_irq(irq); -+ return 0; -+} -+ -+static void shutdown_dma_irq(unsigned int irq) -+{ -+ disable_dma_irq(irq); -+} -+ -+static struct irq_chip dma_irq_type = { -+ .typename = "DMA", -+ .startup = startup_dma_irq, -+ .shutdown = shutdown_dma_irq, -+ .enable = enable_dma_irq, -+ .disable = disable_dma_irq, -+ .ack = mask_and_ack_dma_irq, -+ .end = end_dma_irq, -+}; -+ -+//---------------------------------------------------------------------- -+ -+void __init arch_init_irq(void) -+{ -+ int i; -+ -+ clear_c0_status(0xff04); /* clear ERL */ -+ set_c0_status(0x0400); /* set IP2 */ -+ -+ /* Set up INTC irq -+ */ -+ for (i = 0; i < 32; i++) { -+ disable_intc_irq(i); -+ irq_desc[i].chip = &intc_irq_type; -+ } -+ -+ /* Set up DMAC irq -+ */ -+ for (i = 0; i < NUM_DMA; i++) { -+ disable_dma_irq(IRQ_DMA_0 + i); -+ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; -+ } -+ -+ /* Set up GPIO irq -+ */ -+ for (i = 0; i < NUM_GPIO; i++) { -+ disable_gpio_irq(IRQ_GPIO_0 + i); -+ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; -+ } -+} -+ -+static int plat_real_irq(int irq) -+{ -+ switch (irq) { -+ case IRQ_GPIO0: -+ irq = __gpio_group_irq(0) + IRQ_GPIO_0; -+ break; -+ case IRQ_GPIO1: -+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; -+ break; -+ case IRQ_GPIO2: -+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; -+ break; -+ case IRQ_GPIO3: -+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; -+ break; -+ case IRQ_GPIO4: -+ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128; -+ break; -+ case IRQ_GPIO5: -+ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160; -+ break; -+ case IRQ_DMAC0: -+ case IRQ_DMAC1: -+ irq = __dmac_get_irq() + IRQ_DMA_0; -+ break; -+ } -+ -+ return irq; -+} -+ -+asmlinkage void plat_irq_dispatch(void) -+{ -+ int irq = 0; -+ static unsigned long intc_ipr = 0; -+ -+ intc_ipr |= REG_INTC_IPR; -+ -+ if (!intc_ipr) return; -+ -+ irq = ffs(intc_ipr) - 1; -+ intc_ipr &= ~(1< -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* OHCI (USB full speed host controller) */ -+static struct resource jz_usb_ohci_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap -+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UHC, -+ .end = IRQ_UHC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+/* The dmamask must be set for OHCI to work */ -+static u64 ohci_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_ohci_device = { -+ .name = "jz-ohci", -+ .id = 0, -+ .dev = { -+ .dma_mask = &ohci_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), -+ .resource = jz_usb_ohci_resources, -+}; -+ -+/*** LCD controller ***/ -+static struct resource jz_lcd_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(LCD_BASE), -+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_LCD, -+ .end = IRQ_LCD, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_lcd_dmamask = ~(u32)0; -+ -+static struct platform_device jz_lcd_device = { -+ .name = "jz-lcd", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_lcd_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_lcd_resources), -+ .resource = jz_lcd_resources, -+}; -+ -+/* UDC (USB gadget controller) */ -+static struct resource jz_usb_gdt_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UDC_BASE), -+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UDC, -+ .end = IRQ_UDC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static u64 udc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_gdt_device = { -+ .name = "jz-udc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &udc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), -+ .resource = jz_usb_gdt_resources, -+}; -+ -+/** MMC/SD controller **/ -+static struct resource jz_mmc_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(MSC_BASE), -+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_MSC0, -+ .end = IRQ_MSC0, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_mmc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_mmc_device = { -+ .name = "jz-mmc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_mmc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_mmc_resources), -+ .resource = jz_mmc_resources, -+}; -+ -+/* All */ -+static struct platform_device *jz_platform_devices[] __initdata = { -+ &jz_usb_ohci_device, -+ &jz_lcd_device, -+ &jz_usb_gdt_device, -+ &jz_mmc_device, -+}; -+ -+static int __init jz_platform_init(void) -+{ -+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); -+} -+ -+arch_initcall(jz_platform_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/pm.c linux-2.6.24.7/arch/mips/jz4750/pm.c ---- linux-2.6.24.7.old/arch/mips/jz4750/pm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/pm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,461 @@ -+/* -+ * linux/arch/mips/jz4750/common/pm.c -+ * -+ * JZ4750 Power Management Routines -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+#define GPIO_PORT_NUM 6 -+ -+/* -+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input -+ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select. -+ */ -+#define __gpio_as_sleep() \ -+do { \ -+ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(2) = ~0x01e00000; \ -+ REG_GPIO_PXSELC(2) = ~0x01e00000; \ -+ REG_GPIO_PXDIRC(2) = ~0x01e00000; \ -+ REG_GPIO_PXPES(2) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(3) = 0xffffffff; \ -+ REG_GPIO_PXSELC(3) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(3) = 0xffffffff; \ -+ REG_GPIO_PXPES(3) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(4) = 0xffffffff; \ -+ REG_GPIO_PXSELC(4) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(4) = 0xffffffff; \ -+ REG_GPIO_PXPES(4) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(5) = 0xffffffff; \ -+ REG_GPIO_PXSELC(5) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(5) = 0xffffffff; \ -+ REG_GPIO_PXPES(5) = 0xffffffff; \ -+} while (0) -+ -+static int jz_pm_do_hibernate(void) -+{ -+ printk("Put CPU into hibernate mode.\n"); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* -+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled -+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). -+ */ -+ -+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); -+ -+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ -+ -+ /* Scratch pad register to be reserved */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HSPR = 0x12345678; -+ -+ /* clear wakeup status register */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWRSR = 0x0; -+ -+ /* Put CPU to power down mode */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HCR = RTC_HCR_PD; -+ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ while(1); -+ -+ /* We can't get here */ -+ return 0; -+} -+ -+/* NOTES: -+ * 1: Pins that are floated (NC) should be set as input and pull-enable. -+ * 2: Pins that are pull-up or pull-down by outside should be set as input -+ * and pull-disable. -+ * 3: Pins that are connected to a chip except sdram and nand flash -+ * should be set as input and pull-disable, too. -+ */ -+static void jz_board_do_sleep(unsigned long *ptr) -+{ -+ unsigned char i; -+ -+ /* Print messages of GPIO registers for debug */ -+ for(i=0;i -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+//#define DEBUG 1 -+#undef DEBUG -+ -+ -+struct proc_dir_entry *proc_jz_root; -+ -+ -+/* -+ * EMC Modules -+ */ -+static int emc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); -+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); -+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); -+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); -+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); -+ return len; -+} -+ -+/* -+ * Power Manager Module -+ */ -+static int pmc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned long lcr = REG_CPM_LCR; -+ unsigned long clkgr = REG_CPM_CLKGR; -+ -+ len += sprintf (page+len, "Low Power Mode : %s\n", -+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? -+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? -+ "SLEEP" : "HIBERNATE")); -+ len += sprintf (page+len, "Doze Mode : %s\n", -+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); -+ if (lcr & CPM_LCR_DOZE_ON) -+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); -+ len += sprintf (page+len, "IPU : %s\n", -+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); -+ len += sprintf (page+len, "DMAC : %s\n", -+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UHC : %s\n", -+ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UDC : %s\n", -+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); -+ len += sprintf (page+len, "LCD : %s\n", -+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); -+ len += sprintf (page+len, "CIM : %s\n", -+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); -+ len += sprintf (page+len, "SADC : %s\n", -+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); -+ len += sprintf (page+len, "MSC0 : %s\n", -+ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running"); -+ len += sprintf (page+len, "MSC1 : %s\n", -+ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC1 : %s\n", -+ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC2 : %s\n", -+ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI0 : %s\n", -+ (clkgr & CPM_CLKGR_SSI0) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI1 : %s\n", -+ (clkgr & CPM_CLKGR_SSI1) ? "stopped" : "running"); -+ len += sprintf (page+len, "I2C : %s\n", -+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); -+ len += sprintf (page+len, "RTC : %s\n", -+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); -+ len += sprintf (page+len, "TCU : %s\n", -+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART1 : %s\n", -+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART0 : %s\n", -+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); -+ return len; -+} -+ -+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+/* -+ * Clock Generation Module -+ */ -+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 -+#define TO_KHZ(x) (x/1000),(x%1000)/10 -+ -+static int cgm_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ -+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ -+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int od[4] = {1, 2, 2, 4}; -+ -+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); -+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); -+ len += sprintf (page+len, "PLL : %s\n", -+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); -+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", -+ __cpm_get_pllm() + 2, -+ __cpm_get_plln() + 2, -+ od[__cpm_get_pllod()] -+ ); -+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", -+ div[__cpm_get_cdiv()], -+ div[__cpm_get_hdiv()], -+ div[__cpm_get_mdiv()], -+ div[__cpm_get_pdiv()] -+ ); -+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); -+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); -+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); -+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); -+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); -+ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); -+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); -+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); -+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); -+ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0))); -+ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1))); -+ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0())); -+ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); -+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); -+ -+ return len; -+} -+ -+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+ -+/* USAGE: -+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. -+ * echo FF > /proc/jz/ipu // 255, free all buffer -+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx -+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) -+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf -+ * od -X /proc/jz/ipu // read mem addr -+ */ -+ -+typedef struct _ipu_buf { -+ unsigned int addr; /* phys addr */ -+ unsigned int page_shift; -+} ipu_buf_t; -+ -+#define IPU_BUF_MAX 4 /* 4 buffers */ -+ -+static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; -+static int ipu_buf_cnt = 0; -+static unsigned char g_asid=0; -+ -+extern void local_flush_tlb_all(void); -+ -+/* CP0 hazard avoidance. */ -+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ -+ "nop; nop; nop; nop; nop; nop;\n\t" \ -+ ".set reorder\n\t") -+void show_tlb(void) -+{ -+#define ASID_MASK 0xFF -+ -+ unsigned long flags; -+ unsigned int old_ctx; -+ unsigned int entry; -+ unsigned int entrylo0, entrylo1, entryhi; -+ unsigned int pagemask; -+ -+ local_irq_save(flags); -+ -+ /* Save old context */ -+ old_ctx = (read_c0_entryhi() & 0xff); -+ -+ printk("TLB content:\n"); -+ entry = 0; -+ while(entry < 32) { -+ write_c0_index(entry); -+ BARRIER; -+ tlb_read(); -+ BARRIER; -+ entryhi = read_c0_entryhi(); -+ entrylo0 = read_c0_entrylo0(); -+ entrylo1 = read_c0_entrylo1(); -+ pagemask = read_c0_pagemask(); -+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); -+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); -+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); -+ -+ printk("\t\tpagemask=0x%08x", pagemask); -+ printk("\tentryhi=0x%08x\n", entryhi); -+ printk("\t\tentrylo0=0x%08x", entrylo0); -+ printk("\tentrylo1=0x%08x\n", entrylo1); -+ -+ entry++; -+ } -+ BARRIER; -+ write_c0_entryhi(old_ctx); -+ -+ local_irq_restore(flags); -+} -+ -+static void ipu_add_wired_entry(unsigned long pid, -+ unsigned long entrylo0, unsigned long entrylo1, -+ unsigned long entryhi, unsigned long pagemask) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ unsigned long old_pagemask; -+ unsigned long old_ctx; -+ struct task_struct *g, *p; -+ -+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ -+ entrylo0 = entrylo0 >> 6; -+ entrylo0 |= 0x6 | (0 << 3); -+ /*entrylo0 |= 0x6 | (1 << 3);*/ -+ -+ do_each_thread(g, p) { -+ if (p->pid == pid ) -+ g_asid = p->mm->context[0]; -+ } while_each_thread(g, p); -+ -+ local_irq_save(flags); -+ /* Save old context and create impossible VPN2 value */ -+ old_ctx = read_c0_entryhi() & 0xff; -+ old_pagemask = read_c0_pagemask(); -+ wired = read_c0_wired(); -+ write_c0_wired(wired + 1); -+ write_c0_index(wired); -+ BARRIER; -+ entryhi &= ~0xff; /* new add, 20070906 */ -+ entryhi |= g_asid; /* new add, 20070906 */ -+// entryhi |= old_ctx; /* new add, 20070906 */ -+ write_c0_pagemask(pagemask); -+ write_c0_entryhi(entryhi); -+ write_c0_entrylo0(entrylo0); -+ write_c0_entrylo1(entrylo1); -+ BARRIER; -+ tlb_write_indexed(); -+ BARRIER; -+ -+ write_c0_entryhi(old_ctx); -+ BARRIER; -+ write_c0_pagemask(old_pagemask); -+ local_flush_tlb_all(); -+ local_irq_restore(flags); -+#if defined(DEBUG) -+ printk("\nold_ctx=%03d\n", old_ctx); -+ -+ show_tlb(); -+#endif -+} -+ -+static void ipu_del_wired_entry( void ) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ -+ local_irq_save(flags); -+ wired = read_c0_wired(); -+ if (wired) { -+ write_c0_wired(0); -+ } -+ local_irq_restore(flags); -+} -+ -+static inline void ipu_buf_get( unsigned int page_shift ) -+{ -+ unsigned char * virt_addr; -+ int i; -+ for ( i=0; i< IPU_BUF_MAX; ++i ) { -+ if ( ipu_buf[i].addr == 0 ) { -+ break; -+ } -+ } -+ -+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { -+ printk("Error, no free ipu buffer.\n"); -+ return ; -+ } -+ -+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ -+ if ( virt_addr ) { -+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); -+ ipu_buf[ipu_buf_cnt].page_shift = page_shift; -+ -+ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ -+ printk("no free buffer.\n"); -+ *pint = 0; -+ } -+ else -+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ -+ len += sizeof(unsigned int); -+ -+#if defined(DEBUG) -+ show_tlb(); -+#endif -+ return len; -+ -+} -+ -+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val ; -+ int cnt,i; -+ char buf[12]; -+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; -+#if defined(DEBUG) -+ printk("ipu write count=%u\n", count); -+#endif -+ if (count == 41) { -+ for (i=0;i<12;i++) -+ buf[i]=0; -+ strncpy(buf, buffer+8*0, 8); -+ pid = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) -+ buf[i]=0; -+ strncpy(buf, buffer+8*1, 8); -+ entrylo0 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) -+ buf[i]=0; -+ strncpy(buf, buffer+8*2, 8); -+ entrylo1 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) -+ buf[i]=0; -+ strncpy(buf, buffer+8*3, 8); -+ entryhi = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) -+ buf[i]=0; -+ strncpy(buf, buffer+8*4, 8); -+ pagemask = simple_strtoul(buf, 0, 16); -+ -+#if defined(DEBUG) -+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", -+ pid, entrylo0, entrylo1, entryhi, pagemask); -+#endif -+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); -+ return 41; -+ } else if ( count <= 9 ) { -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer, 8); -+ val = simple_strtoul(buf, 0, 16); -+ } else if (count == 44) { -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer, 10); -+ pid = simple_strtoul(buf, 0, 16); -+ -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 11, 10); -+ entryhi = simple_strtoul(buf, 0, 16);//vaddr -+ -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 22, 10); -+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr -+ -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 33, 10); -+ pagemask = simple_strtoul(buf, 0, 16); -+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ -+ //pagemask = 0xfff << 13; /* Fixed to 16MB page size */ -+ -+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); -+ return 44; -+ } else if (count == 12) { -+ printk("\necho release tlb > /proc/jz/ipu\n"); -+ ipu_del_wired_entry(); -+ return 12; -+ } else { -+ printk("ipu write count error, count=%d\n.", (unsigned int)count); -+ return -1; -+ } -+ -+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ -+ if ( val == 0 ) { /* debug, print ipu_buf info */ -+ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages -+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx -+ * echo FF > /proc/jz/ipu // FF, free all buffers -+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer -+ */ -+ -+//#define DEBUG_IMEM 1 -+ -+#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */ -+ -+static unsigned int jz_imem_base; /* physical base address of ipu memory */ -+ -+static unsigned int allocated_phys_addr = 0; -+ -+/* -+ * Allocated buffer list -+ */ -+typedef struct imem_list { -+ unsigned int phys_start; /* physical start addr */ -+ unsigned int phys_end; /* physical end addr */ -+ struct imem_list *next; -+} imem_list_t; -+ -+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */ -+ -+#ifdef DEBUG_IMEM -+static void dump_imem_list(void) -+{ -+ struct imem_list *imem; -+ -+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head); -+ imem = imem_list_head; -+ while (imem) { -+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next); -+ imem = imem->next; -+ } -+} -+#endif -+ -+/* allocate 2^order pages inside the 4MB memory */ -+static int imem_alloc(unsigned int order) -+{ -+ int alloc_ok = 0; -+ unsigned int start, end; -+ unsigned int size = (1 << order) * PAGE_SIZE; -+ struct imem_list *imem, *imemn, *imemp; -+ -+ allocated_phys_addr = 0; -+ -+ start = jz_imem_base; -+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ imem = imem_list_head; -+ while (imem) { -+ if ((imem->phys_start - start) >= size) { -+ /* we got a valid address range */ -+ alloc_ok = 1; -+ break; -+ } -+ -+ start = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (!alloc_ok) { -+ if ((end - start) >= size) -+ alloc_ok = 1; -+ } -+ -+ if (alloc_ok) { -+ end = start + size - 1; -+ allocated_phys_addr = start; -+ -+ /* add to imem_list, up sorted by phys_start */ -+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL); -+ if (!imemn) { -+ return -ENOMEM; -+ } -+ imemn->phys_start = start; -+ imemn->phys_end = end; -+ imemn->next = NULL; -+ -+ if (!imem_list_head) -+ imem_list_head = imemn; -+ else { -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (start < imem->phys_start) { -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+ if (imem == imem_list_head) { -+ imem_list_head = imemn; -+ imemn->next = imem; -+ } -+ else { -+ imemn->next = imemp->next; -+ imemp->next = imemn; -+ } -+ } -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+ return 0; -+} -+ -+static void imem_free(unsigned int phys_addr) -+{ -+ struct imem_list *imem, *imemp; -+ -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (phys_addr == imem->phys_start) { -+ if (imem == imem_list_head) { -+ imem_list_head = imem->next; -+ } -+ else { -+ imemp->next = imem->next; -+ } -+ -+ kfree(imem); -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+static void imem_free_all(void) -+{ -+ struct imem_list *imem; -+ -+ imem = imem_list_head; -+ while (imem) { -+ kfree(imem); -+ imem = imem->next; -+ } -+ -+ imem_list_head = NULL; -+ -+ allocated_phys_addr = 0; -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+/* -+ * Return the allocated buffer address and the max order of free buffer -+ */ -+static int imem_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int start_addr, end_addr, max_order, max_size; -+ struct imem_list *imem; -+ -+ unsigned int *tmp = (unsigned int *)(page + len); -+ -+ start_addr = jz_imem_base; -+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ if (!imem_list_head) -+ max_size = end_addr - start_addr; -+ else { -+ max_size = 0; -+ imem = imem_list_head; -+ while (imem) { -+ if (max_size < (imem->phys_start - start_addr)) -+ max_size = imem->phys_start - start_addr; -+ -+ start_addr = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (max_size < (end_addr - start_addr)) -+ max_size = end_addr - start_addr; -+ } -+ -+ if (max_size > 0) { -+ max_order = get_order(max_size); -+ if (((1 << max_order) * PAGE_SIZE) > max_size) -+ max_order--; -+ } -+ else { -+ max_order = 0xffffffff; /* No any free buffer */ -+ } -+ -+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */ -+ *tmp = max_order; /* max order of current free buffers */ -+ -+ len += 2 * sizeof(unsigned int); -+ -+ return len; -+} -+ -+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val; -+ -+ val = simple_strtoul(buffer, 0, 16); -+ -+ if (val == 0xff) { -+ /* free all memory */ -+ imem_free_all(); -+ ipu_del_wired_entry(); -+ } else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) { -+ /* allocate 2^val pages */ -+ imem_alloc(val); -+ } else { -+ /* free buffer which phys_addr is val */ -+ imem_free(val); -+ } -+ -+ return count; -+} -+ -+/* -+ * /proc/jz/xxx entry -+ * -+ */ -+static int __init jz_proc_init(void) -+{ -+ struct proc_dir_entry *res; -+ unsigned int virt_addr, i; -+ -+ proc_jz_root = proc_mkdir("jz", 0); -+ -+ /* External Memory Controller */ -+ res = create_proc_entry("emc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = emc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* Power Management Controller */ -+ res = create_proc_entry("pmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = pmc_read_proc; -+ res->write_proc = pmc_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Clock Generation Module */ -+ res = create_proc_entry("cgm", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = cgm_read_proc; -+ res->write_proc = cgm_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Image process unit */ -+ res = create_proc_entry("ipu", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = ipu_read_proc; -+ res->write_proc = ipu_write_proc; -+ res->data = NULL; -+ } -+ -+ /* udc hotplug */ -+ res = create_proc_entry("udc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = udc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* mmc hotplug */ -+ res = create_proc_entry("mmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = mmc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* show tlb */ -+ res = create_proc_entry("tlb", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = tlb_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* -+ * Reserve a 4MB memory for IPU on JZ4750. -+ */ -+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); -+ if (jz_imem_base) { -+ /* imem (IPU memory management) */ -+ res = create_proc_entry("imem", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = imem_read_proc; -+ res->write_proc = imem_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Set page reserved */ -+ virt_addr = jz_imem_base; -+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { -+ SetPageReserved(virt_to_page((void *)virt_addr)); -+ virt_addr += PAGE_SIZE; -+ } -+ -+ /* Convert to physical address */ -+ jz_imem_base = virt_to_phys((void *)jz_imem_base); -+ -+ printk("Total %dMB memory at 0x%x was reserved for IPU\n", -+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); -+ } else -+ printk("NOT enough memory for imem\n"); -+ -+ return 0; -+} -+ -+__initcall(jz_proc_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/prom.c linux-2.6.24.7/arch/mips/jz4750/prom.c ---- linux-2.6.24.7.old/arch/mips/jz4750/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/prom.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,198 @@ -+/* -+ * -+ * BRIEF MODULE DESCRIPTION -+ * PROM library initialisation code, supports YAMON and U-Boot. -+ * -+ * Copyright 2000, 2001, 2006 MontaVista Software Inc. -+ * Author: MontaVista Software, Inc. -+ * ppopov@mvista.com or source@mvista.com -+ * -+ * This file was derived from Carsten Langgaard's -+ * arch/mips/mips-boards/xx files. -+ * -+ * Carsten Langgaard, carstenl@mips.com -+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* #define DEBUG_CMDLINE */ -+ -+int prom_argc; -+char **prom_argv, **prom_envp; -+ -+char * prom_getcmdline(void) -+{ -+ return &(arcs_cmdline[0]); -+} -+ -+void prom_init_cmdline(void) -+{ -+ char *cp; -+ int actr; -+ -+ actr = 1; /* Always ignore argv[0] */ -+ -+ cp = &(arcs_cmdline[0]); -+ while(actr < prom_argc) { -+ strcpy(cp, prom_argv[actr]); -+ cp += strlen(prom_argv[actr]); -+ *cp++ = ' '; -+ actr++; -+ } -+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ -+ --cp; -+ if (prom_argc > 1) -+ *cp = '\0'; -+ -+} -+ -+ -+char *prom_getenv(char *envname) -+{ -+#if 0 -+ /* -+ * Return a pointer to the given environment variable. -+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". -+ */ -+ -+ char **env = prom_envp; -+ int i = strlen(envname); -+ int yamon = (*env && strchr(*env, '=') == NULL); -+ -+ while (*env) { -+ if (yamon) { -+ if (strcmp(envname, *env++) == 0) -+ return *env; -+ } else { -+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') -+ return *env + i + 1; -+ } -+ env++; -+ } -+#endif -+ return NULL; -+} -+ -+inline unsigned char str2hexnum(unsigned char c) -+{ -+ if(c >= '0' && c <= '9') -+ return c - '0'; -+ if(c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if(c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for(i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+int get_ethernet_addr(char *ethernet_addr) -+{ -+ char *ethaddr_str; -+ -+ ethaddr_str = prom_getenv("ethaddr"); -+ if (!ethaddr_str) { -+ printk("ethaddr not set in boot prom\n"); -+ return -1; -+ } -+ str2eaddr(ethernet_addr, ethaddr_str); -+ -+#if 0 -+ { -+ int i; -+ -+ printk("get_ethernet_addr: "); -+ for (i=0; i<5; i++) -+ printk("%02x:", (unsigned char)*(ethernet_addr+i)); -+ printk("%02x\n", *(ethernet_addr+i)); -+ } -+#endif -+ -+ return 0; -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+} -+ -+void __init prom_init(void) -+{ -+ unsigned char *memsize_str; -+ unsigned long memsize; -+ -+ prom_argc = (int) fw_arg0; -+ prom_argv = (char **) fw_arg1; -+ prom_envp = (char **) fw_arg2; -+ -+ mips_machtype = MACH_INGENIC_JZ4750; -+ -+ prom_init_cmdline(); -+ memsize_str = prom_getenv("memsize"); -+ if (!memsize_str) { -+ memsize = 0x04000000; -+ } else { -+ memsize = simple_strtol(memsize_str, NULL, 0); -+ } -+ add_memory_region(0, memsize, BOOT_MEM_RAM); -+} -+ -+/* used by early printk */ -+void prom_putchar(char c) -+{ -+ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); -+ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); -+ -+ /* Wait for fifo to shift out some bytes */ -+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); -+ -+ *uart_tdr = (u8)c; -+} -+ -+const char *get_system_type(void) -+{ -+ return "JZ4750"; -+} -+ -+EXPORT_SYMBOL(prom_getcmdline); -+EXPORT_SYMBOL(get_ethernet_addr); -+EXPORT_SYMBOL(str2eaddr); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/reset.c linux-2.6.24.7/arch/mips/jz4750/reset.c ---- linux-2.6.24.7.old/arch/mips/jz4750/reset.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/reset.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,46 @@ -+/* -+ * linux/arch/mips/jz4750/reset.c -+ * -+ * JZ4750 reset routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+void jz_restart(char *command) -+{ -+ printk("Restarting after 4 ms\n"); -+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; -+ REG_WDT_TCNT = 0; -+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ -+ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */ -+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ -+ while (1); -+} -+ -+void jz_halt(void) -+{ -+ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); -+ -+ while (1) -+ __asm__(".set\tmips3\n\t" -+ "wait\n\t" -+ ".set\tmips0"); -+} -+ -+void jz_power_off(void) -+{ -+ jz_halt(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/setup.c linux-2.6.24.7/arch/mips/jz4750/setup.c ---- linux-2.6.24.7.old/arch/mips/jz4750/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/setup.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,197 @@ -+/* -+ * linux/arch/mips/jz4750/common/setup.c -+ * -+ * JZ4750 common setup routines. -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PC_KEYB -+#include -+#endif -+ -+jz_clocks_t jz_clocks; -+ -+extern char * __init prom_getcmdline(void); -+extern void __init jz_board_setup(void); -+extern void jz_restart(char *); -+extern void jz_halt(void); -+extern void jz_power_off(void); -+extern void jz_time_init(void); -+ -+static void __init sysclocks_setup(void) -+{ -+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(0); -+ jz_clocks.extalclk = __cpm_get_extalclk(); -+ jz_clocks.rtcclk = __cpm_get_rtcclk(); -+#else -+ -+#define FPGACLK 8000000 -+ -+ jz_clocks.cclk = FPGACLK; -+ jz_clocks.hclk = FPGACLK; -+ jz_clocks.pclk = FPGACLK; -+ jz_clocks.mclk = FPGACLK; -+ jz_clocks.lcdclk = FPGACLK; -+ jz_clocks.pixclk = FPGACLK; -+ jz_clocks.i2sclk = FPGACLK; -+ jz_clocks.usbclk = FPGACLK; -+ jz_clocks.mscclk = FPGACLK; -+ jz_clocks.extalclk = FPGACLK; -+ jz_clocks.rtcclk = FPGACLK; -+#endif -+ -+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", -+ (jz_clocks.cclk + 500000) / 1000000, -+ (jz_clocks.hclk + 500000) / 1000000, -+ (jz_clocks.pclk + 500000) / 1000000, -+ (jz_clocks.mclk + 500000) / 1000000); -+} -+ -+static void __init soc_cpm_setup(void) -+{ -+ /* Start all module clocks -+ */ -+ __cpm_start_all(); -+ -+ /* Enable CKO to external memory */ -+ __cpm_enable_cko(); -+ -+ /* CPU enters IDLE mode when executing 'wait' instruction */ -+ __cpm_idle_mode(); -+ -+ /* Setup system clocks */ -+ sysclocks_setup(); -+} -+ -+static void __init soc_harb_setup(void) -+{ -+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ -+} -+ -+static void __init soc_emc_setup(void) -+{ -+} -+ -+static void __init soc_dmac_setup(void) -+{ -+ __dmac_enable_module(0); -+ __dmac_enable_module(1); -+} -+ -+static void __init jz_soc_setup(void) -+{ -+ soc_cpm_setup(); -+ soc_harb_setup(); -+ soc_emc_setup(); -+ soc_dmac_setup(); -+} -+ -+static void __init jz_serial_setup(void) -+{ -+#ifdef CONFIG_SERIAL_8250 -+ struct uart_port s; -+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ -+ memset(&s, 0, sizeof(s)); -+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; -+ s.iotype = SERIAL_IO_MEM; -+ s.regshift = 2; -+ s.uartclk = jz_clocks.extalclk ; -+ -+ s.line = 0; -+ s.membase = (u8 *)UART0_BASE; -+ s.irq = IRQ_UART0; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); -+ } -+ -+ s.line = 1; -+ s.membase = (u8 *)UART1_BASE; -+ s.irq = IRQ_UART1; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); -+ } -+ -+ s.line = 2; -+ s.membase = (u8 *)UART2_BASE; -+ s.irq = IRQ_UART2; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); -+ } -+ -+ s.line = 3; -+ s.membase = (u8 *)UART3_BASE; -+ s.irq = IRQ_UART3; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); -+ } -+#endif -+} -+ -+void __init plat_mem_setup(void) -+{ -+ char *argptr; -+ -+ argptr = prom_getcmdline(); -+ -+ /* IO/MEM resources. Which will be the addtion value in `inX' and -+ * `outX' macros defined in asm/io.h */ -+ set_io_port_base(0); -+ ioport_resource.start = 0x00000000; -+ ioport_resource.end = 0xffffffff; -+ iomem_resource.start = 0x00000000; -+ iomem_resource.end = 0xffffffff; -+ -+ _machine_restart = jz_restart; -+ _machine_halt = jz_halt; -+ pm_power_off = jz_power_off; -+ -+ jz_soc_setup(); -+ jz_serial_setup(); -+ jz_board_setup(); -+} -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4750/time.c linux-2.6.24.7/arch/mips/jz4750/time.c ---- linux-2.6.24.7.old/arch/mips/jz4750/time.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750/time.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* -+ * linux/arch/mips/jz4750/time.c -+ * -+ * Setting up the clock on the JZ4750 boards. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* This is for machines which generate the exact clock. */ -+ -+#define JZ_TIMER_IRQ IRQ_TCU0 -+ -+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ -+ -+static struct clocksource clocksource_jz; /* Jz clock source */ -+static struct clock_event_device jz_clockevent_device; /* Jz clock event */ -+ -+void (*jz_timer_callback)(void); -+ -+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ -+ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */ -+ -+ if (jz_timer_callback) -+ jz_timer_callback(); -+ -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct irqaction jz_irqaction = { -+ .handler = jz_timer_interrupt, -+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, -+ .name = "jz-timerirq", -+}; -+ -+ -+cycle_t jz_get_cycles(void) -+{ -+ /* convert jiffes to jz timer cycles */ -+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT); -+} -+ -+static struct clocksource clocksource_jz = { -+ .name = "jz_clocksource", -+ .rating = 300, -+ .read = jz_get_cycles, -+ .mask = 0xFFFFFFFF, -+ .shift = 10, -+ .flags = CLOCK_SOURCE_WATCHDOG, -+}; -+ -+static int __init jz_clocksource_init(void) -+{ -+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); -+ clocksource_register(&clocksource_jz); -+ return 0; -+} -+ -+static int jz_set_next_event(unsigned long evt, -+ struct clock_event_device *unused) -+{ -+ return 0; -+} -+ -+static void jz_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ switch (mode) { -+ case CLOCK_EVT_MODE_PERIODIC: -+ break; -+ case CLOCK_EVT_MODE_ONESHOT: -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ break; -+ case CLOCK_EVT_MODE_RESUME: -+ break; -+ } -+} -+ -+static struct clock_event_device jz_clockevent_device = { -+ .name = "jz-clockenvent", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ -+ -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 300, -+ .irq = JZ_TIMER_IRQ, -+ .set_mode = jz_set_mode, -+ .set_next_event = jz_set_next_event, -+}; -+ -+static void __init jz_clockevent_init(void) -+{ -+ struct clock_event_device *cd = &jz_clockevent_device; -+ unsigned int cpu = smp_processor_id(); -+ -+ cd->cpumask = cpumask_of_cpu(cpu); -+ clockevents_register_device(cd); -+} -+ -+static void __init jz_timer_setup(void) -+{ -+ jz_clocksource_init(); /* init jz clock source */ -+ jz_clockevent_init(); /* init jz clock event */ -+ -+ /* -+ * Make irqs happen for the system timer -+ */ -+ jz_irqaction.dev_id = &jz_clockevent_device; -+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); -+} -+ -+ -+void __init plat_time_init(void) -+{ -+ unsigned int latch; -+ -+ /* Init timer */ -+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; -+ -+ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN; -+ REG_TCU_OSTCNT = 0; -+ REG_TCU_OSTDR = latch; -+ -+ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */ -+ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */ -+ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */ -+ -+ jz_timer_setup(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/Makefile linux-2.6.24.7/arch/mips/jz4750d/Makefile ---- linux-2.6.24.7.old/arch/mips/jz4750d/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,22 @@ -+# -+# Makefile for the Ingenic JZ4750D. -+# -+ -+# Object file lists. -+ -+obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ -+ platform.o i2c.o -+ -+obj-$(CONFIG_PROC_FS) += proc.o -+ -+# board specific support -+ -+obj-$(CONFIG_JZ4750D_FUWA1) += board-fuwa1.o -+ -+# PM support -+ -+obj-$(CONFIG_PM_LEGACY) +=pm.o -+ -+# CPU Frequency scaling support -+ -+obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/board-fuwa1.c linux-2.6.24.7/arch/mips/jz4750d/board-fuwa1.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/board-fuwa1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/board-fuwa1.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,72 @@ -+/* -+ * linux/arch/mips/jz4750d/board-fuwa1.c -+ * -+ * JZ4750D FUWA1 board setup routines. -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+extern void (*jz_timer_callback)(void); -+ -+static void dancing(void) -+{ -+ static unsigned char slash[] = "\\|/-"; -+// static volatile unsigned char *p = (unsigned char *)0xb6000058; -+ static volatile unsigned char *p = (unsigned char *)0xb6000016; -+ static unsigned int count = 0; -+ *p = slash[count++]; -+ count &= 3; -+} -+ -+static void fuwa1_timer_callback(void) -+{ -+ static unsigned long count = 0; -+ -+ if ((++count) % 50 == 0) { -+ dancing(); -+ count = 0; -+ } -+} -+ -+static void __init board_cpm_setup(void) -+{ -+ /* Stop unused module clocks here. -+ * We have started all module clocks at arch/mips/jz4750d/setup.c. -+ */ -+} -+ -+static void __init board_gpio_setup(void) -+{ -+ /* -+ * Initialize SDRAM pins -+ */ -+} -+ -+void __init jz_board_setup(void) -+{ -+ printk("JZ4750D FUWA1 board setup\n"); -+ -+ board_cpm_setup(); -+ board_gpio_setup(); -+ -+ jz_timer_callback = fuwa1_timer_callback; -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/cpufreq.c linux-2.6.24.7/arch/mips/jz4750d/cpufreq.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/cpufreq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,601 @@ -+/* -+ * linux/arch/mips/jz4750d/cpufreq.c -+ * -+ * cpufreq driver for JZ4750D -+ * -+ * Copyright (c) 2006-2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ -+ "cpufreq-jz4750d", msg) -+ -+#undef CHANGE_PLL -+ -+#define PLL_UNCHANGED 0 -+#define PLL_GOES_UP 1 -+#define PLL_GOES_DOWN 2 -+ -+#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) -+ -+/* Saved the boot-time parameters */ -+static struct { -+ /* SDRAM parameters */ -+ unsigned int mclk; /* memory clock, KHz */ -+ unsigned int tras; /* RAS pulse width, cycles of mclk */ -+ unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ -+ unsigned int tpc; /* RAS Precharge time, cycles of mclk */ -+ unsigned int trwl; /* Write Precharge Time, cycles of mclk */ -+ unsigned int trc; /* RAS Cycle Time, cycles of mclk */ -+ unsigned int rtcor; /* Refresh Time Constant */ -+ unsigned int sdram_initialized; -+ -+ /* LCD parameters */ -+ unsigned int lcd_clk; /* LCD clock, Hz */ -+ unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ -+ unsigned int lcd_clks_initialized; -+} boot_config; -+ -+struct jz4750d_freq_percpu_info { -+ struct cpufreq_frequency_table table[7]; -+}; -+ -+static struct jz4750d_freq_percpu_info jz4750d_freq_table; -+ -+/* -+ * This contains the registers value for an operating point. -+ * If only part of a register needs to change then there is -+ * a mask value for that register. -+ * When going to a new operating point the current register -+ * value is ANDed with the ~mask and ORed with the new value. -+ */ -+struct dpm_regs { -+ u32 cpccr; /* Clock Freq Control Register */ -+ u32 cpccr_mask; /* Clock Freq Control Register mask */ -+ u32 cppcr; /* PLL1 Control Register */ -+ u32 cppcr_mask; /* PLL1 Control Register mask */ -+ u32 pll_up_flag; /* New PLL freq is higher than current or not */ -+}; -+ -+extern jz_clocks_t jz_clocks; -+ -+static void jz_update_clocks(void) -+{ -+ /* Next clocks must be updated if we have changed -+ * the PLL or divisors. -+ */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(0); -+} -+ -+static void -+jz_init_boot_config(void) -+{ -+ if (!boot_config.lcd_clks_initialized) { -+ /* the first time to scale pll */ -+ boot_config.lcd_clk = __cpm_get_lcdclk(); -+ boot_config.lcdpix_clk = __cpm_get_pixclk(); -+ boot_config.lcd_clks_initialized = 1; -+ } -+ -+ if (!boot_config.sdram_initialized) { -+ /* the first time to scale frequencies */ -+ unsigned int dmcr, rtcor; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ -+ dmcr = REG_EMC_DMCR; -+ rtcor = REG_EMC_RTCOR; -+ -+ tras = (dmcr >> 13) & 0x7; -+ rcd = (dmcr >> 11) & 0x3; -+ tpc = (dmcr >> 8) & 0x7; -+ trwl = (dmcr >> 5) & 0x3; -+ trc = (dmcr >> 2) & 0x7; -+ -+ boot_config.mclk = __cpm_get_mclk() / 1000; -+ boot_config.tras = tras + 4; -+ boot_config.rcd = rcd + 1; -+ boot_config.tpc = tpc + 1; -+ boot_config.trwl = trwl + 1; -+ boot_config.trc = trc * 2 + 1; -+ boot_config.rtcor = rtcor; -+ -+ boot_config.sdram_initialized = 1; -+ } -+} -+ -+static void jz_update_dram_rtcor(unsigned int new_mclk) -+{ -+ unsigned int rtcor; -+ -+ new_mclk /= 1000; -+ rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; -+ rtcor--; -+ -+ if (rtcor < 1) rtcor = 1; -+ if (rtcor > 255) rtcor = 255; -+ -+ REG_EMC_RTCOR = rtcor; -+ REG_EMC_RTCNT = rtcor; -+} -+ -+static void jz_update_dram_dmcr(unsigned int new_mclk) -+{ -+ unsigned int dmcr; -+ unsigned int tras, rcd, tpc, trwl, trc; -+ unsigned int valid_time, new_time; /* ns */ -+ -+ new_mclk /= 1000; -+ tras = boot_config.tras * new_mclk / boot_config.mclk; -+ rcd = boot_config.rcd * new_mclk / boot_config.mclk; -+ tpc = boot_config.tpc * new_mclk / boot_config.mclk; -+ trwl = boot_config.trwl * new_mclk / boot_config.mclk; -+ trc = boot_config.trc * new_mclk / boot_config.mclk; -+ -+ /* Validation checking */ -+ valid_time = (boot_config.tras * 1000000) / boot_config.mclk; -+ new_time = (tras * 1000000) / new_mclk; -+ if (new_time < valid_time) tras += 1; -+ -+ valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; -+ new_time = (rcd * 1000000) / new_mclk; -+ if (new_time < valid_time) rcd += 1; -+ -+ valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; -+ new_time = (tpc * 1000000) / new_mclk; -+ if (new_time < valid_time) tpc += 1; -+ -+ valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; -+ new_time = (trwl * 1000000) / new_mclk; -+ if (new_time < valid_time) trwl += 1; -+ -+ valid_time = (boot_config.trc * 1000000) / boot_config.mclk; -+ new_time = (trc * 1000000) / new_mclk; -+ if (new_time < valid_time) trc += 2; -+ -+ tras = (tras < 4) ? 4: tras; -+ tras = (tras > 11) ? 11: tras; -+ tras -= 4; -+ -+ rcd = (rcd < 1) ? 1: rcd; -+ rcd = (rcd > 4) ? 4: rcd; -+ rcd -= 1; -+ -+ tpc = (tpc < 1) ? 1: tpc; -+ tpc = (tpc > 8) ? 8: tpc; -+ tpc -= 1; -+ -+ trwl = (trwl < 1) ? 1: trwl; -+ trwl = (trwl > 4) ? 4: trwl; -+ trwl -= 1; -+ -+ trc = (trc < 1) ? 1: trc; -+ trc = (trc > 15) ? 15: trc; -+ trc /= 2; -+ -+ dmcr = REG_EMC_DMCR; -+ -+ dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); -+ dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); -+ -+ REG_EMC_DMCR = dmcr; -+} -+ -+static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR before changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } else { -+ /* We're going SLOWER: first update RTCOR value -+ * before changing the frequency. -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } -+} -+ -+static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) -+{ -+ /* No risk, no fun: run with interrupts on! */ -+ if (new_mclk > cur_mclk) { -+ /* We're going FASTER, so update RTCOR -+ * after changing the frequency -+ */ -+ jz_update_dram_rtcor(new_mclk); -+ } else { -+ /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL -+ * and TRC of DMCR after changing the frequency. -+ */ -+ jz_update_dram_dmcr(new_mclk); -+ } -+} -+ -+static void jz_scale_divisors(struct dpm_regs *regs) -+{ -+ unsigned int cpccr; -+ unsigned int cur_mclk, new_mclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~((unsigned long)regs->cpccr_mask); -+ cpccr |= regs->cpccr; -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; -+ -+ /* Update some DRAM parameters before changing frequency */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+ -+#ifdef CHANGE_PLL -+/* Maintain the LCD clock and pixel clock */ -+static void jz_scale_lcd_divisors(struct dpm_regs *regs) -+{ -+ unsigned int new_pll, new_lcd_div, new_lcdpix_div; -+ unsigned int cpccr; -+ unsigned int tmp = 0, wait = PLL_WAIT_500NS; -+ -+ if (!boot_config.lcd_clks_initialized) return; -+ -+ new_pll = __cpm_get_pllout(); -+ new_lcd_div = new_pll / boot_config.lcd_clk; -+ new_lcdpix_div = new_pll / boot_config.lcdpix_clk; -+ -+ if (new_lcd_div < 1) -+ new_lcd_div = 1; -+ if (new_lcd_div > 16) -+ new_lcd_div = 16; -+ -+ if (new_lcdpix_div < 1) -+ new_lcdpix_div = 1; -+ if (new_lcdpix_div > 512) -+ new_lcdpix_div = 512; -+ -+// REG_CPM_CPCCR2 = new_lcdpix_div - 1; -+ -+ cpccr = REG_CPM_CPCCR; -+ cpccr &= ~CPM_CPCCR_LDIV_MASK; -+ cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); -+ cpccr |= CPM_CPCCR_CE; /* update immediately */ -+ -+ /* update register to change the clocks. -+ * align this code to a cache line. -+ */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "li %3,0\n\t" -+ "1:\n\t" -+ "bne %3,%2,1b\n\t" -+ "addi %3, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); -+} -+ -+static void jz_scale_pll(struct dpm_regs *regs) -+{ -+ unsigned int cppcr; -+ unsigned int cur_mclk, new_mclk, new_pll; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ int od[] = {1, 2, 2, 4}; -+ -+ cppcr = REG_CPM_CPPCR; -+ cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); -+ regs->cppcr &= ~CPM_CPPCR_PLLEN; -+ cppcr |= (regs->cppcr | 0xff); -+ -+ /* Update some DRAM parameters before changing frequency */ -+ new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); -+ cur_mclk = __cpm_get_mclk(); -+ new_mclk = new_pll / div[(REG_CPM_CPCCR>>16) & 0xf]; -+ -+ /* -+ * Update some SDRAM parameters -+ */ -+ jz_update_dram_prev(cur_mclk, new_mclk); -+ -+ /* -+ * Update PLL, align code to cache line. -+ */ -+ cppcr |= CPM_CPPCR_PLLEN; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (CPM_CPPCR), "r" (cppcr)); -+ -+ /* Update some other DRAM parameters after changing frequency */ -+ jz_update_dram_post(cur_mclk, new_mclk); -+} -+#endif -+ -+static void jz4750d_transition(struct dpm_regs *regs) -+{ -+ /* -+ * Get and save some boot-time conditions. -+ */ -+ jz_init_boot_config(); -+ -+#ifdef CHANGE_PLL -+ /* -+ * Disable LCD before scaling pll. -+ * LCD and LCD pixel clocks should not be changed even if the PLL -+ * output frequency has been changed. -+ */ -+ REG_LCD_CTRL &= ~LCD_CTRL_ENA; -+ -+ /* -+ * Stop module clocks before scaling PLL -+ */ -+ __cpm_stop_eth(); -+ __cpm_stop_aic(1); -+ __cpm_stop_aic(2); -+#endif -+ -+ /* ... add more as necessary */ -+ -+ if (regs->pll_up_flag == PLL_GOES_UP) { -+ /* the pll frequency is going up, so change dividors first */ -+ jz_scale_divisors(regs); -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ } -+ else if (regs->pll_up_flag == PLL_GOES_DOWN) { -+ /* the pll frequency is going down, so change pll first */ -+#ifdef CHANGE_PLL -+ jz_scale_pll(regs); -+#endif -+ jz_scale_divisors(regs); -+ } -+ else { -+ /* the pll frequency is unchanged, so change divisors only */ -+ jz_scale_divisors(regs); -+ } -+ -+#ifdef CHANGE_PLL -+ /* -+ * Restart module clocks before scaling PLL -+ */ -+ __cpm_start_eth(); -+ __cpm_start_aic(1); -+ __cpm_start_aic(2); -+ -+ /* ... add more as necessary */ -+ -+ /* Scale the LCD divisors after scaling pll */ -+ if (regs->pll_up_flag != PLL_UNCHANGED) { -+ jz_scale_lcd_divisors(regs); -+ } -+ -+ /* Enable LCD controller */ -+ REG_LCD_CTRL &= ~LCD_CTRL_DIS; -+ REG_LCD_CTRL |= LCD_CTRL_ENA; -+#endif -+ -+ /* Update system clocks */ -+ jz_update_clocks(); -+} -+ -+extern unsigned int idle_times; -+static unsigned int jz4750d_freq_get(unsigned int cpu) -+{ -+ return (__cpm_get_cclk() / 1000); -+} -+ -+static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) -+{ -+ int n2FR[33] = { -+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, -+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, -+ 9 -+ }; -+ int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ -+ unsigned int div_of_cclk, new_freq, i; -+ -+ regs->pll_up_flag = PLL_UNCHANGED; -+ regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; -+ -+ new_freq = jz4750d_freq_table.table[index].frequency; -+ -+ do { -+ div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); -+ } while (div_of_cclk==0); -+ -+ if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { -+ for(i = 1; i<4; i++) { -+ div[i] = 3; -+ } -+ } else { -+ for(i = 1; i<4; i++) { -+ div[i] = 2; -+ } -+ } -+ -+ for(i = 0; i<4; i++) { -+ div[i] *= div_of_cclk; -+ } -+ -+ dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); -+ -+ regs->cpccr = -+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | -+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | -+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | -+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); -+ -+ return div_of_cclk; -+} -+ -+static void jz4750d_set_cpu_divider_index(unsigned int cpu, unsigned int index) -+{ -+ unsigned long divisor, old_divisor; -+ struct cpufreq_freqs freqs; -+ struct dpm_regs regs; -+ -+ old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); -+ divisor = index_to_divisor(index, ®s); -+ -+ freqs.old = __cpm_get_cclk() / 1000; -+ freqs.new = __cpm_get_pllout() / (1000 * divisor); -+ freqs.cpu = cpu; -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -+ -+ if (old_divisor != divisor) -+ jz4750d_transition(®s); -+ -+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -+} -+ -+static int jz4750d_freq_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ unsigned int new_index = 0; -+ -+ if (cpufreq_frequency_table_target(policy, -+ &jz4750d_freq_table.table[0], -+ target_freq, relation, &new_index)) -+ return -EINVAL; -+ -+ jz4750d_set_cpu_divider_index(policy->cpu, new_index); -+ -+ dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); -+ -+ return 0; -+} -+ -+static int jz4750d_freq_verify(struct cpufreq_policy *policy) -+{ -+ return cpufreq_frequency_table_verify(policy, -+ &jz4750d_freq_table.table[0]); -+} -+ -+static int __init jz4750d_cpufreq_driver_init(struct cpufreq_policy *policy) -+{ -+ -+ struct cpufreq_frequency_table *table = &jz4750d_freq_table.table[0]; -+ unsigned int MAX_FREQ; -+ -+ dprintk(KERN_INFO "Jz4750d cpufreq driver\n"); -+ -+ if (policy->cpu != 0) -+ return -EINVAL; -+ -+ policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ -+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; -+ -+ policy->cpuinfo.min_freq = MAX_FREQ/8; -+ policy->cpuinfo.max_freq = MAX_FREQ; -+ policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ -+ -+ table[0].index = 0; -+ table[0].frequency = MAX_FREQ/8; -+ table[1].index = 1; -+ table[1].frequency = MAX_FREQ/6; -+ table[2].index = 2; -+ table[2].frequency = MAX_FREQ/4; -+ table[3].index = 3; -+ table[3].frequency = MAX_FREQ/3; -+ table[4].index = 4; -+ table[4].frequency = MAX_FREQ/2; -+ table[5].index = 5; -+ table[5].frequency = MAX_FREQ; -+ table[6].index = 6; -+ table[6].frequency = CPUFREQ_TABLE_END; -+ -+#ifdef CONFIG_CPU_FREQ_STAT_DETAILS -+ cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ -+#endif -+ -+ return cpufreq_frequency_table_cpuinfo(policy, table); -+} -+ -+static struct cpufreq_driver cpufreq_jz4750d_driver = { -+// .flags = CPUFREQ_STICKY, -+ .init = jz4750d_cpufreq_driver_init, -+ .verify = jz4750d_freq_verify, -+ .target = jz4750d_freq_target, -+ .get = jz4750d_freq_get, -+ .name = "jz4750d", -+}; -+ -+static int __init jz4750d_cpufreq_init(void) -+{ -+ return cpufreq_register_driver(&cpufreq_jz4750d_driver); -+} -+ -+static void __exit jz4750d_cpufreq_exit(void) -+{ -+ cpufreq_unregister_driver(&cpufreq_jz4750d_driver); -+} -+ -+module_init(jz4750d_cpufreq_init); -+module_exit(jz4750d_cpufreq_exit); -+ -+MODULE_AUTHOR("Regen "); -+MODULE_DESCRIPTION("cpufreq driver for Jz4750d"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/dma.c linux-2.6.24.7/arch/mips/jz4750d/dma.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/dma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/dma.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,822 @@ -+/* -+ * linux/arch/mips/jz4750d/dma.c -+ * -+ * Support functions for the JZ4750D internal DMA channels. -+ * No-descriptor transfer only. -+ * Descriptor transfer should also call jz_request_dma() to get a free -+ * channel and call jz_free_dma() to free the channel. And driver should -+ * build the DMA descriptor and setup the DMA channel by itself. -+ * -+ * Copyright (C) 2006 - 2008 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * A note on resource allocation: -+ * -+ * All drivers needing DMA channels, should allocate and release them -+ * through the public routines `jz_request_dma()' and `jz_free_dma()'. -+ * -+ * In order to avoid problems, all processes should allocate resources in -+ * the same sequence and release them in the reverse order. -+ * -+ * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. -+ * When releasing them, first release the IRQ, then release the DMA. The -+ * main reason for this order is that, if you are requesting the DMA buffer -+ * done interrupt, you won't know the irq number until the DMA channel is -+ * returned from jz_request_dma(). -+ */ -+ -+struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { -+ {dev_id:DMA_ID_BCH_ENC,}, /* DMAC0 channel 0, reserved for BCH */ -+ {dev_id:-1,}, /* DMAC0 channel 1 */ -+ {dev_id:-1,}, /* DMAC0 channel 2 */ -+ {dev_id:-1,}, /* DMAC0 channel 3 */ -+ {dev_id:-1,}, /* DMAC1 channel 0 */ -+ {dev_id:-1,}, /* DMAC1 channel 1 */ -+ {dev_id:-1,}, /* DMAC1 channel 2 */ -+ {dev_id:-1,}, /* DMAC1 channel 3 */ -+}; -+ -+// Device FIFO addresses and default DMA modes -+static const struct { -+ unsigned int fifo_addr; -+ unsigned int dma_mode; -+ unsigned int dma_source; -+} dma_dev_table[DMA_ID_MAX] = { -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_EXT}, /* External request with DREQn */ -+ {0x18000000, DMA_AUTOINIT, DMAC_DRSR_RS_NAND}, /* NAND request */ -+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_ENC}, -+ {CPHYSADDR(BCH_DR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_BCH_DEC}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, -+// {CPHYSADDR(TSSI_FIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_TSSIIN}, -+ {CPHYSADDR(UART3_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART3OUT}, -+ {CPHYSADDR(UART3_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART3IN}, -+ {CPHYSADDR(UART2_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART2OUT}, -+ {CPHYSADDR(UART2_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART2IN}, -+ {CPHYSADDR(UART1_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART1OUT}, -+ {CPHYSADDR(UART1_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART1IN}, -+ {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, -+ {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, -+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI0OUT}, -+ {CPHYSADDR(SSI_DR(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI0IN}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, -+ {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, -+ {CPHYSADDR(MSC_TXFIFO(0)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC0OUT}, -+ {CPHYSADDR(MSC_RXFIFO(0)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC0IN}, -+ {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, -+ {SADC_TSDAT, DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SADC},/* Touch Screen Data Register */ -+ {CPHYSADDR(MSC_TXFIFO(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSC1OUT}, /* SSC1 TX */ -+ {CPHYSADDR(MSC_RXFIFO(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSC1IN}, /* SSC1 RX */ -+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSI1OUT}, -+ {CPHYSADDR(SSI_DR(1)), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSI1IN}, -+ {CPHYSADDR(PCM_DP), DMA_16BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_PMOUT}, -+ {CPHYSADDR(PCM_DP), DMA_16BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_PMIN}, -+ {}, -+}; -+ -+ -+int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data) -+{ -+ int i, len = 0; -+ struct jz_dma_chan *chan; -+ -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if ((chan = get_dma_chan(i)) != NULL) { -+ len += sprintf(buf + len, "%2d: %s\n", -+ i, chan->dev_str); -+ } -+ } -+ -+ if (fpos >= len) { -+ *start = buf; -+ *eof = 1; -+ return 0; -+ } -+ *start = buf + fpos; -+ if ((len -= fpos) > length) -+ return length; -+ *eof = 1; -+ return len; -+} -+ -+ -+void dump_jz_dma_channel(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return; -+ chan = &jz_dma_table[dmanr]; -+ -+ printk("DMA%d Registers:\n", dmanr); -+ printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR(chan->io/HALF_DMA_NUM)); -+ printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); -+ printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); -+ printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); -+ printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); -+ printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); -+ printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); -+ printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); -+ printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR(chan->io/HALF_DMA_NUM)); -+} -+ -+ -+/** -+ * jz_request_dma - dynamically allcate an idle DMA channel to return -+ * @dev_id: the specified dma device id or DMA_ID_RAW_SET -+ * @dev_str: the specified dma device string name -+ * @irqhandler: the irq handler, or NULL -+ * @irqflags: the irq handler flags -+ * @irq_dev_id: the irq handler device id for shared irq -+ * -+ * Finds a free channel, and binds the requested device to it. -+ * Returns the allocated channel number, or negative on error. -+ * Requests the DMA done IRQ if irqhandler != NULL. -+ * -+*/ -+/*int jz_request_dma(int dev_id, const char *dev_str, -+ void (*irqhandler)(int, void *, struct pt_regs *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+*/ -+ -+int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id) -+{ -+ struct jz_dma_chan *chan; -+ int i, ret; -+ -+ if (dev_id < 0 || dev_id >= DMA_ID_MAX) -+ return -EINVAL; -+ -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) /* no free channel */ -+ return -ENODEV; -+ -+ /* we got a free channel */ -+ chan = &jz_dma_table[i]; -+ -+ if (irqhandler) { -+ chan->irq = IRQ_DMA_0 + i; // allocate irq number -+ chan->irq_dev = irq_dev_id; -+ if ((ret = request_irq(chan->irq, irqhandler, irqflags, -+ dev_str, chan->irq_dev))) { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ return ret; -+ } -+ } else { -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ } -+ -+ // fill it in -+ chan->io = i; -+ chan->dev_id = dev_id; -+ chan->dev_str = dev_str; -+ chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; -+ chan->mode = dma_dev_table[dev_id].dma_mode; -+ chan->source = dma_dev_table[dev_id].dma_source; -+ -+ if (i < HALF_DMA_NUM) -+ REG_DMAC_DMACKE(0) = 1 << i; -+ else -+ REG_DMAC_DMACKE(1) = 1 << (i - HALF_DMA_NUM); -+ -+ return i; -+} -+ -+void jz_free_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) { -+ printk("Trying to free DMA%d\n", dmanr); -+ return; -+ } -+ -+ disable_dma(dmanr); -+ if (chan->irq) -+ free_irq(chan->irq, chan->irq_dev); -+ -+ chan->irq = -1; -+ chan->irq_dev = NULL; -+ chan->dev_id = -1; -+} -+ -+void jz_set_dma_dest_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_DWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_src_width(int dmanr, int nbit) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_SWDH_MASK; -+ switch (nbit) { -+ case 8: -+ chan->mode |= DMAC_DCMD_SWDH_8; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_SWDH_16; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_SWDH_32; -+ break; -+ } -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode &= ~DMAC_DCMD_DS_MASK; -+ switch (nbyte) { -+ case 1: -+ chan->mode |= DMAC_DCMD_DS_8BIT; -+ break; -+ case 2: -+ chan->mode |= DMAC_DCMD_DS_16BIT; -+ break; -+ case 4: -+ chan->mode |= DMAC_DCMD_DS_32BIT; -+ break; -+ case 16: -+ chan->mode |= DMAC_DCMD_DS_16BYTE; -+ break; -+ case 32: -+ chan->mode |= DMAC_DCMD_DS_32BYTE; -+ break; -+ } -+} -+ -+unsigned int jz_get_dma_command(int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ return chan->mode; -+} -+ -+/** -+ * jz_set_dma_mode - do the raw settings for the specified DMA channel -+ * @dmanr: the specified DMA channel -+ * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE -+ * @dma_mode: dma raw mode -+ * @dma_source: dma raw request source -+ * @fifo_addr: dma raw device fifo address -+ * -+ * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call -+ * jz_set_dma_mode() rather than set_dma_mode() if you work with -+ * and external request dma device. -+ * -+ * NOTE: Don not dynamically allocate dma channel if one external request -+ * dma device will occupy this channel. -+*/ -+int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, -+ unsigned int dma_mode, unsigned int dma_source, -+ unsigned int fifo_addr) -+{ -+ int dev_id, i; -+ struct jz_dma_chan *chan; -+ -+ if (dmanr > MAX_DMA_NUM) -+ return -ENODEV; -+ for (i = 0; i < MAX_DMA_NUM; i++) { -+ if (jz_dma_table[i].dev_id < 0) -+ break; -+ } -+ if (i == MAX_DMA_NUM) -+ return -ENODEV; -+ -+ chan = &jz_dma_table[dmanr]; -+ dev_id = chan->dev_id; -+ if (dev_id > 0) { -+ printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", -+ __FUNCTION__, dmanr); -+ return -ENODEV; -+ } -+ -+ /* clone it from the dynamically allocated. */ -+ if (i != dmanr) { -+ chan->irq = jz_dma_table[i].irq; -+ chan->irq_dev = jz_dma_table[i].irq_dev; -+ chan->dev_str = jz_dma_table[i].dev_str; -+ jz_dma_table[i].irq = 0; -+ jz_dma_table[i].irq_dev = NULL; -+ jz_dma_table[i].dev_id = -1; -+ } -+ chan->dev_id = DMA_ID_RAW_SET; -+ chan->io = dmanr; -+ chan->fifo_addr = fifo_addr; -+ chan->mode = dma_mode; -+ chan->source = dma_source; -+ -+ set_dma_mode(dmanr, dma_mode); -+ -+ return dmanr; -+} -+ -+void enable_dma(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ -+ __dmac_enable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_enable_irq(dmanr); -+} -+ -+#define DMA_DISABLE_POLL 0x10000 -+ -+void disable_dma(unsigned int dmanr) -+{ -+ int i; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ if (!__dmac_channel_enabled(dmanr)) -+ return; -+ -+ for (i = 0; i < DMA_DISABLE_POLL; i++) -+ if (__dmac_channel_transmit_end_detected(dmanr)) -+ break; -+#if 0 -+ if (i == DMA_DISABLE_POLL) -+ printk(KERN_INFO "disable_dma: poll expired!\n"); -+#endif -+ -+ __dmac_disable_channel(dmanr); -+ if (chan->irq) -+ __dmac_channel_disable_irq(dmanr); -+} -+ -+/* Note: DMA_MODE_MASK is simulated by sw */ -+void set_dma_mode(unsigned int dmanr, unsigned int mode) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else { -+ printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ } -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+} -+ -+void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) -+{ -+ unsigned int mode; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ mode = chan->mode & DMA_MODE_MASK; -+ if (mode == DMA_MODE_READ) { -+ REG_DMAC_DSAR(chan->io) = chan->fifo_addr; -+ REG_DMAC_DTAR(chan->io) = phyaddr; -+ } else if (mode == DMA_MODE_WRITE) { -+ REG_DMAC_DSAR(chan->io) = phyaddr; -+ REG_DMAC_DTAR(chan->io) = chan->fifo_addr; -+ } else -+ printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); -+} -+ -+void set_dma_count(unsigned int dmanr, unsigned int bytecnt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ unsigned int ds; -+ -+ if (!chan) -+ return; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ REG_DMAC_DTCR(chan->io) = bytecnt / dma_ds[ds]; // transfer count -+} -+ -+unsigned int get_dma_residue(unsigned int dmanr) -+{ -+ unsigned int count, ds; -+ int dma_ds[] = {4, 1, 2, 16, 32}; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ -+ ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; -+ count = REG_DMAC_DTCR(chan->io); -+ count = count * dma_ds[ds]; -+ -+ return count; -+} -+ -+void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case AFMT_U8: -+ /* burst mode : 32BIT */ -+ break; -+ case AFMT_S16_LE: -+ /* burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ //chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ -+ if (!chan) -+ return; -+ -+ switch (audio_fmt) { -+ case 8: -+ /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ -+ break; -+ case 16: -+ /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ -+ if (mode == DMA_MODE_READ) { -+ chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_DAI; -+ chan->mode &= ~DMAC_DCMD_SAI; -+ } else if (mode == DMA_MODE_WRITE) { -+ chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; -+ chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); -+ mode &= DMA_MODE_MASK; -+ chan->mode |= DMAC_DCMD_SAI; -+ chan->mode &= ~DMAC_DCMD_DAI; -+ } else -+ printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); -+ -+ REG_DMAC_DCMD(chan->io) = chan->mode & ~DMA_MODE_MASK; -+ REG_DMAC_DRSR(chan->io) = chan->source; -+ break; -+ } -+} -+ -+//#define JZ4750D_DMAC_TEST_ENABLE -+#undef JZ4750D_DMAC_TEST_ENABLE -+ -+#ifdef JZ4750D_DMAC_TEST_ENABLE -+ -+/* -+ * DMA test: external address <--> external address -+ */ -+#define TEST_DMA_SIZE 16*1024 -+ -+static jz_dma_desc *dma_desc; -+ -+static int dma_chan; -+static dma_addr_t dma_desc_phys_addr; -+static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; -+ -+static int dma_check_result(void *src, void *dst, int size) -+{ -+ unsigned int addr1, addr2, i, err = 0; -+ -+ addr1 = (unsigned int)src; -+ addr2 = (unsigned int)dst; -+ -+ for (i = 0; i < size; i += 4) { -+ if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { -+ err++; -+ printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); -+ } -+ addr1 += 4; -+ addr2 += 4; -+ } -+ printk("check DMA result err=%d\n", err); -+ return err; -+} -+ -+static irqreturn_t jz4750d_dma_irq(int irq, void *dev_id) -+{ -+ printk("jz4750d_dma_irq %d\n", irq); -+ -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ printk("DMA HALT\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ printk("DMA ADDR ERROR\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ REG_DMAC_DSAR(dma_chan) = 0; /* clear source address register */ -+ REG_DMAC_DTAR(dma_chan) = 0; /* clear target address register */ -+ __dmac_channel_clear_address_error(dma_chan); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ printk("DMA DESC INVALID\n"); -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ } -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ printk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ } -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ printk("DMA TT\n"); -+ __dmac_channel_clear_transmit_end(dma_chan); -+ dump_jz_dma_channel(dma_chan); -+ dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+void dma_nodesc_test(void) -+{ -+ unsigned int addr, i; -+ -+ printk("dma_nodesc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq, -+ IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Init DMA module */ -+ printk("Starting DMA\n"); -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; -+ REG_DMAC_DCCSR(dma_chan) = 0; -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = 512; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+ -+ /* wait a long time, ensure transfer end */ -+ printk("wait 3s...\n"); -+ mdelay(3000); /* wait 3s */ -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ /* free buffers */ -+ printk("free DMA buffers\n"); -+ free_pages(dma_src_addr, 2); -+ free_pages(dma_dst_addr, 2); -+ -+ if (dma_desc) -+ free_pages((unsigned int)dma_desc, 0); -+ -+ /* free dma */ -+ jz_free_dma(dma_chan); -+} -+ -+void dma_desc_test(void) -+{ -+ unsigned int next, addr, i; -+ static jz_dma_desc *desc; -+ -+ printk("dma_desc_test\n"); -+ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4750d_dma_irq, -+ IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq failed\n"); -+ return; -+ } -+ -+ printk("Requested DMA channel = %d\n", dma_chan); -+ -+ /* Allocate DMA buffers */ -+ dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ -+ -+ dma_src_phys_addr = CPHYSADDR(dma_src_addr); -+ dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); -+ -+ printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); -+ -+ /* Prepare data for source buffer */ -+ addr = (unsigned int)dma_src_addr; -+ for (i = 0; i < TEST_DMA_SIZE; i += 4) { -+ *(volatile unsigned int *)addr = addr; -+ addr += 4; -+ } -+ dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); -+ -+ /* Init target buffer */ -+ memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); -+ dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); -+ -+ /* Allocate DMA descriptors */ -+ dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); -+ dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); -+ -+ printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); -+ -+ /* Setup DMA descriptors */ -+ desc = dma_desc; -+ next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr; /* DMA target address */ -+ desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; -+ desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ -+ desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ -+ -+ desc++; -+ next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; -+ -+ desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; -+ desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ -+ desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ -+ desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ -+ -+ dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ REG_DMAC_DMADBSR(dma_chan/HALF_DMA_NUM) = 1 << dma_chan; -+ -+ printk("DMA started. IMR=%08x\n", REG_INTC_IMR); -+ /* wait a long time, ensure transfer end */ -+ printk("wait 3s...\n"); -+ mdelay(3000); /* wait 3s */ -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ /* free buffers */ -+ printk("free DMA buffers\n"); -+ free_pages(dma_src_addr, 2); -+ free_pages(dma_dst_addr, 2); -+ -+ if (dma_desc) -+ free_pages((unsigned int)dma_desc, 0); -+ -+ /* free dma */ -+ jz_free_dma(dma_chan); -+} -+ -+#endif -+ -+//EXPORT_SYMBOL_NOVERS(jz_dma_table); -+EXPORT_SYMBOL(jz_dma_table); -+EXPORT_SYMBOL(jz_request_dma); -+EXPORT_SYMBOL(jz_free_dma); -+EXPORT_SYMBOL(jz_set_dma_src_width); -+EXPORT_SYMBOL(jz_set_dma_dest_width); -+EXPORT_SYMBOL(jz_set_dma_block_size); -+EXPORT_SYMBOL(jz_set_dma_mode); -+EXPORT_SYMBOL(set_dma_mode); -+EXPORT_SYMBOL(jz_set_oss_dma); -+EXPORT_SYMBOL(jz_set_alsa_dma); -+EXPORT_SYMBOL(set_dma_addr); -+EXPORT_SYMBOL(set_dma_count); -+EXPORT_SYMBOL(get_dma_residue); -+EXPORT_SYMBOL(enable_dma); -+EXPORT_SYMBOL(disable_dma); -+EXPORT_SYMBOL(dump_jz_dma_channel); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/i2c.c linux-2.6.24.7/arch/mips/jz4750d/i2c.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/i2c.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,273 @@ -+/* -+ * linux/arch/mips/jz4750d/i2c.c -+ * -+ * Jz4750D I2C routines. -+ * -+ * Copyright (C) 2005,2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* I2C protocol */ -+#define I2C_READ 1 -+#define I2C_WRITE 0 -+ -+#define TIMEOUT 1000 -+ -+/* -+ * I2C bus protocol basic routines -+ */ -+static int i2c_put_data(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (!__i2c_received_ack() && timeout) -+ timeout--; -+ -+ if (timeout) -+ return 0; -+ else -+ return -ETIMEDOUT; -+} -+ -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+static int i2c_put_data_nack(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (timeout--); -+ return 0; -+} -+#endif -+ -+static int i2c_get_data(unsigned char *data, int ack) -+{ -+ int timeout = TIMEOUT*10; -+ -+ if (!ack) -+ __i2c_send_nack(); -+ else -+ __i2c_send_ack(); -+ -+ while (__i2c_check_drf() == 0 && timeout) -+ timeout--; -+ -+ if (timeout) { -+ if (!ack) -+ __i2c_send_stop(); -+ *data = __i2c_read(); -+ __i2c_clear_drf(); -+ return 0; -+ } else -+ return -ETIMEDOUT; -+} -+ -+/* -+ * I2C interface -+ */ -+void i2c_open(void) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ -+ __i2c_enable(); -+} -+ -+void i2c_close(void) -+{ -+ udelay(300); /* wait for STOP goes over. */ -+ __i2c_disable(); -+} -+ -+void i2c_setclk(unsigned int i2cclk) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, i2cclk); -+} -+ -+int i2c_lseek(unsigned char device, unsigned char offset) -+{ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (i2c_put_data(offset) < 0) -+ goto address_err; -+ return 0; -+ device_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) installed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+ address_err: -+ printk(KERN_DEBUG "No I2C device (0x%02x) response.\n", device); -+ __i2c_send_stop(); -+ return -EREMOTEIO; -+} -+ -+int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int timeout = 5; -+ -+L_try_again: -+ -+ if (timeout < 0) -+ goto L_timeout; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_werr; -+ if (i2c_put_data(address) < 0) -+ goto address_err; -+ -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_READ ) < 0) -+ goto device_rerr; -+ __i2c_send_ack(); /* Master sends ACK for continue reading */ -+ while (cnt) { -+ if (cnt == 1) { -+ if (i2c_get_data(buf, 0) < 0) -+ break; -+ } else { -+ if (i2c_get_data(buf, 1) < 0) -+ break; -+ } -+ cnt--; -+ buf++; -+ } -+ -+ __i2c_send_stop(); -+ return count - cnt; -+ device_rerr: -+ device_werr: -+ address_err: -+ timeout --; -+ __i2c_send_stop(); -+ goto L_try_again; -+ -+L_timeout: -+ __i2c_send_stop(); -+ printk("Read I2C device 0x%2x failed.\n", device); -+ return -ENODEV; -+} -+ -+int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count) -+{ -+ int cnt = count; -+ int cnt_in_pg; -+ int timeout = 5; -+ unsigned char *tmpbuf; -+ unsigned char tmpaddr; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ W_try_again: -+ if (timeout < 0) -+ goto W_timeout; -+ -+ cnt = count; -+ tmpbuf = (unsigned char *)buf; -+ tmpaddr = address; -+ -+ start_write_page: -+ cnt_in_pg = 0; -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+#ifdef CONFIG_JZ_TPANEL_ATA2508 -+ if (address == 0xff) { -+ if (i2c_put_data_nack(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data_nack(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+ else { -+ -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ } -+#else -+ if (i2c_put_data(tmpaddr) < 0) -+ goto address_err; -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ tmpaddr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+#endif -+ __i2c_send_stop(); -+ return count - cnt; -+ device_err: -+ address_err: -+ timeout--; -+ __i2c_send_stop(); -+ goto W_try_again; -+ -+ W_timeout: -+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+} -+ -+EXPORT_SYMBOL(i2c_open); -+EXPORT_SYMBOL(i2c_close); -+EXPORT_SYMBOL(i2c_setclk); -+EXPORT_SYMBOL(i2c_read); -+EXPORT_SYMBOL(i2c_write); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/irq.c linux-2.6.24.7/arch/mips/jz4750d/irq.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/irq.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,299 @@ -+/* -+ * linux/arch/mips/jz4750d/irq.c -+ * -+ * JZ4750D interrupt routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * INTC irq type -+ */ -+ -+static void enable_intc_irq(unsigned int irq) -+{ -+ __intc_unmask_irq(irq); -+} -+ -+static void disable_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+} -+ -+static void mask_and_ack_intc_irq(unsigned int irq) -+{ -+ __intc_mask_irq(irq); -+ __intc_ack_irq(irq); -+} -+ -+static void end_intc_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_intc_irq(irq); -+ } -+} -+ -+static unsigned int startup_intc_irq(unsigned int irq) -+{ -+ enable_intc_irq(irq); -+ return 0; -+} -+ -+static void shutdown_intc_irq(unsigned int irq) -+{ -+ disable_intc_irq(irq); -+} -+ -+static struct irq_chip intc_irq_type = { -+ .typename = "INTC", -+ .startup = startup_intc_irq, -+ .shutdown = shutdown_intc_irq, -+ .enable = enable_intc_irq, -+ .disable = disable_intc_irq, -+ .ack = mask_and_ack_intc_irq, -+ .end = end_intc_irq, -+}; -+ -+/* -+ * GPIO irq type -+ */ -+ -+static void enable_gpio_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if (irq < (IRQ_GPIO_0 + 32)) { -+ intc_irq = IRQ_GPIO0; -+ } -+ else if (irq < (IRQ_GPIO_0 + 64)) { -+ intc_irq = IRQ_GPIO1; -+ } -+ else if (irq < (IRQ_GPIO_0 + 96)) { -+ intc_irq = IRQ_GPIO2; -+ } -+ else if (irq < (IRQ_GPIO_0 + 128)) { -+ intc_irq = IRQ_GPIO3; -+ } -+ else if (irq < (IRQ_GPIO_0 + 160)) { -+ intc_irq = IRQ_GPIO4; -+ } -+ else { -+ intc_irq = IRQ_GPIO5; -+ } -+ -+ enable_intc_irq(intc_irq); -+ __gpio_unmask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void disable_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+} -+ -+static void mask_and_ack_gpio_irq(unsigned int irq) -+{ -+ __gpio_mask_irq(irq - IRQ_GPIO_0); -+ __gpio_ack_irq(irq - IRQ_GPIO_0); -+} -+ -+static void end_gpio_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_gpio_irq(irq); -+ } -+} -+ -+static unsigned int startup_gpio_irq(unsigned int irq) -+{ -+ enable_gpio_irq(irq); -+ return 0; -+} -+ -+static void shutdown_gpio_irq(unsigned int irq) -+{ -+ disable_gpio_irq(irq); -+} -+ -+static struct irq_chip gpio_irq_type = { -+ .typename = "GPIO", -+ .startup = startup_gpio_irq, -+ .shutdown = shutdown_gpio_irq, -+ .enable = enable_gpio_irq, -+ .disable = disable_gpio_irq, -+ .ack = mask_and_ack_gpio_irq, -+ .end = end_gpio_irq, -+}; -+ -+/* -+ * DMA irq type -+ */ -+ -+static void enable_dma_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ -+ intc_irq = IRQ_DMAC0; -+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ -+ intc_irq = IRQ_DMAC1; -+ else { -+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); -+ return; -+ } -+ __intc_unmask_irq(intc_irq); -+ __dmac_channel_enable_irq(irq - IRQ_DMA_0); -+} -+ -+static void disable_dma_irq(unsigned int irq) -+{ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void mask_and_ack_dma_irq(unsigned int irq) -+{ -+ unsigned int intc_irq; -+ -+ if ( irq < (IRQ_DMA_0 + HALF_DMA_NUM) ) /* DMAC Group 0 irq */ -+ intc_irq = IRQ_DMAC0; -+ else if ( irq < (IRQ_DMA_0 + MAX_DMA_NUM) ) /* DMAC Group 1 irq */ -+ intc_irq = IRQ_DMAC1; -+ else { -+ printk("%s, unexpected dma irq #%d\n", __FILE__, irq); -+ return ; -+ } -+ __intc_ack_irq(intc_irq); -+ __dmac_channel_ack_irq(irq-IRQ_DMA_0); /* needed?? add 20080506, Wolfgang */ -+ __dmac_channel_disable_irq(irq - IRQ_DMA_0); -+} -+ -+static void end_dma_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { -+ enable_dma_irq(irq); -+ } -+} -+ -+static unsigned int startup_dma_irq(unsigned int irq) -+{ -+ enable_dma_irq(irq); -+ return 0; -+} -+ -+static void shutdown_dma_irq(unsigned int irq) -+{ -+ disable_dma_irq(irq); -+} -+ -+static struct irq_chip dma_irq_type = { -+ .typename = "DMA", -+ .startup = startup_dma_irq, -+ .shutdown = shutdown_dma_irq, -+ .enable = enable_dma_irq, -+ .disable = disable_dma_irq, -+ .ack = mask_and_ack_dma_irq, -+ .end = end_dma_irq, -+}; -+ -+//---------------------------------------------------------------------- -+ -+void __init arch_init_irq(void) -+{ -+ int i; -+ -+ clear_c0_status(0xff04); /* clear ERL */ -+ set_c0_status(0x0400); /* set IP2 */ -+ -+ /* Set up INTC irq -+ */ -+ for (i = 0; i < 32; i++) { -+ disable_intc_irq(i); -+ irq_desc[i].chip = &intc_irq_type; -+ } -+ -+ /* Set up DMAC irq -+ */ -+ for (i = 0; i < NUM_DMA; i++) { -+ disable_dma_irq(IRQ_DMA_0 + i); -+ irq_desc[IRQ_DMA_0 + i].chip = &dma_irq_type; -+ } -+ -+ /* Set up GPIO irq -+ */ -+ for (i = 0; i < NUM_GPIO; i++) { -+ disable_gpio_irq(IRQ_GPIO_0 + i); -+ irq_desc[IRQ_GPIO_0 + i].chip = &gpio_irq_type; -+ } -+} -+ -+static int plat_real_irq(int irq) -+{ -+ switch (irq) { -+ case IRQ_GPIO0: -+ irq = __gpio_group_irq(0) + IRQ_GPIO_0; -+ break; -+ case IRQ_GPIO1: -+ irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32; -+ break; -+ case IRQ_GPIO2: -+ irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64; -+ break; -+ case IRQ_GPIO3: -+ irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96; -+ break; -+ case IRQ_GPIO4: -+ irq = __gpio_group_irq(4) + IRQ_GPIO_0 + 128; -+ break; -+ case IRQ_GPIO5: -+ irq = __gpio_group_irq(5) + IRQ_GPIO_0 + 160; -+ break; -+ case IRQ_DMAC0: -+ case IRQ_DMAC1: -+ irq = __dmac_get_irq() + IRQ_DMA_0; -+ break; -+ } -+ -+ return irq; -+} -+ -+asmlinkage void plat_irq_dispatch(void) -+{ -+ int irq = 0; -+ static unsigned long intc_ipr = 0; -+ -+ intc_ipr |= REG_INTC_IPR; -+ -+ if (!intc_ipr) return; -+ -+ irq = ffs(intc_ipr) - 1; -+ intc_ipr &= ~(1< -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#if 0 -+/* OHCI (USB full speed host controller) */ -+static struct resource jz_usb_ohci_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UHC_BASE), // phys addr for ioremap -+ .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UHC, -+ .end = IRQ_UHC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+/* The dmamask must be set for OHCI to work */ -+static u64 ohci_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_ohci_device = { -+ .name = "jz-ohci", -+ .id = 0, -+ .dev = { -+ .dma_mask = &ohci_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_ohci_resources), -+ .resource = jz_usb_ohci_resources, -+}; -+#endif -+/*** LCD controller ***/ -+static struct resource jz_lcd_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(LCD_BASE), -+ .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_LCD, -+ .end = IRQ_LCD, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_lcd_dmamask = ~(u32)0; -+ -+static struct platform_device jz_lcd_device = { -+ .name = "jz-lcd", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_lcd_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_lcd_resources), -+ .resource = jz_lcd_resources, -+}; -+ -+/* UDC (USB gadget controller) */ -+static struct resource jz_usb_gdt_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(UDC_BASE), -+ .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_UDC, -+ .end = IRQ_UDC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static u64 udc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_usb_gdt_device = { -+ .name = "jz-udc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &udc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_usb_gdt_resources), -+ .resource = jz_usb_gdt_resources, -+}; -+ -+/** MMC/SD controller **/ -+static struct resource jz_mmc_resources[] = { -+ [0] = { -+ .start = CPHYSADDR(MSC_BASE), -+ .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ [1] = { -+ .start = IRQ_MSC0, -+ .end = IRQ_MSC0, -+ .flags = IORESOURCE_IRQ, -+ } -+}; -+ -+static u64 jz_mmc_dmamask = ~(u32)0; -+ -+static struct platform_device jz_mmc_device = { -+ .name = "jz-mmc", -+ .id = 0, -+ .dev = { -+ .dma_mask = &jz_mmc_dmamask, -+ .coherent_dma_mask = 0xffffffff, -+ }, -+ .num_resources = ARRAY_SIZE(jz_mmc_resources), -+ .resource = jz_mmc_resources, -+}; -+ -+/* All */ -+static struct platform_device *jz_platform_devices[] __initdata = { -+// &jz_usb_ohci_device, -+ &jz_lcd_device, -+ &jz_usb_gdt_device, -+ &jz_mmc_device, -+}; -+ -+static int __init jz_platform_init(void) -+{ -+ return platform_add_devices(jz_platform_devices, ARRAY_SIZE(jz_platform_devices)); -+} -+ -+arch_initcall(jz_platform_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/pm.c linux-2.6.24.7/arch/mips/jz4750d/pm.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/pm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/pm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,461 @@ -+/* -+ * linux/arch/mips/jz4750d/common/pm.c -+ * -+ * JZ4750D Power Management Routines -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+#define GPIO_PORT_NUM 6 -+ -+/* -+ * __gpio_as_sleep set all pins to pull-disable, and set all pins as input -+ * except sdram and the pins which can be used as CS1_N to CS4_N for chip select. -+ */ -+#define __gpio_as_sleep() \ -+do { \ -+ REG_GPIO_PXFUNC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXDIRC(1) = ~0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(2) = ~0x01e00000; \ -+ REG_GPIO_PXSELC(2) = ~0x01e00000; \ -+ REG_GPIO_PXDIRC(2) = ~0x01e00000; \ -+ REG_GPIO_PXPES(2) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(3) = 0xffffffff; \ -+ REG_GPIO_PXSELC(3) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(3) = 0xffffffff; \ -+ REG_GPIO_PXPES(3) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(4) = 0xffffffff; \ -+ REG_GPIO_PXSELC(4) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(4) = 0xffffffff; \ -+ REG_GPIO_PXPES(4) = 0xffffffff; \ -+ REG_GPIO_PXFUNC(5) = 0xffffffff; \ -+ REG_GPIO_PXSELC(5) = 0xffffffff; \ -+ REG_GPIO_PXDIRC(5) = 0xffffffff; \ -+ REG_GPIO_PXPES(5) = 0xffffffff; \ -+} while (0) -+ -+static int jz_pm_do_hibernate(void) -+{ -+ printk("Put CPU into hibernate mode.\n"); -+ -+ /* Mask all interrupts */ -+ REG_INTC_IMSR = 0xffffffff; -+ -+ /* -+ * RTC Wakeup or 1Hz interrupt can be enabled or disabled -+ * through RTC driver's ioctl (linux/driver/char/rtc_jz.c). -+ */ -+ -+ /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWFCR = (100 << RTC_HWFCR_BIT); -+ -+ /* Set reset pin low-level assertion time after wakeup: must > 60ms */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HRCR = (60 << RTC_HRCR_BIT); /* 60 ms */ -+ -+ /* Scratch pad register to be reserved */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HSPR = 0x12345678; -+ -+ /* clear wakeup status register */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HWRSR = 0x0; -+ -+ /* Put CPU to power down mode */ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_HCR = RTC_HCR_PD; -+ -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ while(1); -+ -+ /* We can't get here */ -+ return 0; -+} -+ -+/* NOTES: -+ * 1: Pins that are floated (NC) should be set as input and pull-enable. -+ * 2: Pins that are pull-up or pull-down by outside should be set as input -+ * and pull-disable. -+ * 3: Pins that are connected to a chip except sdram and nand flash -+ * should be set as input and pull-disable, too. -+ */ -+static void jz_board_do_sleep(unsigned long *ptr) -+{ -+ unsigned char i; -+ -+ /* Print messages of GPIO registers for debug */ -+ for(i=0;i -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+//#define DEBUG 1 -+#undef DEBUG -+ -+ -+struct proc_dir_entry *proc_jz_root; -+ -+ -+/* -+ * EMC Modules -+ */ -+static int emc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ -+ len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); -+ len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); -+ len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); -+ len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); -+ len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); -+ return len; -+} -+ -+/* -+ * Power Manager Module -+ */ -+static int pmc_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned long lcr = REG_CPM_LCR; -+ unsigned long clkgr = REG_CPM_CLKGR; -+ -+ len += sprintf (page+len, "Low Power Mode : %s\n", -+ ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? -+ "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? -+ "SLEEP" : "HIBERNATE")); -+ len += sprintf (page+len, "Doze Mode : %s\n", -+ (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); -+ if (lcr & CPM_LCR_DOZE_ON) -+ len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); -+ len += sprintf (page+len, "IPU : %s\n", -+ (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); -+ len += sprintf (page+len, "DMAC : %s\n", -+ (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UHC : %s\n", -+ (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); -+ len += sprintf (page+len, "UDC : %s\n", -+ (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); -+ len += sprintf (page+len, "LCD : %s\n", -+ (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); -+ len += sprintf (page+len, "CIM : %s\n", -+ (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); -+ len += sprintf (page+len, "SADC : %s\n", -+ (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); -+ len += sprintf (page+len, "MSC0 : %s\n", -+ (clkgr & CPM_CLKGR_MSC0) ? "stopped" : "running"); -+ len += sprintf (page+len, "MSC1 : %s\n", -+ (clkgr & CPM_CLKGR_MSC1) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC1 : %s\n", -+ (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); -+ len += sprintf (page+len, "AIC2 : %s\n", -+ (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI0 : %s\n", -+ (clkgr & CPM_CLKGR_SSI0) ? "stopped" : "running"); -+ len += sprintf (page+len, "SSI1 : %s\n", -+ (clkgr & CPM_CLKGR_SSI1) ? "stopped" : "running"); -+ len += sprintf (page+len, "I2C : %s\n", -+ (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); -+ len += sprintf (page+len, "RTC : %s\n", -+ (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); -+ len += sprintf (page+len, "TCU : %s\n", -+ (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART1 : %s\n", -+ (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); -+ len += sprintf (page+len, "UART0 : %s\n", -+ (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); -+ return len; -+} -+ -+static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+/* -+ * Clock Generation Module -+ */ -+#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 -+#define TO_KHZ(x) (x/1000),(x%1000)/10 -+ -+static int cgm_read_proc (char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ -+ unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ -+ unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned int od[4] = {1, 2, 2, 4}; -+ -+ len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); -+ len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); -+ len += sprintf (page+len, "PLL : %s\n", -+ (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); -+ len += sprintf (page+len, "m:n:o : %d:%d:%d\n", -+ __cpm_get_pllm() + 2, -+ __cpm_get_plln() + 2, -+ od[__cpm_get_pllod()] -+ ); -+ len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", -+ div[__cpm_get_cdiv()], -+ div[__cpm_get_hdiv()], -+ div[__cpm_get_mdiv()], -+ div[__cpm_get_pdiv()] -+ ); -+ len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); -+ len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); -+ len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); -+ len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); -+ len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); -+ len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); -+ len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); -+ len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); -+ len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); -+ len += sprintf (page+len, "MSC0CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(0))); -+ len += sprintf (page+len, "MSC1CLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk(1))); -+ len += sprintf (page+len, "EXTALCLK0 : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk0())); -+ len += sprintf (page+len, "EXTALCLK(by CPM): %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); -+ len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); -+ -+ return len; -+} -+ -+static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); -+ return count; -+} -+ -+ -+/* USAGE: -+ * echo n > /proc/jz/ipu // n = [1,...,9], alloc mem, 2^n pages. -+ * echo FF > /proc/jz/ipu // 255, free all buffer -+ * echo xxxx > /proc/jz/ipu // free buffer which addr is xxxx -+ * echo llll > /proc/jz/ipu // add_wired_entry(l,l,l,l) -+ * echo 0 > /proc/jz/ipu // debug, print ipu_buf -+ * od -X /proc/jz/ipu // read mem addr -+ */ -+ -+typedef struct _ipu_buf { -+ unsigned int addr; /* phys addr */ -+ unsigned int page_shift; -+} ipu_buf_t; -+ -+#define IPU_BUF_MAX 4 /* 4 buffers */ -+ -+static struct _ipu_buf ipu_buf[IPU_BUF_MAX]; -+static int ipu_buf_cnt = 0; -+static unsigned char g_asid=0; -+ -+extern void local_flush_tlb_all(void); -+ -+/* CP0 hazard avoidance. */ -+#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ -+ "nop; nop; nop; nop; nop; nop;\n\t" \ -+ ".set reorder\n\t") -+void show_tlb(void) -+{ -+#define ASID_MASK 0xFF -+ -+ unsigned long flags; -+ unsigned int old_ctx; -+ unsigned int entry; -+ unsigned int entrylo0, entrylo1, entryhi; -+ unsigned int pagemask; -+ -+ local_irq_save(flags); -+ -+ /* Save old context */ -+ old_ctx = (read_c0_entryhi() & 0xff); -+ -+ printk("TLB content:\n"); -+ entry = 0; -+ while(entry < 32) { -+ write_c0_index(entry); -+ BARRIER; -+ tlb_read(); -+ BARRIER; -+ entryhi = read_c0_entryhi(); -+ entrylo0 = read_c0_entrylo0(); -+ entrylo1 = read_c0_entrylo1(); -+ pagemask = read_c0_pagemask(); -+ printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); -+ printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); -+ printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); -+ -+ printk("\t\tpagemask=0x%08x", pagemask); -+ printk("\tentryhi=0x%08x\n", entryhi); -+ printk("\t\tentrylo0=0x%08x", entrylo0); -+ printk("\tentrylo1=0x%08x\n", entrylo1); -+ -+ entry++; -+ } -+ BARRIER; -+ write_c0_entryhi(old_ctx); -+ -+ local_irq_restore(flags); -+} -+ -+static void ipu_add_wired_entry(unsigned long pid, -+ unsigned long entrylo0, unsigned long entrylo1, -+ unsigned long entryhi, unsigned long pagemask) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ unsigned long old_pagemask; -+ unsigned long old_ctx; -+ struct task_struct *g, *p; -+ -+ /* We will lock an 4MB page size entry to map the 4MB reserved IPU memory */ -+ wired = read_c0_wired(); -+ if (wired) return; -+ -+ do_each_thread(g, p) { -+ if (p->pid == pid ) -+ g_asid = p->mm->context[0]; -+ } while_each_thread(g, p); -+ -+ -+ local_irq_save(flags); -+ -+ entrylo0 = entrylo0 >> 6; /* PFN */ -+ entrylo0 |= 0x6 | (0 << 3); /* Write-through cacheable, dirty, valid */ -+ -+ /* Save old context and create impossible VPN2 value */ -+ old_ctx = read_c0_entryhi() & 0xff; -+ old_pagemask = read_c0_pagemask(); -+ wired = read_c0_wired(); -+ write_c0_wired(wired + 1); -+ write_c0_index(wired); -+ BARRIER; -+ entryhi &= ~0xff; /* new add, 20070906 */ -+ entryhi |= g_asid; /* new add, 20070906 */ -+// entryhi |= old_ctx; /* new add, 20070906 */ -+ write_c0_pagemask(pagemask); -+ write_c0_entryhi(entryhi); -+ write_c0_entrylo0(entrylo0); -+ write_c0_entrylo1(entrylo1); -+ BARRIER; -+ tlb_write_indexed(); -+ BARRIER; -+ -+ write_c0_entryhi(old_ctx); -+ BARRIER; -+ write_c0_pagemask(old_pagemask); -+ local_flush_tlb_all(); -+ local_irq_restore(flags); -+#if defined(DEBUG) -+ printk("\nold_ctx=%03d\n", old_ctx); -+ -+ show_tlb(); -+#endif -+} -+ -+static void ipu_del_wired_entry( void ) -+{ -+ unsigned long flags; -+ unsigned long wired; -+ -+ local_irq_save(flags); -+ wired = read_c0_wired(); -+ if ( wired > 0 ) { -+ write_c0_wired(wired - 1); -+ } -+ local_irq_restore(flags); -+} -+ -+static inline void ipu_buf_get( unsigned int page_shift ) -+{ -+ unsigned char * virt_addr; -+ int i; -+ for ( i=0; i< IPU_BUF_MAX; ++i ) { -+ if ( ipu_buf[i].addr == 0 ) { -+ break; -+ } -+ } -+ -+ if ( (ipu_buf_cnt = i) == IPU_BUF_MAX ) { -+ printk("Error, no free ipu buffer.\n"); -+ return ; -+ } -+ -+ virt_addr = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ -+ if ( virt_addr ) { -+ ipu_buf[ipu_buf_cnt].addr = (unsigned int)virt_to_phys((void *)virt_addr); -+ ipu_buf[ipu_buf_cnt].page_shift = page_shift; -+ -+ for (i = 0; i < (1<= IPU_BUF_MAX ) { /* failed alloc mem, rturn 0 */ -+ printk("no free buffer.\n"); -+ *pint = 0; -+ } -+ else -+ *pint = (unsigned int )ipu_buf[ipu_buf_cnt].addr; /* phys addr */ -+ len += sizeof(unsigned int); -+ -+#if defined(DEBUG) -+ show_tlb(); -+#endif -+ return len; -+ -+} -+ -+static int ipu_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val ; -+ int cnt,i; -+ char buf[12]; -+ unsigned long pid, entrylo0, entrylo1, entryhi, pagemask; -+#if defined(DEBUG) -+ printk("ipu write count=%u\n", count); -+#endif -+ if (count == (8*5+1)) { -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*0, 8); -+ pid = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*1, 8); -+ entrylo0 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*2, 8); -+ entrylo1 = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*3, 8); -+ entryhi = simple_strtoul(buf, 0, 16); -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer+8*4, 8); -+ pagemask = simple_strtoul(buf, 0, 16); -+ -+#if defined(DEBUG) -+ printk("pid=0x%08x, entrylo0=0x%08x, entrylo1=0x%08x, entryhi=0x%08x, pagemask=0x%08x\n", -+ pid, entrylo0, entrylo1, entryhi, pagemask); -+#endif -+ ipu_add_wired_entry( pid, entrylo0, entrylo1, entryhi, pagemask); -+ return 41; -+ } -+ else if ( count <= 8+1 ) { -+ for (i=0;i<12;i++) buf[i]=0; -+ strncpy(buf, buffer, 8); -+ val = simple_strtoul(buf, 0, 16); -+ } else if (count == 44) { -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer, 10); -+ pid = simple_strtoul(buf, 0, 16); -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 11, 10); -+ entryhi = simple_strtoul(buf, 0, 16);//vaddr -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 22, 10); -+ entrylo0 = simple_strtoul(buf, 0, 16);//paddr -+ for (i = 0; i < 12; i++) -+ buf[i] = 0; -+ strncpy(buf, buffer + 33, 10); -+ pagemask = simple_strtoul(buf, 0, 16); -+ pagemask = 0x3ff << 13; /* Fixed to 4MB page size */ -+ ipu_add_wired_entry(pid, entrylo0, 0, entryhi, pagemask); -+ return 44; -+ } else { -+ printk("ipu write count error, count=%d\n.", (unsigned int)count); -+ return -1; -+ } -+ -+ /* val: 1-9, page_shift, val>= 10: ipu_buf.addr */ -+ if ( val == 0 ) { /* debug, print ipu_buf info */ -+ for ( cnt=0; cnt /proc/jz/imem // n = [0,...,10], allocate memory, 2^n pages -+ * echo xxxxxxxx > /proc/jz/imem // free buffer which addr is xxxxxxxx -+ * echo FF > /proc/jz/ipu // FF, free all buffers -+ * od -X /proc/jz/imem // return the allocated buffer address and the max order of free buffer -+ */ -+ -+//#define DEBUG_IMEM 1 -+ -+#define IMEM_MAX_ORDER 10 /* max 2^10 * 4096 = 4MB */ -+ -+static unsigned int jz_imem_base; /* physical base address of ipu memory */ -+ -+static unsigned int allocated_phys_addr = 0; -+ -+/* -+ * Allocated buffer list -+ */ -+typedef struct imem_list { -+ unsigned int phys_start; /* physical start addr */ -+ unsigned int phys_end; /* physical end addr */ -+ struct imem_list *next; -+} imem_list_t; -+ -+static struct imem_list *imem_list_head = NULL; /* up sorted by phys_start */ -+ -+#ifdef DEBUG_IMEM -+static void dump_imem_list(void) -+{ -+ struct imem_list *imem; -+ -+ printk("*** dump_imem_list 0x%x ***\n", (u32)imem_list_head); -+ imem = imem_list_head; -+ while (imem) { -+ printk("imem=0x%x phys_start=0x%x phys_end=0x%x next=0x%x\n", (u32)imem, imem->phys_start, imem->phys_end, (u32)imem->next); -+ imem = imem->next; -+ } -+} -+#endif -+ -+/* allocate 2^order pages inside the 4MB memory */ -+static int imem_alloc(unsigned int order) -+{ -+ int alloc_ok = 0; -+ unsigned int start, end; -+ unsigned int size = (1 << order) * PAGE_SIZE; -+ struct imem_list *imem, *imemn, *imemp; -+ -+ allocated_phys_addr = 0; -+ -+ start = jz_imem_base; -+ end = start + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ imem = imem_list_head; -+ while (imem) { -+ if ((imem->phys_start - start) >= size) { -+ /* we got a valid address range */ -+ alloc_ok = 1; -+ break; -+ } -+ -+ start = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (!alloc_ok) { -+ if ((end - start) >= size) -+ alloc_ok = 1; -+ } -+ -+ if (alloc_ok) { -+ end = start + size - 1; -+ allocated_phys_addr = start; -+ -+ /* add to imem_list, up sorted by phys_start */ -+ imemn = kmalloc(sizeof(struct imem_list), GFP_KERNEL); -+ if (!imemn) { -+ return -ENOMEM; -+ } -+ imemn->phys_start = start; -+ imemn->phys_end = end; -+ imemn->next = NULL; -+ -+ if (!imem_list_head) -+ imem_list_head = imemn; -+ else { -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (start < imem->phys_start) { -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+ if (imem == imem_list_head) { -+ imem_list_head = imemn; -+ imemn->next = imem; -+ } -+ else { -+ imemn->next = imemp->next; -+ imemp->next = imemn; -+ } -+ } -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+ return 0; -+} -+ -+static void imem_free(unsigned int phys_addr) -+{ -+ struct imem_list *imem, *imemp; -+ -+ imem = imemp = imem_list_head; -+ while (imem) { -+ if (phys_addr == imem->phys_start) { -+ if (imem == imem_list_head) { -+ imem_list_head = imem->next; -+ } -+ else { -+ imemp->next = imem->next; -+ } -+ -+ kfree(imem); -+ break; -+ } -+ -+ imemp = imem; -+ imem = imem->next; -+ } -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+static void imem_free_all(void) -+{ -+ struct imem_list *imem; -+ -+ imem = imem_list_head; -+ while (imem) { -+ kfree(imem); -+ imem = imem->next; -+ } -+ -+ imem_list_head = NULL; -+ -+ allocated_phys_addr = 0; -+ -+#ifdef DEBUG_IMEM -+ dump_imem_list(); -+#endif -+} -+ -+/* -+ * Return the allocated buffer address and the max order of free buffer -+ */ -+static int imem_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = 0; -+ unsigned int start_addr, end_addr, max_order, max_size; -+ struct imem_list *imem; -+ -+ unsigned int *tmp = (unsigned int *)(page + len); -+ -+ start_addr = jz_imem_base; -+ end_addr = start_addr + (1 << IMEM_MAX_ORDER) * PAGE_SIZE; -+ -+ if (!imem_list_head) -+ max_size = end_addr - start_addr; -+ else { -+ max_size = 0; -+ imem = imem_list_head; -+ while (imem) { -+ if (max_size < (imem->phys_start - start_addr)) -+ max_size = imem->phys_start - start_addr; -+ -+ start_addr = imem->phys_end + 1; -+ imem = imem->next; -+ } -+ -+ if (max_size < (end_addr - start_addr)) -+ max_size = end_addr - start_addr; -+ } -+ -+ if (max_size > 0) { -+ max_order = get_order(max_size); -+ if (((1 << max_order) * PAGE_SIZE) > max_size) -+ max_order--; -+ } -+ else { -+ max_order = 0xffffffff; /* No any free buffer */ -+ } -+ -+ *tmp++ = allocated_phys_addr; /* address allocated by 'echo n > /proc/jz/imem' */ -+ *tmp = max_order; /* max order of current free buffers */ -+ -+ len += 2 * sizeof(unsigned int); -+ -+ return len; -+} -+ -+static int imem_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -+{ -+ unsigned int val; -+ -+ val = simple_strtoul(buffer, 0, 16); -+ -+ if (val == 0xff) { -+ /* free all memory */ -+ imem_free_all(); -+ } -+ else if ((val >= 0) && (val <= IMEM_MAX_ORDER)) { -+ /* allocate 2^val pages */ -+ imem_alloc(val); -+ } -+ else { -+ /* free buffer which phys_addr is val */ -+ imem_free(val); -+ } -+ -+ return count; -+} -+ -+/* -+ * /proc/jz/xxx entry -+ * -+ */ -+static int __init jz_proc_init(void) -+{ -+ struct proc_dir_entry *res; -+ unsigned int virt_addr, i; -+ -+ proc_jz_root = proc_mkdir("jz", 0); -+ -+ /* External Memory Controller */ -+ res = create_proc_entry("emc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = emc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* Power Management Controller */ -+ res = create_proc_entry("pmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = pmc_read_proc; -+ res->write_proc = pmc_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Clock Generation Module */ -+ res = create_proc_entry("cgm", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = cgm_read_proc; -+ res->write_proc = cgm_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Image process unit */ -+ res = create_proc_entry("ipu", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = ipu_read_proc; -+ res->write_proc = ipu_write_proc; -+ res->data = NULL; -+ } -+ -+ /* udc hotplug */ -+ res = create_proc_entry("udc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = udc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* mmc hotplug */ -+ res = create_proc_entry("mmc", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = mmc_read_proc; -+ res->write_proc = NULL; -+ res->data = NULL; -+ } -+ -+ /* -+ * Reserve a 4MB memory for IPU on JZ4750D. -+ */ -+ jz_imem_base = (unsigned int)__get_free_pages(GFP_KERNEL, IMEM_MAX_ORDER); -+ if (jz_imem_base) { -+ /* imem (IPU memory management) */ -+ res = create_proc_entry("imem", 0644, proc_jz_root); -+ if (res) { -+ res->read_proc = imem_read_proc; -+ res->write_proc = imem_write_proc; -+ res->data = NULL; -+ } -+ -+ /* Set page reserved */ -+ virt_addr = jz_imem_base; -+ for (i = 0; i < (1 << IMEM_MAX_ORDER); i++) { -+ SetPageReserved(virt_to_page((void *)virt_addr)); -+ virt_addr += PAGE_SIZE; -+ } -+ -+ /* Convert to physical address */ -+ jz_imem_base = virt_to_phys((void *)jz_imem_base); -+ -+ printk("Total %dMB memory at 0x%x was reserved for IPU\n", -+ (unsigned int)((1 << IMEM_MAX_ORDER) * PAGE_SIZE)/1000000, jz_imem_base); -+ } -+ -+ return 0; -+} -+ -+__initcall(jz_proc_init); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/prom.c linux-2.6.24.7/arch/mips/jz4750d/prom.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/prom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/prom.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,198 @@ -+/* -+ * -+ * BRIEF MODULE DESCRIPTION -+ * PROM library initialisation code, supports YAMON and U-Boot. -+ * -+ * Copyright 2000, 2001, 2006 MontaVista Software Inc. -+ * Author: MontaVista Software, Inc. -+ * ppopov@mvista.com or source@mvista.com -+ * -+ * This file was derived from Carsten Langgaard's -+ * arch/mips/mips-boards/xx files. -+ * -+ * Carsten Langgaard, carstenl@mips.com -+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. 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 as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* #define DEBUG_CMDLINE */ -+ -+int prom_argc; -+char **prom_argv, **prom_envp; -+ -+char * prom_getcmdline(void) -+{ -+ return &(arcs_cmdline[0]); -+} -+ -+void prom_init_cmdline(void) -+{ -+ char *cp; -+ int actr; -+ -+ actr = 1; /* Always ignore argv[0] */ -+ -+ cp = &(arcs_cmdline[0]); -+ while(actr < prom_argc) { -+ strcpy(cp, prom_argv[actr]); -+ cp += strlen(prom_argv[actr]); -+ *cp++ = ' '; -+ actr++; -+ } -+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ -+ --cp; -+ if (prom_argc > 1) -+ *cp = '\0'; -+ -+} -+ -+ -+char *prom_getenv(char *envname) -+{ -+#if 0 -+ /* -+ * Return a pointer to the given environment variable. -+ * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". -+ */ -+ -+ char **env = prom_envp; -+ int i = strlen(envname); -+ int yamon = (*env && strchr(*env, '=') == NULL); -+ -+ while (*env) { -+ if (yamon) { -+ if (strcmp(envname, *env++) == 0) -+ return *env; -+ } else { -+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') -+ return *env + i + 1; -+ } -+ env++; -+ } -+#endif -+ return NULL; -+} -+ -+inline unsigned char str2hexnum(unsigned char c) -+{ -+ if(c >= '0' && c <= '9') -+ return c - '0'; -+ if(c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if(c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for(i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+int get_ethernet_addr(char *ethernet_addr) -+{ -+ char *ethaddr_str; -+ -+ ethaddr_str = prom_getenv("ethaddr"); -+ if (!ethaddr_str) { -+ printk("ethaddr not set in boot prom\n"); -+ return -1; -+ } -+ str2eaddr(ethernet_addr, ethaddr_str); -+ -+#if 0 -+ { -+ int i; -+ -+ printk("get_ethernet_addr: "); -+ for (i=0; i<5; i++) -+ printk("%02x:", (unsigned char)*(ethernet_addr+i)); -+ printk("%02x\n", *(ethernet_addr+i)); -+ } -+#endif -+ -+ return 0; -+} -+ -+void __init prom_free_prom_memory(void) -+{ -+} -+ -+void __init prom_init(void) -+{ -+ unsigned char *memsize_str; -+ unsigned long memsize; -+ -+ prom_argc = (int) fw_arg0; -+ prom_argv = (char **) fw_arg1; -+ prom_envp = (char **) fw_arg2; -+ -+ mips_machtype = MACH_INGENIC_JZ4750D; -+ -+ prom_init_cmdline(); -+ memsize_str = prom_getenv("memsize"); -+ if (!memsize_str) { -+ memsize = 0x04000000; -+ } else { -+ memsize = simple_strtol(memsize_str, NULL, 0); -+ } -+ add_memory_region(0, memsize, BOOT_MEM_RAM); -+} -+ -+/* used by early printk */ -+void prom_putchar(char c) -+{ -+ volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); -+ volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); -+ -+ /* Wait for fifo to shift out some bytes */ -+ while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); -+ -+ *uart_tdr = (u8)c; -+} -+ -+const char *get_system_type(void) -+{ -+ return "JZ4750D"; -+} -+ -+EXPORT_SYMBOL(prom_getcmdline); -+EXPORT_SYMBOL(get_ethernet_addr); -+EXPORT_SYMBOL(str2eaddr); -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/reset.c linux-2.6.24.7/arch/mips/jz4750d/reset.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/reset.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/reset.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,46 @@ -+/* -+ * linux/arch/mips/jz4750/reset.c -+ * -+ * JZ4750 reset routines. -+ * -+ * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+void jz_restart(char *command) -+{ -+ printk("Restarting after 4 ms\n"); -+ REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; -+ REG_WDT_TCNT = 0; -+ REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ -+ REG_TCU_TSCR = TCU_TSCR_WDTSC; /* enable wdt clock */ -+ REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ -+ while (1); -+} -+ -+void jz_halt(void) -+{ -+ printk(KERN_NOTICE "\n** You can safely turn off the power\n"); -+ -+ while (1) -+ __asm__(".set\tmips3\n\t" -+ "wait\n\t" -+ ".set\tmips0"); -+} -+ -+void jz_power_off(void) -+{ -+ jz_halt(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/setup.c linux-2.6.24.7/arch/mips/jz4750d/setup.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/setup.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/setup.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,199 @@ -+/* -+ * linux/arch/mips/jz4750d/common/setup.c -+ * -+ * JZ4750D common setup routines. -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_PC_KEYB -+#include -+#endif -+ -+jz_clocks_t jz_clocks; -+ -+extern char * __init prom_getcmdline(void); -+extern void __init jz_board_setup(void); -+extern void jz_restart(char *); -+extern void jz_halt(void); -+extern void jz_power_off(void); -+extern void jz_time_init(void); -+ -+static void __init sysclocks_setup(void) -+{ -+#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ -+ jz_clocks.cclk = __cpm_get_cclk(); -+ jz_clocks.hclk = __cpm_get_hclk(); -+ jz_clocks.pclk = __cpm_get_pclk(); -+ jz_clocks.mclk = __cpm_get_mclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.i2sclk = __cpm_get_i2sclk(); -+ jz_clocks.usbclk = __cpm_get_usbclk(); -+ jz_clocks.mscclk = __cpm_get_mscclk(0); -+ jz_clocks.extalclk = __cpm_get_extalclk(); -+ jz_clocks.rtcclk = __cpm_get_rtcclk(); -+#else -+ -+#define FPGACLK 8000000 -+ -+ jz_clocks.cclk = FPGACLK; -+ jz_clocks.hclk = FPGACLK; -+ jz_clocks.pclk = FPGACLK; -+ jz_clocks.mclk = FPGACLK; -+ jz_clocks.lcdclk = FPGACLK; -+ jz_clocks.pixclk = FPGACLK; -+ jz_clocks.i2sclk = FPGACLK; -+ jz_clocks.usbclk = FPGACLK; -+ jz_clocks.mscclk = FPGACLK; -+ jz_clocks.extalclk = FPGACLK; -+ jz_clocks.rtcclk = FPGACLK; -+#endif -+ -+ printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", -+ (jz_clocks.cclk + 500000) / 1000000, -+ (jz_clocks.hclk + 500000) / 1000000, -+ (jz_clocks.pclk + 500000) / 1000000, -+ (jz_clocks.mclk + 500000) / 1000000); -+} -+ -+static void __init soc_cpm_setup(void) -+{ -+ /* Start all module clocks -+ */ -+ __cpm_start_all(); -+ -+ /* Enable CKO to external memory */ -+ __cpm_enable_cko(); -+ -+ /* CPU enters IDLE mode when executing 'wait' instruction */ -+ __cpm_idle_mode(); -+ -+ /* Setup system clocks */ -+ sysclocks_setup(); -+} -+ -+static void __init soc_harb_setup(void) -+{ -+// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ -+// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ -+} -+ -+static void __init soc_emc_setup(void) -+{ -+} -+ -+static void __init soc_dmac_setup(void) -+{ -+ __dmac_enable_module(0); -+ __dmac_enable_module(1); -+} -+ -+static void __init jz_soc_setup(void) -+{ -+ soc_cpm_setup(); -+ soc_harb_setup(); -+ soc_emc_setup(); -+ soc_dmac_setup(); -+} -+ -+static void __init jz_serial_setup(void) -+{ -+#ifdef CONFIG_SERIAL_8250 -+ struct uart_port s; -+ REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ -+ memset(&s, 0, sizeof(s)); -+ s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; -+ s.iotype = SERIAL_IO_MEM; -+ s.regshift = 2; -+ s.uartclk = jz_clocks.extalclk ; -+ -+ s.line = 0; -+ s.membase = (u8 *)UART0_BASE; -+ s.irq = IRQ_UART0; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS0 setup failed!\n"); -+ } -+ -+ s.line = 1; -+ s.membase = (u8 *)UART1_BASE; -+ s.irq = IRQ_UART1; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS1 setup failed!\n"); -+ } -+ -+ s.line = 2; -+ s.membase = (u8 *)UART2_BASE; -+ s.irq = IRQ_UART2; -+ -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS2 setup failed!\n"); -+ } -+/* -+ s.line = 3; -+ s.membase = (u8 *)UART3_BASE; -+ s.irq = IRQ_UART3; -+ if (early_serial_setup(&s) != 0) { -+ printk(KERN_ERR "Serial ttyS3 setup failed!\n"); -+ } -+*/ -+#endif -+} -+ -+void __init plat_mem_setup(void) -+{ -+ char *argptr; -+ -+ argptr = prom_getcmdline(); -+ -+ /* IO/MEM resources. Which will be the addtion value in `inX' and -+ * `outX' macros defined in asm/io.h */ -+ set_io_port_base(0); -+ ioport_resource.start = 0x00000000; -+ ioport_resource.end = 0xffffffff; -+ iomem_resource.start = 0x00000000; -+ iomem_resource.end = 0xffffffff; -+ -+ _machine_restart = jz_restart; -+ _machine_halt = jz_halt; -+ pm_power_off = jz_power_off; -+ -+ jz_soc_setup(); -+ jz_serial_setup(); -+ jz_board_setup(); -+} -+ -diff -urN linux-2.6.24.7.old/arch/mips/jz4750d/time.c linux-2.6.24.7/arch/mips/jz4750d/time.c ---- linux-2.6.24.7.old/arch/mips/jz4750d/time.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/arch/mips/jz4750d/time.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* -+ * linux/arch/mips/jz4750d/time.c -+ * -+ * Setting up the clock on the JZ4750D boards. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can distribute 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 it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -+ * -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* This is for machines which generate the exact clock. */ -+ -+#define JZ_TIMER_IRQ IRQ_TCU0 -+ -+#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ -+ -+static struct clocksource clocksource_jz; /* Jz clock source */ -+static struct clock_event_device jz_clockevent_device; /* Jz clock event */ -+ -+void (*jz_timer_callback)(void); -+ -+static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) -+{ -+ struct clock_event_device *cd = dev_id; -+ -+ REG_TCU_TFCR = TCU_TFCR_OSTFCL; /* ACK timer */ -+ -+ if (jz_timer_callback) -+ jz_timer_callback(); -+ -+ cd->event_handler(cd); -+ -+ return IRQ_HANDLED; -+} -+ -+static struct irqaction jz_irqaction = { -+ .handler = jz_timer_interrupt, -+ .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, -+ .name = "jz-timerirq", -+}; -+ -+ -+cycle_t jz_get_cycles(void) -+{ -+ /* convert jiffes to jz timer cycles */ -+ return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_OSTCNT); -+} -+ -+static struct clocksource clocksource_jz = { -+ .name = "jz_clocksource", -+ .rating = 300, -+ .read = jz_get_cycles, -+ .mask = 0xFFFFFFFF, -+ .shift = 10, -+ .flags = CLOCK_SOURCE_WATCHDOG, -+}; -+ -+static int __init jz_clocksource_init(void) -+{ -+ clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); -+ clocksource_register(&clocksource_jz); -+ return 0; -+} -+ -+static int jz_set_next_event(unsigned long evt, -+ struct clock_event_device *unused) -+{ -+ return 0; -+} -+ -+static void jz_set_mode(enum clock_event_mode mode, -+ struct clock_event_device *evt) -+{ -+ switch (mode) { -+ case CLOCK_EVT_MODE_PERIODIC: -+ break; -+ case CLOCK_EVT_MODE_ONESHOT: -+ case CLOCK_EVT_MODE_UNUSED: -+ case CLOCK_EVT_MODE_SHUTDOWN: -+ break; -+ case CLOCK_EVT_MODE_RESUME: -+ break; -+ } -+} -+ -+static struct clock_event_device jz_clockevent_device = { -+ .name = "jz-clockenvent", -+ .features = CLOCK_EVT_FEAT_PERIODIC, -+// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ -+ -+ /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ -+ .rating = 300, -+ .irq = JZ_TIMER_IRQ, -+ .set_mode = jz_set_mode, -+ .set_next_event = jz_set_next_event, -+}; -+ -+static void __init jz_clockevent_init(void) -+{ -+ struct clock_event_device *cd = &jz_clockevent_device; -+ unsigned int cpu = smp_processor_id(); -+ -+ cd->cpumask = cpumask_of_cpu(cpu); -+ clockevents_register_device(cd); -+} -+ -+static void __init jz_timer_setup(void) -+{ -+ jz_clocksource_init(); /* init jz clock source */ -+ jz_clockevent_init(); /* init jz clock event */ -+ -+ /* -+ * Make irqs happen for the system timer -+ */ -+ jz_irqaction.dev_id = &jz_clockevent_device; -+ setup_irq(JZ_TIMER_IRQ, &jz_irqaction); -+} -+ -+ -+void __init plat_time_init(void) -+{ -+ unsigned int latch; -+ -+ /* Init timer */ -+ latch = (JZ_TIMER_CLOCK + (HZ>>1)) / HZ; -+ -+ REG_TCU_OSTCSR = TCU_OSTCSR_PRESCALE16 | TCU_OSTCSR_EXT_EN; -+ REG_TCU_OSTCNT = 0; -+ REG_TCU_OSTDR = latch; -+ -+ REG_TCU_TMCR = TCU_TMCR_OSTMCL; /* unmask match irq */ -+ REG_TCU_TSCR = TCU_TSCR_OSTSC; /* enable timer clock */ -+ REG_TCU_TESR = TCU_TESR_OSTST; /* start counting up */ -+ -+ jz_timer_setup(); -+} -diff -urN linux-2.6.24.7.old/arch/mips/kernel/cpu-probe.c linux-2.6.24.7/arch/mips/kernel/cpu-probe.c ---- linux-2.6.24.7.old/arch/mips/kernel/cpu-probe.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/kernel/cpu-probe.c 2009-04-12 18:13:57.000000000 +0200 -@@ -160,6 +160,7 @@ - case CPU_25KF: - case CPU_PR4450: - case CPU_BCM3302: -+ case CPU_JZRISC: - cpu_wait = r4k_wait; - break; - -@@ -802,6 +803,22 @@ - } - } - -+static inline void cpu_probe_ingenic(struct cpuinfo_mips *c) -+{ -+ decode_configs(c); -+ c->options &= ~MIPS_CPU_COUNTER; /* JZRISC does not implement the CP0 counter. */ -+ switch (c->processor_id & 0xff00) { -+ case PRID_IMP_JZRISC: -+ c->cputype = CPU_JZRISC; -+ c->isa_level = MIPS_CPU_ISA_M32R1; -+ c->tlbsize = 32; -+ break; -+ default: -+ panic("Unknown Ingenic Processor ID!"); -+ break; -+ } -+} -+ - const char *__cpu_name[NR_CPUS]; - - /* -@@ -880,6 +897,7 @@ - case CPU_BCM4710: name = "Broadcom BCM4710"; break; - case CPU_PR4450: name = "Philips PR4450"; break; - case CPU_LOONGSON2: name = "ICT Loongson-2"; break; -+ case CPU_JZRISC: name = "Ingenic JZRISC"; break; - default: - BUG(); - } -@@ -919,6 +937,9 @@ - case PRID_COMP_PHILIPS: - cpu_probe_philips(c); - break; -+ case PRID_COMP_INGENIC: -+ cpu_probe_ingenic(c); -+ break; - default: - c->cputype = CPU_UNKNOWN; - } -diff -urN linux-2.6.24.7.old/arch/mips/mm/c-r4k.c linux-2.6.24.7/arch/mips/mm/c-r4k.c ---- linux-2.6.24.7.old/arch/mips/mm/c-r4k.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/mm/c-r4k.c 2009-04-12 18:13:57.000000000 +0200 -@@ -874,6 +874,36 @@ - c->dcache.waybit = 0; - break; - -+ case CPU_JZRISC: -+ config1 = read_c0_config1(); -+ config1 = (config1 >> 22) & 0x07; -+ if (config1 == 0x07) -+ config1 = 10; -+ else -+ config1 = config1 + 11; -+ config1 += 2; -+ icache_size = (1 << config1); -+ c->icache.linesz = 32; -+ c->icache.ways = 4; -+ c->icache.waybit = __ffs(icache_size / c->icache.ways); -+ -+ config1 = read_c0_config1(); -+ config1 = (config1 >> 13) & 0x07; -+ if (config1 == 0x07) -+ config1 = 10; -+ else -+ config1 = config1 + 11; -+ config1 += 2; -+ dcache_size = (1 << config1); -+ c->dcache.linesz = 32; -+ c->dcache.ways = 4; -+ c->dcache.waybit = __ffs(dcache_size / c->dcache.ways); -+ -+ c->dcache.flags = 0; -+ c->options |= MIPS_CPU_PREFETCH; -+ -+ break; -+ - default: - if (!(config & MIPS_CONF_M)) - panic("Don't know how to probe P-caches on this cpu."); -diff -urN linux-2.6.24.7.old/arch/mips/mm/cache.c linux-2.6.24.7/arch/mips/mm/cache.c ---- linux-2.6.24.7.old/arch/mips/mm/cache.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/mm/cache.c 2009-04-12 18:13:57.000000000 +0200 -@@ -47,6 +47,8 @@ - void (*_dma_cache_inv)(unsigned long start, unsigned long size); - - EXPORT_SYMBOL(_dma_cache_wback_inv); -+EXPORT_SYMBOL(_dma_cache_wback); -+EXPORT_SYMBOL(_dma_cache_inv); - - #endif /* CONFIG_DMA_NONCOHERENT */ - -diff -urN linux-2.6.24.7.old/arch/mips/mm/tlbex.c linux-2.6.24.7/arch/mips/mm/tlbex.c ---- linux-2.6.24.7.old/arch/mips/mm/tlbex.c 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/arch/mips/mm/tlbex.c 2009-04-12 18:13:57.000000000 +0200 -@@ -981,6 +981,11 @@ - tlbw(p); - break; - -+ case CPU_JZRISC: -+ tlbw(p); -+ i_nop(p); -+ break; -+ - default: - panic("No TLB refill handler yet (CPU type: %d)", - current_cpu_data.cputype); -diff -urN linux-2.6.24.7.old/crypto/Kconfig linux-2.6.24.7/crypto/Kconfig ---- linux-2.6.24.7.old/crypto/Kconfig 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/crypto/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -502,6 +502,14 @@ - Authenc: Combined mode wrapper for IPsec. - This is required for IPSec. - -+config CRYPTO_LZO -+ tristate "LZO compression algorithm" -+ select CRYPTO_ALGAPI -+ select LZO_COMPRESS -+ select LZO_DECOMPRESS -+ help -+ This is the LZO algorithm. -+ - source "drivers/crypto/Kconfig" - - endif # if CRYPTO -diff -urN linux-2.6.24.7.old/crypto/Makefile linux-2.6.24.7/crypto/Makefile ---- linux-2.6.24.7.old/crypto/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/crypto/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -51,6 +51,7 @@ - obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o - obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o - obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o -+obj-$(CONFIG_CRYPTO_LZO) += lzo.o - obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o - - obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o -diff -urN linux-2.6.24.7.old/crypto/lzo.c linux-2.6.24.7/crypto/lzo.c ---- linux-2.6.24.7.old/crypto/lzo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/crypto/lzo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,106 @@ -+/* -+ * Cryptographic API. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct lzo_ctx { -+ void *lzo_comp_mem; -+}; -+ -+static int lzo_init(struct crypto_tfm *tfm) -+{ -+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ ctx->lzo_comp_mem = vmalloc(LZO1X_MEM_COMPRESS); -+ if (!ctx->lzo_comp_mem) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static void lzo_exit(struct crypto_tfm *tfm) -+{ -+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ vfree(ctx->lzo_comp_mem); -+} -+ -+static int lzo_compress(struct crypto_tfm *tfm, const u8 *src, -+ unsigned int slen, u8 *dst, unsigned int *dlen) -+{ -+ struct lzo_ctx *ctx = crypto_tfm_ctx(tfm); -+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ -+ int err; -+ -+ err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx->lzo_comp_mem); -+ -+ if (err != LZO_E_OK) -+ return -EINVAL; -+ -+ *dlen = tmp_len; -+ return 0; -+} -+ -+static int lzo_decompress(struct crypto_tfm *tfm, const u8 *src, -+ unsigned int slen, u8 *dst, unsigned int *dlen) -+{ -+ int err; -+ size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */ -+ -+ err = lzo1x_decompress_safe(src, slen, dst, &tmp_len); -+ -+ if (err != LZO_E_OK) -+ return -EINVAL; -+ -+ *dlen = tmp_len; -+ return 0; -+ -+} -+ -+static struct crypto_alg alg = { -+ .cra_name = "lzo", -+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, -+ .cra_ctxsize = sizeof(struct lzo_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(alg.cra_list), -+ .cra_init = lzo_init, -+ .cra_exit = lzo_exit, -+ .cra_u = { .compress = { -+ .coa_compress = lzo_compress, -+ .coa_decompress = lzo_decompress } } -+}; -+ -+static int __init init(void) -+{ -+ return crypto_register_alg(&alg); -+} -+ -+static void __exit fini(void) -+{ -+ crypto_unregister_alg(&alg); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("LZO Compression Algorithm"); -diff -urN linux-2.6.24.7.old/crypto/tcrypt.c linux-2.6.24.7/crypto/tcrypt.c ---- linux-2.6.24.7.old/crypto/tcrypt.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/crypto/tcrypt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -78,7 +78,7 @@ - "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea", - "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", -- "camellia", "seed", NULL -+ "camellia", "seed", "lzo", NULL - }; - - static void hexdump(unsigned char *buf, unsigned int len) -@@ -800,7 +800,8 @@ - crypto_free_hash(tfm); - } - --static void test_deflate(void) -+static void test_comp(char *algo, struct comp_testvec *ctemplate, -+ struct comp_testvec *dtemplate, int ctcount, int dtcount) - { - unsigned int i; - char result[COMP_BUF_SIZE]; -@@ -808,25 +809,26 @@ - struct comp_testvec *tv; - unsigned int tsize; - -- printk("\ntesting deflate compression\n"); -+ printk("\ntesting %s compression\n", algo); - -- tsize = sizeof (deflate_comp_tv_template); -+ tsize = sizeof(struct comp_testvec); -+ tsize *= ctcount; - if (tsize > TVMEMSIZE) { - printk("template (%u) too big for tvmem (%u)\n", tsize, - TVMEMSIZE); - return; - } - -- memcpy(tvmem, deflate_comp_tv_template, tsize); -+ memcpy(tvmem, ctemplate, tsize); - tv = (void *)tvmem; - -- tfm = crypto_alloc_comp("deflate", 0, CRYPTO_ALG_ASYNC); -+ tfm = crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { -- printk("failed to load transform for deflate\n"); -+ printk("failed to load transform for %s\n", algo); - return; - } - -- for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) { -+ for (i = 0; i < ctcount; i++) { - int ilen, ret, dlen = COMP_BUF_SIZE; - - printk("test %u:\n", i + 1); -@@ -845,19 +847,20 @@ - ilen, dlen); - } - -- printk("\ntesting deflate decompression\n"); -+ printk("\ntesting %s decompression\n", algo); - -- tsize = sizeof (deflate_decomp_tv_template); -+ tsize = sizeof(struct comp_testvec); -+ tsize *= dtcount; - if (tsize > TVMEMSIZE) { - printk("template (%u) too big for tvmem (%u)\n", tsize, - TVMEMSIZE); - goto out; - } - -- memcpy(tvmem, deflate_decomp_tv_template, tsize); -+ memcpy(tvmem, dtemplate, tsize); - tv = (void *)tvmem; - -- for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) { -+ for (i = 0; i < dtcount; i++) { - int ilen, ret, dlen = COMP_BUF_SIZE; - - printk("test %u:\n", i + 1); -@@ -1057,7 +1060,11 @@ - test_hash("tgr192", tgr192_tv_template, TGR192_TEST_VECTORS); - test_hash("tgr160", tgr160_tv_template, TGR160_TEST_VECTORS); - test_hash("tgr128", tgr128_tv_template, TGR128_TEST_VECTORS); -- test_deflate(); -+ test_comp("deflate", deflate_comp_tv_template, -+ deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS, -+ DEFLATE_DECOMP_TEST_VECTORS); -+ test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template, -+ LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS); - test_hash("crc32c", crc32c_tv_template, CRC32C_TEST_VECTORS); - test_hash("hmac(md5)", hmac_md5_tv_template, - HMAC_MD5_TEST_VECTORS); -@@ -1167,7 +1174,9 @@ - break; - - case 13: -- test_deflate(); -+ test_comp("deflate", deflate_comp_tv_template, -+ deflate_decomp_tv_template, DEFLATE_COMP_TEST_VECTORS, -+ DEFLATE_DECOMP_TEST_VECTORS); - break; - - case 14: -@@ -1292,6 +1301,11 @@ - CAMELLIA_CBC_DEC_TEST_VECTORS); - break; - -+ case 33: -+ test_comp("lzo", lzo_comp_tv_template, lzo_decomp_tv_template, -+ LZO_COMP_TEST_VECTORS, LZO_DECOMP_TEST_VECTORS); -+ break; -+ - case 100: - test_hash("hmac(md5)", hmac_md5_tv_template, - HMAC_MD5_TEST_VECTORS); -diff -urN linux-2.6.24.7.old/crypto/tcrypt.h linux-2.6.24.7/crypto/tcrypt.h ---- linux-2.6.24.7.old/crypto/tcrypt.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/crypto/tcrypt.h 2009-04-12 18:13:57.000000000 +0200 -@@ -4408,6 +4408,88 @@ - }; - - /* -+ * LZO test vectors (null-terminated strings). -+ */ -+#define LZO_COMP_TEST_VECTORS 2 -+#define LZO_DECOMP_TEST_VECTORS 2 -+ -+static struct comp_testvec lzo_comp_tv_template[] = { -+ { -+ .inlen = 70, -+ .outlen = 46, -+ .input = "Join us now and share the software " -+ "Join us now and share the software ", -+ .output = { 0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, -+ 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, -+ 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, -+ 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, -+ 0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e, -+ 0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 }, -+ }, { -+ .inlen = 159, -+ .outlen = 133, -+ .input = "This document describes a compression method based on the LZO " -+ "compression algorithm. This document defines the application of " -+ "the LZO algorithm used in UBIFS.", -+ .output = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64, -+ 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, -+ 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, -+ 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, -+ 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, -+ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62, -+ 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, -+ 0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b, -+ 0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72, -+ 0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54, -+ 0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66, -+ 0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61, -+ 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76, -+ 0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27, -+ 0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64, -+ 0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46, -+ 0x53, 0x2e, 0x11, 0x00, 0x00 }, -+ }, -+}; -+ -+static struct comp_testvec lzo_decomp_tv_template[] = { -+ { -+ .inlen = 133, -+ .outlen = 159, -+ .input = { 0x00, 0x2b, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64, -+ 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, -+ 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, -+ 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x70, -+ 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, -+ 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x62, -+ 0x61, 0x73, 0x65, 0x64, 0x20, 0x6f, 0x6e, 0x20, -+ 0x74, 0x68, 0x65, 0x20, 0x4c, 0x5a, 0x4f, 0x2b, -+ 0x8c, 0x00, 0x0d, 0x61, 0x6c, 0x67, 0x6f, 0x72, -+ 0x69, 0x74, 0x68, 0x6d, 0x2e, 0x20, 0x20, 0x54, -+ 0x68, 0x69, 0x73, 0x2a, 0x54, 0x01, 0x02, 0x66, -+ 0x69, 0x6e, 0x65, 0x73, 0x94, 0x06, 0x05, 0x61, -+ 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x76, -+ 0x0a, 0x6f, 0x66, 0x88, 0x02, 0x60, 0x09, 0x27, -+ 0xf0, 0x00, 0x0c, 0x20, 0x75, 0x73, 0x65, 0x64, -+ 0x20, 0x69, 0x6e, 0x20, 0x55, 0x42, 0x49, 0x46, -+ 0x53, 0x2e, 0x11, 0x00, 0x00 }, -+ .output = "This document describes a compression method based on the LZO " -+ "compression algorithm. This document defines the application of " -+ "the LZO algorithm used in UBIFS.", -+ }, { -+ .inlen = 46, -+ .outlen = 70, -+ .input = { 0x00, 0x0d, 0x4a, 0x6f, 0x69, 0x6e, 0x20, 0x75, -+ 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x61, 0x6e, -+ 0x64, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, -+ 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x66, 0x74, -+ 0x77, 0x70, 0x01, 0x01, 0x4a, 0x6f, 0x69, 0x6e, -+ 0x3d, 0x88, 0x00, 0x11, 0x00, 0x00 }, -+ .output = "Join us now and share the software " -+ "Join us now and share the software ", -+ }, -+}; -+ -+/* - * Michael MIC test vectors from IEEE 802.11i - */ - #define MICHAEL_MIC_TEST_VECTORS 6 -diff -urN linux-2.6.24.7.old/drivers/char/Kconfig linux-2.6.24.7/drivers/char/Kconfig ---- linux-2.6.24.7.old/drivers/char/Kconfig 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/char/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -731,6 +731,16 @@ - To compile this driver as a module, choose M here: the - module will be called rtc. - -+config RTC_PCF8563 -+ bool 'Philips PCF8563 Real Time Clock (I2C Bus)' -+ help -+ Philips PCF8563 Real Time Clock (I2C Bus) -+ -+config RTC_JZ -+ bool 'Jz47XX On-Chip Real Time Clock' -+ help -+ Jz47XX On-Chip Real Time Clock -+ - config JS_RTC - tristate "Enhanced Real Time Clock Support" - depends on SPARC32 && PCI -@@ -1046,6 +1056,7 @@ - default y - - source "drivers/s390/char/Kconfig" -+source "drivers/char/jzchar/Kconfig" - - endmenu - -diff -urN linux-2.6.24.7.old/drivers/char/Kconfig.orig linux-2.6.24.7/drivers/char/Kconfig.orig ---- linux-2.6.24.7.old/drivers/char/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/Kconfig.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,1051 @@ -+# -+# Character device configuration -+# -+ -+menu "Character devices" -+ -+config VT -+ bool "Virtual terminal" if EMBEDDED -+ depends on !S390 -+ select INPUT -+ default y if !VIOCONS -+ ---help--- -+ If you say Y here, you will get support for terminal devices with -+ display and keyboard devices. These are called "virtual" because you -+ can run several virtual terminals (also called virtual consoles) on -+ one physical terminal. This is rather useful, for example one -+ virtual terminal can collect system messages and warnings, another -+ one can be used for a text-mode user session, and a third could run -+ an X session, all in parallel. Switching between virtual terminals -+ is done with certain key combinations, usually Alt-. -+ -+ The setterm command ("man setterm") can be used to change the -+ properties (such as colors or beeping) of a virtual terminal. The -+ man page console_codes(4) ("man console_codes") contains the special -+ character sequences that can be used to change those properties -+ directly. The fonts used on virtual terminals can be changed with -+ the setfont ("man setfont") command and the key bindings are defined -+ with the loadkeys ("man loadkeys") command. -+ -+ You need at least one virtual terminal device in order to make use -+ of your keyboard and monitor. Therefore, only people configuring an -+ embedded system would want to say N here in order to save some -+ memory; the only way to log into such a system is then via a serial -+ or network connection. -+ -+ If unsure, say Y, or else you won't be able to do much with your new -+ shiny Linux system :-) -+ -+config VT_CONSOLE -+ bool "Support for console on virtual terminal" if EMBEDDED -+ depends on VT -+ default y -+ ---help--- -+ The system console is the device which receives all kernel messages -+ and warnings and which allows logins in single user mode. If you -+ answer Y here, a virtual terminal (the device used to interact with -+ a physical terminal) can be used as system console. This is the most -+ common mode of operations, so you should say Y here unless you want -+ the kernel messages be output only to a serial port (in which case -+ you should say Y to "Console on serial port", below). -+ -+ If you do say Y here, by default the currently visible virtual -+ terminal (/dev/tty0) will be used as system console. You can change -+ that with a kernel command line option such as "console=tty3" which -+ would use the third virtual terminal as system console. (Try "man -+ bootparam" or see the documentation of your boot loader (lilo or -+ loadlin) about how to pass options to the kernel at boot time.) -+ -+ If unsure, say Y. -+ -+config HW_CONSOLE -+ bool -+ depends on VT && !S390 && !UML -+ default y -+ -+config VT_HW_CONSOLE_BINDING -+ bool "Support for binding and unbinding console drivers" -+ depends on HW_CONSOLE -+ default n -+ ---help--- -+ The virtual terminal is the device that interacts with the physical -+ terminal through console drivers. On these systems, at least one -+ console driver is loaded. In other configurations, additional console -+ drivers may be enabled, such as the framebuffer console. If more than -+ 1 console driver is enabled, setting this to 'y' will allow you to -+ select the console driver that will serve as the backend for the -+ virtual terminals. -+ -+ See for more -+ information. For framebuffer console users, please refer to -+ . -+ -+config SERIAL_NONSTANDARD -+ bool "Non-standard serial port support" -+ depends on HAS_IOMEM -+ ---help--- -+ Say Y here if you have any non-standard serial boards -- boards -+ which aren't supported using the standard "dumb" serial driver. -+ This includes intelligent serial boards such as Cyclades, -+ Digiboards, etc. These are usually used for systems that need many -+ serial ports because they serve many terminals or dial-in -+ connections. -+ -+ Note that the answer to this question won't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about non-standard serial boards. -+ -+ Most people can say N here. -+ -+config COMPUTONE -+ tristate "Computone IntelliPort Plus serial support" -+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) -+ ---help--- -+ This driver supports the entire family of Intelliport II/Plus -+ controllers with the exception of the MicroChannel controllers and -+ products previous to the Intelliport II. These are multiport cards, -+ which give you many serial ports. You would need something like this -+ to connect more than two modems to your Linux box, for instance in -+ order to become a dial-in server. If you have a card like that, say -+ Y here and read . -+ -+ To compile this driver as modules, choose M here: the -+ modules will be called ip2 and ip2main. -+ -+config ROCKETPORT -+ tristate "Comtrol RocketPort support" -+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) -+ help -+ This driver supports Comtrol RocketPort and RocketModem PCI boards. -+ These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or -+ modems. For information about the RocketPort/RocketModem boards -+ and this driver read . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called rocket. -+ -+ If you want to compile this driver into the kernel, say Y here. If -+ you don't have a Comtrol RocketPort/RocketModem card installed, say N. -+ -+config CYCLADES -+ tristate "Cyclades async mux support" -+ depends on SERIAL_NONSTANDARD && (PCI || ISA) -+ select FW_LOADER -+ ---help--- -+ This driver supports Cyclades Z and Y multiserial boards. -+ You would need something like this to connect more than two modems to -+ your Linux box, for instance in order to become a dial-in server. -+ -+ For information about the Cyclades-Z card, read -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called cyclades. -+ -+ If you haven't heard about it, it's safe to say N. -+ -+config CYZ_INTR -+ bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && CYCLADES -+ help -+ The Cyclades-Z family of multiport cards allows 2 (two) driver op -+ modes: polling and interrupt. In polling mode, the driver will check -+ the status of the Cyclades-Z ports every certain amount of time -+ (which is called polling cycle and is configurable). In interrupt -+ mode, it will use an interrupt line (IRQ) in order to check the -+ status of the Cyclades-Z ports. The default op mode is polling. If -+ unsure, say N. -+ -+config DIGIEPCA -+ tristate "Digiboard Intelligent Async Support" -+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) -+ ---help--- -+ This is a driver for Digi International's Xx, Xeve, and Xem series -+ of cards which provide multiple serial ports. You would need -+ something like this to connect more than two modems to your Linux -+ box, for instance in order to become a dial-in server. This driver -+ supports the original PC (ISA) boards as well as PCI, and EISA. If -+ you have a card like this, say Y here and read the file -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called epca. -+ -+config ESPSERIAL -+ tristate "Hayes ESP serial port support" -+ depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API -+ help -+ This is a driver which supports Hayes ESP serial ports. Both single -+ port cards and multiport cards are supported. Make sure to read -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called esp. -+ -+ If unsure, say N. -+ -+config MOXA_INTELLIO -+ tristate "Moxa Intellio support" -+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) -+ help -+ Say Y here if you have a Moxa Intellio multiport serial card. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called moxa. -+ -+config MOXA_SMARTIO -+ tristate "Moxa SmartIO support (OBSOLETE)" -+ depends on SERIAL_NONSTANDARD -+ help -+ Say Y here if you have a Moxa SmartIO multiport serial card. -+ -+ This driver can also be built as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called mxser. If you want to do that, say M -+ here. -+ -+config MOXA_SMARTIO_NEW -+ tristate "Moxa SmartIO support v. 2.0" -+ depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) -+ help -+ Say Y here if you have a Moxa SmartIO multiport serial card and/or -+ want to help develop a new version of this driver. -+ -+ This is upgraded (1.9.1) driver from original Moxa drivers with -+ changes finally resulting in PCI probing. -+ -+ This driver can also be built as a module. The module will be called -+ mxser_new. If you want to do that, say M here. -+ -+config ISI -+ tristate "Multi-Tech multiport card support (EXPERIMENTAL)" -+ depends on SERIAL_NONSTANDARD && PCI -+ select FW_LOADER -+ help -+ This is a driver for the Multi-Tech cards which provide several -+ serial ports. The driver is experimental and can currently only be -+ built as a module. The module will be called isicom. -+ If you want to do that, choose M here. -+ -+config SYNCLINK -+ tristate "Microgate SyncLink card support" -+ depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API -+ help -+ Provides support for the SyncLink ISA and PCI multiprotocol serial -+ adapters. These adapters support asynchronous and HDLC bit -+ synchronous communication up to 10Mbps (PCI adapter). -+ -+ This driver can only be built as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called synclink. If you want to do that, say M -+ here. -+ -+config SYNCLINKMP -+ tristate "SyncLink Multiport support" -+ depends on SERIAL_NONSTANDARD && PCI -+ help -+ Enable support for the SyncLink Multiport (2 or 4 ports) -+ serial adapter, running asynchronous and HDLC communications up -+ to 2.048Mbps. Each ports is independently selectable for -+ RS-232, V.35, RS-449, RS-530, and X.21 -+ -+ This driver may be built as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called synclinkmp. If you want to do that, say M -+ here. -+ -+config SYNCLINK_GT -+ tristate "SyncLink GT/AC support" -+ depends on SERIAL_NONSTANDARD && PCI -+ help -+ Support for SyncLink GT and SyncLink AC families of -+ synchronous and asynchronous serial adapters -+ manufactured by Microgate Systems, Ltd. (www.microgate.com) -+ -+config N_HDLC -+ tristate "HDLC line discipline support" -+ depends on SERIAL_NONSTANDARD -+ help -+ Allows synchronous HDLC communications with tty device drivers that -+ support synchronous HDLC such as the Microgate SyncLink adapter. -+ -+ This driver can only be built as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called n_hdlc. If you want to do that, say M -+ here. -+ -+config RISCOM8 -+ tristate "SDL RISCom/8 card support" -+ depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP -+ help -+ This is a driver for the SDL Communications RISCom/8 multiport card, -+ which gives you many serial ports. You would need something like -+ this to connect more than two modems to your Linux box, for instance -+ in order to become a dial-in server. If you have a card like that, -+ say Y here and read the file . -+ -+ Also it's possible to say M here and compile this driver as kernel -+ loadable module; the module will be called riscom8. -+ -+config SPECIALIX -+ tristate "Specialix IO8+ card support" -+ depends on SERIAL_NONSTANDARD -+ help -+ This is a driver for the Specialix IO8+ multiport card (both the -+ ISA and the PCI version) which gives you many serial ports. You -+ would need something like this to connect more than two modems to -+ your Linux box, for instance in order to become a dial-in server. -+ -+ If you have a card like that, say Y here and read the file -+ . Also it's possible to say M here -+ and compile this driver as kernel loadable module which will be -+ called specialix. -+ -+config SPECIALIX_RTSCTS -+ bool "Specialix DTR/RTS pin is RTS" -+ depends on SPECIALIX -+ help -+ The Specialix IO8+ card can only support either RTS or DTR. If you -+ say N here, the driver will use the pin as "DTR" when the tty is in -+ software handshake mode. If you say Y here or hardware handshake is -+ on, it will always be RTS. Read the file -+ for more information. -+ -+config SX -+ tristate "Specialix SX (and SI) card support" -+ depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) -+ help -+ This is a driver for the SX and SI multiport serial cards. -+ Please read the file for details. -+ -+ This driver can only be built as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called sx. If you want to do that, say M here. -+ -+config RIO -+ tristate "Specialix RIO system support" -+ depends on SERIAL_NONSTANDARD -+ help -+ This is a driver for the Specialix RIO, a smart serial card which -+ drives an outboard box that can support up to 128 ports. Product -+ information is at . -+ There are both ISA and PCI versions. -+ -+config RIO_OLDPCI -+ bool "Support really old RIO/PCI cards" -+ depends on RIO -+ help -+ Older RIO PCI cards need some initialization-time configuration to -+ determine the IRQ and some control addresses. If you have a RIO and -+ this doesn't seem to work, try setting this to Y. -+ -+config STALDRV -+ bool "Stallion multiport serial support" -+ depends on SERIAL_NONSTANDARD -+ help -+ Stallion cards give you many serial ports. You would need something -+ like this to connect more than two modems to your Linux box, for -+ instance in order to become a dial-in server. If you say Y here, -+ you will be asked for your specific card model in the next -+ questions. Make sure to read in -+ this case. If you have never heard about all this, it's safe to -+ say N. -+ -+config STALLION -+ tristate "Stallion EasyIO or EC8/32 support" -+ depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) -+ help -+ If you have an EasyIO or EasyConnection 8/32 multiport Stallion -+ card, then this is for you; say Y. Make sure to read -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called stallion. -+ -+config ISTALLION -+ tristate "Stallion EC8/64, ONboard, Brumby support" -+ depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) -+ help -+ If you have an EasyConnection 8/64, ONboard, Brumby or Stallion -+ serial multiport card, say Y here. Make sure to read -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called istallion. -+ -+config A2232 -+ tristate "Commodore A2232 serial support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP -+ ---help--- -+ This option supports the 2232 7-port serial card shipped with the -+ Amiga 2000 and other Zorro-bus machines, dating from 1989. At -+ a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip -+ each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The -+ ports were connected with 8 pin DIN connectors on the card bracket, -+ for which 8 pin to DB25 adapters were supplied. The card also had -+ jumpers internally to toggle various pinning configurations. -+ -+ This driver can be built as a module; but then "generic_serial" -+ will also be built as a module. This has to be loaded before -+ "ser_a2232". If you want to do this, answer M here. -+ -+config SGI_SNSC -+ bool "SGI Altix system controller communication support" -+ depends on (IA64_SGI_SN2 || IA64_GENERIC) -+ help -+ If you have an SGI Altix and you want to enable system -+ controller communication from user space (you want this!), -+ say Y. Otherwise, say N. -+ -+config SGI_TIOCX -+ bool "SGI TIO CX driver support" -+ depends on (IA64_SGI_SN2 || IA64_GENERIC) -+ help -+ If you have an SGI Altix and you have fpga devices attached -+ to your TIO, say Y here, otherwise say N. -+ -+config SGI_MBCS -+ tristate "SGI FPGA Core Services driver support" -+ depends on SGI_TIOCX -+ help -+ If you have an SGI Altix with an attached SABrick -+ say Y or M here, otherwise say N. -+ -+source "drivers/serial/Kconfig" -+ -+config UNIX98_PTYS -+ bool "Unix98 PTY support" if EMBEDDED -+ default y -+ ---help--- -+ A pseudo terminal (PTY) is a software device consisting of two -+ halves: a master and a slave. The slave device behaves identical to -+ a physical terminal; the master device is used by a process to -+ read data from and write data to the slave, thereby emulating a -+ terminal. Typical programs for the master side are telnet servers -+ and xterms. -+ -+ Linux has traditionally used the BSD-like names /dev/ptyxx for -+ masters and /dev/ttyxx for slaves of pseudo terminals. This scheme -+ has a number of problems. The GNU C library glibc 2.1 and later, -+ however, supports the Unix98 naming standard: in order to acquire a -+ pseudo terminal, a process opens /dev/ptmx; the number of the pseudo -+ terminal is then made available to the process and the pseudo -+ terminal slave can be accessed as /dev/pts/. What was -+ traditionally /dev/ttyp2 will then be /dev/pts/2, for example. -+ -+ All modern Linux systems use the Unix98 ptys. Say Y unless -+ you're on an embedded system and want to conserve memory. -+ -+config LEGACY_PTYS -+ bool "Legacy (BSD) PTY support" -+ default y -+ ---help--- -+ A pseudo terminal (PTY) is a software device consisting of two -+ halves: a master and a slave. The slave device behaves identical to -+ a physical terminal; the master device is used by a process to -+ read data from and write data to the slave, thereby emulating a -+ terminal. Typical programs for the master side are telnet servers -+ and xterms. -+ -+ Linux has traditionally used the BSD-like names /dev/ptyxx -+ for masters and /dev/ttyxx for slaves of pseudo -+ terminals. This scheme has a number of problems, including -+ security. This option enables these legacy devices; on most -+ systems, it is safe to say N. -+ -+ -+config LEGACY_PTY_COUNT -+ int "Maximum number of legacy PTY in use" -+ depends on LEGACY_PTYS -+ range 0 256 -+ default "256" -+ ---help--- -+ The maximum number of legacy PTYs that can be used at any one time. -+ The default is 256, and should be more than enough. Embedded -+ systems may want to reduce this to save memory. -+ -+ When not in use, each legacy PTY occupies 12 bytes on 32-bit -+ architectures and 24 bytes on 64-bit architectures. -+ -+config BRIQ_PANEL -+ tristate 'Total Impact briQ front panel driver' -+ depends on PPC_CHRP -+ ---help--- -+ The briQ is a small footprint CHRP computer with a frontpanel VFD, a -+ tristate led and two switches. It is the size of a CDROM drive. -+ -+ If you have such one and want anything showing on the VFD then you -+ must answer Y here. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called briq_panel. -+ -+ It's safe to say N here. -+ -+config PRINTER -+ tristate "Parallel printer support" -+ depends on PARPORT -+ ---help--- -+ If you intend to attach a printer to the parallel port of your Linux -+ box (as opposed to using a serial printer; if the connector at the -+ printer has 9 or 25 holes ["female"], then it's serial), say Y. -+ Also read the Printing-HOWTO, available from -+ . -+ -+ It is possible to share one parallel port among several devices -+ (e.g. printer and ZIP drive) and it is safe to compile the -+ corresponding drivers into the kernel. -+ -+ To compile this driver as a module, choose M here and read -+ . The module will be called lp. -+ -+ If you have several parallel ports, you can specify which ports to -+ use with the "lp" kernel command line option. (Try "man bootparam" -+ or see the documentation of your boot loader (lilo or loadlin) about -+ how to pass options to the kernel at boot time.) The syntax of the -+ "lp" command line option can be found in . -+ -+ If you have more than 8 printers, you need to increase the LP_NO -+ macro in lp.c and the PARPORT_MAX macro in parport.h. -+ -+config LP_CONSOLE -+ bool "Support for console on line printer" -+ depends on PRINTER -+ ---help--- -+ If you want kernel messages to be printed out as they occur, you -+ can have a console on the printer. This option adds support for -+ doing that; to actually get it to happen you need to pass the -+ option "console=lp0" to the kernel at boot time. -+ -+ If the printer is out of paper (or off, or unplugged, or too -+ busy..) the kernel will stall until the printer is ready again. -+ By defining CONSOLE_LP_STRICT to 0 (at your own risk) you -+ can make the kernel continue when this happens, -+ but it'll lose the kernel messages. -+ -+ If unsure, say N. -+ -+config PPDEV -+ tristate "Support for user-space parallel port device drivers" -+ depends on PARPORT -+ ---help--- -+ Saying Y to this adds support for /dev/parport device nodes. This -+ is needed for programs that want portable access to the parallel -+ port, for instance deviceid (which displays Plug-and-Play device -+ IDs). -+ -+ This is the parallel port equivalent of SCSI generic support (sg). -+ It is safe to say N to this -- it is not needed for normal printing -+ or parallel port CD-ROM/disk support. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ppdev. -+ -+ If unsure, say N. -+ -+config HVC_DRIVER -+ bool -+ help -+ Generic "hypervisor virtual console" infrastructure for various -+ hypervisors (pSeries, iSeries, Xen, lguest). -+ It will automatically be selected if one of the back-end console drivers -+ is selected. -+ -+ -+config HVC_CONSOLE -+ bool "pSeries Hypervisor Virtual Console support" -+ depends on PPC_PSERIES -+ select HVC_DRIVER -+ help -+ pSeries machines when partitioned support a hypervisor virtual -+ console. This driver allows each pSeries partition to have a console -+ which is accessed via the HMC. -+ -+config HVC_ISERIES -+ bool "iSeries Hypervisor Virtual Console support" -+ depends on PPC_ISERIES -+ default y -+ select HVC_DRIVER -+ help -+ iSeries machines support a hypervisor virtual console. -+ -+config HVC_RTAS -+ bool "IBM RTAS Console support" -+ depends on PPC_RTAS -+ select HVC_DRIVER -+ help -+ IBM Console device driver which makes use of RTAS -+ -+config HVC_BEAT -+ bool "Toshiba's Beat Hypervisor Console support" -+ depends on PPC_CELLEB -+ select HVC_DRIVER -+ help -+ Toshiba's Cell Reference Set Beat Console device driver -+ -+config HVC_XEN -+ bool "Xen Hypervisor Console support" -+ depends on XEN -+ select HVC_DRIVER -+ default y -+ help -+ Xen virtual console device driver -+ -+config VIRTIO_CONSOLE -+ bool -+ select HVC_DRIVER -+ -+config HVCS -+ tristate "IBM Hypervisor Virtual Console Server support" -+ depends on PPC_PSERIES -+ help -+ Partitionable IBM Power5 ppc64 machines allow hosting of -+ firmware virtual consoles from one Linux partition by -+ another Linux partition. This driver allows console data -+ from Linux partitions to be accessed through TTY device -+ interfaces in the device tree of a Linux partition running -+ this driver. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called hvcs.ko. Additionally, this module -+ will depend on arch specific APIs exported from hvcserver.ko -+ which will also be compiled when this driver is built as a -+ module. -+ -+source "drivers/char/ipmi/Kconfig" -+ -+config DS1620 -+ tristate "NetWinder thermometer support" -+ depends on ARCH_NETWINDER -+ help -+ Say Y here to include support for the thermal management hardware -+ found in the NetWinder. This driver allows the user to control the -+ temperature set points and to read the current temperature. -+ -+ It is also possible to say M here to build it as a module (ds1620) -+ It is recommended to be used on a NetWinder, but it is not a -+ necessity. -+ -+config NWBUTTON -+ tristate "NetWinder Button" -+ depends on ARCH_NETWINDER -+ ---help--- -+ If you say Y here and create a character device node /dev/nwbutton -+ with major and minor numbers 10 and 158 ("man mknod"), then every -+ time the orange button is pressed a number of times, the number of -+ times the button was pressed will be written to that device. -+ -+ This is most useful for applications, as yet unwritten, which -+ perform actions based on how many times the button is pressed in a -+ row. -+ -+ Do not hold the button down for too long, as the driver does not -+ alter the behaviour of the hardware reset circuitry attached to the -+ button; it will still execute a hard reset if the button is held -+ down for longer than approximately five seconds. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called nwbutton. -+ -+ Most people will answer Y to this question and "Reboot Using Button" -+ below to be able to initiate a system shutdown from the button. -+ -+config NWBUTTON_REBOOT -+ bool "Reboot Using Button" -+ depends on NWBUTTON -+ help -+ If you say Y here, then you will be able to initiate a system -+ shutdown and reboot by pressing the orange button a number of times. -+ The number of presses to initiate the shutdown is two by default, -+ but this can be altered by modifying the value of NUM_PRESSES_REBOOT -+ in nwbutton.h and recompiling the driver or, if you compile the -+ driver as a module, you can specify the number of presses at load -+ time with "insmod button reboot_count=". -+ -+config NWFLASH -+ tristate "NetWinder flash support" -+ depends on ARCH_NETWINDER -+ ---help--- -+ If you say Y here and create a character device /dev/flash with -+ major 10 and minor 160 you can manipulate the flash ROM containing -+ the NetWinder firmware. Be careful as accidentally overwriting the -+ flash contents can render your computer unbootable. On no account -+ allow random users access to this device. :-) -+ -+ To compile this driver as a module, choose M here: the -+ module will be called nwflash. -+ -+ If you're not sure, say N. -+ -+source "drivers/char/hw_random/Kconfig" -+ -+config NVRAM -+ tristate "/dev/nvram support" -+ depends on ATARI || X86 || ARM || GENERIC_NVRAM -+ ---help--- -+ If you say Y here and create a character special file /dev/nvram -+ with major number 10 and minor number 144 using mknod ("man mknod"), -+ you get read and write access to the extra bytes of non-volatile -+ memory in the real time clock (RTC), which is contained in every PC -+ and most Ataris. The actual number of bytes varies, depending on the -+ nvram in the system, but is usually 114 (128-14 for the RTC). -+ -+ This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" -+ on Ataris. /dev/nvram may be used to view settings there, or to -+ change them (with some utility). It could also be used to frequently -+ save a few bits of very important data that may not be lost over -+ power-off and for which writing to disk is too insecure. Note -+ however that most NVRAM space in a PC belongs to the BIOS and you -+ should NEVER idly tamper with it. See Ralf Brown's interrupt list -+ for a guide to the use of CMOS bytes by your BIOS. -+ -+ On Atari machines, /dev/nvram is always configured and does not need -+ to be selected. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called nvram. -+ -+config RTC -+ tristate "Enhanced Real Time Clock Support" -+ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 -+ ---help--- -+ If you say Y here and create a character special file /dev/rtc with -+ major number 10 and minor number 135 using mknod ("man mknod"), you -+ will get access to the real time clock (or hardware clock) built -+ into your computer. -+ -+ Every PC has such a clock built in. It can be used to generate -+ signals from as low as 1Hz up to 8192Hz, and can also be used -+ as a 24 hour alarm. It reports status information via the file -+ /proc/driver/rtc and its behaviour is set by various ioctls on -+ /dev/rtc. -+ -+ If you run Linux on a multiprocessor machine and said Y to -+ "Symmetric Multi Processing" above, you should say Y here to read -+ and set the RTC in an SMP compatible fashion. -+ -+ If you think you have a use for such a device (such as periodic data -+ sampling), then say Y here, and read -+ for details. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called rtc. -+ -+config JS_RTC -+ tristate "Enhanced Real Time Clock Support" -+ depends on SPARC32 && PCI -+ ---help--- -+ If you say Y here and create a character special file /dev/rtc with -+ major number 10 and minor number 135 using mknod ("man mknod"), you -+ will get access to the real time clock (or hardware clock) built -+ into your computer. -+ -+ Every PC has such a clock built in. It can be used to generate -+ signals from as low as 1Hz up to 8192Hz, and can also be used -+ as a 24 hour alarm. It reports status information via the file -+ /proc/driver/rtc and its behaviour is set by various ioctls on -+ /dev/rtc. -+ -+ If you think you have a use for such a device (such as periodic data -+ sampling), then say Y here, and read -+ for details. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called js-rtc. -+ -+config SGI_DS1286 -+ tristate "SGI DS1286 RTC support" -+ depends on SGI_IP22 -+ help -+ If you say Y here and create a character special file /dev/rtc with -+ major number 10 and minor number 135 using mknod ("man mknod"), you -+ will get access to the real time clock built into your computer. -+ Every SGI has such a clock built in. It reports status information -+ via the file /proc/rtc and its behaviour is set by various ioctls on -+ /dev/rtc. -+ -+config SGI_IP27_RTC -+ bool "SGI M48T35 RTC support" -+ depends on SGI_IP27 -+ help -+ If you say Y here and create a character special file /dev/rtc with -+ major number 10 and minor number 135 using mknod ("man mknod"), you -+ will get access to the real time clock built into your computer. -+ Every SGI has such a clock built in. It reports status information -+ via the file /proc/rtc and its behaviour is set by various ioctls on -+ /dev/rtc. -+ -+config GEN_RTC -+ tristate "Generic /dev/rtc emulation" -+ depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH -+ ---help--- -+ If you say Y here and create a character special file /dev/rtc with -+ major number 10 and minor number 135 using mknod ("man mknod"), you -+ will get access to the real time clock (or hardware clock) built -+ into your computer. -+ -+ It reports status information via the file /proc/driver/rtc and its -+ behaviour is set by various ioctls on /dev/rtc. If you enable the -+ "extended RTC operation" below it will also provide an emulation -+ for RTC_UIE which is required by some programs and may improve -+ precision in some cases. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called genrtc. -+ -+config GEN_RTC_X -+ bool "Extended RTC operation" -+ depends on GEN_RTC -+ help -+ Provides an emulation for RTC_UIE which is required by some programs -+ and may improve precision of the generic RTC support in some cases. -+ -+config EFI_RTC -+ bool "EFI Real Time Clock Services" -+ depends on IA64 -+ -+config DS1302 -+ tristate "DS1302 RTC support" -+ depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT) -+ help -+ If you say Y here and create a character special file /dev/rtc with -+ major number 121 and minor number 0 using mknod ("man mknod"), you -+ will get access to the real time clock (or hardware clock) built -+ into your computer. -+ -+config COBALT_LCD -+ bool "Support for Cobalt LCD" -+ depends on MIPS_COBALT -+ help -+ This option enables support for the LCD display and buttons found -+ on Cobalt systems through a misc device. -+ -+config DTLK -+ tristate "Double Talk PC internal speech card support" -+ depends on ISA -+ help -+ This driver is for the DoubleTalk PC, a speech synthesizer -+ manufactured by RC Systems (). It is also -+ called the `internal DoubleTalk'. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called dtlk. -+ -+config R3964 -+ tristate "Siemens R3964 line discipline" -+ ---help--- -+ This driver allows synchronous communication with devices using the -+ Siemens R3964 packet protocol. Unless you are dealing with special -+ hardware like PLCs, you are unlikely to need this. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called n_r3964. -+ -+ If unsure, say N. -+ -+config APPLICOM -+ tristate "Applicom intelligent fieldbus card support" -+ depends on PCI -+ ---help--- -+ This driver provides the kernel-side support for the intelligent -+ fieldbus cards made by Applicom International. More information -+ about these cards can be found on the WWW at the address -+ , or by email from David Woodhouse -+ . -+ -+ To compile this driver as a module, choose M here: the -+ module will be called applicom. -+ -+ If unsure, say N. -+ -+config SONYPI -+ tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT -+ ---help--- -+ This driver enables access to the Sony Programmable I/O Control -+ Device which can be found in many (all ?) Sony Vaio laptops. -+ -+ If you have one of those laptops, read -+ , and say Y or M here. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called sonypi. -+ -+config GPIO_TB0219 -+ tristate "TANBAC TB0219 GPIO support" -+ depends on TANBAC_TB022X -+ select GPIO_VR41XX -+ -+source "drivers/char/pcmcia/Kconfig" -+ -+config MWAVE -+ tristate "ACP Modem (Mwave) support" -+ depends on X86 -+ select SERIAL_8250 -+ ---help--- -+ The ACP modem (Mwave) for Linux is a WinModem. It is composed of a -+ kernel driver and a user level application. Together these components -+ support direct attachment to public switched telephone networks (PSTNs) -+ and support selected world wide countries. -+ -+ This version of the ACP Modem driver supports the IBM Thinkpad 600E, -+ 600, and 770 that include on board ACP modem hardware. -+ -+ The modem also supports the standard communications port interface -+ (ttySx) and is compatible with the Hayes AT Command Set. -+ -+ The user level application needed to use this driver can be found at -+ the IBM Linux Technology Center (LTC) web site: -+ . -+ -+ If you own one of the above IBM Thinkpads which has the Mwave chipset -+ in it, say Y. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called mwave. -+ -+config SCx200_GPIO -+ tristate "NatSemi SCx200 GPIO Support" -+ depends on SCx200 -+ select NSC_GPIO -+ help -+ Give userspace access to the GPIO pins on the National -+ Semiconductor SCx200 processors. -+ -+ If compiled as a module, it will be called scx200_gpio. -+ -+config PC8736x_GPIO -+ tristate "NatSemi PC8736x GPIO Support" -+ depends on X86 -+ default SCx200_GPIO # mostly N -+ select NSC_GPIO # needed for support routines -+ help -+ Give userspace access to the GPIO pins on the National -+ Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip -+ has multiple functional units, inc several managed by -+ hwmon/pc87360 driver. Tested with PC-87366 -+ -+ If compiled as a module, it will be called pc8736x_gpio. -+ -+config NSC_GPIO -+ tristate "NatSemi Base GPIO Support" -+ depends on X86_32 -+ # selected by SCx200_GPIO and PC8736x_GPIO -+ # what about 2 selectors differing: m != y -+ help -+ Common support used (and needed) by scx200_gpio and -+ pc8736x_gpio drivers. If those drivers are built as -+ modules, this one will be too, named nsc_gpio -+ -+config CS5535_GPIO -+ tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" -+ depends on X86_32 -+ help -+ Give userspace access to the GPIO pins on the AMD CS5535 and -+ CS5536 Geode companion devices. -+ -+ If compiled as a module, it will be called cs5535_gpio. -+ -+config GPIO_DEVICE -+ tristate "GPIO device support" -+ depends on GENERIC_GPIO -+ help -+ Say Y to enable Linux GPIO device support. This allows control of -+ GPIO pins using a character device -+ -+config GPIO_VR41XX -+ tristate "NEC VR4100 series General-purpose I/O Unit support" -+ depends on CPU_VR41XX -+ -+config RAW_DRIVER -+ tristate "RAW driver (/dev/raw/rawN)" -+ depends on BLOCK -+ help -+ The raw driver permits block devices to be bound to /dev/raw/rawN. -+ Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. -+ See the raw(8) manpage for more details. -+ -+ Applications should preferably open the device (eg /dev/hda1) -+ with the O_DIRECT flag. -+ -+config MAX_RAW_DEVS -+ int "Maximum number of RAW devices to support (1-8192)" -+ depends on RAW_DRIVER -+ default "256" -+ help -+ The maximum number of RAW devices that are supported. -+ Default is 256. Increase this number in case you need lots of -+ raw devices. -+ -+config HPET -+ bool "HPET - High Precision Event Timer" if (X86 || IA64) -+ default n -+ depends on ACPI -+ help -+ If you say Y here, you will have a miscdevice named "/dev/hpet/". Each -+ open selects one of the timers supported by the HPET. The timers are -+ non-periodic and/or periodic. -+ -+config HPET_RTC_IRQ -+ bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC -+ default n -+ depends on HPET -+ help -+ If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It -+ is assumed the platform called hpet_alloc with the RTC IRQ values for -+ the HPET timers. -+ -+config HPET_MMAP -+ bool "Allow mmap of HPET" -+ default y -+ depends on HPET -+ help -+ If you say Y here, user applications will be able to mmap -+ the HPET registers. -+ -+ In some hardware implementations, the page containing HPET -+ registers may also contain other things that shouldn't be -+ exposed to the user. If this applies to your hardware, -+ say N here. -+ -+config HANGCHECK_TIMER -+ tristate "Hangcheck timer" -+ depends on X86 || IA64 || PPC64 || S390 -+ help -+ The hangcheck-timer module detects when the system has gone -+ out to lunch past a certain margin. It can reboot the system -+ or merely print a warning. -+ -+config MMTIMER -+ tristate "MMTIMER Memory mapped RTC for SGI Altix" -+ depends on IA64_GENERIC || IA64_SGI_SN2 -+ default y -+ help -+ The mmtimer device allows direct userspace access to the -+ Altix system timer. -+ -+source "drivers/char/tpm/Kconfig" -+ -+config TELCLOCK -+ tristate "Telecom clock driver for ATCA SBC" -+ depends on EXPERIMENTAL && X86 -+ default n -+ help -+ The telecom clock device is specific to the MPCBL0010 and MPCBL0050 -+ ATCA computers and allows direct userspace access to the -+ configuration of the telecom clock configuration settings. This -+ device is used for hardware synchronization across the ATCA backplane -+ fabric. Upon loading, the driver exports a sysfs directory, -+ /sys/devices/platform/telco_clock, with a number of files for -+ controlling the behavior of this hardware. -+ -+config DEVPORT -+ bool -+ depends on !M68K -+ depends on ISA || PCI -+ default y -+ -+source "drivers/s390/char/Kconfig" -+ -+endmenu -+ -diff -urN linux-2.6.24.7.old/drivers/char/Makefile linux-2.6.24.7/drivers/char/Makefile ---- linux-2.6.24.7.old/drivers/char/Makefile 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/char/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -98,6 +98,10 @@ - obj-$(CONFIG_GPIO_TB0219) += tb0219.o - obj-$(CONFIG_TELCLOCK) += tlclk.o - -+obj-$(CONFIG_RTC_PCF8563) += rtc_pcf8563.o -+obj-$(CONFIG_RTC_JZ) += rtc_jz.o -+obj-$(CONFIG_JZCHAR) += jzchar/ -+ - obj-$(CONFIG_MWAVE) += mwave/ - obj-$(CONFIG_AGP) += agp/ - obj-$(CONFIG_DRM) += drm/ -diff -urN linux-2.6.24.7.old/drivers/char/Makefile.orig linux-2.6.24.7/drivers/char/Makefile.orig ---- linux-2.6.24.7.old/drivers/char/Makefile.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/Makefile.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,138 @@ -+# -+# Makefile for the kernel character device drivers. -+# -+ -+# -+# This file contains the font map for the default (hardware) font -+# -+FONTMAPFILE = cp437.uni -+ -+obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o -+ -+obj-$(CONFIG_LEGACY_PTYS) += pty.o -+obj-$(CONFIG_UNIX98_PTYS) += pty.o -+obj-y += misc.o -+obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \ -+ consolemap_deftbl.o selection.o keyboard.o -+obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o -+obj-$(CONFIG_AUDIT) += tty_audit.o -+obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o -+obj-$(CONFIG_ESPSERIAL) += esp.o -+obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o -+obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o -+obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o -+obj-$(CONFIG_ROCKETPORT) += rocket.o -+obj-$(CONFIG_SERIAL167) += serial167.o -+obj-$(CONFIG_CYCLADES) += cyclades.o -+obj-$(CONFIG_STALLION) += stallion.o -+obj-$(CONFIG_ISTALLION) += istallion.o -+obj-$(CONFIG_DIGIEPCA) += epca.o -+obj-$(CONFIG_SPECIALIX) += specialix.o -+obj-$(CONFIG_MOXA_INTELLIO) += moxa.o -+obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o -+obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o -+obj-$(CONFIG_MOXA_SMARTIO) += mxser.o -+obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o -+obj-$(CONFIG_COMPUTONE) += ip2/ -+obj-$(CONFIG_RISCOM8) += riscom8.o -+obj-$(CONFIG_ISI) += isicom.o -+obj-$(CONFIG_SYNCLINK) += synclink.o -+obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o -+obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o -+obj-$(CONFIG_N_HDLC) += n_hdlc.o -+obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -+obj-$(CONFIG_SX) += sx.o generic_serial.o -+obj-$(CONFIG_RIO) += rio/ generic_serial.o -+obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o -+obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o -+obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o -+obj-$(CONFIG_HVC_BEAT) += hvc_beat.o -+obj-$(CONFIG_HVC_DRIVER) += hvc_console.o -+obj-$(CONFIG_HVC_XEN) += hvc_xen.o -+obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o -+obj-$(CONFIG_RAW_DRIVER) += raw.o -+obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o -+obj-$(CONFIG_MSPEC) += mspec.o -+obj-$(CONFIG_MMTIMER) += mmtimer.o -+obj-$(CONFIG_VIOCONS) += viocons.o -+obj-$(CONFIG_VIOTAPE) += viotape.o -+obj-$(CONFIG_HVCS) += hvcs.o -+obj-$(CONFIG_SGI_MBCS) += mbcs.o -+obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o -+ -+obj-$(CONFIG_PRINTER) += lp.o -+obj-$(CONFIG_TIPAR) += tipar.o -+ -+obj-$(CONFIG_APM_EMULATION) += apm-emulation.o -+ -+obj-$(CONFIG_DTLK) += dtlk.o -+obj-$(CONFIG_R3964) += n_r3964.o -+obj-$(CONFIG_APPLICOM) += applicom.o -+obj-$(CONFIG_SONYPI) += sonypi.o -+obj-$(CONFIG_RTC) += rtc.o -+obj-$(CONFIG_HPET) += hpet.o -+obj-$(CONFIG_GEN_RTC) += genrtc.o -+obj-$(CONFIG_EFI_RTC) += efirtc.o -+obj-$(CONFIG_SGI_DS1286) += ds1286.o -+obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o -+obj-$(CONFIG_DS1302) += ds1302.o -+ifeq ($(CONFIG_GENERIC_NVRAM),y) -+ obj-$(CONFIG_NVRAM) += generic_nvram.o -+else -+ obj-$(CONFIG_NVRAM) += nvram.o -+endif -+obj-$(CONFIG_TOSHIBA) += toshiba.o -+obj-$(CONFIG_I8K) += i8k.o -+obj-$(CONFIG_DS1620) += ds1620.o -+obj-$(CONFIG_HW_RANDOM) += hw_random/ -+obj-$(CONFIG_COBALT_LCD) += lcd.o -+obj-$(CONFIG_PPDEV) += ppdev.o -+obj-$(CONFIG_NWBUTTON) += nwbutton.o -+obj-$(CONFIG_NWFLASH) += nwflash.o -+obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o -+obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o -+obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -+obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o -+obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o -+obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o -+obj-$(CONFIG_GPIO_TB0219) += tb0219.o -+obj-$(CONFIG_TELCLOCK) += tlclk.o -+ -+obj-$(CONFIG_MWAVE) += mwave/ -+obj-$(CONFIG_AGP) += agp/ -+obj-$(CONFIG_DRM) += drm/ -+obj-$(CONFIG_PCMCIA) += pcmcia/ -+obj-$(CONFIG_IPMI_HANDLER) += ipmi/ -+ -+obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o -+obj-$(CONFIG_TCG_TPM) += tpm/ -+ -+obj-$(CONFIG_PS3_FLASH) += ps3flash.o -+ -+obj-$(CONFIG_JS_RTC) += js-rtc.o -+js-rtc-y = rtc.o -+ -+# Files generated that shall be removed upon make clean -+clean-files := consolemap_deftbl.c defkeymap.c -+ -+quiet_cmd_conmk = CONMK $@ -+ cmd_conmk = scripts/conmakehash $< > $@ -+ -+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) -+ $(call cmd,conmk) -+ -+$(obj)/defkeymap.o: $(obj)/defkeymap.c -+ -+# Uncomment if you're changing the keymap and have an appropriate -+# loadkeys version for the map. By default, we'll use the shipped -+# versions. -+# GENERATE_KEYMAP := 1 -+ -+ifdef GENERATE_KEYMAP -+ -+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map -+ loadkeys --mktable $< > $@.tmp -+ sed -e 's/^static *//' $@.tmp > $@ -+ rm $@.tmp -+ -+endif -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/Kconfig linux-2.6.24.7/drivers/char/jzchar/Kconfig ---- linux-2.6.24.7.old/drivers/char/jzchar/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+# -+# JzSOC char devices configuration -+# -+ -+menu "JZSOC char device support" -+ depends on SOC_JZ4740 || SOC_JZ4730 || SOC_JZ4750 || SOC_JZ4750D -+ -+config JZCHAR -+ tristate 'JzSOC char device support' -+ -+config JZ_CAMERA_SENSOR -+ bool -+ -+config JZ_CIM -+ tristate 'JzSOC Camera Interface Module (CIM) support' -+ depends on JZCHAR -+ select JZ_CAMERA_SENSOR -+ -+config JZ_TPANEL_ATA2508 -+ tristate 'JzSOC MPEG4 TOUCH PANEL ATA2508 support' -+ depends on JZCHAR -+ -+config JZ_TPANEL -+ tristate 'JzSOC touchpanel driver support' -+ depends on JZCHAR -+# select JZ_SADC if SOC_JZ4740 -+# select JZ_TPANEL_AK4182 if SOC_JZ4730 -+ -+choice -+ prompt "Touch Panel ADC type" -+ depends on JZ_TPANEL -+ default JZ_SADC if SOC_JZ4740 || SOC_JZ4750 || SOC_JZ4750D -+ default JZ_TPANEL_AK4182 if SOC_JZ4730 -+ -+config JZ_SADC -+ bool 'Select the JZ47XX internal SADC' -+ -+config JZ_TPANEL_AK4182 -+ bool 'Select the AK4182 codec' -+ -+config JZ_TPANEL_UCB1400 -+ bool 'Select the UCB1400 codec' -+ -+config JZ_TPANEL_WM9712 -+ bool 'Select the WM9712 codec' -+ -+endchoice -+ -+config JZ_UDC_HOTPLUG -+ tristate 'JZ UDC hotplug driver support' -+ depends on JZCHAR -+ -+config JZ_POWEROFF -+ tristate 'JZ board poweroff support' -+ depends on JZCHAR -+ -+config JZ_OW -+ tristate 'JZ One-wire bus support' -+ depends on JZCHAR -+ -+config JZ_TCSM -+ tristate 'JZ TCSM support' -+ depends on JZCHAR -+ -+config JZ_TSSI -+ tristate 'JZ MPEG2-TS interface support' -+ depends on JZCHAR && (SOC_JZ4750 || SOC_JZ4750D) -+ -+endmenu -+ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/Makefile linux-2.6.24.7/drivers/char/jzchar/Makefile ---- linux-2.6.24.7.old/drivers/char/jzchar/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,24 @@ -+# -+# Makefile for jzchar -+# -+obj-$(CONFIG_JZCHAR) += jzchars.o -+ -+obj-$(CONFIG_JZ_SCC) += scc.o -+obj-$(CONFIG_JZ_CIM) += cim.o -+obj-$(CONFIG_JZ_TPANEL_ATA2508) += ata2508.o -+obj-$(CONFIG_JZ_CAMERA_SENSOR) += sensor.o -+obj-$(CONFIG_JZ_I2C_EEPROM) += eeprom.o -+obj-$(CONFIG_JZ_EJTAG) += ejtag.o -+obj-$(CONFIG_JZ_POWEROFF) += poweroff.o -+ -+obj-$(CONFIG_JZ_TPANEL) += jz_ts.o -+obj-$(CONFIG_JZ_TPANEL_UCB1400) += ucb1400.o -+obj-$(CONFIG_JZ_TPANEL_WM9712) += wm9712.o -+obj-$(CONFIG_JZ_TPANEL_AK4182) += ak4182.o -+obj-$(CONFIG_JZ_SADC) += sadc.o -+ -+obj-$(CONFIG_JZ_SMART_LCD) += slcd.o -+obj-$(CONFIG_JZ_UDC_HOTPLUG) += udc_hotplug.o -+obj-$(CONFIG_JZ_OW) += jz_ow.o -+obj-$(CONFIG_JZ_TCSM) += tcsm.o -+obj-$(CONFIG_JZ_TSSI) += jz_tssi.o -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/ak4182.c linux-2.6.24.7/drivers/char/jzchar/ak4182.c ---- linux-2.6.24.7.old/drivers/char/jzchar/ak4182.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/ak4182.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,657 @@ -+/* -+ * ak4182.c using national microwire protocol -+ * -+ * Touch screen driver interface to the AK4182A . -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jz_ts.h" -+#include "ak4182.h" -+ -+#define TS_PIN GPIO_TS_PENIRQ -+#define TS_IRQ (IRQ_GPIO_0 + TS_PIN) -+ -+static int samples = 5; -+static int first_time = 0; -+static unsigned long last_x, last_y, last_p; -+ -+static int adcsync = 0; -+ -+static struct ak4182 *ak; -+ -+extern unsigned int (*codec_read_battery)(void); -+ -+/*------------------JzSoc SSI configure----------------*/ -+static void ak4182_ssi_reset(void) -+{ -+ REG_SSI_CR0 = 0x0000; -+ REG_SSI_CR1 = 0x00007960; -+ REG_SSI_SR = 0x00000098; -+ REG_SSI_ITR = 0x0000; -+ REG_SSI_ICR = 0x00; -+ REG_SSI_GR = 0x0000; -+ -+ __ssi_disable(); -+ __ssi_flush_fifo(); -+ __ssi_clear_errors(); -+ __ssi_select_ce(); -+} -+ -+static void ak4182_ssi_enable(void) -+{ -+ __ssi_enable(); -+} -+ -+#ifdef CONFIG_PM -+static void ak4182_ssi_disable(void) -+{ -+ __ssi_disable(); -+} -+#endif -+ -+static void ak4182_ssi_set_trans_mode_format(void) -+{ -+ __ssi_microwire_format(); -+ __ssi_set_msb(); -+ __ssi_set_microwire_command_length(8); -+ __ssi_set_frame_length(12); -+} -+ -+static void ak4182_ssi_set_clk_div_ratio(int dev_clk, int ssi_clk) -+{ -+ __ssi_set_clk(dev_clk, ssi_clk); -+} -+ -+static void ak4182_ssi_set_normal_mode(void) -+{ -+ __ssi_normal_mode(); -+} -+ -+static void ak4182_ssi_set_IRQ(void) -+{ -+ __ssi_disable_tx_intr(); -+ __ssi_disable_rx_intr(); -+} -+ -+/*------------------ AK4182 routines ------------------*/ -+static inline void ak4182_reg_write(unsigned short val) -+{ -+ __ssi_transmit_data(val); -+} -+ -+static inline unsigned int ak4182_reg_read(void) -+{ -+ unsigned int val; -+ val = __ssi_receive_data(); -+ return val; -+} -+ -+static unsigned int ak4182_adc_read(int cmd_code, int sync) -+{ -+ unsigned int val, timeout = 10000; -+ unsigned int status,valid1,valid2,dataentry; -+ -+ ak4182_reg_write(cmd_code); -+ udelay(2);//wait 2 D_CLK -+ for (;;) { -+ status =0; -+ status = REG_SSI_SR; -+ valid1 = (status>>7) & 1; -+ valid2 = (status>>6) & 1; -+ if( valid1==1 && valid2==0 )//SSI transfer is finished -+ { -+ //Receive FIFO data entry number -+ dataentry = val = 0; -+ dataentry = (status>>8) & 0x1F; -+ if( dataentry > 5 ) -+ { -+ printk("R-FIFO entry=%d,SSI transfer is wrong!\n",dataentry); -+ while(dataentry > 0) -+ { -+ ak4182_reg_read(); -+ dataentry--; -+ } -+ return 0; -+ } -+ while(dataentry > 0) -+ { -+ val = ak4182_reg_read(); -+ dataentry--; -+ } -+ return val; -+ } -+ -+ if (--timeout == 0) -+ break; -+ udelay(1); -+ } -+ return 0; -+} -+ -+ -+//enable pen down IRQ -+static void ak4182_enable_irq(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ak->lock, flags); -+ __gpio_unmask_irq(TS_PIN); -+ spin_unlock_irqrestore(&ak->lock, flags); -+} -+ -+//disable pen down IRQ -+static void ak4182_disable_irq(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ak->lock, flags); -+ __gpio_mask_irq(TS_PIN); -+// spin_unlock_irqrestore(&ucb->lock, flags); -+ spin_unlock_irqrestore(&ak->lock, flags); -+} -+/* -+ * Switch to X position mode and measure Y plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ak4182_ts_read_xpos(void) -+{ -+ return ak4182_adc_read(0xD0, adcsync);//X-axis,0xD0 for 12bit,0xD8 for 8bit -+} -+ -+ -+/* -+ * Switch to pressure mode, and read pressure. We don't need to wait -+ * here, since both plates are being driven. -+ */ -+static inline unsigned int ak4182_ts_read_pressure(void) -+{ -+ unsigned int z1,z2,xpos,pressureval=0;//300 Om -+ //Z1 pressure -+ z1 = ak4182_adc_read(0xB0, adcsync);//0xB0 for 12bit,0xB8 for 8bit -+ if(z1>0) -+ { -+ //Z2 pressure -+ z2 = ak4182_adc_read(0xC0, adcsync);//0xC0 for 12bit,0xC8 for 8bit -+ if(z2>z1) -+ { -+ xpos = ak4182_ts_read_xpos(); -+ pressureval = (300*xpos*(z2-z1))/(4096*z1); -+ } -+ } -+ -+ return pressureval; -+} -+ -+ -+/* -+ * Switch to Y position mode and measure X plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ak4182_ts_read_ypos(void) -+{ -+ return ak4182_adc_read(0x90, adcsync);//Y-axis,0x90 for 12bit,0x98 for 8bit -+} -+ -+/*------------------------------------------------------------ -+ * Read the battery voltage -+ */ -+ -+unsigned int ak4182_read_battery(void) -+{ -+ unsigned int v; -+ int bat_val[5]; -+ int total = 0, max_bat, min_bat; -+ -+ v = ak4182_adc_read(0xA7, adcsync); -+ v = ak4182_adc_read(0xA7, adcsync); -+ for(v = 0;v <= 4;v++) -+ bat_val[v] = ak4182_adc_read(0xA7, adcsync); -+ -+ ak4182_adc_read(0xA4, adcsync); -+ max_bat = min_bat = bat_val[0]; -+ for(v = 0;v <= 4;v++) { -+ total += bat_val[v]; -+ if(bat_val[v] > max_bat) -+ max_bat = bat_val[v]; -+ if(bat_val[v] < min_bat) -+ min_bat = bat_val[v]; -+ } -+ total = total - max_bat - min_bat; -+ v = total / 3; -+ return v; -+} -+ -+/*------------------ Calibrate samples -------------------*/ -+ -+#define DIFF(a,b) ((a>b)?(a-b):(b-a)) -+ -+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) -+{ -+ unsigned long *xp = (unsigned long *)xbuf; -+ unsigned long *yp = (unsigned long *)ybuf; -+ unsigned long *pp = (unsigned long *)pbuf; -+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp; -+ int ignored, i, j; -+ int valid = 0; -+ -+ /* throw away the max cases */ -+ tmp = xp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (xp[i] > tmp) { -+ tmp = xp[i]; -+ ignored = i; -+ } -+ }//find the max val -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ xp[j++] = xp[i]; -+ }//shift val and delete the max val -+ -+ tmp = yp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (yp[i] > tmp) { -+ tmp = yp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ yp[j++] = yp[i]; -+ } -+ -+ tmp = pp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (pp[i] > tmp) { -+ tmp = pp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ pp[j++] = pp[i]; -+ } -+ -+ /* throw away the min cases */ -+ -+ count -= 1; // decrement by 1 -+ -+ tmp = xp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (xp[i] < tmp) { -+ tmp = xp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ xp[j++] = xp[i]; -+ } -+ -+ tmp = yp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (yp[i] < tmp) { -+ tmp = yp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ yp[j++] = yp[i]; -+ } -+ -+ tmp = pp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (pp[i] < tmp) { -+ tmp = pp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ pp[j++] = pp[i]; -+ } -+ -+ count -= 1; // decrement by 1 -+ -+ /* calculate the average of the rest */ -+ for (i = 0; i < count; i++) { -+ x_cal += xp[i]; -+ y_cal += yp[i]; -+ p_cal += pp[i]; -+ } -+ x_cal /= count; -+ y_cal /= count; -+ p_cal /= count; -+ -+ if (first_time) { -+ first_time = 0; -+ last_x = x_cal; -+ last_y = y_cal; -+ last_p = p_cal; -+ valid = 1; -+ } -+ else { -+ if ((DIFF(x_cal, last_x) > 100) || -+ (DIFF(y_cal, last_y) > 100)) -+ valid = 0; -+ else -+ valid = 1; -+ } -+ -+ //printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid); -+ -+ if (valid) { -+ *xp = last_x = x_cal; -+ *yp = last_y = y_cal; -+ *pp = last_p = p_cal; -+ } -+ -+ return valid; -+} -+ -+ -+#define TSMAXX 945 -+#define TSMAXY 830 -+#define TSMINX 90 -+#define TSMINY 105 -+ -+#define SCREEN_X 480 -+#define SCREEN_Y 272 -+ -+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ -+ -+ if (ts->minx) -+ { -+ if (x < ts->minx) x = ts->minx; -+ if (x > ts->maxx) x = ts->maxx; -+ -+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); -+ } -+ else -+ { -+ if (x < TSMINX) x = TSMINX; -+ if (x > TSMAXX) x = TSMAXX; -+ -+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); -+ } -+} -+ -+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) -+{ -+ if (ts->miny) -+ { -+ if (y < ts->miny) y = ts->miny; -+ if (y > ts->maxy) y = ts->maxy; -+ -+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); -+ } -+ else -+ { -+ if (y < TSMINY) y = TSMINY; -+ if (y > TSMAXY) y = TSMAXY; -+ -+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); -+ } -+} -+ -+/*------------------ Common routines -------------------*/ -+ -+void ts_enable_irq(void) -+{ -+ /* interrupt mode */ -+ ak4182_enable_irq(); -+ enable_irq(TS_IRQ); -+} -+ -+void ts_disable_irq(void) -+{ -+ ak4182_disable_irq(); -+ disable_irq(TS_IRQ); -+} -+ -+int ts_request_irq(u32 *irq, -+ irqreturn_t (*handler)(int, void *), -+ const char *devname, -+ void *dev_id) -+{ -+ int retval; -+ -+ /* return the irq number */ -+ *irq = TS_IRQ; -+ /* initializate ssi for AK4182 */ -+ ak4182_ssi_reset(); -+ ak4182_ssi_set_trans_mode_format(); -+ ak4182_ssi_set_normal_mode(); -+ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max -+ ak4182_ssi_set_IRQ(); -+ -+ ak4182_enable_irq(); -+ -+ /* enable gpio irq */ -+ __gpio_as_irq_fall_edge(TS_PIN); -+ -+ /* register irq handler */ -+ retval = request_irq(TS_IRQ, handler, IRQF_DISABLED, devname, dev_id); -+ ak4182_ssi_enable(); -+ udelay(10); -+ return retval; -+} -+ -+void ts_free_irq(struct jz_ts_t *ts) -+{ -+ free_irq(ts->pendown_irq, ts); -+ //Close SSI mode -+ ak4182_ssi_reset(); -+} -+ -+void ts_irq_callback(void) -+{ -+ /* clear interrupt status */ -+ __gpio_ack_irq(TS_PIN); -+ first_time = 1; // first time to acquire sample -+} -+ -+int PenIsDown(void) -+{ -+ unsigned int p; -+ p = ak4182_ts_read_pressure(); -+ return (p > 100) ? 1 : 0; -+} -+ -+/* -+ * Acquire Raw pen coodinate data and compute touch screen -+ * pressure resistance. Hold spinlock when calling. -+ */ -+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned int x_raw[8], y_raw[8], p_raw[8]; -+ int valid, i; -+ -+ for (i = 0; i < samples; i++) { -+ x_raw[i] = ak4182_ts_read_xpos(); -+ } -+ for (i = 0; i < samples; i++) { -+ y_raw[i] = ak4182_ts_read_ypos(); -+ } -+ for (i = 0; i < samples; i++) { -+ p_raw[i] = ak4182_ts_read_pressure(); -+ } -+ -+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); -+ -+ if (valid) { -+ unsigned int x_scr, y_scr; -+ -+ if(ts->filter) { -+ x_scr = transform_to_screen_x(ts, x_raw[0]); -+ y_scr = transform_to_screen_y(ts, y_raw[0]); -+ -+ if (ts->prints) -+ printk("filter:x_raw:%d,y_raw:%d,x_tran:%d,y_tran:%d\n", x_raw[0], y_raw[0], x_scr, y_scr); -+ } -+ else { -+ x_scr = x_raw[0]; -+ y_scr = y_raw[0]; -+ -+ if (ts->prints) -+ printk("no filter:x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); -+ } -+ -+ event->x = x_scr; -+ event->y = y_scr; -+ event->pressure = (u16)p_raw[0]; -+ event->status = PENDOWN; -+ return 1; -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+/* -+ * Suspend the Touch pad. -+ */ -+static int ak4182_suspend(struct ak4182 *ak , int state) -+{ -+ ak4182_ssi_disable(); -+ -+ return 0; -+} -+ -+/* -+ * Resume the Touch panel. -+ */ -+static int ak4182_resume(struct ak4182 *ak) -+{ -+ /* initializate ssi for AK4182 */ -+ ak4182_ssi_reset(); -+ ak4182_ssi_set_trans_mode_format(); -+ ak4182_ssi_set_normal_mode(); -+ ak4182_ssi_set_clk_div_ratio(JZ_EXTAL, 200*1000);//DCLK is 1.5M Hz max -+ ak4182_ssi_set_IRQ(); -+ -+ ak4182_enable_irq(); -+ -+ ak4182_ssi_enable(); -+ -+ return 0; -+} -+ -+static int ak4182_pm_callback(struct pm_dev *pm_dev, pm_request_t rqst, void *data) -+{ -+ int ret; -+ struct ak4182 *akinfo = pm_dev->data; -+ -+ if (!akinfo) -+ return -EINVAL; -+ -+ -+ switch (rqst) { -+ case PM_SUSPEND: -+ ret = ak4182_suspend(akinfo, (int)data); -+ break; -+ -+ case PM_RESUME: -+ ret = ak4182_resume(akinfo); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* -+ * Module init and exit -+ */ -+ -+int __init ak4182_init(void) -+{ -+ ak = kmalloc(sizeof(struct ak4182), GFP_KERNEL); -+ if (!ak) return -ENOMEM; -+ -+ memset(ak, 0, sizeof(struct ak4182)); -+ -+ codec_read_battery = ak4182_read_battery; -+ -+ spin_lock_init(&ak->lock); -+ sema_init(&ak->adc_sem, 1); -+ -+ //initialize AK4182 register -+ __gpio_clear_pin(73); -+ __gpio_as_output(73); -+ mdelay(2); -+ __gpio_set_pin(73); -+ __gpio_as_ssi(); -+ -+ ak4182_read_battery(); -+ -+#ifdef CONFIG_PM -+ ak->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ak4182_pm_callback); -+ if (ak->pmdev) -+ { -+ ak->pmdev->data = ak; -+ } -+#endif -+ -+ printk("AK4182 touch screen driver initialized\n"); -+ -+ return 0; -+} -+ -+void ak4182_cleanup(void) -+{ -+} -+ -+module_init(ak4182_init); -+module_exit(ak4182_cleanup); -+ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/ak4182.h linux-2.6.24.7/drivers/char/jzchar/ak4182.h ---- linux-2.6.24.7.old/drivers/char/jzchar/ak4182.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/ak4182.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#ifndef __AK4182_H__ -+#define __AK4182_H__ -+ -+/* Device data structure */ -+ -+struct ak4182 { -+ spinlock_t lock; -+ struct pm_dev *pmdev; -+ struct semaphore adc_sem; -+ u16 adc_cr; -+ u16 irq_fal_enbl; -+ u16 irq_ris_enbl; -+ int irq_enabled; -+}; -+ -+#endif /* __AK4182_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/ata2508.c linux-2.6.24.7/drivers/char/jzchar/ata2508.c ---- linux-2.6.24.7.old/drivers/char/jzchar/ata2508.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/ata2508.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,227 @@ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define MP4_KEY_RST (32*3+3) -+#define MP4_KEY_TINT (32*3+2) -+#define MP4_KEY_SCL (32*3+1) -+#define MP4_KEY_SDA (32*3+0) -+#define MP4_TINT_IRQ (IRQ_GPIO_0 + MP4_KEY_TINT) -+ -+#define ADDR_WARM_RESET 0xFF -+#define ATA2508_SENSOR_MASK 0x1F -+ -+const unsigned char init_data_burst[] = {//Address:0x0D-0x3E -+ 0x04, // BETA -+ 0x27, // AIC_WAIT -+ //0x32, // REF_DELAY -+ 0x16, // REF_DELAY -+ 0x02, // HYSTERESIS01 -+ 0x02, // HYSTERESIS1 -+ 0x02, // HYSTERESIS2 -+ 0x02, // HYSTERESIS3 -+ 0x02, // HYSTERESIS4 -+ 0x02, // HYSTERESIS51 -+ 0x02, // HYSTERESIS61 -+ 0x02, // HYSTERESIS7 -+ 0x02, // HYSTERESIS8 -+ 0x02, // HYSTERESIS9 -+ 0x02, // HYSTERESIS10 -+ 0x02, // HYSTERESIS11 -+ 0x64, // STRENGTH_THRESHOLD0 -+ 0x64, // STRENGTH_THRESHOLD1 -+ 0x64, // STRENGTH_THRESHOLD2 -+ 0x64, // STRENGTH_THRESHOLD3 -+ 0x64, // STRENGTH_THRESHOLD4 -+ 0x64, // STRENGTH_THRESHOLD5 -+ 0x64, // STRENGTH_THRESHOLD6 -+ 0x64, // STRENGTH_THRESHOLD7 -+ 0x64, // STRENGTH_THRESHOLD8 -+ 0x64, // STRENGTH_THRESHOLD9 -+ 0x64, // STRENGTH_THRESHOLD10 -+ 0x64, // STRENGTH_THRESHOLD11 -+ 0x0f, // Sampling Interval -+ 0xC8, // INTEGRATION TIME -+ 0x0f, // IDLE TIME -+ 0x00, // SIF_SETUP(RESERVED) -+ 0x01, // MODE -+ 0x00, // GPIO_REG_L -+ 0x00, // GPIO_REG_H -+ 0x00, // GPIO_CONFIGURATION_L -+ 0x00, // GPIO_CONFIGURATION_H -+ 0x00, // GPIO_DIR_L -+ 0x00, // GPIO_DIR_H -+ 0x0c, // CONTROL -+ 0x38, // INT_MASK -+ 0x00, // INT_CLEAR -+ 0xFF, // INT_edge -+ 0x02, // CONTROL_2 -+ 0xAF, // BEEP_TIME -+ 0x7F, // BEEP_FREQUENCY -+ 0x30, // CALIBRATION INTERVAL -+ 0x00, // EINT_ENABLE -+ 0x00, // EINT_POL -+ 0x00, // FILTER_PERIOD -+ 0x00, // FILTER_THRESHOLD -+}; -+const unsigned char init_data_alpha[] = {//Address:0x00-0x0C -+ 0x02, // APIS -+ 0x08, // ALPHA0 -+ 0x08, // ALPHA1 -+ 0x08, // ALPHA2 -+ 0x08, // ALPHA3 -+ 0x08, // ALPHA4 -+ 0x28, // ALPHA5 -+ 0x28, // ALPHA6 -+ 0x28, // ALPHA7 -+ 0x28, // ALPHA8 -+ 0x28, // ALPHA9 -+ 0x28, // ALPHA10 -+ 0x28, // ALPHA11 -+}; -+static unsigned int i2c_addr = 0x58; -+static unsigned int i2c_clk = 100000; -+ -+static void write_reg(u8 reg, u8 val) -+{ -+ int ret; -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ ret = i2c_write(i2c_addr, &val, reg, 1); -+ i2c_close(); -+} -+ -+static u8 read_reg(u8 reg) -+{ -+ u8 val; -+ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_read(i2c_addr, &val, reg, 1); -+ i2c_close(); -+ return val; -+} -+ -+/* -+ * Interrupt handler -+ */ -+static irqreturn_t mp4_tint_irq(int irq, void *dev_id) -+{ -+ int key_num = 0; -+ u8 value0, value1; -+ -+ __gpio_ack_irq(MP4_KEY_TINT); -+ value0 = read_reg(0x75); -+ value1 = read_reg(0x76); -+ value0 &= ATA2508_SENSOR_MASK; -+ if (value0 == 0) { -+ printk("\nRelease key!\n"); -+ return IRQ_HANDLED; -+ } -+ while(value0 >> 1){ -+ value0 >>= 1; -+ key_num++; -+ } -+ -+ printk("\nPress key %d!\n", key_num); -+ return IRQ_HANDLED; -+} -+ -+static int __init init_ata2508(void) -+{ -+ int i; -+ unsigned char data1; -+ int retval; -+ -+ __gpio_as_output(MP4_KEY_RST); -+ __gpio_set_pin(MP4_KEY_RST); -+ mdelay(100); -+ __gpio_clear_pin(MP4_KEY_RST); -+ mdelay(800); -+ __gpio_set_pin(MP4_KEY_RST); -+ __gpio_mask_irq(MP4_KEY_TINT); -+ -+ /*write registers*/ -+ for(i=0; i<13; i++) -+ { -+ data1 = init_data_alpha[i]; -+ write_reg(i, data1); -+ } -+ -+ for(i=13; i<63; i++) -+ { -+ data1 = init_data_burst[i-13]; -+ write_reg(i, data1); -+ } -+#if 0 -+ for (i = 0; i < 63; i++) -+ { -+ data1 = read_reg(i); -+ printk("REG0x%02x = 0x%02x\n", i, data1); -+ } -+#endif -+ -+ /* wait for 1 ms*/ -+ mdelay(1); -+#if 0 -+ while(1) -+ { -+ data1 = read_reg(0x68); -+ printk("REG0x68 = %d\n", data1); -+ data1 = read_reg(0x75); -+ printk("REG0x75 = 0x%02x\n", data1); -+ data1 = read_reg(0x76); -+ printk("REG0x76 = 0x%02x\n", data1); -+ mdelay(2000); -+ } -+#endif -+ data1 = read_reg(0x68); -+ printk("REG0x68 = %d\n", data1); -+ -+ /* to activate all the new settings, give a WARM RESET.*/ -+ write_reg(ADDR_WARM_RESET, 0x00); //ADDR_WARM_RESET=0xFF -+ -+ //printk("REG0x68 = %d\n", data1); -+ -+ /* wait for 1 ~ 10 ms.*/ -+ mdelay(10); -+ data1 = read_reg(0x68); -+ -+ /* Enable INT that connected to ATA2508's TINT.*/ -+ __gpio_as_irq_rise_edge(MP4_KEY_TINT); -+ -+ retval = request_irq(MP4_TINT_IRQ, mp4_tint_irq, -+ IRQF_DISABLED, "mp4_key_tint", NULL); -+ if (retval) { -+ printk("Could not get mp4 key irq %d\n", MP4_TINT_IRQ); -+ return retval; -+ } -+ -+ printk("MP4 touch panel register!\n"); -+ -+ return 0; -+} -+ -+static void __exit exit_ata2508(void) -+{ -+ free_irq(MP4_TINT_IRQ, NULL); -+} -+ -+module_init(init_ata2508); -+module_exit(exit_ata2508); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/cim.c linux-2.6.24.7/drivers/char/jzchar/cim.c ---- linux-2.6.24.7.old/drivers/char/jzchar/cim.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/cim.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,366 @@ -+/* -+ * linux/drivers/char/jzchar/cim.c -+ * -+ * Camera Interface Module (CIM) driver for JzSOC -+ * This driver is independent of the camera sensor -+ * -+ * Copyright (C) 2005 JunZheng semiconductor -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "jzchars.h" -+ -+#define CIM_NAME "cim" -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * Define the Max Image Size -+ */ -+#define MAX_IMAGE_WIDTH 640 -+#define MAX_IMAGE_HEIGHT 480 -+#define MAX_IMAGE_BPP 16 -+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) -+ -+typedef struct -+{ -+ u32 width; -+ u32 height; -+ u32 bpp; -+} img_param_t; -+ -+typedef struct -+{ -+ u32 cfg; -+ u32 ctrl; -+ u32 mclk; -+} cim_config_t; -+ -+/* -+ * IOCTL_XXX commands -+ */ -+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * -+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * -+ -+/* Actual image size, must less than max values */ -+static int img_width = MAX_IMAGE_WIDTH, img_height = MAX_IMAGE_HEIGHT, img_bpp = MAX_IMAGE_BPP; -+ -+/* -+ * CIM DMA descriptor -+ */ -+struct cim_desc { -+ u32 nextdesc; /* Physical address of next desc */ -+ u32 framebuf; /* Physical address of frame buffer */ -+ u32 frameid; /* Frame ID */ -+ u32 dmacmd; /* DMA command */ -+}; -+ -+/* -+ * CIM device structure -+ */ -+struct cim_device { -+ unsigned char *framebuf; -+ unsigned int frame_size; -+ unsigned int page_order; -+ wait_queue_head_t wait_queue; -+ struct cim_desc frame_desc __attribute__ ((aligned (16))); -+}; -+ -+// global -+static struct cim_device *cim_dev; -+ -+/*========================================================================== -+ * CIM init routines -+ *========================================================================*/ -+ -+static void cim_config(cim_config_t *c) -+{ -+ REG_CIM_CFG = c->cfg; -+ REG_CIM_CTRL = c->ctrl; -+ // Set the master clock output -+#if defined(CONFIG_SOC_JZ4730) -+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); -+#elif defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) -+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); -+#else -+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); -+#endif -+ // Enable sof, eof and stop interrupts -+ __cim_enable_sof_intr(); -+ __cim_enable_eof_intr(); -+ __cim_enable_stop_intr(); -+} -+ -+/*========================================================================== -+ * CIM start/stop operations -+ *========================================================================*/ -+ -+static int cim_start_dma(char *ubuf) -+{ -+ __cim_disable(); -+ -+ dma_cache_wback((unsigned long)cim_dev->framebuf, (2 ^ (cim_dev->page_order)) * 4096); -+ -+ // set the desc addr -+ __cim_set_da(virt_to_phys(&(cim_dev->frame_desc))); -+ -+ __cim_clear_state(); // clear state register -+ __cim_reset_rxfifo(); // resetting rxfifo -+ __cim_unreset_rxfifo(); -+ __cim_enable_dma(); // enable dma -+ -+ // start -+ __cim_enable(); -+ -+ // wait for interrupts -+ interruptible_sleep_on(&cim_dev->wait_queue); -+ -+ // copy frame data to user buffer -+ memcpy(ubuf, cim_dev->framebuf, cim_dev->frame_size); -+ -+ return cim_dev->frame_size; -+} -+ -+static void cim_stop(void) -+{ -+ __cim_disable(); -+ __cim_clear_state(); -+} -+ -+/*========================================================================== -+ * Framebuffer allocation and destroy -+ *========================================================================*/ -+ -+static void cim_fb_destroy(void) -+{ -+ if (cim_dev->framebuf) { -+ free_pages((unsigned long)(cim_dev->framebuf), cim_dev->page_order); -+ cim_dev->framebuf = NULL; -+ } -+} -+ -+static int cim_fb_alloc(void) -+{ -+ cim_dev->frame_size = img_width * img_height * (img_bpp/8); -+ cim_dev->page_order = get_order(cim_dev->frame_size); -+ -+ /* frame buffer */ -+ cim_dev->framebuf = (unsigned char *)__get_free_pages(GFP_KERNEL, cim_dev->page_order); -+ if ( !(cim_dev->framebuf) ) { -+ return -ENOMEM; -+ } -+ -+ cim_dev->frame_desc.nextdesc = virt_to_phys(&(cim_dev->frame_desc)); -+ cim_dev->frame_desc.framebuf = virt_to_phys(cim_dev->framebuf); -+ cim_dev->frame_desc.frameid = 0x52052018; -+ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame -+ -+ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16); -+ -+ return 0; -+} -+ -+/*========================================================================== -+ * File operations -+ *========================================================================*/ -+ -+static int cim_open(struct inode *inode, struct file *filp); -+static int cim_release(struct inode *inode, struct file *filp); -+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -+ -+static struct file_operations cim_fops = -+{ -+ open: cim_open, -+ release: cim_release, -+ read: cim_read, -+ write: cim_write, -+ ioctl: cim_ioctl -+}; -+ -+static int cim_open(struct inode *inode, struct file *filp) -+{ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int cim_release(struct inode *inode, struct file *filp) -+{ -+ cim_stop(); -+ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ if (size < cim_dev->frame_size) -+ return -EINVAL; -+ -+ return cim_start_dma(buf); -+} -+ -+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("cim error: write is not implemented\n"); -+ return -1; -+} -+ -+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ switch (cmd) { -+ case IOCTL_SET_IMG_PARAM: -+ { -+ img_param_t i; -+ -+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) -+ return -EFAULT; -+ -+ img_width = i.width; -+ img_height = i.height; -+ img_bpp = i.bpp; -+ -+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE) { -+ /* realloc the buffer */ -+ cim_fb_destroy(); -+ if (cim_fb_alloc() < 0) -+ return -ENOMEM; -+ } -+ -+ cim_dev->frame_size = img_width * img_height * (img_bpp/8); -+ -+ cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame -+ -+ dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16); -+ -+ break; -+ } -+ case IOCTL_CIM_CONFIG: -+ { -+ cim_config_t c; -+ -+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) -+ return -EFAULT; -+ -+ cim_config(&c); -+ -+ break; -+ } -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return 0; -+} -+ -+/*========================================================================== -+ * Interrupt handler -+ *========================================================================*/ -+ -+static irqreturn_t cim_irq_handler(int irq, void *dev_id) -+{ -+ u32 state = REG_CIM_STATE; -+#if 0 -+ if (state & CIM_STATE_DMA_EOF) { -+ wake_up_interruptible(&cim_dev->wait_queue); -+ } -+#endif -+ if (state & CIM_STATE_DMA_STOP) { -+ // Got a frame, wake up wait routine -+ wake_up_interruptible(&cim_dev->wait_queue); -+ } -+ -+ // clear status flags -+ REG_CIM_STATE = 0; -+ return IRQ_HANDLED; -+} -+ -+/*========================================================================== -+ * Module init and exit -+ *========================================================================*/ -+ -+static int __init cim_init(void) -+{ -+ struct cim_device *dev; -+ int ret; -+ -+ /* allocate device */ -+ dev = kmalloc(sizeof(struct cim_device), GFP_KERNEL); -+ if (!dev) return -ENOMEM; -+ -+ /* record device */ -+ cim_dev = dev; -+ -+ /* allocate a frame buffer */ -+ if (cim_fb_alloc() < 0) { -+ kfree(dev); -+ return -ENOMEM; -+ } -+ -+ init_waitqueue_head(&dev->wait_queue); -+ -+ ret = jz_register_chrdev(CIM_MINOR, CIM_NAME, &cim_fops, dev); -+ if (ret < 0) { -+ cim_fb_destroy(); -+ kfree(dev); -+ return ret; -+ } -+ -+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, -+ CIM_NAME, dev))) { -+ cim_fb_destroy(); -+ kfree(dev); -+ printk(KERN_ERR "CIM could not get IRQ"); -+ return ret; -+ } -+ -+ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit cim_exit(void) -+{ -+ free_irq(IRQ_CIM, cim_dev); -+ jz_unregister_chrdev(CIM_MINOR, CIM_NAME); -+ cim_fb_destroy(); -+ kfree(cim_dev); -+} -+ -+module_init(cim_init); -+module_exit(cim_exit); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/cim.h linux-2.6.24.7/drivers/char/jzchar/cim.h ---- linux-2.6.24.7.old/drivers/char/jzchar/cim.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/cim.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * JzSOC CIM driver -+ * -+ * Copyright (C) 2005 Ingenic 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. -+ * -+ * 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 __CIM_H__ -+#define __CIM_H__ -+ -+typedef struct -+{ -+ u32 width; -+ u32 height; -+ u32 bpp; -+} IMG_PARAM; -+ -+/* -+ * IOCTL_XXX commands -+ */ -+#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM * -+ -+#endif /* __CIM_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jz_ow.c linux-2.6.24.7/drivers/char/jzchar/jz_ow.c ---- linux-2.6.24.7.old/drivers/char/jzchar/jz_ow.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jz_ow.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,497 @@ -+/* -+ * linux/drivers/char/jzchar/jz_ow.c -+ * -+ * One Wire Bus test driver -+ * -+ * Copyright (C) 2006 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "jzchars.h" -+ -+#define OW_CPU_READ_ROM 1 -+#define OW_INTC_READ_ROM 1 -+#define OW_CPU_SEARCH_ROM 0 -+#define OW_INTC_SEARCH_ROM 0 -+ -+#define OW_DEBUG 0 -+#if OW_DEBUG -+#define OWI_MAX 10 -+static char CFG[OWI_MAX]; -+static char CTL[OWI_MAX]; -+static char STS[OWI_MAX]; -+static char DAT[OWI_MAX]; -+static char DIV[OWI_MAX]; -+static void owi_register_dump(int i) -+{ -+ CFG[i]= REG_OWI_CFG; -+ CTL[i]= REG_OWI_CTL; -+ STS[i]= REG_OWI_STS; -+ DAT[i]= REG_OWI_DAT; -+ DIV[i]= REG_OWI_DIV; -+} -+static void owi_register_print(int i) -+{ -+ printk(" REG_OWI_CFG: 0x%08x\n", CFG[i]); -+ printk(" REG_OWI_CTL: 0x%08x\n", CTL[i]); -+ printk(" REG_OWI_STS: 0x%08x\n", STS[i]); -+ printk(" REG_OWI_DAT: 0x%08x\n", DAT[i]); -+ printk(" REG_OWI_DIV: 0x%08x\n", DIV[i]); -+} -+#endif -+ -+static DECLARE_WAIT_QUEUE_HEAD (ow_wait_queue); -+ -+/* -+ * fops routines -+ */ -+static int ow_open(struct inode *inode, struct file *filp); -+static int ow_release(struct inode *inode, struct file *filp); -+static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int ow_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -+ -+static void do_ow_rddata(void); -+static void do_ow_wrdata(void); -+static void do_ow_wr1rd(void); -+static void do_ow_wr0(void); -+static void do_ow_rst(void); -+ -+static void do_interrupt_mode_test(void); -+static void do_cpu_mode_test(void); -+ -+static struct file_operations ow_fops = -+{ -+ open: ow_open, -+ release: ow_release, -+ read: ow_read, -+ write: ow_write, -+ ioctl: ow_ioctl, -+}; -+ -+static int ow_open(struct inode *inode, struct file *filp) -+{ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int ow_release(struct inode *inode, struct file *filp) -+{ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t ow_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ printk("OW: read is not implemented\n"); -+ return -1; -+} -+ -+static ssize_t ow_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("ow: write is not implemented\n"); -+ return -1; -+} -+ -+static int ow_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ switch (cmd) { -+ -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static void do_ow_rddata(void) -+{ -+ __owi_clr_sts(); -+ __owi_set_rddata(); -+ __owi_enable_ow_ops(); -+} -+ -+static void do_ow_wrdata(void) -+{ -+ __owi_clr_sts(); -+ __owi_set_wrdata(); -+ __owi_enable_ow_ops(); -+} -+ -+static void do_ow_wr1rd(void) -+{ -+ __owi_clr_sts(); -+ __owi_set_wr1rd(); -+ __owi_enable_ow_ops(); -+} -+ -+static void do_ow_wr0(void) -+{ -+ __owi_clr_sts(); -+ __owi_set_wr0(); -+ __owi_enable_ow_ops(); -+} -+ -+static void do_ow_rst(void) -+{ -+ __owi_clr_sts(); -+ __owi_set_rst(); -+ __owi_enable_ow_ops(); -+} -+ -+static irqreturn_t ow_interrupt(int irq, void *dev_id) -+{ -+ __owi_clr_sts(); -+ wake_up(&ow_wait_queue); -+ -+ return IRQ_HANDLED; -+} -+ -+static void ow_intcm_read_rom(char *rom) -+{ -+ int i; -+ -+ __owi_select_regular_mode(); -+ REG_OWI_DIV = 23; -+ __owi_clr_sts(); -+ __intc_unmask_irq(IRQ_OWI); -+ __owi_enable_all_interrupts(); -+ -+ do_ow_rst(); -+ sleep_on(&ow_wait_queue); -+ -+ REG_OWI_DAT = 0x33; -+ do_ow_wrdata(); -+ sleep_on(&ow_wait_queue); -+ -+ for(i=0; i<8; i++){ -+ do_ow_rddata(); -+ sleep_on(&ow_wait_queue); -+ rom[i] = REG_OWI_DAT; -+ } -+ __intc_mask_irq(IRQ_OWI); -+} -+ -+static void ow_intcm_search_rom(void) -+{ -+ int i, j; -+ int normal, reverse; -+#if 1 -+ unsigned char rom[8]={0x01, 0xf9, 0x35, 0x53, 0x11, 0x00, 0x00, 0x3e}; -+#else -+ unsigned char rom[8]={0x01, 0xd8, 0x10, 0x02, 0x10, 0x00, 0x00, 0x22}; -+#endif -+ __owi_select_regular_mode(); -+ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; -+ __owi_clr_sts(); -+ __intc_unmask_irq(IRQ_OWI); -+ __owi_enable_all_interrupts(); -+ -+ /* reset */ -+ do_ow_rst(); -+ sleep_on(&ow_wait_queue); -+ -+ /* send search ROM command */ -+ REG_OWI_DAT = 0xf0; -+ do_ow_wrdata(); -+ sleep_on(&ow_wait_queue); -+ -+ for( i=0; i<8; i++){ -+ for (j=0; j<8; j++){ -+ do_ow_wr1rd(); -+ sleep_on(&ow_wait_queue); -+ normal = ( __owi_get_rdst() !=0); -+ printk("normal: %d\n",normal); -+ -+ do_ow_wr1rd(); -+ sleep_on(&ow_wait_queue); -+ reverse = ( __owi_get_rdst() !=0); -+ printk("reverse: %d\n",reverse); -+ -+ if(normal ==1 && reverse ==1){ -+ printk("Search rom INTC mode: 11 NO device found\n"); -+ __intc_mask_irq(IRQ_OWI); -+ return; -+ } -+#if 1 -+ if ( (rom[i]>>j) & 1 ){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ sleep_on(&ow_wait_queue); -+ } -+ else{ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ sleep_on(&ow_wait_queue); -+ } -+ -+#else -+ if(normal ==0 && reverse ==0){ -+ if (!((rom[i]>>j) & 1) ){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ sleep_on(&ow_wait_queue); -+ } -+ else{ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ sleep_on(&ow_wait_queue); -+ } -+ }else{ -+ -+ if(normal ==0){ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ sleep_on(&ow_wait_queue); -+ } -+ if(normal ==1){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ sleep_on(&ow_wait_queue); -+ } -+ } -+#endif -+ -+ } -+ printk("\n\n"); -+ } -+ -+ printk("\nSearch rom INTC mode: device found SUCCESSFULLY\n"); -+ __intc_mask_irq(IRQ_OWI); -+ -+} -+ -+static void ow_cpum_read_rom(char *rom) -+{ -+ int i; -+ -+ __owi_select_regular_mode(); -+ REG_OWI_DIV = __cpm_get_extalclk()/1000000 - 1; -+ __owi_clr_sts(); -+ __owi_disable_all_interrupts(); -+ -+ do_ow_rst(); -+ __owi_wait_ops_rdy(); -+ -+ if(!__owi_get_sts_pst()) -+ printk("read rom no device found\n"); -+ -+ REG_OWI_DAT = 0x33; -+ do_ow_wrdata(); -+ __owi_wait_ops_rdy(); -+ -+ for(i=0; i<8; i++){ -+ do_ow_rddata(); -+ __owi_wait_ops_rdy(); -+ rom[i] = REG_OWI_DAT; -+ } -+} -+ -+ -+static void ow_comm_bit(unsigned comm) -+{ -+ int i; -+ for(i=0; i<8; i++){ -+ if ( comm & (1<>j) & 1 ){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ else{ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ -+#else -+ if(normal ==0 && reverse ==0){ -+ if (!((rom[i]>>j) & 1) ){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ else{ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ }else{ -+ -+ if(normal ==0){ -+ printk("write 0\n"); -+ do_ow_wr0(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ if(normal ==1){ -+ printk("write 1\n"); -+ do_ow_wr1rd(); -+ while(!__owi_get_sts_bit_rdy()) ; -+ } -+ } -+#endif -+ -+ } -+ printk("\n\n"); -+ } -+ printk("\nSearch rom CPU mode: device found SUCCESSFULLY\n"); -+} -+ -+static void do_interrupt_mode_test(void) -+{ -+ int ret, i; -+ unsigned char rom[8]; -+ -+ /* interrupt mode */ -+ ret = request_irq(IRQ_OWI, ow_interrupt, IRQF_DISABLED, -+ "JZ_OWI", NULL); -+ if(ret) -+ printk("failed irq \n"); -+ -+#if OW_INTC_READ_ROM -+ ow_intcm_read_rom(rom); -+ printk("\n\nAfter intc mode read ROM ops: \n"); -+ printk("ROM: "); -+ for(i=0; i<8; i++) -+ printk("0x%02x,",rom[i]); -+#endif -+ -+#if OW_INTC_SEARCH_ROM -+ ow_intcm_search_rom(); -+#endif -+ -+} -+ -+static void do_cpu_mode_test(void) -+{ -+ -+#if OW_CPU_READ_ROM -+ int i; -+ unsigned char rom[8]; -+ -+ ow_cpum_read_rom(rom); -+ printk("\n\nAfter CPU mode read ROM ops: \n"); -+ printk("ROM: "); -+ for(i=0; i<8; i++) -+ printk("0x%02x,",rom[i]); -+#endif -+ -+#if OW_CPU_SEARCH_ROM -+ ow_cpum_search_rom(); -+#endif -+} -+ -+/* -+ * Module init and exit -+ */ -+static int __init ow_init(void) -+{ -+ int ret; -+ -+ ret = jz_register_chrdev(OW_MINOR, "ow", &ow_fops, NULL); -+ if (ret < 0) { -+ return ret; -+ } -+ __gpio_as_func1(153); -+ -+ REG_OWI_CFG=0; -+ REG_OWI_CTL=0; -+ REG_OWI_STS=0; -+ REG_OWI_DAT=0; -+ REG_OWI_DIV=0; -+ -+ do_interrupt_mode_test(); -+ do_cpu_mode_test(); -+ -+ printk("Ingenic OW driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit ow_exit(void) -+{ -+ free_irq(IRQ_OWI, NULL); -+ jz_unregister_chrdev(OW_MINOR, "ow"); -+} -+ -+module_init(ow_init); -+module_exit(ow_exit); -+ -+MODULE_AUTHOR("Yurong Tan"); -+MODULE_DESCRIPTION("One Wire Bus test Driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jz_ts.c linux-2.6.24.7/drivers/char/jzchar/jz_ts.c ---- linux-2.6.24.7.old/drivers/char/jzchar/jz_ts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jz_ts.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,443 @@ -+/* -+ * jz_ts.c -+ * -+ * Touch screen driver for the Ingenic JZ47XX. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz_ts.h" -+ -+MODULE_AUTHOR("Peter Wei "); -+MODULE_DESCRIPTION("Ingenic Touch Screen Driver"); -+MODULE_LICENSE("GPL"); -+ -+#define TS_NAME "jz-ts" -+#define TS_MINOR 16 /* MAJOR: 10, MINOR: 16 */ -+#define PFX TS_NAME -+ -+//#define JZ_TS_DEBUG -+ -+#ifdef JZ_TS_DEBUG -+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) do {} while (0) -+#endif -+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) -+ -+static struct jz_ts_t jz_ts; -+ -+unsigned int (*codec_read_battery)(void) = NULL; -+ -+// hold the spinlock before calling. -+static void event_add(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ts->lock, flags); -+ -+ // add this event to the event queue -+ ts->event_buf[ts->nextIn] = *event; -+ ts->nextIn = (ts->nextIn + 1) & (EVENT_BUFSIZE - 1); -+ if (ts->event_count < EVENT_BUFSIZE) { -+ ts->event_count++; -+ } else { -+ // throw out the oldest event -+ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1); -+ } -+ -+ spin_unlock_irqrestore(&ts->lock, flags); -+ -+ // async notify -+ if (ts->fasync) -+ kill_fasync(&ts->fasync, SIGIO, POLL_IN); -+ // wake up any read call -+ if (waitqueue_active(&ts->wait)) -+ wake_up_interruptible(&ts->wait); -+} -+ -+static int event_pull(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&ts->lock, flags); -+ ret = ts->event_count; -+ if (ts->event_count) { -+ *event = ts->event_buf[ts->nextOut]; -+ ts->nextOut = (ts->nextOut + 1) & (EVENT_BUFSIZE - 1); -+ ts->event_count--; -+ } -+ spin_unlock_irqrestore(&ts->lock, flags); -+ -+ return ret; -+} -+ -+static int pen_is_down = 0; -+ -+static irqreturn_t pendown_interrupt(int irq, void * dev_id) -+{ -+ struct jz_ts_t* ts = &jz_ts; -+ struct ts_event event; -+ -+ dbg("pen down"); -+#if defined(CONFIG_SOC_JZ4740) -+ if (ts->sleeping) { -+ ts->sleeping = 0; -+ ts_data_ready(); -+ return IRQ_HANDLED; -+ } -+#endif -+ spin_lock(&ts->lock); -+ -+ if (ts->irq_enabled) { -+ ts->irq_enabled = 0; -+ } -+ else -+ ts->irq_enabled = 1; -+ -+ -+ if (pen_is_down) -+ pen_is_down = 0; -+ else -+ pen_is_down = 1; -+ -+ // callback routine to clear irq status -+ ts_irq_callback(); -+ -+ if ( (pen_is_down == 0)){ -+ del_timer(&ts->acq_timer); -+ spin_unlock(&ts->lock); -+ event.x = event.y = event.pressure = 0; -+ event.status = PENUP; -+ ts->first_read = 0; -+ event_add(ts, &event); -+ return IRQ_HANDLED; -+ } -+ -+ if ( (pen_is_down == 1)) -+ { -+ ts->acq_timer.expires = jiffies + HZ / 100; -+ del_timer(&ts->acq_timer); -+ ts->first_read = 1; -+ add_timer(&ts->acq_timer); -+ spin_unlock(&ts->lock); -+ } -+ return IRQ_HANDLED; -+} -+ -+ -+/* -+ * Raw X,Y,pressure acquisition timer function. It gets scheduled -+ * only while pen is down. Its duration between calls is the polling -+ * rate. -+ */ -+static void -+jz_acq_timer(unsigned long data) -+{ -+ struct jz_ts_t *ts = (struct jz_ts_t *)data; -+ struct ts_event event; -+ int pen_was_down = ts->pen_is_down; -+ -+ spin_lock(&ts->lock); -+ -+ if (PenIsDown()) { -+ -+ ts->pen_is_down = 1; -+ -+ if (AcquireEvent(ts, &event)) // check event is valid or not? -+ event_add(ts, &event); -+ -+ // schedule next acquire -+ ts->acq_timer.expires = jiffies + HZ / 100; -+ del_timer(&ts->acq_timer); -+ add_timer(&ts->acq_timer); -+ } else { -+ -+ if (!ts->irq_enabled) { -+ ts->irq_enabled = 1; -+ } -+ ts->pen_is_down = 0; -+ if (pen_was_down) { -+ event.x = event.y = event.pressure = 0; -+ event.status = PENUP; -+ event_add(ts, &event); -+ } -+ } -+ -+ spin_unlock(&ts->lock); -+} -+ -+/* +++++++++++++ Read battery voltage routine ++++++++++++++*/ -+ -+unsigned int jz_read_battery(void) -+{ -+ unsigned int v = 0; -+ struct jz_ts_t *ts = &jz_ts; -+ -+ spin_lock(&ts->lock); -+ -+ if (codec_read_battery) -+ v = codec_read_battery(); -+ -+ spin_unlock(&ts->lock); -+ -+ return v; -+} -+ -+/* +++++++++++++ File operations ++++++++++++++*/ -+ -+static int -+jz_fasync(int fd, struct file *filp, int mode) -+{ -+ struct jz_ts_t *ts = (struct jz_ts_t *)filp->private_data; -+ return fasync_helper(fd, filp, mode, &ts->fasync); -+} -+ -+ -+static unsigned int -+jz_poll(struct file * filp, poll_table * wait) -+{ -+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; -+ poll_wait(filp, &ts->wait, wait); -+ if (ts->event_count) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+static ssize_t -+jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; -+ char *ptr = buffer; -+ struct ts_event event; -+ int err = 0; -+ -+ dbg("jz_read"); -+ -+ add_wait_queue(&ts->wait, &wait); -+ while (count >= sizeof(struct ts_event)) { -+ err = -ERESTARTSYS; -+ if (signal_pending(current)) -+ break; -+ -+ -+ if (event_pull(ts, &event)) { -+ err = copy_to_user(ptr, &event, -+ sizeof(struct ts_event)); -+ if (err) -+ break; -+ ptr += sizeof(struct ts_event); -+ count -= sizeof(struct ts_event); -+ } else { -+ set_current_state(TASK_INTERRUPTIBLE); -+ err = -EAGAIN; -+ if (filp->f_flags & O_NONBLOCK) -+ break; -+ schedule(); -+ } -+ } -+ -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&ts->wait, &wait); -+ -+ return ptr == buffer ? err : ptr - buffer; -+} -+ -+ -+static int -+jz_open(struct inode * inode, struct file * filp) -+{ -+ struct jz_ts_t *ts; -+ int retval; -+ -+ dbg("open ts device"); -+ filp->private_data = ts = &jz_ts; -+ -+ spin_lock(&ts->lock); -+ -+ ts->pen_is_down = 0; // start with pen up -+ ts->sleeping = 0; -+ // flush event queue -+ ts->nextIn = ts->nextOut = ts->event_count = 0; -+ -+ // Init acquisition timer function -+ init_timer(&ts->acq_timer); -+ ts->acq_timer.function = jz_acq_timer; -+ ts->acq_timer.data = (unsigned long)ts; -+ -+ ts->irq_enabled = 1; -+ -+ spin_unlock(&ts->lock); -+ -+ /* Since ts interrupt can happen immediately after request_irq, -+ * we wait until we've completed init of all relevent driver -+ * state variables. Now we grab the PenDown IRQ -+ */ -+ retval = ts_request_irq(&ts->pendown_irq, pendown_interrupt, TS_NAME, ts); -+ if (retval) { -+ err("unable to get PenDown IRQ %d", ts->pendown_irq); -+ return retval; -+ } -+ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int -+jz_release(struct inode * inode, struct file * filp) -+{ -+ struct jz_ts_t* ts = (struct jz_ts_t*)filp->private_data; -+ -+ ts_free_irq(ts); -+ jz_fasync(-1, filp, 0); -+ del_timer_sync(&ts->acq_timer); -+ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static int jz_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) -+{ -+ struct txy { -+ int minx; -+ int miny; -+ int maxx; -+ int maxy; -+ }; -+ -+ struct txy ch; -+ -+ /* -+ * Switch according to the ioctl called -+ */ -+ switch (ioctl_num) -+ { -+ case IOCTL_SET_MSG: -+ jz_ts.filter=1; -+ break; -+ case IOCTL_SET_NUM: -+ if (copy_from_user((void *)&ch, (void *)ioctl_param, sizeof(ch))) -+ return -EFAULT; -+ jz_ts.minx = ch.minx; -+ jz_ts.miny = ch.miny; -+ jz_ts.maxx = ch.maxx; -+ jz_ts.maxy = ch.maxy; -+ break; -+ } -+ -+ return 0; -+} -+ -+static struct file_operations ts_fops = { -+ owner: THIS_MODULE, -+ read: jz_read, -+ poll: jz_poll, -+ fasync: jz_fasync, -+ ioctl: jz_ioctl, -+ open: jz_open, -+ release: jz_release, -+}; -+ -+/* +++++++++++++ End File operations ++++++++++++++*/ -+ -+static int __init minx_setup(char *str) -+{ -+ int i; -+ -+ if (get_option(&str,&i)) jz_ts.minx = i; -+ jz_ts.filter=i; -+ return 1; -+} -+ -+__setup("ts_minx=", minx_setup); -+ -+static int __init miny_setup(char *str) -+{ -+ int i; -+ if (get_option(&str,&i)) jz_ts.miny = i; -+ return 1; -+} -+ -+__setup("ts_miny=", miny_setup); -+ -+static int __init maxx_setup(char *str) -+{ -+ int i; -+ if (get_option(&str,&i)) jz_ts.maxx = i; -+ return 1; -+} -+ -+__setup("ts_maxx=", maxx_setup); -+ -+static int __init maxy_setup(char *str) -+{ -+ int i; -+ if (get_option(&str,&i)) jz_ts.maxy = i; -+ return 1; -+} -+ -+__setup("ts_maxy=", maxy_setup); -+ -+static int __init printraw_setup(char *str) -+{ -+ if (str) -+ jz_ts.prints = 1; -+ -+ return 0; -+} -+ -+__setup("ts_debug", printraw_setup); -+ -+ -+static struct miscdevice jz_ts_dev = { -+ minor: TS_MINOR, -+ name: TS_NAME, -+ fops: &ts_fops, -+}; -+ -+static int __init jzts_init_module(void) -+{ -+ struct jz_ts_t *ts = &jz_ts; -+ int ret; -+ -+ if ((ret = misc_register(&jz_ts_dev)) < 0) { -+ err("can't register misc device"); -+ return ret; -+ } -+ -+// memset(ts, 0, sizeof(struct jz_ts_t)); -+ init_waitqueue_head(&ts->wait); -+ spin_lock_init(&ts->lock); -+ -+ printk("Jz generic touch screen driver registered\n"); -+ -+ return 0; -+} -+ -+static void jzts_cleanup_module(void) -+{ -+ misc_deregister(&jz_ts_dev); -+} -+ -+module_init(jzts_init_module); -+module_exit(jzts_cleanup_module); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jz_ts.h linux-2.6.24.7/drivers/char/jzchar/jz_ts.h ---- linux-2.6.24.7.old/drivers/char/jzchar/jz_ts.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jz_ts.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,54 @@ -+#ifndef __JZ_TS_H__ -+#define __JZ_TS_H__ -+ -+/* -+ * IOCTL commands -+ */ -+#define IOCTL_SET_MSG 0 -+#define IOCTL_SET_NUM 1 -+ -+ -+/* -+ * TS Event type -+ */ -+struct ts_event { -+ u16 status; -+ u16 x; -+ u16 y; -+ u16 pressure; -+ u16 pad; -+}; -+ -+/* TS event status */ -+#define PENUP 0x00 -+#define PENDOWN 0x01 -+ -+#define EVENT_BUFSIZE 64 // must be power of two -+ -+struct jz_ts_t { -+ int pendown_irq; // IRQ of pendown interrupt -+ int pen_is_down; // 1 = pen is down, 0 = pen is up -+ int irq_enabled; -+ struct ts_event event_buf[EVENT_BUFSIZE];// The event queue -+ int nextIn, nextOut; -+ int event_count; -+ struct fasync_struct *fasync; // asynch notification -+ struct timer_list acq_timer; // Timer for triggering acquisitions -+ wait_queue_head_t wait; // read wait queue -+ spinlock_t lock; -+ int minx, miny, maxx, maxy; -+ int filter, prints; -+ int sleeping; -+ int first_read; -+}; -+ -+extern void ts_enable_irq(void); -+extern void ts_disable_irq(void); -+extern int ts_request_irq(u32 *irq,irqreturn_t (*handler)(int, void *), const char *devname, void *dev_id); -+extern void ts_free_irq(struct jz_ts_t *ts); -+extern int PenIsDown(void); -+extern int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event); -+extern void ts_irq_callback(void); -+extern void ts_data_ready(void); -+ -+#endif /* __JZ_TS_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jz_tssi.c linux-2.6.24.7/drivers/char/jzchar/jz_tssi.c ---- linux-2.6.24.7.old/drivers/char/jzchar/jz_tssi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jz_tssi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,457 @@ -+/* -+ * jz_tssi.c -+ * -+ * MPEG2-TS interface driver for the Ingenic JZ47XX. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "jzchars.h" -+ -+#include "jz_tssi.h" -+ -+ -+MODULE_AUTHOR("Lucifer Liu "); -+MODULE_DESCRIPTION("Ingenic MPEG2-TS interface Driver"); -+MODULE_LICENSE("GPL"); -+ -+#define TSSI_NAME "JZ MPEG2-TS SI" -+#define TSSI_MINOR 204 /* MAJOR: 10, MINOR: 16 */ -+#define TSSI_IRQ IRQ_TSSI -+#define PFX TSSI_NAME -+#define RING_BUF_NUM 100 -+ -+#define USE_DMA -+#define TRIG_PIN ( 32 * 2 + 15 ) -+#define DMA_ID_TSSI 5 -+//#define JZ_TSSI_DEBUG -+ -+#ifdef JZ_TSSISI_DEBUG -+#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) do {} while (0) -+#endif -+#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg) -+ -+static struct jz_tssi_t jz_tssi_g; -+static struct jz_tssi_buf_ring_t jz_tssi_ring_g; -+static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size); -+ -+static void print_reg( void ) -+{ -+ printk("REG_TSSI_ENA %8x \n ", REG8( TSSI_ENA )); -+ printk("REG_TSSI_CFG %8x \n ", REG16( TSSI_CFG )); -+ printk("REG_TSSI_CTRL %8x \n ", REG8( TSSI_CTRL )); -+ printk("REG_TSSI_STAT %8x \n ", REG8( TSSI_STAT )); -+ printk("REG_TSSI_FIFO %8x \n ", REG32( TSSI_FIFO )); -+ printk("REG_TSSI_PEN %8x \n ", REG32( TSSI_PEN )); -+ printk("REG_TSSI_PID0 %8x \n ", REG32( TSSI_PID0 )); -+ printk("REG_TSSI_PID1 %8x \n ", REG32( TSSI_PID1 )); -+ printk("REG_TSSI_PID2 %8x \n ", REG32( TSSI_PID2 )); -+ printk("REG_TSSI_PID3 %8x \n ", REG32( TSSI_PID3 )); -+ printk("REG_TSSI_PID4 %8x \n ", REG32( TSSI_PID4 )); -+ printk("REG_TSSI_PID5 %8x \n ", REG32( TSSI_PID5 )); -+ printk("REG_TSSI_PID6 %8x \n ", REG32( TSSI_PID6 )); -+ printk("REG_TSSI_PID7 %8x \n ", REG32( TSSI_PID7 )); -+} -+ -+void dump_dma_channel(unsigned int dmanr) -+{ -+ printk("DMA%d Registers:\n", dmanr); -+ printk(" DMACR = 0x%8x\n", REG_DMAC_DMACR(0)); -+ printk(" DSAR = 0x%8x\n", REG_DMAC_DSAR(dmanr)); -+ printk(" DTAR = 0x%8x\n", REG_DMAC_DTAR(dmanr)); -+ printk(" DTCR = 0x%8x\n", REG_DMAC_DTCR(dmanr)); -+ printk(" DRSR = 0x%8x\n", REG_DMAC_DRSR(dmanr)); -+ printk(" DCCSR = 0x%8x\n", REG_DMAC_DCCSR(dmanr)); -+ printk(" DCMD = 0x%8x\n", REG_DMAC_DCMD(dmanr)); -+ printk(" DDA = 0x%8x\n", REG_DMAC_DDA(dmanr)); -+ printk(" DMADBR = 0x%8x\n", REG_DMAC_DMADBR(1)); -+} -+ -+static int tssi_buf_init( struct jz_tssi_buf_ring_t * ring ) -+{ -+ int i; -+ struct jz_tssi_buf * bp,* ap, *cp; -+ -+ ap = cp = bp = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); //the first -+ if ( !bp ) { -+ printk("Can not malloc buffer! \n"); -+ return -1; -+ } -+ -+ for ( i = 0; i < RING_BUF_NUM; i ++ ) { -+ bp = ap; -+ bp->buf = (unsigned int *) kmalloc(MPEG2_TS_PACHAGE_SIZE / 4 * sizeof(unsigned int) ,GFP_KERNEL); -+ if ( !bp->buf ) { -+ printk("Can not malloc buffer! \n"); -+ return -1; -+ } -+ bp->index = i; -+ bp->pos = 0; -+ ap = (struct jz_tssi_buf *)kmalloc( sizeof( struct jz_tssi_buf ) ,GFP_KERNEL ); -+ if ( !ap ) { -+ printk("Can not malloc buffer! \n"); -+ return -1; -+ } -+ -+ bp->next = ap; //point to next ! -+ } -+ -+ bp->next = cp; //point loop to first! -+ ring->front = cp; -+ ring->rear = cp; -+ ring->fu_num = 0; -+ kfree(ap); -+ return 0; -+} -+ -+static void tssi_free_buf( struct jz_tssi_buf_ring_t * ring ) -+{ -+ int i; -+ struct jz_tssi_buf * ap; -+ for ( i = 0; i < RING_BUF_NUM; i ++ ) -+ { -+ ap = ring->front; -+ ring->front = ring->front->next; -+ kfree( ap ); -+ } -+} -+ -+#if 0 -+static void tssi_read_fifo(void *dev_id) -+{ -+ struct jz_tssi_t* tssi = ( struct jz_tssi_t* )dev_id; -+ struct jz_tssi_buf_ring_t * ring = tssi->cur_buf; -+ struct jz_tssi_buf *buf = ring->rear; -+ int i; -+#if 0 -+ if ( ring->fu_num > RING_BUF_NUM ) -+ { -+ printk("Ring buffer full ! %d \n",ring->fu_num); -+ return; -+ } -+#endif -+ -+ for ( i = 0; i < 8 ; i ++ ) -+ { -+ ring->front->buf[ring->front->pos++] = REG_TSSI_FIFO; -+ } -+ -+ if ( ring->front->pos >= MPEG2_TS_PACHAGE_SIZE ) -+ { -+ ring->fu_num ++; -+ ring->front = ring->front->next; -+ ring->front->pos = 0; -+ } -+} -+#endif -+ -+static void tssi_config_filting( void ) -+{ -+ __tssi_soft_reset(); -+ __gpio_as_tssi(); -+ __tssi_disable_ovrn_irq(); //use dma ,no need irq -+ __tssi_disable_trig_irq(); -+ __tssi_set_tigger_num( 8 ); //trig is 4 word! -+// __tssi_filter_enable(); -+ __tssi_clear_state(); -+ __tssi_filter_disable(); -+ __tssi_state_clear_overrun(); -+// __tssi_clear_trig_irq_flag(); -+#ifdef USE_DMA -+ __tssi_dma_enable(); -+#else -+ __tssi_dma_disable(); -+#endif -+ -+ __tssi_enable_ovrn_irq(); -+// __tssi_enable_trig_irq(); -+ -+ //set config -+// __tssi_set_bt_1(); -+ __tssi_set_wd_1(); -+ __tssi_set_data_use_data7(); -+ __tssi_set_data_pola_high(); -+// __tssi_select_serail_mode(); -+ __tssi_select_paral_mode(); -+ __tssi_select_clk_fast(); -+ __tssi_select_clk_posi_edge(); -+ __tssi_select_frm_act_high(); -+ __tssi_select_str_act_high(); -+ __tssi_select_fail_act_high(); -+// __tssi_select_fail_act_low(); -+ __tssi_disable_filte_pid0(); //we disable pid0 filter for ever! -+} -+ -+static void tssi_add_pid(int pid_num, int pid) -+{ -+ unsigned int addr ; -+ int n = pid_num / 2, hl = pid_num % 2; -+ if ( hl ) //use high pid, pid1 -+ { -+ addr = TSSI_PID0 + ( n * 4 ); -+ REG32( addr ) |= ( (pid & 0x1fff) << 16 ); //13bit -+ REG_TSSI_PEN |= ( 1 << (16 + n) ); -+ } -+ else //use low pid, pid0 -+ { -+ addr = TSSI_PID0 + ( n * 4 ); -+ REG32( addr ) |= pid & 0x1fff; //13bit -+ REG_TSSI_PEN |= ( 1 << n ); -+ } -+} -+ -+static irqreturn_t tssi_dma_irq(int irq, void * dev_id) -+{ -+ struct jz_tssi_t *tssi = (struct jz_tssi_t *)dev_id; -+ struct jz_tssi_buf_ring_t *buf = tssi->cur_buf; -+ -+ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ -+ if (__dmac_channel_transmit_end_detected(tssi->dma_chan)) { -+ __dmac_channel_clear_transmit_end(tssi->dma_chan); -+ if ( buf->fu_num < RING_BUF_NUM ) -+ { -+ buf->front = buf->front->next; -+ REG_DMAC_DSAR(tssi->dma_chan) = CPHYSADDR(TSSI_FIFO); -+ REG_DMAC_DTAR(tssi->dma_chan) = CPHYSADDR((unsigned int)buf->front->buf); -+ REG_DMAC_DTCR(tssi->dma_chan) = MPEG2_TS_PACHAGE_SIZE / 32; -+ REG_DMAC_DCCSR(tssi->dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ buf->fu_num ++; -+ } -+ __tssi_clear_state(); -+ } -+ -+ if (__dmac_channel_transmit_halt_detected(tssi->dma_chan)) { -+ printk("DMA HALT\n"); -+ __dmac_channel_clear_transmit_halt(tssi->dma_chan); -+ } -+ -+ if (__dmac_channel_address_error_detected(tssi->dma_chan)) { -+ printk("DMA ADDR ERROR\n"); -+ __dmac_channel_clear_address_error(tssi->dma_chan); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(tssi->dma_chan)) { -+ printk("DMA DESC INVALID\n"); -+ __dmac_channel_clear_descriptor_invalid(tssi->dma_chan); -+ } -+ -+ if (__dmac_channel_count_terminated_detected(tssi->dma_chan)) { -+ printk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(tssi->dma_chan); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t tssi_interrupt(int irq, void * dev_id) -+{ -+ __intc_mask_irq(TSSI_IRQ); -+#if 1 -+ if ( REG_TSSI_STAT & TSSI_STAT_OVRN ) -+ { -+ printk("tssi over run occur! %x\n",REG8( TSSI_STAT )); -+ __tssi_clear_state(); -+ printk("clear ! %x\n",REG8( TSSI_STAT )); -+ } -+#endif -+ if ( REG_TSSI_STAT & TSSI_STAT_TRIG ) -+ { -+ printk("tssi trig irq occur! \n"); -+ tssi_read_fifo( dev_id ); -+ } -+ -+ __intc_ack_irq(TSSI_IRQ); -+ __intc_unmask_irq(TSSI_IRQ); -+ return IRQ_HANDLED; -+} -+ -+static ssize_t jz_read(struct file * filp, char * buffer, size_t count, loff_t * ppos) -+{ -+ jz_char_dev_t *adev = (jz_char_dev_t *)filp->private_data; -+ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private; -+ struct jz_tssi_buf_ring_t* ring = tssi->cur_buf; -+ -+ int i; -+ -+ count /= MPEG2_TS_PACHAGE_SIZE; -+ -+ if ( count > ring->fu_num ) -+ count = ring->fu_num; -+ -+ for ( i = 0; i < count; i ++ ) -+ { -+ memcpy( buffer + ( i * MPEG2_TS_PACHAGE_SIZE), -+ ring->rear->buf, MPEG2_TS_PACHAGE_SIZE ); -+ ring->rear->pos = 0; -+ ring->rear = ring->rear->next; -+ } -+ ring->fu_num -= count; -+ return count * MPEG2_TS_PACHAGE_SIZE; -+} -+ -+static int tssi_dma_reinit(int dma_chan, unsigned char *dma_buf, int size) -+{ -+ static unsigned int dma_src_phys_addr, dma_dst_phys_addr; -+ REG_DMAC_DMACKE(0) = 0xff; -+ dma_src_phys_addr = CPHYSADDR(TSSI_FIFO); -+ dma_dst_phys_addr = CPHYSADDR((unsigned int)dma_buf); -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = 0; -+ REG_DMAC_DCCSR(dma_chan) = 0; -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_TSSIIN; -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = size / 32; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR(dma_chan/HALF_DMA_NUM) = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ return 0; -+} -+ -+static int jz_open(struct inode * inode, struct file * filp) -+{ -+ try_module_get(THIS_MODULE); -+ -+ __tssi_soft_reset(); -+ __intc_mask_irq(TSSI_IRQ); -+ tssi_config_filting(); -+ -+ return 0; -+} -+ -+static int jz_release(struct inode * inode, struct file * filp) -+{ -+ __intc_mask_irq(TSSI_IRQ); -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static int jz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ jz_char_dev_t *adev = (jz_char_dev_t *)file->private_data; -+ struct jz_tssi_t* tssi = (struct jz_tssi_t*)adev->private; -+ -+ switch (cmd) -+ { -+ case IOCTL_TSSI_ENABLE : -+ __intc_ack_irq(TSSI_IRQ); -+ __intc_unmask_irq(TSSI_IRQ); -+ __tssi_enable(); -+ print_reg(); -+ -+ break; -+ case IOCTL_TSSI_DISABLE : -+ __tssi_disable(); -+ -+ break; -+ case IOCTL_TSSI_SOFTRESET : -+ __tssi_soft_reset(); -+ -+ break; -+ case IOCTL_TSSI_ENFILTER : -+ __tssi_filter_enable(); -+ break; -+ case IOCTL_TSSI_DEFILTER : -+ __tssi_filter_disable(); -+ break; -+ case IOCTL_TSSI_ADDPID : //add one pid to filter -+ if ( tssi->pid_num < 15 ) -+ { -+ tssi_add_pid(tssi->pid_num, arg); -+ tssi->pid_num ++ ; -+ } -+ break; -+ -+ case IOCTL_TSSI_FLUSHPID : //set all filting pid to false -+ REG_TSSI_PEN = 0x0; -+ REG_TSSI_PID0 = 0x0; -+ REG_TSSI_PID1 = 0x0; -+ REG_TSSI_PID2 = 0x0; -+ REG_TSSI_PID3 = 0x0; -+ REG_TSSI_PID4 = 0x0; -+ REG_TSSI_PID5 = 0x0; -+ REG_TSSI_PID6 = 0x0; -+ REG_TSSI_PID7 = 0x0; -+ break; -+ -+ case IOCTL_TSSI_INIT_DMA: -+ tssi_dma_reinit(tssi->dma_chan, tssi->cur_buf->front->buf, MPEG2_TS_PACHAGE_SIZE); -+ break; -+ case IOCTL_TSSI_DISABLE_DMA: -+ REG_DMAC_DCCSR(tssi->dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ break; -+ } -+ -+ return 0; -+} -+ -+static struct file_operations tssi_fops = { -+ owner: THIS_MODULE, -+ read: jz_read, -+ poll: NULL, -+ fasync: NULL, -+ ioctl: jz_ioctl, -+ open: jz_open, -+ release: jz_release, -+}; -+ -+static int __init jztssi_init_module(void) -+{ -+ int retval; -+ struct jz_tssi_t *tssi = &jz_tssi_g; -+ -+ __cpm_start_tssi(); -+ __cpm_start_dmac(); -+ tssi_buf_init( &jz_tssi_ring_g ); -+ tssi->cur_buf = &jz_tssi_ring_g; -+ tssi->pid_num = 0; -+ retval = request_irq(TSSI_IRQ, tssi_interrupt, IRQF_DISABLED, TSSI_NAME, &jz_tssi_g); -+ -+ if (retval) { -+ printk("unable to get IRQ %d",TSSI_IRQ); -+ return retval; -+ } -+ -+ tssi->dma_chan = jz_request_dma(DMA_ID_TSSI, "tssi", tssi_dma_irq, -+ IRQF_DISABLED, &jz_tssi_g); -+ if ( tssi->dma_chan < 0 ) -+ { -+ printk("MPEG2-TS request irq fail! \n"); -+ return -1; -+ } -+ -+ jz_register_chrdev(TSSI_MINOR, TSSI_NAME, &tssi_fops, &jz_tssi_g); -+ -+ printk("Jz MPEG2-TS interface driver registered %x %d\n",&jz_tssi_g,tssi->dma_chan); -+ return 0; -+} -+ -+static void jztssi_cleanup_module(void) -+{ -+ free_irq(TSSI_IRQ,0); -+ jz_free_dma(jz_tssi_g.dma_chan); -+ tssi_free_buf( &jz_tssi_ring_g ); -+ jz_unregister_chrdev(TSSI_MINOR, TSSI_NAME); -+} -+ -+module_init(jztssi_init_module); -+module_exit(jztssi_cleanup_module); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jz_tssi.h linux-2.6.24.7/drivers/char/jzchar/jz_tssi.h ---- linux-2.6.24.7.old/drivers/char/jzchar/jz_tssi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jz_tssi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+#ifndef __JZ_TSSI_H__ -+#define __JZ_TSSI_H__ -+ -+/* -+ * IOCTL commands -+ */ -+#define IOCTL_TSSI_ENABLE 0x01 -+#define IOCTL_TSSI_DISABLE 0x02 -+#define IOCTL_TSSI_SOFTRESET 0x03 -+#define IOCTL_TSSI_ENFILTER 0x04 -+#define IOCTL_TSSI_DEFILTER 0x05 -+#define IOCTL_TSSI_ADDPID 0x06 -+#define IOCTL_TSSI_FLUSHPID 0x07 -+#define IOCTL_TSSI_INIT_DMA 0x08 -+#define IOCTL_TSSI_DISABLE_DMA 0x09 -+ -+#if 0 -+#define IOCTL_TSSI_SET_CFG 0x06 -+#define IOCTL_TSSI_GET_CFG 0x07 -+#define IOCTL_TSSI_ENIRQ_TRIG 0x08 -+#define IOCTL_TSSI_DEIRQ_TRIG 0x09 -+#define IOCTL_TSSI_ENIRQ_OVRN 0x0a -+#define IOCTL_TSSI_DEIRQ_OVRN 0x0b -+#define IOCTL_TSSI_ENPID0 0x0c -+#define IOCTL_TSSI_DEPID0 0x0d -+#define IOCTL_TSSI_ENPIDN 0x0e -+#define IOCTL_TSSI_DEPIDN 0x0f -+#define IOCTL_TSSI_SETPIDN 0x10 -+#define IOCTL_TSSI_SET_TRIG 0x11 -+#endif -+ -+#define MAX_PID_NUM 15 -+#define MPEG2_TS_PACHAGE_SIZE 19200 -+ -+struct jz_tssi_cfg_t -+{ -+ unsigned char wordorder; -+ unsigned char byteorder; -+ unsigned char dataploa; -+ unsigned char use0; -+ unsigned char clkch; -+ unsigned char mode; -+ unsigned char clkpola; -+ unsigned char frmpola; -+ unsigned char strpola; -+ unsigned char failpola; -+ unsigned char trignum; -+ -+ unsigned short pid; -+ unsigned char pid_index; //0 to 15 -+}; -+ -+struct jz_tssi_buf -+{ -+ unsigned int *buf; -+ unsigned int pos; -+ unsigned int index; -+ struct jz_tssi_buf *next; -+}; -+ -+struct jz_tssi_buf_ring_t -+{ -+ struct jz_tssi_buf *front; -+ struct jz_tssi_buf *rear; -+ unsigned int fu_num; -+}; -+ -+struct jz_tssi_t -+{ -+ struct jz_tssi_cfg_t cur_config; -+ struct jz_tssi_buf_ring_t *cur_buf; -+ struct semaphore tssi_sem; -+ int dma_chan, pid_num; -+}; -+ -+#endif /* __JZ_TSSI_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jzchars.c linux-2.6.24.7/drivers/char/jzchar/jzchars.c ---- linux-2.6.24.7.old/drivers/char/jzchar/jzchars.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jzchars.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,158 @@ -+/* -+ * linux/drivers/char/jzchar/jzchars.c -+ * -+ * JzSOC char device family common layer. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "jzchars.h" -+ -+LIST_HEAD(jz_char_devs); -+ -+int jz_register_chrdev(unsigned char minor, const char *name, -+ struct file_operations *fops, void *private) -+{ -+ struct list_head *p; -+ jz_char_dev_t *new; -+ list_for_each(p, &jz_char_devs) { -+ jz_char_dev_t *dev = (jz_char_dev_t *)p; -+ if (minor == dev->dev_minor) -+ return -EBUSY; -+ } -+ new = (jz_char_dev_t *)kmalloc(sizeof(jz_char_dev_t), GFP_KERNEL); -+ new->dev_minor = minor; -+ new->name = (char *)name; -+ new->fops = fops; -+ new->private = private; -+ list_add_tail((struct list_head *)new, &jz_char_devs); -+ return 0; -+} -+ -+int jz_unregister_chrdev(unsigned char minor, const char *name) -+{ -+ struct list_head *p; -+ jz_char_dev_t *dev = NULL; -+ list_for_each(p, &jz_char_devs) { -+ jz_char_dev_t *one = (jz_char_dev_t *)p; -+ if (minor == one->dev_minor) { -+ dev = one; -+ break; -+ } -+ } -+ if (dev == NULL) -+ return -EINVAL; -+ list_del((struct list_head *)dev); -+ kfree(dev); -+ return 0; -+} -+ -+static ssize_t jz_char_read(struct file *, char *, size_t, loff_t *); -+static ssize_t jz_char_write(struct file *, const char *, size_t, loff_t *); -+static int jz_char_open(struct inode *, struct file *); -+static int jz_char_release(struct inode *, struct file *); -+static int jz_char_ioctl(struct inode *, struct file *, -+ unsigned int, unsigned long); -+ -+static struct file_operations jz_char_fops = -+{ -+ read: jz_char_read, -+ write: jz_char_write, -+ ioctl: jz_char_ioctl, -+ open: jz_char_open, -+ release: jz_char_release -+}; -+ -+static int __init jz_char_family_init(void) -+{ -+ printk("JzSOC: char device family.\n"); -+ return register_chrdev(JZ_CHAR_MAJOR, "JzChar", &jz_char_fops); -+} -+ -+static void __exit jz_char_family_exit(void) -+{ -+ printk("JzSOC: exit char device family.\n"); -+ unregister_chrdev(JZ_CHAR_MAJOR, "JzChar"); -+} -+ -+module_init(jz_char_family_init); -+module_exit(jz_char_family_exit); -+ -+static int jz_char_open(struct inode *inode, struct file *filp) -+{ -+ jz_char_dev_t *dev = NULL; -+ unsigned int minor = iminor(inode); //minor extend to 20bit! -+ struct list_head *p; -+ list_for_each(p, &jz_char_devs) { -+ jz_char_dev_t *one = (jz_char_dev_t *)p; -+ if (one->dev_minor == minor) { -+ dev = one; -+ filp->private_data = dev; -+ return dev->fops->open(inode, filp); -+ } -+ } -+ printk("JzChar: No such device\n"); -+ return -EINVAL; -+} -+ -+static int jz_char_release(struct inode *inode, struct file *filp) -+{ -+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; -+ if (dev->fops->release) -+ return dev->fops->release(inode, filp); -+ return 0; -+} -+ -+static int jz_char_ioctl(struct inode *inode, struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; -+ if (dev->fops->ioctl) -+ return dev->fops->ioctl(inode, filp, cmd, arg); -+ return 0; -+} -+ -+static ssize_t jz_char_read(struct file *filp, char *buf, -+ size_t count, loff_t *ppos) -+{ -+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; -+ if (dev->fops->read) -+ return dev->fops->read(filp, buf, count, ppos); -+ return 0; -+} -+ -+static ssize_t jz_char_write(struct file *filp, const char *buf, -+ size_t count, loff_t *ppos) -+{ -+ jz_char_dev_t *dev = (jz_char_dev_t *)filp->private_data; -+ if (dev->fops->write) -+ return dev->fops->write(filp, buf, count, ppos); -+ return 0; -+} -+ -+EXPORT_SYMBOL(jz_register_chrdev); -+EXPORT_SYMBOL(jz_unregister_chrdev); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/jzchars.h linux-2.6.24.7/drivers/char/jzchar/jzchars.h ---- linux-2.6.24.7.old/drivers/char/jzchar/jzchars.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/jzchars.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,47 @@ -+#ifndef __JZ_CHARS_H__ -+#define __JZ_CHARS_H__ -+ -+#include -+#include -+ -+#define JZ_CHAR_MAJOR 238 -+ -+#define UPRT_MINOR 0 // Micro printer -+#define CIM_MINOR 1 // Camera interface module -+#define TPANEL_MINOR 2 // Touchpanel -+#define KEYPAD_MINOR 3 // Keypad -+#define MEMCARD_MINOR 4 // Memory card -+#define MAGCARD_MINOR 5 // Magcard -+#define VFD_MINOR 6 // VFD -+#define POWERFAIL_MINOR 7 // Powerfail -+#define EJTAG_MINOR 8 // EJTAG emulation -+#define REMR0_MINOR 9 // Remote output receive 0 -+#define REMR1_MINOR 10 // Remote output receive 1 -+#define USPI_MINOR 11 // Ultra-speed SPI device -+#define SADC_MINOR 12 // SAR-ADC -+#define SLCD_MINOR 13 // Smart LCD -+ -+// 32 to 47 are reserved for SCC -+#define SCC_MINOR 32 -+// 48 to 63 are reserved for Camera sensor -+#define SENSOR_MINOR 48 -+// 64 to 71 are for EEPROM -+#define EEPROM_MINOR_BASE 64 -+// 72 for OWI -+#define OW_MINOR 72 -+// 73 for TCSM_MINOR -+#define TCSM_MINOR 73 -+ -+typedef struct { -+ struct list_head list; -+ char *name; -+ struct file_operations *fops; -+ void *private; -+ unsigned short dev_minor; -+} jz_char_dev_t; -+ -+extern int jz_register_chrdev(unsigned char minor, const char *name, -+ struct file_operations *fops, void * private); -+extern int jz_unregister_chrdev(unsigned char minor, const char *name); -+ -+#endif /* __JZ_CHARS_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/poweroff.c linux-2.6.24.7/drivers/char/jzchar/poweroff.c ---- linux-2.6.24.7.old/drivers/char/jzchar/poweroff.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/poweroff.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,383 @@ -+/* -+ * linux/drivers/char/jzchar/poweroff.c -+ * -+ * Power off handling. -+ * -+ * Copyright (C) 2005-2007 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "jzchars.h" -+ -+MODULE_AUTHOR("Jianli Wei "); -+MODULE_DESCRIPTION("Poweroff handling"); -+MODULE_LICENSE("GPL"); -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+//#define USE_SUSPEND_HOTPLUG -+ -+#ifdef CONFIG_SOC_JZ4730 -+#define GPIO_PW_I 97 -+#define GPIO_PW_O 66 -+#define POWEROFF_PIN_DOWN 1 -+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_rise_edge(POWEROFF_PIN) -+#define DO_SHUTDOWN_SYSTEM __gpio_clear_pin(GPIO_PW_O) -+#define DO_SUSPEND jz_pm_suspend() -+ -+#define GPIO_DISP_OFF_N 93 -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ REG_PWM_DUT(0) = n; \ -+ REG_PWM_PER(0) = 7; \ -+ REG_PWM_CTR(0) = 0x81; \ -+} while (0) -+#define __lcd_close_backlight() \ -+do { \ -+ __lcd_set_backlight_level(0); \ -+} while (0) -+#endif -+ -+#ifdef CONFIG_SOC_JZ4740 -+#define GPIO_PW_I 125 -+#define POWEROFF_PIN_DOWN 0 -+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) -+#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate() -+#define DO_SUSPEND { \ -+ jz_pm_sleep();\ -+ suspend_flag = 0;\ -+ SET_POWEROFF_PIN_AS_IRQ;\ -+ } -+ -+#define GPIO_DISP_OFF_N 118 -+#define GPIO_PWM 123 -+#define __lcd_close_backlight() \ -+do { \ -+__gpio_as_output(GPIO_PWM); \ -+__gpio_clear_pin(GPIO_PWM); \ -+} while (0) -+#endif -+ -+#ifdef CONFIG_SOC_JZ4750 -+#define GPIO_PW_I GPIO_WAKEUP -+#define POWEROFF_PIN_DOWN 0 -+#define SET_POWEROFF_PIN_AS_IRQ __gpio_as_irq_fall_edge(POWEROFF_PIN) -+#define DO_SHUTDOWN_SYSTEM jz_pm_hibernate() -+#define DO_SUSPEND { \ -+ jz_pm_sleep();\ -+ suspend_flag = 0;\ -+ SET_POWEROFF_PIN_AS_IRQ;\ -+ } -+#endif -+ -+#define POWEROFF_PIN GPIO_PW_I -+#define POWEROFF_IRQ (IRQ_GPIO_0 + POWEROFF_PIN) -+ -+#define POWEROFF_PERIOD 1000 /* unit: ms */ -+#define POWEROFF_DELAY 100 /* unit: ms */ -+ -+static struct timer_list poweroff_timer; -+static struct timer_list poweroff_delaytimer; -+static struct work_struct suspend_work; -+ -+static int poweroff_flag = 0; -+static int suspend_flag = 0; -+static int num_seconds = 0; -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+extern int jz_udc_active; -+#endif -+ -+extern void jz_pm_suspend(void); -+extern int jz_pm_hibernate(void); -+extern int jz_pm_sleep(void); -+ -+static void poweroff_timer_routine(unsigned long dummy) -+{ -+ if (__gpio_get_pin(POWEROFF_PIN) == POWEROFF_PIN_DOWN) { -+ if (++num_seconds > 3) -+ { -+ printk("\nShutdown system now ..\n"); -+ -+#ifndef USE_SUSPEND_HOTPLUG -+ /* Turn off LCD to inform user that the system is shutting down. -+ * But the information of shutting down system will be shown -+ * by userspace program if hotplug is used. -+ */ -+ __lcd_close_backlight(); -+#endif -+ -+ /* -+ * Wait until the power key is up, or the system will reset with -+ * power key down after entering hibernate. -+ */ -+ while(__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN); -+ -+ poweroff_flag = 1; -+ schedule_work(&suspend_work); /* inform user to poweroff */ -+ } -+ else { -+ del_timer(&poweroff_timer); -+ init_timer(&poweroff_timer); -+ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/10; -+ poweroff_timer.data = 0; -+ poweroff_timer.function = poweroff_timer_routine; -+ add_timer(&poweroff_timer); -+ } -+ } -+ else -+ { -+ printk("\nSuspend system now ..\n"); -+ num_seconds = 0; -+ suspend_flag = 1; -+ poweroff_flag = 0; -+ schedule_work(&suspend_work); /* we are entering suspend */ -+ } -+} -+ -+static void poweroff_delaytimer_routine(unsigned long dummy) -+{ -+ __gpio_as_input(POWEROFF_PIN); -+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN) { -+ if (suspend_flag) { -+ suspend_flag = 0; -+ del_timer(&poweroff_delaytimer); -+ SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); -+ return; -+ } -+ del_timer(&poweroff_delaytimer); -+ del_timer(&poweroff_timer); -+ init_timer(&poweroff_timer); -+ poweroff_timer.expires = jiffies + POWEROFF_PERIOD/100; -+ poweroff_timer.data = 0; -+ poweroff_timer.function = poweroff_timer_routine; -+ add_timer(&poweroff_timer); -+ } -+ else { -+ del_timer(&poweroff_delaytimer); -+ SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); -+ -+ printk("This is a dummy key\n"); -+ } -+} -+ -+/* -+ * Poweroff pin interrupt handler -+ */ -+static irqreturn_t poweroff_irq(int irq, void *dev_id) -+{ -+ __gpio_ack_irq(POWEROFF_PIN); -+ __gpio_mask_irq(POWEROFF_PIN); -+ __gpio_as_input(POWEROFF_PIN); -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN && jz_udc_active == 0){ -+#else -+ if (__gpio_get_pin(POWEROFF_PIN)==POWEROFF_PIN_DOWN){ -+#endif -+ del_timer(&poweroff_delaytimer); -+ init_timer(&poweroff_delaytimer); -+ poweroff_delaytimer.expires = jiffies + POWEROFF_DELAY/10; -+ poweroff_delaytimer.data = 0; -+ poweroff_delaytimer.function = poweroff_delaytimer_routine; -+ add_timer(&poweroff_delaytimer); -+ } -+ else { -+ -+/* -+ * If it reaches here without jz_udc_active == 0, then it indicates POWEROFF_PIN was -+ * changed to WAKEUP key in pm.c for hand is not able to rise up so quickly, so the -+ * irq handler entered because of WAKEUP key not POWEROFF_PIN. -+ */ -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ if (jz_udc_active == 1) -+ printk("\nUSB is working; Operation is denied\n"); -+#endif -+ SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+#ifdef CONFIG_PM -+ -+static struct pm_dev *poweroff_dev; -+ -+static int poweroff_suspend(int *poweroff , int state) -+{ -+ suspend_flag = 1; -+ poweroff_flag = 0; -+ -+ return 0; -+} -+ -+static int poweroff_resume(int *poweroff) -+{ -+ suspend_flag = 0; -+ SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); -+ -+ return 0; -+} -+ -+static int poweroff_pm_callback(struct pm_dev *pm_dev, pm_request_t rqst, void *data) -+{ -+ int ret; -+ int *poweroff_info = pm_dev->data; -+ -+ if (!poweroff_info) -+ return -EINVAL; -+ -+ switch (rqst) { -+ case PM_SUSPEND: -+ ret = poweroff_suspend(poweroff_info, (int)data); -+ break; -+ case PM_RESUME: -+ ret = poweroff_resume(poweroff_info); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#endif /* CONFIG_PM */ -+ -+#ifdef USE_SUSPEND_HOTPLUG -+static void run_sbin_hotplug(int state) -+{ -+ int i; -+ char *argv[3], *envp[8]; -+ char media[64], slotnum[16]; -+ if (!uevent_helper[0]) -+ return; -+ -+ i = 0; -+ argv[i++] = uevent_helper; -+ //argv[i++] = "home/lhhuang/hotplug"; -+ -+ if ( poweroff_flag == 1 ) -+ argv[i++] = "poweroff"; -+ else -+ argv[i++] = "suspend"; -+ -+ argv[i] = 0; -+ -+ /* minimal command environment */ -+ i = 0; -+ envp[i++] = "HOME=/"; -+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -+ -+ /* other stuff we want to pass to /sbin/hotplug */ -+ sprintf(slotnum, "SLOT=0"); -+ -+ if ( poweroff_flag == 1 ) -+ sprintf(media, "MEDIA=poweroff"); -+ else -+ sprintf(media, "MEDIA=suspend"); -+ -+ envp[i++] = slotnum; -+ envp[i++] = media; -+ -+ if (state) -+ envp[i++] = "ACTION=enter"; -+ else -+ envp[i++] = "ACTION=exit"; -+ -+ envp[i] = 0; -+ -+ dprintk("SUSPEND: hotplug path=%s state=%d\n", argv[0], state); -+ -+ SET_POWEROFF_PIN_AS_IRQ; -+ __gpio_unmask_irq(POWEROFF_PIN); /* set it because call hotplug with call_usermodehelper() \ -+ might failed, especially when using nfsroot */ -+ -+ call_usermodehelper (argv [0], argv, envp, -1); -+} -+#endif -+ -+static void suspend_handler(struct work_struct *work) -+{ -+#ifdef USE_SUSPEND_HOTPLUG -+ int state = 1; -+ run_sbin_hotplug(state); -+#else -+ if (poweroff_flag) { -+ dprintk("DO_SHUTDOWN_SYSTEM\n"); -+ DO_SHUTDOWN_SYSTEM; -+ } else { -+ dprintk("DO_SUSPEND\n"); -+ DO_SUSPEND; -+ } -+#endif -+} -+ -+static int __init poweroff_init(void) -+{ -+ int retval; -+ -+ retval = request_irq(POWEROFF_IRQ, poweroff_irq, -+ IRQF_DISABLED, "poweroff", NULL); -+ -+ SET_POWEROFF_PIN_AS_IRQ; -+ -+ if (retval) { -+ printk("Could not get poweroff irq %d\n", POWEROFF_IRQ); -+ return retval; -+ } -+ -+#ifdef CONFIG_PM -+ poweroff_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, poweroff_pm_callback); -+ if (poweroff_dev) { -+ poweroff_dev->data = &poweroff_dev; -+ } -+#endif -+ -+ INIT_WORK(&suspend_work, suspend_handler); -+ -+ return 0; -+} -+ -+static void __exit poweroff_exit(void) -+{ -+ free_irq(POWEROFF_IRQ, NULL); -+} -+ -+module_init(poweroff_init); -+module_exit(poweroff_exit); -+ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/sadc.c linux-2.6.24.7/drivers/char/jzchar/sadc.c ---- linux-2.6.24.7.old/drivers/char/jzchar/sadc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/sadc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,580 @@ -+/* -+ * linux/drivers/char/jzchar/sadc.c -+ * -+ * SAR-ADC driver for JZ4740. -+ * -+ * Copyright (C) 2006 Ingenic 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. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "jzchars.h" -+#include "jz_ts.h" -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("JZ4740 SADC driver"); -+MODULE_LICENSE("GPL"); -+ -+#define SADC_NAME "sadc" -+static DECLARE_WAIT_QUEUE_HEAD (sadc_wait_queue); -+ -+struct sadc_device { -+ int mode; -+ int dma_chan; -+ char *ts_buf; -+ char *pbat_buf; -+}; -+ -+static struct sadc_device *sadc_dev; -+ -+static int samples = 3; /* we sample 3 every time */ -+static int first_time = 0; -+static unsigned long last_x, last_y, last_p; -+ -+typedef struct datasource { -+ u16 xbuf; -+ u16 ybuf; -+ u16 zbuf; -+}datasource_t; -+ -+static datasource_t data_s; -+static unsigned int p; -+static unsigned int old_x, old_y; -+extern unsigned int (*codec_read_battery)(void); -+ -+/* -+ * set adc clock to 12MHz/div. A/D works at freq between 500KHz to 6MHz. -+ */ -+static void sadc_init_clock(int div) -+{ -+ if (div < 2) div = 2; -+ if (div > 23) div = 23; -+#if defined(CONFIG_SOC_JZ4740) -+ REG_SADC_CFG &= ~SADC_CFG_CLKDIV_MASK; -+ REG_SADC_CFG |= (div - 1) << SADC_CFG_CLKDIV_BIT; -+#endif -+#if defined(CONFIG_SOC_JZ4750) -+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_MASK; -+ REG_SADC_ADCLK |= (div - 1) << SADC_ADCLK_CLKDIV_BIT; -+ REG_SADC_ADCLK &= ~SADC_ADCLK_CLKDIV_BIT; -+ REG_SADC_ADCLK |= 39 << SADC_ADCLK_CLKDIV_10_BIT; /* if div ==3,here is 39 */ -+#endif -+} -+ -+void start_sadcin(void) -+{ -+ REG_SADC_CTRL &= ~SADC_CTRL_SRDYM; /* enable interrupt */ -+ REG_SADC_ENA |= SADC_ENA_SADCINEN; -+} -+ -+void start_pbat_adc(void) -+{ -+ REG_SADC_CFG |= SADC_CFG_PBAT_HIGH ; /* full baterry voltage >= 2.5V */ -+// REG_SADC_CFG |= SADC_CFG_PBAT_LOW; /* full baterry voltage < 2.5V */ -+ -+ REG_SADC_ENA |= SADC_ENA_PBATEN; /* Enable pbat adc */ -+} -+ -+void start_ts_adc(void) -+{ -+ REG_SADC_SAMETIME = 10; /* about 0.1 ms,you can change it */ -+ REG_SADC_WAITTIME = 2; /* about 0.02 ms,you can change it */ -+ -+ REG_SADC_CFG &= ~(SADC_CFG_TS_DMA | SADC_CFG_XYZ_MASK | SADC_CFG_SNUM_MASK); -+ REG_SADC_CFG |= (SADC_CFG_EXIN | SADC_CFG_XYZ | SADC_CFG_SNUM_3); -+ REG_SADC_CTRL |= (SADC_CTRL_TSRDYM|SADC_CTRL_PBATRDYM|SADC_CTRL_PENUM |SADC_CTRL_SRDYM); -+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; -+ REG_SADC_ENA |= SADC_ENA_TSEN; -+} -+ -+static int jz4740_adc_read(struct jz_ts_t *ts) -+{ -+ struct datasource *ds = &data_s; -+ u32 xybuf,z; -+ -+ if (!(REG_SADC_STATE & SADC_STATE_TSRDY)) { -+ /* sleep */ -+ REG_SADC_CTRL &= ~SADC_CTRL_TSRDYM; -+ ts->sleeping = 1; -+ sleep_on(&sadc_wait_queue); -+ } -+ ts->sleeping = 0; -+ -+ xybuf = REG_SADC_TSDAT; -+ ds->xbuf = (xybuf>>16) & 0x0fff; -+ ds->ybuf = (xybuf)& 0x0fff; -+ z = REG_SADC_TSDAT; -+ ds->zbuf = z& 0x0fff; -+ REG_SADC_STATE &= ~SADC_STATE_TSRDY; -+ return 0; -+} -+ -+/*------------------------------------------------------------ -+ * Read the battery voltage -+ */ -+unsigned int jz4740_read_battery(void) -+{ -+ unsigned int v; -+ unsigned int timeout = 0x3ff; -+ u16 pbat; -+ -+ if(!(REG_SADC_STATE & SADC_STATE_PBATRDY) ==1) -+ start_pbat_adc(); -+ -+ while(!(REG_SADC_STATE & SADC_STATE_PBATRDY) && --timeout) -+ ; -+ -+ pbat = REG_SADC_BATDAT; -+ v = pbat & 0x0fff; -+ REG_SADC_STATE = SADC_STATE_PBATRDY; -+ return v; -+} -+ -+/*------------------ Calibrate samples -------------------*/ -+ -+#define DIFF(a,b) (((a)>(b))?((a)-(b)):((b)-(a))) -+#define MIN(a,b) (((a)<(b))?(a):(b)) -+ -+#if 0 -+#define XM 36 /* XM and YM may be changed for your screen */ -+#define YM 20 -+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) -+{ -+ unsigned long usd0,usd1,usd2; -+ int xMaxError = XM,yMaxError = YM; -+ int x_valid = 0,y_valid = 0,valid = 0; -+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0; -+ unsigned long *xp = (unsigned long *)xbuf; -+ unsigned long *yp = (unsigned long *)ybuf; -+ unsigned long *pp = (unsigned long *)pbuf; -+ -+ usd0 = (xp[0] > xp[1]) ? (xp[0] - xp[1]) : (xp[1] - xp[0]); -+ usd1 = (xp[1] > xp[2]) ? (xp[1] - xp[2]) : (xp[2] - xp[1]); -+ usd2 = (xp[2] > xp[0]) ? (xp[2] - xp[0]) : (xp[0] - xp[2]); -+ -+ if ( usd0 < usd1) -+ x_cal = xp[0] + ((usd2 < usd0) ? xp[2] : xp[1]); -+ else -+ x_cal= xp[2] + ((usd2 < usd1) ? xp[0] : xp[1]); -+ x_cal >>= 1; -+ -+ if ( (usd0 < xMaxError) && (usd1 < xMaxError) && (usd2 < xMaxError) ) -+ x_valid = 1; -+ -+ usd0 = (yp[0] > yp[1]) ? (yp[0] - yp[1]) : (yp[1] - yp[0]); -+ usd1 = (yp[1] > yp[2]) ? (yp[1] - yp[2]) : (yp[2] - yp[1]); -+ usd2 = (yp[2] > yp[0]) ? (yp[2] - yp[0]) : (yp[0] - yp[2]); -+ -+ if ( usd0 < usd1) -+ y_cal = yp[0] + ((usd2 < usd0) ? yp[2] : yp[1]); -+ else -+ y_cal = yp[2] + ((usd2 < usd1) ? yp[0] : yp[1]); -+ -+ y_cal >>= 1; -+ -+ if ( (usd0 < yMaxError) && (usd1 < yMaxError) && (usd2 < yMaxError) ) -+ y_valid = 1; -+ -+ if( x_valid && y_valid) -+ valid = 1; -+ -+ usd0 = (pp[0] > pp[1]) ? (pp[0] - pp[1]) : (pp[1] - pp[0]); -+ usd1 = (pp[1] > pp[2]) ? (pp[1] - pp[2]) : (pp[2] - pp[1]); -+ usd2 = (pp[2] > pp[0]) ? (pp[2] - pp[0]) : (pp[0] - pp[2]); -+ -+ if ( usd0 < usd1) -+ p_cal = pp[0] + ((usd2 < usd0) ? pp[2] : pp[1]); -+ else -+ p_cal= pp[2] + ((usd2 < usd1) ? pp[0] : pp[1]); -+ -+ p_cal >>= 1; -+ -+ if (first_time) { -+ first_time = 0; -+ last_x = x_cal; -+ last_y = y_cal; -+ last_p = p_cal; -+ } -+ else{ -+ if ((DIFF(x_cal, last_x) > 50) || -+ (DIFF(y_cal, last_y) > 50)) -+ valid = 0; -+ else -+ valid = 1; -+ } -+ *xp = last_x = x_cal; -+ *yp = last_y = y_cal; -+ *pp = last_p = p_cal; -+ -+ return valid; -+} -+#endif -+ -+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) -+{ -+ unsigned long *xp = (unsigned long *)xbuf; -+ unsigned long *yp = (unsigned long *)ybuf; -+ unsigned long *pp = (unsigned long *)pbuf; -+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0; -+ int i; -+ int valid = 1; -+ -+ /* calculate the average of the rest */ -+ for (i = 0; i < count; i++) { -+ x_cal += xp[i]; -+ y_cal += yp[i]; -+ p_cal += pp[i]; -+ } -+ x_cal /= count; -+ y_cal /= count; -+ p_cal /= count; -+ -+ if (first_time) { -+ first_time = 0; -+ last_x = x_cal; -+ last_y = y_cal; -+ last_p = p_cal; -+ } -+ else { -+ if ((DIFF(x_cal, last_x) > 50) || -+ (DIFF(y_cal, last_y) > 50)) -+ valid = 0; -+ else -+ valid = 1; -+ } -+ -+ *xp = last_x = x_cal; -+ *yp = last_y = y_cal; -+ *pp = last_p = p_cal; -+ -+ return valid; -+} -+ -+#define TSMAXX 945 -+#define TSMAXY 830 -+#define TSMINX 90 -+#define TSMINY 105 -+ -+#define SCREEN_X 480 -+#define SCREEN_Y 272 -+ -+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ -+ -+ if (ts->minx) -+ { -+ if (x < ts->minx) x = ts->minx; -+ if (x > ts->maxx) x = ts->maxx; -+ -+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); -+ } -+ else -+ { -+ if (x < TSMINX) x = TSMINX; -+ if (x > TSMAXX) x = TSMAXX; -+ -+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); -+ } -+} -+ -+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) -+{ -+ if (ts->minx) -+ { -+ if (y < ts->minx) y = ts->miny; -+ if (y > ts->maxx) y = ts->maxy; -+ -+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); -+ } -+ else -+ { -+ if (y < TSMINX) y = TSMINY; -+ if (y > TSMAXX) y = TSMAXY; -+ -+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); -+ } -+} -+ -+/* -+ * File operations -+ */ -+static int sadc_open(struct inode *inode, struct file *filp); -+static int sadc_release(struct inode *inode, struct file *filp); -+static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int sadc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -+ -+static struct file_operations sadc_fops = -+{ -+ open: sadc_open, -+ release: sadc_release, -+ read: sadc_read, -+ write: sadc_write, -+ ioctl: sadc_ioctl -+}; -+ -+static int sadc_open(struct inode *inode, struct file *filp) -+{ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int sadc_release(struct inode *inode, struct file *filp) -+{ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t sadc_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ return size; -+} -+ -+static ssize_t sadc_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ return size; -+} -+ -+static int sadc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ switch (cmd) { -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return 0; -+} -+ -+/*------------------ Common routines -------------------*/ -+ -+void ts_enable_irq(void) -+{ -+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; -+} -+ -+void ts_disable_irq(void) -+{ -+ REG_SADC_CTRL |= (SADC_CTRL_PENDM | SADC_CTRL_PENUM); -+} -+ -+void ts_free_irq(struct jz_ts_t *ts) -+{ -+ free_irq(ts->pendown_irq, ts); -+} -+ -+void ts_data_ready(void) -+{ -+ REG_SADC_CTRL |= SADC_CTRL_TSRDYM; -+ wake_up(&sadc_wait_queue); -+} -+ -+/* -+ * Interrupt handler -+ */ -+void ts_irq_callback(void) -+{ -+ u32 state; -+ -+ state = REG_SADC_STATE; -+ if (!(REG_SADC_CTRL&SADC_CTRL_PENDM)&&(REG_SADC_STATE & SADC_STATE_PEND)) { -+ REG_SADC_STATE = SADC_STATE_PEND; -+ REG_SADC_STATE = SADC_STATE_PENU; -+ REG_SADC_CTRL |= SADC_CTRL_PENDM; -+ REG_SADC_CTRL &= ~SADC_CTRL_PENUM; -+ p = 1; -+ } -+ -+ if (!(REG_SADC_CTRL&SADC_CTRL_PENUM)&&(REG_SADC_STATE & SADC_STATE_PENU)) { -+ REG_SADC_STATE = SADC_STATE_PENU; -+ REG_SADC_CTRL |= SADC_CTRL_PENUM; -+ REG_SADC_CTRL &= ~SADC_CTRL_PENDM; -+ p = 0; -+ } -+ -+ first_time = 1; // first time to acquire sample -+} -+ -+int PenIsDown(void) -+{ -+ return p; -+} -+ -+int ts_request_irq(u32 *irq, -+ irqreturn_t (*handler)(int, void *), -+ const char *devname, -+ void *dev_id) -+{ -+ int ret; -+ -+ /* return the irq number */ -+ *irq = IRQ_SADC; -+ ts_disable_irq(); -+ /* interrupt mode */ -+ ret = request_irq(IRQ_SADC, handler, IRQF_DISABLED, -+ devname, dev_id); -+ if(ret) -+ printk("failed irq \n"); -+ -+ start_ts_adc(); -+ return ret; -+} -+ -+/* -+ * Acquire Raw pen coodinate data and compute touch screen -+ * pressure resistance. Hold spinlock when calling. -+ */ -+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned int x_raw[8], y_raw[8], p_raw[8]; -+ int valid, i; -+ unsigned int avl_x, avl_y, diff_x, diff_y; -+ struct datasource *ds = &data_s; -+ avl_x = avl_y = 0; -+ -+ for (i = 0; i < samples; i++) { -+ if (jz4740_adc_read(ts)) { -+ return 0; -+ } -+ -+ x_raw[i] = ds->ybuf; -+ y_raw[i] = ds->xbuf; -+ p_raw[i] = ds->zbuf; -+ avl_x += x_raw[i]; -+ avl_y += y_raw[i]; -+#if 0 -+ printk("x_raw=%x y_raw=%x z_raw=%x\n",x_raw[i],y_raw[i],p_raw[i]); -+#endif -+ } -+ -+ avl_x /= samples; -+ avl_y /= samples; -+#define MAX_DELTA 20 -+ valid = 1; -+ -+ for (i = 1; i < samples; i++) -+ { -+ if ((100 * DIFF(x_raw[i],x_raw[i-1])/MIN(x_raw[i],x_raw[i-1])) > MAX_DELTA) { -+ valid = 0; -+ break; -+ } -+ -+ if ((100 * DIFF(y_raw[i],y_raw[i-1])/MIN(y_raw[i],y_raw[i-1])) > MAX_DELTA) { -+ valid = 0; -+ break; -+ } -+ -+ if ((100 * DIFF(p_raw[i],p_raw[i-1])/MIN(p_raw[i],p_raw[i-1])) > MAX_DELTA) { -+ valid = 0; -+ break; -+ } -+ } -+ -+ if (valid) { -+ if (ts->first_read) { -+ ts->first_read = 0; -+ old_x = avl_x; -+ old_y = avl_y; -+ } -+ diff_x = DIFF(old_x, avl_x); -+ diff_y = DIFF(old_y, avl_y); -+ if (diff_x < 100 && diff_y < 100) { -+ old_x = avl_x; -+ old_y = avl_y; -+ } else -+ valid = 0; -+ } -+ if (valid) { -+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); -+ } -+ -+ if (valid) { -+ unsigned int x_scr, y_scr; -+ -+ if(ts->filter) { -+ x_scr = transform_to_screen_x(ts, x_raw[0]); -+ y_scr = transform_to_screen_y(ts, y_raw[0]); -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr); -+ } -+ else { -+ x_scr = x_raw[0]; -+ y_scr = y_raw[0]; -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); -+ } -+ -+ event->x = x_scr; -+ event->y = y_scr; -+ event->pressure = (u16)p_raw[0]; -+ event->status = PENDOWN; -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * Module init and exit -+ */ -+static int __init sadc_init(void) -+{ -+ struct sadc_device *dev; -+ int ret; -+ -+ /* allocate device */ -+ dev = kmalloc(sizeof(struct sadc_device), GFP_KERNEL); -+ if (!dev) return -ENOMEM; -+ -+ sadc_dev = dev; -+ ret = jz_register_chrdev(SADC_MINOR, SADC_NAME, &sadc_fops, dev); -+ if (ret < 0) { -+ kfree(dev); -+ return ret; -+ } -+ -+ codec_read_battery = jz4740_read_battery; -+ sadc_init_clock(3); -+ -+ printk("JZ4740 SAR-ADC driver registered\n"); -+ return 0; -+} -+ -+static void __exit sadc_exit(void) -+{ -+ struct sadc_device *dev = sadc_dev; -+ -+ free_irq(IRQ_SADC, dev); -+ jz_unregister_chrdev(SADC_MINOR, SADC_NAME); -+ kfree(dev); -+} -+ -+module_init(sadc_init); -+module_exit(sadc_exit); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/sensor.c linux-2.6.24.7/drivers/char/jzchar/sensor.c ---- linux-2.6.24.7.old/drivers/char/jzchar/sensor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/sensor.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,182 @@ -+/* -+ * linux/drivers/char/jzchar/sensor.c -+ * -+ * Common CMOS Camera Sensor Driver -+ * -+ * Copyright (C) 2006 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "jzchars.h" -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * ioctl commands -+ */ -+#define IOCTL_SET_ADDR 0 /* set i2c address */ -+#define IOCTL_SET_CLK 1 /* set i2c clock */ -+#define IOCTL_WRITE_REG 2 /* write sensor register */ -+#define IOCTL_READ_REG 3 /* read sensor register */ -+ -+/* -+ * i2c related -+ */ -+static unsigned int i2c_addr = 0x42; -+static unsigned int i2c_clk = 100000; -+ -+static void write_reg(u8 reg, u8 val) -+{ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_write((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+} -+ -+static u8 read_reg(u8 reg) -+{ -+ u8 val; -+ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_read((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+ return val; -+} -+ -+/* -+ * fops routines -+ */ -+ -+static int sensor_open(struct inode *inode, struct file *filp); -+static int sensor_release(struct inode *inode, struct file *filp); -+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -+ -+static struct file_operations sensor_fops = -+{ -+ open: sensor_open, -+ release: sensor_release, -+ read: sensor_read, -+ write: sensor_write, -+ ioctl: sensor_ioctl, -+}; -+ -+static int sensor_open(struct inode *inode, struct file *filp) -+{ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int sensor_release(struct inode *inode, struct file *filp) -+{ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ printk("sensor: read is not implemented\n"); -+ return -1; -+} -+ -+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("sensor: write is not implemented\n"); -+ return -1; -+} -+ -+static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ -+ switch (cmd) { -+ case IOCTL_SET_ADDR: -+ if (copy_from_user(&i2c_addr, (void *)arg, 4)) -+ return -EFAULT; -+ break; -+ case IOCTL_SET_CLK: -+ if (copy_from_user(&i2c_clk, (void *)arg, 4)) -+ return -EFAULT; -+ break; -+ case IOCTL_WRITE_REG: -+ { -+ u8 regval[2]; -+ -+ if (copy_from_user(regval, (void *)arg, 2)) -+ return -EFAULT; -+ -+ write_reg(regval[0], regval[1]); -+ break; -+ } -+ case IOCTL_READ_REG: -+ { -+ u8 reg, val; -+ -+ if (copy_from_user(®, (void *)arg, 1)) -+ return -EFAULT; -+ -+ val = read_reg(reg); -+ -+ if (copy_to_user((void *)(arg + 1), &val, 1)) -+ return -EFAULT; -+ break; -+ } -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+/* -+ * Module init and exit -+ */ -+ -+static int __init sensor_init(void) -+{ -+ int ret; -+ -+ ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ printk("Ingenic CMOS camera sensor driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit sensor_exit(void) -+{ -+ jz_unregister_chrdev(SENSOR_MINOR, "sensor"); -+} -+ -+module_init(sensor_init); -+module_exit(sensor_exit); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/tcsm.c linux-2.6.24.7/drivers/char/jzchar/tcsm.c ---- linux-2.6.24.7.old/drivers/char/jzchar/tcsm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/tcsm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,123 @@ -+/* -+ * linux/drivers/char/jzchar/tcsm.c -+ * -+ * Virtual device driver with tricky appoach to manage TCSM -+ * -+ * Copyright (C) 2006 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jzchars.h" -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("Virtual Driver of TCSM"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * fops routines -+ */ -+ -+static int tcsm_open(struct inode *inode, struct file *filp); -+static int tcsm_release(struct inode *inode, struct file *filp); -+static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int tcsm_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -+ -+static struct file_operations tcsm_fops = -+{ -+ open: tcsm_open, -+ release: tcsm_release, -+ read: tcsm_read, -+ write: tcsm_write, -+ ioctl: tcsm_ioctl, -+}; -+ -+static int tcsm_open(struct inode *inode, struct file *filp) -+{ -+ // printk("%d[%s]\n", __LINE__, __FILE__); -+ struct pt_regs *info = task_pt_regs(current); -+ printk("pt_regs =%p\n", info); -+ printk("cp0 status=0x%08x\n", info->cp0_status); -+ info->cp0_status &= ~0x10; -+ info->cp0_status |= 0x08000000; // a tricky -+ printk("cp0 status=0x%08x\n", info->cp0_status); -+ return 0; -+} -+ -+static int tcsm_release(struct inode *inode, struct file *filp) -+{ -+ struct pt_regs *info = task_pt_regs(current); -+ info->cp0_status |= 0x10; -+ info->cp0_status &= ~0x08000000; // a tricky -+ return 0; -+} -+ -+static ssize_t tcsm_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ printk("tcsm: read is not implemented\n"); -+ return -1; -+} -+ -+static ssize_t tcsm_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("tcsm: write is not implemented\n"); -+ return -1; -+} -+ -+static int tcsm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ printk("tcsm: ioctl is not implemented\n"); -+ return ret; -+} -+ -+/* -+ * Module init and exit -+ */ -+ -+static int __init tcsm_init(void) -+{ -+ int ret; -+ -+ ret = jz_register_chrdev(TCSM_MINOR, "tcsm", &tcsm_fops, NULL); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ printk("Virtual Driver of TCSM registered\n"); -+ return 0; -+} -+ -+static void __exit tcsm_exit(void) -+{ -+ jz_unregister_chrdev(TCSM_MINOR, "tcsm"); -+} -+ -+module_init(tcsm_init); -+module_exit(tcsm_exit); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/ucb1400.c linux-2.6.24.7/drivers/char/jzchar/ucb1400.c ---- linux-2.6.24.7.old/drivers/char/jzchar/ucb1400.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/ucb1400.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,585 @@ -+/* -+ * ucb1400.c -+ * -+ * Touch screen driver interface to the UCB1400 codec. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz_ts.h" -+#include "ucb1400.h" -+ -+#ifndef GPIO_TS_PENIRQ -+#define GPIO_TS_PENIRQ 68 -+#endif -+ -+#define TS_PIN GPIO_TS_PENIRQ -+#define TS_IRQ (IRQ_GPIO_0 + TS_PIN) -+ -+static int samples = 5; /* we sample 5 every time, and throw away the max and min cases, then use the average of the other 3 samples */ -+static int first_time = 0; -+static unsigned long last_x, last_y, last_p; -+ -+static int adcsync = 0; -+ -+static unsigned int ucb_id = 0; -+static struct ucb1400 *ucb; -+ -+extern struct ac97_codec * find_ac97_codec(void); -+ -+extern unsigned int (*codec_read_battery)(void); -+ -+/*------------------ UCB1400 routines ------------------*/ -+ -+static inline void ucb1400_reg_write(unsigned char reg, unsigned short val) -+{ -+ struct ac97_codec *codec = find_ac97_codec(); -+ if (!codec) -+ return; -+ codec->codec_write(codec, reg, val); -+} -+ -+static inline unsigned int ucb1400_reg_read(unsigned char reg) -+{ -+ struct ac97_codec *codec = find_ac97_codec(); -+ if (!codec) -+ return 0; -+ return codec->codec_read(codec, reg); -+} -+ -+static void ucb1400_adc_enable(void) -+{ -+ down(&ucb->adc_sem); -+ -+ ucb->adc_cr |= UCB_ADC_ENA; -+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr); -+} -+ -+static unsigned int ucb1400_adc_read(int adc_channel, int sync) -+{ -+ unsigned int val, timeout = 10000; -+ -+ if (sync) -+ adc_channel |= UCB_ADC_SYNC_ENA; -+ -+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel); -+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); -+ -+ for (;;) { -+ val = ucb1400_reg_read(UCB_ADC_DATA); -+ if (val & UCB_ADC_DAT_VAL) -+ break; -+ if (--timeout == 0) -+ break; -+ udelay(1); -+ } -+ -+ return UCB_ADC_DAT(val); -+} -+ -+static void ucb1400_adc_disable(void) -+{ -+ ucb->adc_cr &= ~UCB_ADC_ENA; -+ ucb1400_reg_write(UCB_ADC_CR, ucb->adc_cr); -+ -+ up(&ucb->adc_sem); -+} -+ -+static void ucb1400_enable_irq(unsigned int idx, int edges) -+{ -+ unsigned long flags; -+ -+ if (idx < 16) { -+ spin_lock_irqsave(&ucb->lock, flags); -+ -+ /* This prevents spurious interrupts on the UCB1400 */ -+ ucb1400_reg_write(UCB_IE_CLEAR, 1 << idx); -+ ucb1400_reg_write(UCB_IE_CLEAR, 0); -+ -+ if (edges & UCB_RISING) { -+ ucb->irq_ris_enbl |= 1 << idx; -+ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl); -+ } -+ if (edges & UCB_FALLING) { -+ ucb->irq_fal_enbl |= 1 << idx; -+ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl); -+ } -+ spin_unlock_irqrestore(&ucb->lock, flags); -+ } -+} -+ -+static void ucb1400_disable_irq(unsigned int idx, int edges) -+{ -+ unsigned long flags; -+ -+ if (idx < 16) { -+ spin_lock_irqsave(&ucb->lock, flags); -+ -+ if (edges & UCB_RISING) { -+ ucb->irq_ris_enbl &= ~(1 << idx); -+ ucb1400_reg_write(UCB_IE_RIS, ucb->irq_ris_enbl); -+ } -+ if (edges & UCB_FALLING) { -+ ucb->irq_fal_enbl &= ~(1 << idx); -+ ucb1400_reg_write(UCB_IE_FAL, ucb->irq_fal_enbl); -+ } -+ spin_unlock_irqrestore(&ucb->lock, flags); -+ } -+} -+ -+/* -+ * Switch to interrupt mode. -+ */ -+static inline void ucb1400_ts_mode_int(void) -+{ -+ if (!ucb_id) { -+ ucb_id = ucb1400_reg_read(UCB_ID); -+ } -+ -+ if (ucb_id == UCB_ID_1400_BUGGY) -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_INT); -+ else -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_INT); -+} -+ -+/* -+ * Switch to pressure mode, and read pressure. We don't need to wait -+ * here, since both plates are being driven. -+ */ -+static inline unsigned int ucb1400_ts_read_pressure(void) -+{ -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ -+ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync); -+} -+ -+/* -+ * Switch to X position mode and measure Y plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1400_ts_read_xpos(void) -+{ -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1400_adc_read(UCB_ADC_INP_TSPY, adcsync); -+} -+ -+/* -+ * Switch to Y position mode and measure X plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1400_ts_read_ypos(void) -+{ -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1400_reg_write(UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1400_adc_read(UCB_ADC_INP_TSPX, adcsync); -+} -+ -+/*------------------------------------------------------------ -+ * Read the battery voltage -+ */ -+ -+unsigned int ucb1400_read_battery(void) -+{ -+ unsigned int v; -+ -+ ucb1400_adc_enable(); -+ -+ // read twice to reduce fault value -+ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync); -+ v = ucb1400_adc_read(UCB_ADC_INP_AD0, adcsync); -+ -+ ucb1400_adc_disable(); -+ -+// printk("ucb1400_read_battery v=%d\n", v); -+ -+ return v; -+} -+ -+/*------------------ Calibrate samples -------------------*/ -+ -+#define DIFF(a,b) ((a>b)?(a-b):(b-a)) -+ -+static int calibrate_samples(void *xbuf, void *ybuf, void *pbuf, int count) -+{ -+ unsigned long *xp = (unsigned long *)xbuf; -+ unsigned long *yp = (unsigned long *)ybuf; -+ unsigned long *pp = (unsigned long *)pbuf; -+ unsigned long x_cal = 0, y_cal = 0, p_cal = 0, tmp; -+ int ignored, i, j; -+ int valid = 0; -+ -+ /* throw away the max cases */ -+ tmp = xp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (xp[i] > tmp) { -+ tmp = xp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ xp[j++] = xp[i]; -+ } -+ -+ tmp = yp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (yp[i] > tmp) { -+ tmp = yp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ yp[j++] = yp[i]; -+ } -+ -+ tmp = pp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (pp[i] > tmp) { -+ tmp = pp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ pp[j++] = pp[i]; -+ } -+ -+ /* throw away the min cases */ -+ -+ count -= 1; // decrement by 1 -+ -+ tmp = xp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (xp[i] < tmp) { -+ tmp = xp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ xp[j++] = xp[i]; -+ } -+ -+ tmp = yp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (yp[i] < tmp) { -+ tmp = yp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ yp[j++] = yp[i]; -+ } -+ -+ tmp = pp[0]; -+ ignored = 0; -+ for (i = 1; i < count; i++) { -+ if (pp[i] < tmp) { -+ tmp = pp[i]; -+ ignored = i; -+ } -+ } -+ j = 0; -+ for (i = 0; i < count; i++) { -+ if (i == ignored) -+ continue; -+ pp[j++] = pp[i]; -+ } -+ -+ count -= 1; // decrement by 1 -+ -+ /* calculate the average of the rest */ -+ for (i = 0; i < count; i++) { -+ x_cal += xp[i]; -+ y_cal += yp[i]; -+ p_cal += pp[i]; -+ } -+ x_cal /= count; -+ y_cal /= count; -+ p_cal /= count; -+ -+ if (first_time) { -+ first_time = 0; -+ last_x = x_cal; -+ last_y = y_cal; -+ last_p = p_cal; -+ valid = 1; -+ } -+ else { -+ if ((DIFF(x_cal, last_x) > 50) || -+ (DIFF(y_cal, last_y) > 50)) -+ valid = 0; -+ else -+ valid = 1; -+ } -+ -+// printk("x_cal=%d y_cal=%d p_cal=%d valid=%d\n", x_cal, y_cal, p_cal, valid); -+ -+ if (valid) { -+ *xp = last_x = x_cal; -+ *yp = last_y = y_cal; -+ *pp = last_p = p_cal; -+ } -+ -+ return valid; -+} -+ -+ -+#define TSMAXX 945 -+#define TSMAXY 830 -+#define TSMINX 90 -+#define TSMINY 105 -+ -+#define SCREEN_X 480 -+#define SCREEN_Y 272 -+ -+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ -+ -+ if (ts->minx) -+ { -+ if (x < ts->minx) x = ts->minx; -+ if (x > ts->maxx) x = ts->maxx; -+ -+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); -+ } -+ else -+ { -+ if (x < TSMINX) x = TSMINX; -+ if (x > TSMAXX) x = TSMAXX; -+ -+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); -+ } -+} -+ -+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) -+{ -+ if (ts->minx) -+ { -+ if (y < ts->minx) y = ts->miny; -+ if (y > ts->maxx) y = ts->maxy; -+ -+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); -+ } -+ else -+ { -+ if (y < TSMINX) y = TSMINY; -+ if (y > TSMAXX) y = TSMAXY; -+ -+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); -+ } -+} -+ -+/*------------------ Common routines -------------------*/ -+ -+void ts_enable_irq(void) -+{ -+ /* interrupt mode */ -+ ucb1400_ts_mode_int(); -+ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING); -+ -+ enable_irq(TS_IRQ); -+} -+ -+void ts_disable_irq(void) -+{ -+ ucb1400_disable_irq(UCB_IRQ_TSPX, UCB_FALLING); -+ disable_irq(TS_IRQ); -+} -+ -+int ts_request_irq(u32 *irq, -+ void (*handler)(int, void *, struct pt_regs *), -+ const char *devname, -+ void *dev_id) -+{ -+ int retval; -+ -+ /* return the irq number */ -+ *irq = TS_IRQ; -+ -+ /* interrupt mode */ -+ ucb1400_ts_mode_int(); -+ ucb1400_enable_irq(UCB_IRQ_TSPX, UCB_FALLING); -+ -+ /* enable gpio irq */ -+ __gpio_as_irq_rise_edge(TS_PIN); -+ -+ /* register irq handler */ -+ retval = request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id); -+ -+ return retval; -+} -+ -+void ts_free_irq(struct jz_ts_t *ts) -+{ -+ free_irq(ts->pendown_irq, ts); -+} -+ -+void ts_irq_callback(void) -+{ -+ /* clear interrupt status */ -+ ucb1400_reg_write(UCB_IE_CLEAR, ucb1400_reg_read(UCB_IE_STATUS)); -+ __gpio_ack_irq(TS_PIN); -+ -+ first_time = 1; // first time to acquire sample -+} -+ -+int PenIsDown(void) -+{ -+ unsigned int p; -+ -+ ucb1400_adc_enable(); -+ p = ucb1400_ts_read_pressure(); -+ ucb1400_adc_disable(); -+ -+ return (p > 100) ? 1 : 0; -+} -+ -+/* -+ * Acquire Raw pen coodinate data and compute touch screen -+ * pressure resistance. Hold spinlock when calling. -+ */ -+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned int x_raw[8], y_raw[8], p_raw[8]; -+ int valid, i; -+ -+ /* Enable ADC */ -+ ucb1400_adc_enable(); -+ -+ for (i = 0; i < samples; i++) { -+ x_raw[i] = ucb1400_ts_read_xpos(); -+ } -+ for (i = 0; i < samples; i++) { -+ y_raw[i] = ucb1400_ts_read_ypos(); -+ } -+ for (i = 0; i < samples; i++) { -+ p_raw[i] = ucb1400_ts_read_pressure(); -+ } -+ -+ /* Disable ADC */ -+ ucb1400_adc_disable(); -+ -+ valid = calibrate_samples(x_raw, y_raw, p_raw, samples); -+ -+ if (valid) { -+ unsigned int x_scr, y_scr; -+ -+ if(ts->filter) { -+ x_scr = transform_to_screen_x(ts, x_raw[0]); -+ y_scr = transform_to_screen_y(ts, y_raw[0]); -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", x_raw[0], y_raw[0], x_scr, y_scr); -+ } -+ else { -+ x_scr = x_raw[0]; -+ y_scr = y_raw[0]; -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d \n", x_raw[0], y_raw[0]); -+ } -+ -+ event->x = x_scr; -+ event->y = y_scr; -+ event->pressure = (u16)p_raw[0]; -+ event->status = PENDOWN; -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * Module init and exit -+ */ -+ -+int __init ucb1400_init(void) -+{ -+ ucb = kmalloc(sizeof(struct ucb1400), GFP_KERNEL); -+ if (!ucb) return -ENOMEM; -+ -+ memset(ucb, 0, sizeof(struct ucb1400)); -+ -+ codec_read_battery = ucb1400_read_battery; -+ -+ spin_lock_init(&ucb->lock); -+ sema_init(&ucb->adc_sem, 1); -+ -+ return 0; -+} -+ -+void ucb1400_cleanup(void) -+{ -+ kfree(ucb); -+} -+ -+module_init(ucb1400_init); -+module_exit(ucb1400_cleanup); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/ucb1400.h linux-2.6.24.7/drivers/char/jzchar/ucb1400.h ---- linux-2.6.24.7.old/drivers/char/jzchar/ucb1400.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/ucb1400.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,113 @@ -+#ifndef __UCB1400_H__ -+#define __UCB1400_H__ -+ -+/* ucb1400 aclink register mappings */ -+ -+#define UCB_IO_DATA 0x5a -+#define UCB_IO_DIR 0x5c -+#define UCB_IE_RIS 0x5e -+#define UCB_IE_FAL 0x60 -+#define UCB_IE_STATUS 0x62 -+#define UCB_IE_CLEAR 0x62 -+#define UCB_TS_CR 0x64 -+#define UCB_ADC_CR 0x66 -+#define UCB_ADC_DATA 0x68 -+#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */ -+ -+#define UCB_ADC_DAT(x) ((x) & 0x3ff) -+ -+/* register bits */ -+ -+#define UCB_IO_0 (1 << 0) -+#define UCB_IO_1 (1 << 1) -+#define UCB_IO_2 (1 << 2) -+#define UCB_IO_3 (1 << 3) -+#define UCB_IO_4 (1 << 4) -+#define UCB_IO_5 (1 << 5) -+#define UCB_IO_6 (1 << 6) -+#define UCB_IO_7 (1 << 7) -+#define UCB_IO_8 (1 << 8) -+#define UCB_IO_9 (1 << 9) -+ -+#define UCB_IE_ADC (1 << 11) -+#define UCB_IE_TSPX (1 << 12) -+#define UCB_IE_TSMX (1 << 13) -+#define UCB_IE_TCLIP (1 << 14) -+#define UCB_IE_ACLIP (1 << 15) -+ -+#define UCB_IRQ_TSPX 12 -+ -+#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ -+#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ -+ -+#define UCB_TC_B_VOICE_ENA (1 << 3) -+#define UCB_TC_B_CLIP (1 << 4) -+#define UCB_TC_B_ATT (1 << 6) -+#define UCB_TC_B_SIDE_ENA (1 << 11) -+#define UCB_TC_B_MUTE (1 << 13) -+#define UCB_TC_B_IN_ENA (1 << 14) -+#define UCB_TC_B_OUT_ENA (1 << 15) -+ -+#define UCB_AC_B_LOOP (1 << 8) -+#define UCB_AC_B_MUTE (1 << 13) -+#define UCB_AC_B_IN_ENA (1 << 14) -+#define UCB_AC_B_OUT_ENA (1 << 15) -+ -+#define UCB_TS_CR_TSMX_POW (1 << 0) -+#define UCB_TS_CR_TSPX_POW (1 << 1) -+#define UCB_TS_CR_TSMY_POW (1 << 2) -+#define UCB_TS_CR_TSPY_POW (1 << 3) -+#define UCB_TS_CR_TSMX_GND (1 << 4) -+#define UCB_TS_CR_TSPX_GND (1 << 5) -+#define UCB_TS_CR_TSMY_GND (1 << 6) -+#define UCB_TS_CR_TSPY_GND (1 << 7) -+#define UCB_TS_CR_MODE_INT (0 << 8) -+#define UCB_TS_CR_MODE_PRES (1 << 8) -+#define UCB_TS_CR_MODE_POS (2 << 8) -+#define UCB_TS_CR_BIAS_ENA (1 << 11) -+#define UCB_TS_CR_TSPX_LOW (1 << 12) -+#define UCB_TS_CR_TSMX_LOW (1 << 13) -+ -+#define UCB_ADC_SYNC_ENA (1 << 0) -+#define UCB_ADC_VREFBYP_CON (1 << 1) -+#define UCB_ADC_INP_TSPX (0 << 2) -+#define UCB_ADC_INP_TSMX (1 << 2) -+#define UCB_ADC_INP_TSPY (2 << 2) -+#define UCB_ADC_INP_TSMY (3 << 2) -+#define UCB_ADC_INP_AD0 (4 << 2) -+#define UCB_ADC_INP_AD1 (5 << 2) -+#define UCB_ADC_INP_AD2 (6 << 2) -+#define UCB_ADC_INP_AD3 (7 << 2) -+#define UCB_ADC_EXT_REF (1 << 5) -+#define UCB_ADC_START (1 << 7) -+#define UCB_ADC_ENA (1 << 15) -+ -+#define UCB_ADC_DAT_VAL (1 << 15) -+ -+#define UCB_ID_1200 0x1004 -+#define UCB_ID_1300 0x1005 -+#define UCB_ID_1400 0x4304 -+#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ -+ -+#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) -+#define UCB_MODE_AUD_OFF_CAN (1 << 13) -+ -+/* -+ * Which edges of the IRQ do you want to control today? -+ */ -+#define UCB_RISING (1 << 0) -+#define UCB_FALLING (1 << 1) -+ -+/* Device data structure */ -+ -+struct ucb1400 { -+ spinlock_t lock; -+ struct pm_dev *pmdev; -+ struct semaphore adc_sem; -+ u16 adc_cr; -+ u16 irq_fal_enbl; -+ u16 irq_ris_enbl; -+ int irq_enabled; -+}; -+ -+#endif /* __UCB1400_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/udc_hotplug.c linux-2.6.24.7/drivers/char/jzchar/udc_hotplug.c ---- linux-2.6.24.7.old/drivers/char/jzchar/udc_hotplug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/udc_hotplug.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,451 @@ -+/* -+ * linux/drivers/char/jzchar/udc_hotplug.c -+ * -+ * New UDC hotplug driver. -+ * -+ * Copyright (C) 2007 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "jzchars.h" -+ -+#ifndef GPIO_UDC_HOTPLUG -+#define GPIO_UDC_HOTPLUG 86 -+#endif -+ -+#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG -+#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN) -+ -+#define dprintk(x,...) -+ -+//simple meaning define -+#define NOT_CONNECT 0 -+#define YES_CONNECT 1 -+#define MAX_GPIO_TIME 50 -+ -+#define EVENT_USB_ADD 1 -+#define EVENT_USB_REMOVE 2 -+#define EVENT_POWER_ADD 3 -+#define EVENT_POWER_REMOVE 4 -+#define EVENT_POWER_TO_USB 5 -+#define EVENT_USB_SUSPEND_POWER 6 -+ -+struct udc_pnp_stat -+{ -+ char cable_stat, old_cable_stat; -+ char protl_stat, old_protl_stat; -+ char object_stat1; -+ char object_stat2; -+}; -+ -+static struct udc_pnp_stat cur_pnp_stat; -+ -+static struct file_operations cable_fops = { -+ owner: THIS_MODULE, -+}; -+ -+static struct miscdevice cable_dev= -+{ -+ 231, -+ "udc_cable", -+ &cable_fops -+}; -+ -+static struct file_operations power_fops = { -+ owner: THIS_MODULE, -+}; -+ -+static struct miscdevice power_dev= -+{ -+ 232, -+ "power_cable", -+ &power_fops -+}; -+ -+int jz_udc_active = 0; /* 0: Have no actions; 1: Have actions */ -+ -+static int udc_pin_level; -+static int udc_old_state; -+static int udc_pin_time; -+ -+static struct timer_list udc_long_timer, udc_gpio_timer; -+ -+/* Kernel thread to deliver event to user space */ -+static struct task_struct *kudcd_task; -+ -+static void udc_gpio_timer_routine(unsigned long data) -+{ -+ wake_up_process(kudcd_task); -+} -+ -+static void udc_long_timer_routine(unsigned long data) -+{ -+ dprintk("udc_timer\n"); -+ if (jz_udc_active) -+ udc_old_state = 1; -+ if (!jz_udc_active && udc_old_state) //udc irq timeout! do suspend -+ { -+ dprintk("udc suspend!\n"); -+ udc_old_state = 0; -+ cur_pnp_stat.protl_stat = NOT_CONNECT; -+ del_timer(&udc_long_timer); -+ wake_up_process(kudcd_task); -+ return; -+ } -+ jz_udc_active = 0; -+ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */ -+ add_timer(&udc_long_timer); -+} -+ -+static int udc_get_pnp_stat(void) -+{ -+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); -+ udc_pin_time = 1; -+ -+ init_timer(&udc_gpio_timer); -+ del_timer(&udc_gpio_timer); -+ udc_gpio_timer.function = udc_gpio_timer_routine; -+ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */ -+ add_timer(&udc_gpio_timer); -+ -+ while(1) -+ { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ -+ if (__gpio_get_pin(UDC_HOTPLUG_PIN) != udc_pin_level) -+ { -+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); -+ udc_pin_time = 1; -+ dprintk("udc gpio detect restart! \n"); -+ } -+ -+ udc_pin_time ++; -+ if (udc_pin_time > MAX_GPIO_TIME) -+ break; -+ -+ del_timer(&udc_gpio_timer); -+ udc_gpio_timer.function = udc_gpio_timer_routine; -+ udc_gpio_timer.expires = jiffies + 1; /* about 10 ms */ -+ add_timer(&udc_gpio_timer); -+ } -+ -+ del_timer(&udc_gpio_timer); -+ if (__gpio_get_pin(UDC_HOTPLUG_PIN)) -+ return YES_CONNECT; -+ else -+ return NOT_CONNECT; -+} -+ -+static void udc_get_cable(void) -+{ -+ u32 intr_usb; -+ -+ __intc_mask_irq(IRQ_UDC); -+ -+ /* Now enable PHY to start detect */ -+#ifdef CONFIG_SOC_JZ4740 -+ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; -+#elif CONFIG_SOC_JZ4750 -+ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; -+#endif -+ /* Clear IRQs */ -+ REG16(USB_REG_INTRINE) = 0; -+ REG16(USB_REG_INTROUTE) = 0; -+ REG8(USB_REG_INTRUSBE) = 0; -+ -+ /* disable UDC IRQs first */ -+ REG16(USB_REG_INTRINE) = 0; -+ REG16(USB_REG_INTROUTE) = 0; -+ REG8(USB_REG_INTRUSBE) = 0; -+ -+ /* Disable DMA */ -+ REG32(USB_REG_CNTL1) = 0; -+ REG32(USB_REG_CNTL2) = 0; -+ -+ /* Enable HS Mode */ -+ REG8(USB_REG_POWER) |= USB_POWER_HSENAB; -+ /* Enable soft connect */ -+ REG8(USB_REG_POWER) |= USB_POWER_SOFTCONN; -+ -+ dprintk("enable phy! %x %x %x %x %x\n", -+ REG8(USB_REG_POWER), -+ REG_CPM_SCR, -+ REG16(USB_REG_INTRINE), -+ REG16(USB_REG_INTROUTE), -+ REG8(USB_REG_INTRUSBE)); -+ -+ init_timer(&udc_gpio_timer); -+ del_timer(&udc_gpio_timer); -+ udc_gpio_timer.function = udc_gpio_timer_routine; -+ udc_gpio_timer.expires = jiffies + 11; /* about 100 ms */ -+ add_timer(&udc_gpio_timer); -+ /* Sleep a short time to see result */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ -+ del_timer(&udc_gpio_timer); -+ intr_usb = REG8(USB_REG_INTRUSB); -+ if ((intr_usb & USB_INTR_RESET) || -+ (intr_usb & USB_INTR_RESUME) || -+ (intr_usb & USB_INTR_SUSPEND)) -+ { -+ cur_pnp_stat.protl_stat = YES_CONNECT; -+ dprintk("cable is usb! \n"); -+ } -+ else -+ { -+ cur_pnp_stat.protl_stat = NOT_CONNECT; -+ dprintk("cable is power! \n"); -+ } -+ -+ /* Detect finish ,clean every thing */ -+ /* Disconnect from usb */ -+ REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN; -+ /* Disable the USB PHY */ -+#ifdef CONFIG_SOC_JZ4740 -+ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; -+#elif CONFIG_SOC_JZ4750 -+ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; -+#endif -+ /* Clear IRQs */ -+ REG16(USB_REG_INTRINE) = 0; -+ REG16(USB_REG_INTROUTE) = 0; -+ REG8(USB_REG_INTRUSBE) = 0; -+ __intc_ack_irq(IRQ_UDC); -+ __intc_unmask_irq(IRQ_UDC); -+} -+ -+static void send_event_udev(int event) -+{ -+ dprintk("Send udev message: cable=%d old=%d protl=%d old=%d \n", -+ cur_pnp_stat.cable_stat, -+ cur_pnp_stat.old_cable_stat, -+ cur_pnp_stat.protl_stat, -+ cur_pnp_stat.old_protl_stat); -+ -+ switch (event) -+ { -+ case EVENT_USB_ADD: -+ printk("usb cable insert! \n"); -+ misc_register(&cable_dev); -+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD); -+ init_timer(&udc_long_timer); -+ del_timer(&udc_long_timer); -+ udc_long_timer.function = udc_long_timer_routine; -+ udc_long_timer.expires = jiffies + 3 * HZ; /* about 3 s */ -+ add_timer(&udc_long_timer); -+ break; -+ case EVENT_USB_REMOVE: -+ printk("usb cable remove! \n"); -+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE); -+ misc_deregister(&cable_dev); -+ del_timer(&udc_long_timer); -+ break; -+ case EVENT_POWER_ADD: -+ printk("power cable insert! \n"); -+ misc_register(&power_dev); -+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD); -+ break; -+ case EVENT_POWER_REMOVE: -+ printk("power cable remove! \n"); -+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE); -+ misc_deregister(&power_dev); -+ break; -+ case EVENT_POWER_TO_USB: -+ printk("change power cable to usb! \n"); -+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_REMOVE); -+ misc_deregister(&power_dev); -+ misc_register(&cable_dev); -+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_ADD); -+ break; -+ case EVENT_USB_SUSPEND_POWER: -+ printk("usb cable suspend! \n"); -+ printk("as power cable insert! \n"); -+ kobject_uevent(&cable_dev.this_device->kobj, KOBJ_REMOVE); -+ misc_deregister(&cable_dev); -+ misc_register(&power_dev); -+ kobject_uevent(&power_dev.this_device->kobj, KOBJ_ADD); -+ break; -+ }; -+} -+ -+static void udc_pnp_detect(void) -+{ -+ if (cur_pnp_stat.cable_stat == YES_CONNECT) /* already connected! */ -+ { -+ if (udc_get_pnp_stat() == NOT_CONNECT) -+ { -+ dprintk("cable real out! \n"); -+ cur_pnp_stat.cable_stat = NOT_CONNECT; -+ cur_pnp_stat.protl_stat = NOT_CONNECT; -+ /* Deliver this event to user space in udev model */ -+ if (cur_pnp_stat.old_protl_stat) -+ send_event_udev(EVENT_USB_REMOVE); -+ else -+ send_event_udev(EVENT_POWER_REMOVE); -+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; -+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; -+ } -+ else -+ { -+ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat) -+ { -+ send_event_udev(EVENT_USB_SUSPEND_POWER); -+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; -+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; -+ } -+ else //change power to cable -+ { -+#if 0 //not support yet! -+ udc_get_cable(); -+ if (cur_pnp_stat.old_protl_stat != cur_pnp_stat.protl_stat) -+ send_event_udev(EVENT_POWER_TO_USB); -+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; -+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; -+#endif -+ } -+ } -+ } -+ else -+ { -+ if (udc_get_pnp_stat() == YES_CONNECT) -+ { -+ dprintk("cable real in! \n"); -+ cur_pnp_stat.cable_stat = YES_CONNECT; -+ udc_get_cable(); -+ /* Deliver this event to user space in udev model */ -+ if (cur_pnp_stat.protl_stat) -+ send_event_udev(EVENT_USB_ADD); -+ else -+ send_event_udev(EVENT_POWER_ADD); -+ cur_pnp_stat.old_cable_stat = cur_pnp_stat.cable_stat; -+ cur_pnp_stat.old_protl_stat = cur_pnp_stat.protl_stat; -+ } -+ else -+ dprintk("cable false in! \n"); -+ -+ } -+} -+ -+static void udc_pnp_set_gpio(void) -+{ -+ if (cur_pnp_stat.cable_stat == YES_CONNECT) -+ __gpio_as_irq_fall_edge(UDC_HOTPLUG_PIN); -+ else -+ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); -+ -+ /* clear interrupt pending status */ -+ __gpio_ack_irq(UDC_HOTPLUG_PIN); -+ /* unmask interrupt */ -+ __gpio_unmask_irq(UDC_HOTPLUG_PIN); -+} -+ -+static int udc_pnp_thread(void *unused) -+{ -+ printk(KERN_NOTICE "UDC starting pnp monitor thread\n"); -+ -+ while(1) -+ { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ -+ dprintk("pnp thread wake up! \n"); -+ /* wake up here */ -+ udc_pnp_detect(); -+ /* Reset gpio state last */ -+ udc_pnp_set_gpio(); -+ } -+} -+ -+static irqreturn_t udc_pnp_irq(int irq, void *dev_id) -+{ -+ -+ /* clear interrupt pending status */ -+ __gpio_ack_irq(UDC_HOTPLUG_PIN); -+ /* mask interrupt */ -+ __gpio_mask_irq(UDC_HOTPLUG_PIN); -+ /* wake up pnp detect thread */ -+ wake_up_process(kudcd_task); -+ -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Module init and exit -+ */ -+static int __init udc_hotplug_init(void) -+{ -+ int retval; -+ /* Init pnp stat first */ -+ cur_pnp_stat.cable_stat = NOT_CONNECT; -+ cur_pnp_stat.protl_stat = NOT_CONNECT; -+ cur_pnp_stat.old_cable_stat = NOT_CONNECT; -+ cur_pnp_stat.old_protl_stat = NOT_CONNECT; -+ cur_pnp_stat.object_stat1 = NOT_CONNECT; -+ cur_pnp_stat.object_stat2 = NOT_CONNECT; -+ udc_old_state = 0; -+ -+ /* create pnp thread and register IRQ */ -+ kudcd_task = kthread_run(udc_pnp_thread, NULL, "kudcd"); -+ if (IS_ERR(kudcd_task)) { -+ printk(KERN_ERR "jz_udc_hotplug: Failed to create system monitor thread.\n"); -+ return PTR_ERR(kudcd_task); -+ } -+ -+ retval = request_irq(UDC_HOTPLUG_IRQ, udc_pnp_irq, -+ IRQF_DISABLED, "udc_pnp", NULL); -+ if (retval) { -+ printk("Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ); -+ return retval; -+ } -+ -+ /* get current pin level */ -+ __gpio_disable_pull(UDC_HOTPLUG_PIN); -+ __gpio_as_input(UDC_HOTPLUG_PIN); -+ udelay(1); -+ udc_pin_level = __gpio_get_pin(UDC_HOTPLUG_PIN); -+ -+ if (udc_pin_level) { -+ dprintk("Cable already in! \n"); -+ /* Post a event */ -+ wake_up_process(kudcd_task); -+ } -+ else { -+ __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); -+ dprintk("Cable not in! \n"); -+ } -+ -+ printk("JZ UDC hotplug driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit udc_hotplug_exit(void) -+{ -+ free_irq(UDC_HOTPLUG_IRQ, NULL); -+} -+ -+module_init(udc_hotplug_init); -+module_exit(udc_hotplug_exit); -+ -+EXPORT_SYMBOL(jz_udc_active); -+ -+MODULE_AUTHOR("Lucifer "); -+MODULE_DESCRIPTION("JzSOC OnChip udc hotplug driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/wm9712.c linux-2.6.24.7/drivers/char/jzchar/wm9712.c ---- linux-2.6.24.7.old/drivers/char/jzchar/wm9712.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/wm9712.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,334 @@ -+/* -+ * wm9712.c -+ * -+ * Touch screen driver interface to the Wolfson WM9712 codec. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz_ts.h" -+#include "wm9712.h" -+ -+#define POLL_TIMES 10 -+ -+static int samples = 1; -+static int inited = 0, started = 0; -+ -+extern struct ac97_codec * find_ac97_codec(void); -+extern int PenIsDown(void); -+ -+ -+static inline void wm9712_reg_write(unsigned int reg, unsigned int val) -+{ -+ struct ac97_codec *codec = find_ac97_codec(); -+ if (!codec) -+ return; -+ codec->codec_write(codec, reg, val); -+} -+ -+static inline unsigned int wm9712_reg_read(unsigned int reg) -+{ -+ struct ac97_codec *codec = find_ac97_codec(); -+ if (!codec) -+ return 0; -+ return codec->codec_read(codec, reg); -+} -+ -+static unsigned int wm9712_adc_read(int adc_channel) -+{ -+ unsigned int val; -+ -+ if (!PenIsDown()) -+ return 0; -+ -+ val = wm9712_reg_read(DIGI_REG1); -+ wm9712_reg_write(DIGI_REG1, val|adc_channel|DIGI_REG1_POLL); -+ -+ for (;;) { -+ if (wm9712_reg_read(0x54) & (1 << 12)) { -+ val = wm9712_reg_read(DIGI_READBACK); -+ break; -+ } -+ } -+ -+ /* stop the measure */ -+ wm9712_reg_write(DIGI_REG1, 0); -+ -+ return (val & 0x0fff); -+} -+ -+static struct timer_list pndn_timer; -+static void (*irq_handler)(int, void *, struct pt_regs *) = NULL; -+ -+void ts_irq_callback(void) -+{ -+#ifdef TS_IRQ -+ __gpio_ack_irq(TS_IRQ); -+#else -+#endif -+} -+ -+void ts_enable_irq(void) -+{ -+ if (!inited) -+ return; -+#ifdef TS_IRQ -+ enable_irq(TS_IRQ); -+#else -+ pndn_timer.expires = jiffies + HZ/POLL_TIMES; -+ add_timer(&pndn_timer); -+#endif -+} -+ -+void ts_disable_irq(void) -+{ -+ if (!inited) -+ return; -+#ifdef TS_IRQ -+ disable_irq(TS_IRQ); -+#endif -+} -+ -+#ifndef TS_IRQ -+static void pndn_detect(unsigned long data) -+{ -+ if (PenIsDown()) { -+ if (!started) -+ return; -+ if (irq_handler) -+ irq_handler(NULL, data, NULL); -+ } else { -+ pndn_timer.expires = jiffies + HZ/POLL_TIMES; -+ add_timer(&pndn_timer); -+ } -+} -+#endif -+ -+void ts_free_irq(struct jz_ts_t *ts) -+{ -+#ifdef TS_IRQ -+ free_irq(ts->pendown_irq, ts); -+#else -+ started = 0; -+ del_timer_sync(&pndn_timer); -+#endif -+} -+ -+int ts_request_irq(u32 *irq, -+ void (*handler)(int, void *, struct pt_regs *), -+ const char *devname, -+ void *dev_id) -+{ -+ /* 4wire, Ip=400uA, Rpu=64Kohm/64, wake-up on pendown without -+ * reset, meassure on pen down. Do not use wait mode. -+ */ -+ started = 1; -+ if (!inited) { -+ wm9712_reg_write(DIGI_REG2, -+ DIGI_REG2_WIRE_4 | -+ DIGI_REG2_PIL_200uA | -+ (31 << DIGI_REG2_RPU_BIT) | -+ DIGI_REG2_PRP_ALLON | -+ DIGI_REG2_RPR_NWOR); -+ /* Polling mode and no measurement */ -+ wm9712_reg_write(DIGI_REG1, 0); -+ } -+ -+#ifdef TS_IRQ -+ /* Generate irq request on PENDOWN pin, pendown cause the level high */ -+ wm9712_reg_write(0x56, wm9712_reg_read(0x56) & ~(1 << 3)); -+ wm9712_reg_write(0x4c, wm9712_reg_read(0x4c) & ~(1 << 3)); -+ -+ *irq = TS_IRQ; -+ return request_irq(TS_IRQ, handler, SA_INTERRUPT, devname, dev_id); -+#else -+ if (!inited) { -+ irq_handler = handler; -+ init_timer(&pndn_timer); -+ pndn_timer.function = pndn_detect; -+ pndn_timer.data = (unsigned long)dev_id; -+ pndn_timer.expires = jiffies + HZ/POLL_TIMES; -+ add_timer(&pndn_timer); -+ inited = 1; -+ } else { -+ pndn_timer.expires = jiffies + HZ/POLL_TIMES; -+ add_timer(&pndn_timer); -+ } -+ return 0; -+#endif -+} -+ -+int PenIsDown(void) -+{ -+ if (wm9712_reg_read(DIGI_READBACK) & DIGI_READBACK_PNDN) -+ return 1; -+ return 0; -+} -+ -+#if defined(CONFIG_MIPS_JZ4730_GPS) -+#define adj_data(r1, r2, r3, s) \ -+do { \ -+ if (r1 < 0x90) \ -+ r1 = 0x90; \ -+ if (r2 < 0xed) \ -+ r2 = 0xed; \ -+ r1 = ((r1 - 0x90) * 240) / 3354; \ -+ r2 = ((r2 - 0xed) * 320) / 3671; \ -+ if (r1 > 239) \ -+ r1 = 239; \ -+ if (r2 > 319) \ -+ r2 = 319; \ -+ \ -+ *s = r2; \ -+ *(s+1) = 239 - r1; \ -+ *(s+2) = z_raw; \ -+} while (0) -+#endif -+ -+#ifndef adj_data -+#define adj_data(r1, r2, r3, s) -+#endif -+ -+static int read_adc(unsigned int *sdata) -+{ -+ unsigned long x_raw=0, y_raw=0, z_raw=0, t, fail = 0; -+ int i; -+ -+ for (i=0; i 1) { -+ x_raw = (x_raw + (samples>>1)) / samples; -+ y_raw = (y_raw + (samples>>1)) / samples; -+ z_raw = (z_raw + (samples>>1)) / samples; -+ } -+ -+ adj_data (x_raw, y_raw, z_raw, sdata); -+ -+ return 1; -+} -+ -+ -+#define TSMAXX 945 -+#define TSMAXY 830 -+#define TSMINX 90 -+#define TSMINY 105 -+ -+#define SCREEN_X 480 -+#define SCREEN_Y 272 -+ -+static unsigned long transform_to_screen_x(struct jz_ts_t *ts, unsigned long x ) -+{ -+ -+ if (ts->minx) -+ { -+ if (x < ts->minx) x = ts->minx; -+ if (x > ts->maxx) x = ts->maxx; -+ -+ return (x - ts->minx) * SCREEN_X / (ts->maxx - ts->minx); -+ } -+ else -+ { -+ if (x < TSMINX) x = TSMINX; -+ if (x > TSMAXX) x = TSMAXX; -+ -+ return (x - TSMINX) * SCREEN_X / (TSMAXX - TSMINX); -+ } -+} -+ -+static unsigned long transform_to_screen_y(struct jz_ts_t *ts, unsigned long y) -+{ -+ if (ts->minx) -+ { -+ if (y < ts->minx) y = ts->miny; -+ if (y > ts->maxx) y = ts->maxy; -+ -+ return (y - ts->miny) * SCREEN_Y / (ts->maxy - ts->miny); -+ } -+ else -+ { -+ if (y < TSMINX) y = TSMINY; -+ if (y > TSMAXX) y = TSMAXY; -+ -+ return (y - TSMINY) * SCREEN_Y / (TSMAXY - TSMINY); -+ } -+} -+ -+ -+/* -+ * Acquire Raw pen coodinate data and compute touch screen -+ * pressure resistance. Hold spinlock when calling. -+ */ -+int AcquireEvent(struct jz_ts_t *ts, struct ts_event *event) -+{ -+ unsigned int s[3]; -+ unsigned int x_scr, y_scr; -+ if (!read_adc(s)) -+ return 0; -+ if(ts->filter) { -+ x_scr = transform_to_screen_x(ts, s[0]); -+ y_scr = transform_to_screen_y(ts, s[1]); -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d x_transform=%d y_transform=%d\n", s[0], s[1], x_scr, y_scr); } -+ else { -+ x_scr = s[0]; -+ y_scr = s[1]; -+ -+ if (ts->prints) -+ printk("x_raw=%d y_raw=%d \n", s[0], s[1]); -+ } -+ event->x = x_scr; -+ event->y = y_scr; -+ event->pressure = (u16)s[2]; -+ event->status = PENDOWN; -+ return 1; -+#if 0 -+ do_gettimeofday(&event->stamp); -+#endif -+} -+ -+int __init wm9712_init(void) -+{ -+ return 0; -+} -+ -+void wm9712_cleanup(void) -+{ -+} -+ -+module_init(wm9712_init); -+module_exit(wm9712_cleanup); -+ -diff -urN linux-2.6.24.7.old/drivers/char/jzchar/wm9712.h linux-2.6.24.7/drivers/char/jzchar/wm9712.h ---- linux-2.6.24.7.old/drivers/char/jzchar/wm9712.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/jzchar/wm9712.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,58 @@ -+#ifndef __WM9712_H__ -+#define __WM9712_H__ -+ -+#define DIGI_REG1 0x76 -+#define DIGI_REG2 0x78 -+#define DIGI_READBACK 0x7A -+ -+#define ADCSEL_BIT 12 -+#define ADCSEL_MASK (7 << ADCSEL_BIT) -+#define ADCSEL_NONE (0 << ADCSEL_BIT) -+#define ADCSEL_XPOS (1 << ADCSEL_BIT) -+#define ADCSEL_YPOS (2 << ADCSEL_BIT) -+#define ADCSEL_PRESSURE (3 << ADCSEL_BIT) -+#define ADCSEL_COMP1 (4 << ADCSEL_BIT) -+#define ADCSEL_COMP2 (5 << ADCSEL_BIT) -+#define ADCSEL_BMON (6 << ADCSEL_BIT) -+#define ADCSEL_WIPER (7 << ADCSEL_BIT) -+ -+#define DIGI_REG1_CTC (1 << 10) -+#define DIGI_REG1_POLL (1 << 15) -+#define DIGI_REG1_CR_BIT 8 -+#define DIGI_REG1_CR_MASK (3 << DIGI_REG1_CR_BIT) -+#define DIGI_REG1_COO (1 << 11) -+#define DIGI_REG1_SLEN (1 << 3) -+#define DIGI_REG1_SLT_BIT 0 -+#define DIGI_REG1_SLT_MASK (7 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_5 (0 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_6 (1 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_7 (2 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_8 (3 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_9 (4 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_10 (5 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_11 (6 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_SLT_RES (7 << DIGI_REG1_SLT_BIT) -+#define DIGI_REG1_DEL_BIT 4 -+#define DIGI_REG1_DEL_MASK (0x0f << DIGI_REG1_DEL_BIT) -+ -+#define DIGI_REG2_WIRE_5 (1 << 12) -+#define DIGI_REG2_WIRE_4 (0 << 12) -+#define DIGI_REG2_RPU_BIT 0 -+#define DIGI_REG2_RPU_MASK (0x3f << DIGI_REG2_RPU_BIT) -+#define DIGI_REG2_PIL_400uA (1 << 8) -+#define DIGI_REG2_PIL_200uA (0 << 8) -+#define DIGI_REG2_PRP_BIT 14 -+#define DIGI_REG2_PRP_MASK (3 << DIGI_REG2_PRP_BIT) -+#define DIGI_REG2_PRP_ALLOFF (0 << DIGI_REG2_PRP_BIT) -+#define DIGI_REG2_PRP_WOP (1 << DIGI_REG2_PRP_BIT) -+#define DIGI_REG2_PRP_NWOP (2 << DIGI_REG2_PRP_BIT) -+#define DIGI_REG2_PRP_ALLON (3 << DIGI_REG2_PRP_BIT) -+#define DIGI_REG2_RPR_WOR (0 << 13) -+#define DIGI_REG2_RPR_NWOR (1 << 13) -+#define DIGI_REG2_PDEN (1 << 11) -+#define DIGI_REG2_WAIT (1 << 9) -+ -+#define DIGI_READBACK_PNDN (1 << 15) -+ -+#endif /* __WM9712_H__ */ -+ -diff -urN linux-2.6.24.7.old/drivers/char/rtc_jz.c linux-2.6.24.7/drivers/char/rtc_jz.c ---- linux-2.6.24.7.old/drivers/char/rtc_jz.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/rtc_jz.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,503 @@ -+/* -+ * Jz OnChip Real Time Clock interface for Linux -+ * -+ * NOTE: we need to wait rtc write ready before read or write RTC registers. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include /* get the user-level API */ -+#include -+#include -+ -+#include "rtc_jz.h" -+ -+ -+char sbin_rtc_alarm_handler_path[] = "/sbin/rtcalarm"; -+//call_usermodehelper(char *path, char **argv, char **envp, int wait) -+//extern int call_usermodehelper(char *path, char **argv, char **envp); -+ -+extern spinlock_t rtc_lock; -+ -+static int rtc_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+ -+ -+static void get_rtc_time (struct rtc_time *rtc_tm); -+static int set_rtc_time (struct rtc_time *rtc_tm); -+static void get_rtc_alm_time (struct rtc_time *alm_tm); -+static int set_rtc_alm_time (struct rtc_time *alm_tm); -+ -+static void set_rtc_irq_bit(int bit); -+static void mask_rtc_irq_bit(int bit); -+ -+static unsigned int rtc_status = 0; -+static unsigned int epoch = 1900; -+ -+static void get_rtc_time(struct rtc_time *rtc_tm) -+{ -+ unsigned long lval; -+ struct rtc_time ltm; -+ -+ spin_lock_irq(&rtc_lock); -+ while ( !__rtc_write_ready() ) ; -+ lval = REG_RTC_RSR; -+ rtc_time_to_tm(lval, <m); -+ if(rtc_valid_tm(<m) == 0) { -+ /* is valid */ -+ rtc_tm->tm_sec = ltm.tm_sec; -+ rtc_tm->tm_min = ltm.tm_min; -+ rtc_tm->tm_hour = ltm.tm_hour; -+ rtc_tm->tm_mday = ltm.tm_mday; -+ rtc_tm->tm_wday = ltm.tm_wday; -+ rtc_tm->tm_mon = ltm.tm_mon; -+ rtc_tm->tm_year = ltm.tm_year; -+ } else { -+ printk("invlaid data / time!\n"); -+ } -+ spin_unlock_irq(&rtc_lock); -+} -+ -+static int set_rtc_time(struct rtc_time *rtc_tm) -+{ -+ unsigned long lval; -+ -+ rtc_tm_to_time(rtc_tm, &lval); -+ -+ spin_lock_irq(&rtc_lock); -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_RSR = lval; -+ -+ spin_unlock_irq(&rtc_lock); -+ -+ return 0; -+ -+} -+ -+static void get_rtc_alm_time(struct rtc_time *alm_tm) -+{ -+ unsigned long lval; -+ struct rtc_time altm; -+ -+ spin_lock_irq(&rtc_lock); -+ while ( !__rtc_write_ready() ) ; -+ lval = REG_RTC_RSAR; -+ rtc_time_to_tm(lval, &altm); -+ if(rtc_valid_tm(&altm) == 0) { -+ /* is valid */ -+ alm_tm->tm_sec = altm.tm_sec; -+ alm_tm->tm_min = altm.tm_min; -+ alm_tm->tm_hour = altm.tm_hour; -+ alm_tm->tm_mday = altm.tm_mday; -+ alm_tm->tm_wday = altm.tm_wday; -+ alm_tm->tm_mon = altm.tm_mon; -+ alm_tm->tm_year = altm.tm_year; -+ } else { -+ printk("invlaid data / time in Line:%d!\n",__LINE__); -+ } -+ spin_unlock_irq(&rtc_lock); -+} -+ -+static int set_rtc_alm_time(struct rtc_time *alm_tm) -+{ -+ unsigned long lval; -+ -+ rtc_tm_to_time(alm_tm, &lval); -+ -+ spin_lock_irq(&rtc_lock); -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_RSAR = lval; -+ -+ while ( !__rtc_write_ready() ) ; /* set alarm function */ -+ if ( !((REG_RTC_RCR>>2) & 0x1) ) { -+ while ( !__rtc_write_ready() ) ; -+ __rtc_enable_alarm(); -+ } -+ -+ while ( !__rtc_write_ready() ) ; -+ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */ -+ __rtc_enable_alarm_irq(); -+ } -+ -+ spin_unlock_irq(&rtc_lock); -+ -+ return 0; -+} -+ -+static void get_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm) -+{ -+ int enabled, pending; -+ -+ get_rtc_alm_time(&wkalm->time); -+ -+ spin_lock_irq(&rtc_lock); -+ while ( !__rtc_write_ready() ) ; -+ enabled = (REG_RTC_HWCR & 0x1); -+ pending = 0; -+ if ( enabled ) { -+ if ( (u32)REG_RTC_RSAR > (u32)REG_RTC_RSR ) /* 32bit val */ -+ pending = 1; -+ } -+ -+ wkalm->enabled = enabled; -+ wkalm->pending = pending; -+ spin_unlock_irq(&rtc_lock); -+} -+ -+static int set_rtc_wakeup_alarm(struct rtc_wkalrm *wkalm) -+{ -+ int enabled; -+ //int pending; -+ -+ enabled = wkalm->enabled; -+ //pending = wkalm->pending; /* Fix me, what's pending mean??? */ -+ -+ while ( !__rtc_write_ready() ) ; /* set wakeup alarm enable */ -+ if ( enabled != (REG_RTC_HWCR & 0x1) ) { -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_HWCR = (REG_RTC_HWCR & ~0x1) | enabled; -+ } -+ while ( !__rtc_write_ready() ) ; /* set alarm function */ -+ if ( enabled != ((REG_RTC_RCR>>2) & 0x1) ) { -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_RCR = (REG_RTC_RCR & ~(1<<2)) | (enabled<<2); -+ } -+ -+ if ( !enabled ) /* if disabled wkalrm, rturn. */ -+ { -+ return 0; -+ } -+ -+ while ( !__rtc_write_ready() ) ; -+ if ( !(REG_RTC_RCR & RTC_RCR_AIE) ) { /* Enable alarm irq */ -+ __rtc_enable_alarm_irq(); -+ } -+ -+ set_rtc_alm_time(&wkalm->time); -+ -+ return 0; -+} -+ -+ -+static void set_rtc_irq_bit( int bit ) -+{ -+ spin_lock_irq(&rtc_lock); -+ -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_RCR |= (1<= 0xc0 -+ * means "don't care" or "match all". Only the tm_hour, -+ * tm_min, and tm_sec values are filled in. -+ */ -+ -+ get_rtc_alm_time(&wtime); -+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; -+ -+ case RTC_ALM_SET: /* Store a time into the alarm */ -+ { -+ struct rtc_time alm_tm; -+ -+ if (copy_from_user(&alm_tm, (struct rtc_time*)arg, -+ sizeof(struct rtc_time))) -+ return -EFAULT; -+ if(rtc_valid_tm(&alm_tm) != 0) { -+ printk("invalid time set in Line:%d! \n",__LINE__); -+ return -EFAULT; -+ } -+ -+ return set_rtc_alm_time(&alm_tm); -+ } -+ case RTC_RD_TIME: /* Read the time/date from RTC */ -+ get_rtc_time(&wtime); -+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; -+ case RTC_SET_TIME: /* Set the RTC */ -+ { -+ struct rtc_time rtc_tm; -+ -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ -+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, -+ sizeof(struct rtc_time))) -+ return -EFAULT; -+ if(rtc_valid_tm(&rtc_tm) != 0) { -+ printk("invalid time set in Line:%d! \n",__LINE__); -+ return -EFAULT; -+ } -+ -+ return set_rtc_time(&rtc_tm); -+ } -+ case RTC_EPOCH_READ: /* Read the epoch. */ -+ return put_user (epoch, (unsigned long *)arg); -+ case RTC_EPOCH_SET: /* Set the epoch. */ -+ /* -+ * There were no RTC clocks before 1900. -+ */ -+ if (arg < 1900) -+ return -EINVAL; -+ -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ -+ epoch = arg; -+ return 0; -+ case RTC_WKALM_SET: /* Wake alarm set. */ -+ { -+ struct rtc_wkalrm wkalrm; -+ -+ if (copy_from_user(&wkalrm, (struct rtc_wkalrm*)arg, -+ sizeof(struct rtc_wkalrm))) -+ return -EFAULT; -+ return set_rtc_wakeup_alarm(&wkalrm); -+ } -+ case RTC_WKALM_RD: /* Wake alarm read. */ -+ { -+ struct rtc_wkalrm wkalrm; -+ get_rtc_wakeup_alarm(&wkalrm); -+ return copy_to_user((void *)arg, &wkalrm, sizeof(struct rtc_wkalrm)) ? -EFAULT : 0; -+ } -+ /* set power down: shut down the machine. */ -+ case RTC_POWER_DOWN: /* enter HIBERNATE mode */ -+ dprintk("Power down. Bye....\n"); -+ while ( !__rtc_write_ready() ) ; -+ REG_RTC_HCR = 0x1; -+ return 0; -+#ifdef DEBUG -+ case RTC_PRINT_REG: /* Print RTC registers */ -+ print_rtc_registers(); -+ return 0; -+#endif -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/* -+ * We enforce only one user at a time here with the open/close. -+ * Also clear the previous interrupt data on an open, and clean -+ * up things on a close. -+ */ -+ -+/* We use rtc_lock to protect against concurrent opens. So the BKL is not -+ * needed here. Or anywhere else in this driver. */ -+static int rtc_open(struct inode *inode, struct file *file) -+{ -+ spin_lock_irq (&rtc_lock); -+ -+ if(rtc_status) -+ goto out_busy; -+ -+ rtc_status = 1; -+ -+ spin_unlock_irq (&rtc_lock); -+ return 0; -+ -+out_busy: -+ return -EBUSY; -+} -+ -+static int rtc_release(struct inode *inode, struct file *file) -+{ -+ -+ rtc_status = 0; -+ /* No need for locking -- nobody else can do anything until this rmw is -+ * committed, and no timer is running. */ -+ return 0; -+} -+ -+/* -+ * The various file operations we support. -+ */ -+ -+static struct file_operations rtc_fops = { -+ owner: THIS_MODULE, -+ llseek: no_llseek, -+ ioctl: rtc_ioctl, -+ open: rtc_open, -+ release: rtc_release, -+}; -+ -+ -+static void run_sbin_rtc_alarm( void ) -+{ -+ int i; -+ char *argv[2], *envp[3]; -+ -+ if (!sbin_rtc_alarm_handler_path[0]) -+ return; -+ -+ print_dbg(": sbin_rtc_alarm_handler_path=%s\n", sbin_rtc_alarm_handler_path); -+ -+ i = 0; -+ argv[i++] = sbin_rtc_alarm_handler_path; -+ argv[i] = 0; -+ -+ /* minimal command environment */ -+ i = 0; -+ envp[i++] = "HOME=/"; -+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -+ -+ /* other stuff we want to pass to /sbin/hotplug */ -+ -+ envp[i] = 0; -+ -+ call_usermodehelper (argv [0], argv, envp, 0); -+} -+ -+static void rtc_alarm_task_handler(struct work_struct *work) -+{ -+ run_sbin_rtc_alarm(); -+} -+ -+static struct work_struct rtc_alarm_task; -+ -+static irqreturn_t jz_rtc_interrupt(int irq, void *dev_id) -+{ -+ REG_RTC_HCR = 0x0; -+ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); -+ spin_lock_irq(&rtc_lock); -+ -+ if ( __rtc_get_1Hz_flag() ) { -+ while ( !__rtc_write_ready() ) ; -+ __rtc_clear_1Hz_flag(); -+ dprintk("RTC 1Hz interrupt occur.\n"); -+ } -+ -+ if ( __rtc_get_alarm_flag() ) { /* rtc alarm interrupt */ -+ while ( !__rtc_write_ready() ) ; -+ __rtc_clear_alarm_flag(); -+ dprintk("RTC alarm interrupt occur.\n"); -+ //schedule_task( &rtc_alarm_task ); -+ schedule_work( &rtc_alarm_task ); -+ } -+ spin_unlock_irq(&rtc_lock); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+#define RTC_MINOR 135 -+ -+static struct miscdevice rtc_dev= -+{ -+ RTC_MINOR, -+ "rtc", -+ &rtc_fops -+}; -+ -+int __init Jz_rtc_init(void) -+{ -+ -+ INIT_WORK(&rtc_alarm_task, rtc_alarm_task_handler); -+ -+ /* Enabled rtc function, enable rtc alarm function */ -+ while ( !__rtc_write_ready() ) ; /* need we wait for WRDY??? */ -+ if ( !(REG_RTC_RCR & RTC_RCR_RTCE) || !(REG_RTC_RCR &RTC_RCR_AE) ) { -+ REG_RTC_RCR |= RTC_RCR_AE | RTC_RCR_RTCE; -+ } -+ /* clear irq flags */ -+ __rtc_clear_1Hz_flag(); -+ /* In a alarm reset, we expect a alarm interrupt. -+ * We can do something in the interrupt handler. -+ * So, do not clear alarm flag. -+ */ -+/* __rtc_clear_alarm_flag(); */ -+ -+ if (request_irq(IRQ_RTC, jz_rtc_interrupt, 0, "rtc", NULL) < 0) -+ return -EBUSY; -+ -+ misc_register(&rtc_dev); -+ -+ printk("JzSOC onchip RTC installed !!!\n"); -+ return 0; -+ -+} -+ -+void __exit Jz_rtc_exit (void) -+{ -+ misc_deregister(&rtc_dev); -+ free_irq (IRQ_RTC, NULL); -+} -+ -+module_init(Jz_rtc_init); -+module_exit(Jz_rtc_exit); -+ -diff -urN linux-2.6.24.7.old/drivers/char/rtc_jz.h linux-2.6.24.7/drivers/char/rtc_jz.h ---- linux-2.6.24.7.old/drivers/char/rtc_jz.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/rtc_jz.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,74 @@ -+#ifndef __RTC_JZ_H__ -+#define __RTC_JZ_H__ -+ -+//#define DEBUG 1 -+#undef DEBUG -+ -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#define print_dbg(f, arg...) \ -+ printk("%s, %s[%d]:" f , __FUNCTION__, __FILE__, __LINE__ , ##arg ) -+#else -+#define dprintk(x...) -+#define print_dbg(n, arg...) -+#endif -+ -+ -+#ifdef DEBUG -+ -+static void print_rtc_time( struct rtc_time * tm ) -+{ -+ printk("%02d%02d-%02d:%02d:%02d-%d\n", tm->tm_mon, tm->tm_mday, -+ tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_year); -+ printk("sec:\t%d\n", tm->tm_sec); -+ printk("min:\t%d\n", tm->tm_min); -+ printk("hour:\t%d\n", tm->tm_hour); -+ printk("mday:\t%d\n", tm->tm_mday); -+ printk("mon:\t%d\n", tm->tm_mon); -+ printk("year:\t%d\n", tm->tm_year); -+ printk("wday:\t%d\n", tm->tm_wday); -+ printk("yday:\t%d\n", tm->tm_yday); -+ printk("isdst:\t%d\n", tm->tm_isdst); -+ -+} -+ -+static void print_rtc_registers( void ) -+{ -+ while ( !__rtc_write_ready() ) ; -+ printk("REG_RTC_RCR:\t 0x%8.8x\n", REG_RTC_RCR ); -+ printk("REG_RTC_RSR:\t 0x%8.8x\n", REG_RTC_RSR ); -+ printk("REG_RTC_RSAR:\t 0x%8.8x\n", REG_RTC_RSAR ); -+ printk("REG_RTC_RGR:\t 0x%8.8x\n", REG_RTC_RGR ); -+ printk("REG_RTC_HCR:\t 0x%8.8x\n", REG_RTC_HCR ); -+ printk("REG_RTC_HWFCR:\t 0x%8.8x\n", REG_RTC_HWFCR ); -+ printk("REG_RTC_HRCR:\t 0x%8.8x\n", REG_RTC_HRCR ); -+ printk("REG_RTC_HWCR:\t 0x%8.8x\n", REG_RTC_HWCR ); -+ printk("REG_RTC_HWRSR:\t 0x%8.8x\n", REG_RTC_HWRSR ); -+ printk("REG_RTC_HSPR:\t 0x%8.8x\n", REG_RTC_HSPR ); -+} -+ -+#define RTC_PRINT_REG _IOR('p', 0x12, unsigned long)/* Set power down */ -+#endif /* #ifdef DEBUG */ -+ -+ -+/* -+ * JZSOC ioctl calls that are permitted to the /dev/rtc interface -+ */ -+ -+#define RTC_ENABLED _IO('p', 0x11) /* enable rtc */ -+#define RTC_DISABLED _IO('p', 0x12) /* disable rtc */ -+#define RTC_ALM_ON _IO('p', 0x13) /* enable rtc */ -+#define RTC_ALM_OFF _IO('p', 0x14) /* disable rtc */ -+#define RTC_1HZIE_ON _IO('p', 0x15) /* 1Hz int. enable on */ -+#define RTC_1HZIE_OFF _IO('p', 0x16) /* ... off */ -+ -+#define RTC_POWER_DOWN _IOR('p', 0x11, unsigned long)/* Set power down */ -+ -+/* Registers define */ -+/* RTC Control register */ -+#define RTC_AIE 3 /* jz4740_06_rtc_spec.pdf, RTC Control Register */ -+#define RTC_1HZIE 5 /* ... */ -+#define RTC_ALM_EN 2 /* ... */ -+#define RTC_EN 0 /* ... */ -+ -+#endif /* #define __RTC_JZ_H__ */ -diff -urN linux-2.6.24.7.old/drivers/char/rtc_pcf8563.c linux-2.6.24.7/drivers/char/rtc_pcf8563.c ---- linux-2.6.24.7.old/drivers/char/rtc_pcf8563.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/char/rtc_pcf8563.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,448 @@ -+/* -+ * PCF8563 Real Time Clock interface for Linux -+ * -+ * It only support 24Hour Mode, And the stored values are in BCD format. -+ * The alarm register is start at minute reg, no second alarm register. -+ */ -+ -+//#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include /* get the user-level API */ -+#include -+#include -+ -+/********************************************************************** -+ * register summary -+ **********************************************************************/ -+#define RTC_SECONDS 2 -+#define RTC_MINUTES 3 -+#define RTC_HOURS 4 -+#define RTC_DAY_OF_MONTH 5 -+#define RTC_DAY_OF_WEEK 6 -+#define RTC_MONTH 7 -+#define RTC_YEAR 8 -+ -+#define RTC_MINUTES_ALARM 9 -+#define RTC_HOURS_ALARM 0x0a -+#define RTC_DAY_ALARM 0x0b -+#define RTC_WEEKDAY_ALARM 0x0c -+ -+/* control registers - Moto names -+ */ -+#define RTC_CONTROL 0x00 -+#define RTC_STATUS 0x01 -+#define RTC_CLKOUT 0x0d -+#define RTC_TIMERCTL 0x0e -+#define RTC_TIMERCOUNTDOWN 0x0f -+ -+ -+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) -+ * determines if the following two #defines are needed -+ */ -+#ifndef BCD2BIN -+#define BCD2BIN(val) (((val) & 0x0f) + ((val) >> 4) * 10) -+#endif -+ -+#ifndef BIN2BCD -+#define BIN2BCD(val) ((((val) / 10) << 4) + (val) % 10) -+#endif -+ -+extern spinlock_t rtc_lock; -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+extern int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+/* -+ * We sponge a minor off of the misc major. No need slurping -+ * up another valuable major dev number for this. If you add -+ * an ioctl, make sure you don't conflict with SPARC's RTC -+ * ioctls. -+ */ -+ -+static int rtc_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+ -+ -+static void get_rtc_time (struct rtc_time *rtc_tm); -+static void get_rtc_alm_time (struct rtc_time *alm_tm); -+ -+/* -+ * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is -+ * protected by the big kernel lock. However, ioctl can still disable the timer -+ * in rtc_status and then with del_timer after the interrupt has read -+ * rtc_status but before mod_timer is called, which would then reenable the -+ * timer (but you would need to have an awful timing before you'd trip on it) -+ */ -+static unsigned long rtc_status = 0; /* bitmapped status byte. */ -+ -+/* -+ * If this driver ever becomes modularised, it will be really nice -+ * to make the epoch retain its value across module reload... -+ */ -+static unsigned int epoch = 1900; -+static const unsigned char days_in_mo[] = -+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -+ -+static unsigned char rtcframe[16]; -+ -+static void read_rtcframe(void) -+{ -+ i2c_open(); -+ i2c_read(0x51, rtcframe, 0, 16); -+ i2c_close(); -+} -+ -+static void write_rtcframe(void) -+{ -+ i2c_open(); -+ i2c_write(0x51, rtcframe, 0, 16); -+ i2c_close(); -+} -+ -+static void write_rtc(unsigned char addr, unsigned char val) -+{ -+ volatile unsigned char v = val; -+ i2c_open(); -+ i2c_write(0x51, (unsigned char *)&v, addr, 1); -+ i2c_close(); -+} -+ -+static unsigned char read_rtc(unsigned char addr) -+{ -+ volatile unsigned char v; -+ i2c_open(); -+ i2c_read(0x51, (unsigned char *)&v, addr, 1); -+ i2c_close(); -+ return v; -+} -+ -+static void CMOS_WRITE(unsigned char addr, unsigned char val) -+{ -+ rtcframe[addr] = val; -+} -+ -+static unsigned char CMOS_READ(unsigned char addr) -+{ -+ return rtcframe[addr]; -+} -+ -+static void get_rtc_time(struct rtc_time *rtc_tm) -+{ -+ unsigned char sec,mon,mday,wday,year,hour,min; -+ -+ /* -+ * Only the values that we read from the RTC are set. We leave -+ * tm_wday, tm_yday and tm_isdst untouched. Even though the -+ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated -+ * by the RTC when initially set to a non-zero value. -+ */ -+ -+ spin_lock_irq(&rtc_lock); -+ read_rtcframe(); -+ sec = CMOS_READ(RTC_SECONDS) & ~0x80; -+ min = CMOS_READ(RTC_MINUTES) & ~0x80; -+ hour = CMOS_READ(RTC_HOURS) & ~0xc0; -+ mday = CMOS_READ(RTC_DAY_OF_MONTH) & ~0xc0; -+ wday = CMOS_READ(RTC_DAY_OF_WEEK) & ~0xf8; -+ mon = CMOS_READ(RTC_MONTH) & ~0xe0; -+ year = CMOS_READ(RTC_YEAR) ; -+ -+ rtc_tm->tm_sec = BCD2BIN(sec); -+ rtc_tm->tm_min = BCD2BIN(min); -+ rtc_tm->tm_hour = BCD2BIN(hour); -+ rtc_tm->tm_mday = BCD2BIN(mday); -+ rtc_tm->tm_wday = wday; -+ /* Don't use centry, but start from year 1970 */ -+ rtc_tm->tm_mon = BCD2BIN(mon); -+ year = BCD2BIN(year); -+ if ((year += (epoch - 1900)) <= 69) -+ year += 100; -+ rtc_tm->tm_year = year; -+ -+ spin_unlock_irq(&rtc_lock); -+ -+ -+ /* -+ * Account for differences between how the RTC uses the values -+ * and how they are defined in a struct rtc_time; -+ */ -+ rtc_tm->tm_mon--; -+} -+ -+static void get_rtc_alm_time(struct rtc_time *alm_tm) -+{ -+ unsigned char sec, min, hour; -+ -+ /* -+ * Only the values that we read from the RTC are set. That -+ * means only tm_hour, tm_min, and tm_sec. -+ */ -+ spin_lock_irq(&rtc_lock); -+ read_rtcframe(); -+ sec = 0; -+ min = CMOS_READ(RTC_MINUTES_ALARM); -+ hour = CMOS_READ(RTC_HOURS_ALARM); -+ -+ alm_tm->tm_sec = sec;//not set sec -+ alm_tm->tm_min = BCD2BIN(min); -+ alm_tm->tm_hour = BCD2BIN(hour); -+ -+ spin_unlock_irq(&rtc_lock); -+} -+ -+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct rtc_time wtime; -+ switch (cmd) { -+ case RTC_ALM_READ: /* Read the present alarm time */ -+ { -+ /* -+ * This returns a struct rtc_time. Reading >= 0xc0 -+ * means "don't care" or "match all". Only the tm_hour, -+ * tm_min, and tm_sec values are filled in. -+ */ -+ -+ get_rtc_alm_time(&wtime); -+ break; -+ } -+ case RTC_ALM_SET: /* Store a time into the alarm */ -+ { -+ unsigned char hrs, min, sec; -+ struct rtc_time alm_tm; -+ -+ if (copy_from_user(&alm_tm, (struct rtc_time*)arg, -+ sizeof(struct rtc_time))) -+ return -EFAULT; -+ -+ hrs = alm_tm.tm_hour; -+ min = alm_tm.tm_min; -+ sec = alm_tm.tm_sec; -+ -+ -+ -+ if (hrs >= 24) -+ return -EINVAL; -+ -+ hrs = BIN2BCD(hrs); -+ -+ if (min >= 60) -+ return -EINVAL; -+ -+ min = BIN2BCD(min); -+ -+ if (sec >= 60) -+ return -EINVAL; -+ -+ spin_lock_irq(&rtc_lock); -+ read_rtcframe(); -+ CMOS_WRITE(RTC_HOURS_ALARM, hrs | 0x80); -+ CMOS_WRITE(RTC_MINUTES_ALARM, min | 0x80); -+ -+ CMOS_WRITE(RTC_DAY_ALARM, CMOS_READ(RTC_DAY_ALARM) | 0x80); -+ CMOS_WRITE(RTC_WEEKDAY_ALARM, CMOS_READ(RTC_WEEKDAY_ALARM) | 0x80); -+ CMOS_WRITE(RTC_STATUS, CMOS_READ(RTC_STATUS) | 0x02);/*open alarm int*/ -+ write_rtcframe(); -+ spin_unlock_irq(&rtc_lock); -+ break; -+ } -+ case RTC_RD_TIME: /* Read the time/date from RTC */ -+ { -+ get_rtc_time(&wtime); -+ break; -+ } -+ case RTC_SET_TIME: /* Set the RTC */ -+ { -+ struct rtc_time rtc_tm; -+ unsigned char mon, day, hrs, min, sec, leap_yr, date; -+ unsigned int yrs; -+// unsigned char ctr; -+ -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ -+ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, -+ sizeof(struct rtc_time))) -+ return -EFAULT; -+ -+ -+ yrs = rtc_tm.tm_year + 1900; -+ mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ -+ day = rtc_tm.tm_wday; -+ date = rtc_tm.tm_mday; -+ hrs = rtc_tm.tm_hour; -+ min = rtc_tm.tm_min; -+ sec = rtc_tm.tm_sec; -+ -+ -+ if (yrs < 1970) -+ return -EINVAL; -+ -+ leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); -+ -+ if ((mon > 12) || (date == 0)) -+ return -EINVAL; -+ -+ if (date > (days_in_mo[mon] + ((mon == 2) && leap_yr))) -+ return -EINVAL; -+ -+ if ((hrs >= 24) || (min >= 60) || (sec >= 60)) -+ return -EINVAL; -+ -+ if ((yrs -= epoch) > 255) /* They are unsigned */ -+ return -EINVAL; -+ -+ spin_lock_irq(&rtc_lock); -+ /* These limits and adjustments are independant of -+ * whether the chip is in binary mode or not. -+ */ -+ if (yrs > 169) { -+ spin_unlock_irq(&rtc_lock); -+ return -EINVAL; -+ } -+ -+ if (yrs >= 100) -+ yrs -= 100; -+ -+ min = BIN2BCD(min); -+ sec = BIN2BCD(sec); -+ hrs = BIN2BCD(hrs); -+ mon = BIN2BCD(mon); -+ yrs = BIN2BCD(yrs); -+ date = BIN2BCD(date); -+ -+ read_rtcframe(); -+ CMOS_WRITE(RTC_SECONDS, sec ); -+ CMOS_WRITE(RTC_MINUTES, min); -+ CMOS_WRITE(RTC_HOURS, hrs); -+ CMOS_WRITE(RTC_DAY_OF_MONTH, date); -+ CMOS_WRITE(RTC_DAY_OF_WEEK, day); -+ CMOS_WRITE(RTC_MONTH, mon); -+ CMOS_WRITE(RTC_YEAR, yrs); -+ write_rtcframe(); -+ -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ } -+ case RTC_EPOCH_READ: /* Read the epoch. */ -+ { -+ return put_user (epoch, (unsigned long *)arg); -+ } -+ case RTC_EPOCH_SET: /* Set the epoch. */ -+ { -+ /* -+ * There were no RTC clocks before 1900. -+ */ -+ if (arg < 1900) -+ return -EINVAL; -+ -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ -+ epoch = arg; -+ return 0; -+ } -+ default: -+ return -EINVAL; -+ } -+ return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; -+} -+ -+/* -+ * We enforce only one user at a time here with the open/close. -+ * Also clear the previous interrupt data on an open, and clean -+ * up things on a close. -+ */ -+ -+/* We use rtc_lock to protect against concurrent opens. So the BKL is not -+ * needed here. Or anywhere else in this driver. */ -+static int rtc_open(struct inode *inode, struct file *file) -+{ -+ spin_lock_irq (&rtc_lock); -+ -+ if(rtc_status) -+ goto out_busy; -+ -+ rtc_status = 1; -+ -+ spin_unlock_irq (&rtc_lock); -+ return 0; -+ -+out_busy: -+ spin_unlock_irq (&rtc_lock); -+ return -EBUSY; -+} -+ -+static int rtc_release(struct inode *inode, struct file *file) -+{ -+ -+ -+ /* No need for locking -- nobody else can do anything until this rmw is -+ * committed, and no timer is running. */ -+ rtc_status = 0; -+ return 0; -+} -+ -+/* -+ * The various file operations we support. -+ */ -+ -+static struct file_operations rtc_fops = { -+ owner: THIS_MODULE, -+ llseek: no_llseek, -+ ioctl: rtc_ioctl, -+ open: rtc_open, -+ release: rtc_release, -+}; -+ -+#define RTC_MINOR 135 -+ -+static struct miscdevice rtc_dev= -+{ -+ RTC_MINOR, -+ "rtc", -+ &rtc_fops -+}; -+ -+int __init pcf_rtc_init(void) -+{ -+ int r; -+ unsigned char ctr; -+ r = misc_register(&rtc_dev); -+ -+ ctr = read_rtc(RTC_CONTROL); -+ write_rtc(RTC_CONTROL,0x00 ); -+ -+ read_rtcframe(); -+ CMOS_WRITE(RTC_STATUS, 0x00); -+ CMOS_WRITE(RTC_CLKOUT, 0x80); -+ /* RTC clock out, 32.768k */ -+ -+ CMOS_WRITE(RTC_TIMERCTL, 0x00); -+ CMOS_WRITE(RTC_TIMERCOUNTDOWN, 0x00); -+ write_rtcframe(); -+ -+ printk("PCF8563 RTC installed !!!\n"); -+ return 0; -+ -+} -+ -+void __exit pcf_rtc_exit (void) -+{ -+ misc_deregister(&rtc_dev); -+} -+ -+module_init(pcf_rtc_init); -+module_exit(pcf_rtc_exit); -diff -urN linux-2.6.24.7.old/drivers/i2c/busses/Kconfig linux-2.6.24.7/drivers/i2c/busses/Kconfig ---- linux-2.6.24.7.old/drivers/i2c/busses/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/i2c/busses/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -4,6 +4,14 @@ - - menu "I2C Hardware Bus support" - -+config I2C_JZ47XX -+ tristate "JZ47XX I2C Interface support" -+ depends on SOC_JZ4730 || SOC_JZ4740 -+ help -+ If you have devices in the Ingenic JZ4730/JZ4740 I2C bus, say yes to -+ this option. This driver can also be built as a module. If so, the -+ module will be called i2c-jz47xx. -+ - config I2C_ALI1535 - tristate "ALI 1535" - depends on PCI -diff -urN linux-2.6.24.7.old/drivers/i2c/busses/Makefile linux-2.6.24.7/drivers/i2c/busses/Makefile ---- linux-2.6.24.7.old/drivers/i2c/busses/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/i2c/busses/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -2,6 +2,7 @@ - # Makefile for the i2c bus drivers. - # - -+obj-$(CONFIG_I2C_JZ47XX) += i2c-jz47xx.o - obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o - obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o - obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o -diff -urN linux-2.6.24.7.old/drivers/i2c/busses/i2c-jz47xx.c linux-2.6.24.7/drivers/i2c/busses/i2c-jz47xx.c ---- linux-2.6.24.7.old/drivers/i2c/busses/i2c-jz47xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/i2c/busses/i2c-jz47xx.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,330 @@ -+/* -+ * i2c_jz47xx.c -+ * I2C adapter for the INGENIC I2C bus access. -+ * -+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include "i2c-jz47xx.h" -+ -+/* I2C protocol */ -+#define I2C_READ 1 -+#define I2C_WRITE 0 -+ -+#define TIMEOUT 1000 -+unsigned short sub_addr = 0; -+int addr_val = 0; -+struct jz_i2c { -+ spinlock_t lock; -+ wait_queue_head_t wait; -+ struct i2c_msg *msg; -+ unsigned int msg_num; -+ unsigned int slave_addr; -+ struct i2c_adapter adap; -+ struct clk *clk; -+}; -+ -+/* -+ * I2C bus protocol basic routines -+ */ -+static int i2c_put_data(unsigned char data) -+{ -+ unsigned int timeout = TIMEOUT*10; -+ -+ __i2c_write(data); -+ __i2c_set_drf(); -+ while (__i2c_check_drf() != 0); -+ while (!__i2c_transmit_ended()); -+ while (!__i2c_received_ack() && timeout) -+ timeout--; -+ -+ if (timeout) -+ return 0; -+ else -+ return -ETIMEDOUT; -+} -+ -+static int i2c_get_data(unsigned char *data, int ack) -+{ -+ int timeout = TIMEOUT*10; -+ -+ if (!ack) -+ __i2c_send_nack(); -+ else -+ __i2c_send_ack(); -+ -+ while (__i2c_check_drf() == 0 && timeout) -+ timeout--; -+ -+ if (timeout) { -+ if (!ack) -+ __i2c_send_stop(); -+ *data = __i2c_read(); -+ __i2c_clear_drf(); -+ return 0; -+ } else -+ return -ETIMEDOUT; -+} -+ -+/* -+ * I2C interface -+ */ -+void i2c_jz_setclk(unsigned int i2cclk) -+{ -+ __i2c_set_clk(jz_clocks.extalclk, i2cclk); -+} -+ -+static int xfer_read(unsigned char device, struct i2c_adapter *adap, unsigned char *buf, int length) -+{ -+ int cnt = length; -+ int timeout = 5; -+ -+ device = (0xa << 3) | ((sub_addr & 0x0700) >> 8); -+ sub_addr = sub_addr & 0xff; -+ -+L_try_again: -+ -+ if (timeout < 0) -+ goto L_timeout; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ if (addr_val) { -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_werr; -+ if (i2c_put_data(sub_addr) < 0) -+ goto address_err; -+ } -+ __i2c_send_start(); -+ -+ if (i2c_put_data((device << 1) | I2C_READ ) < 0) -+ goto device_rerr; -+ -+ __i2c_send_ack(); /* Master sends ACK for continue reading */ -+ __i2c_send_start(); -+ -+ while (cnt) { -+ if (cnt == 1) { -+ if (i2c_get_data(buf, 0) < 0) -+ break; -+ } else { -+ if (i2c_get_data(buf, 1) < 0) -+ break; -+ } -+ cnt--; -+ buf++; -+ } -+ addr_val = 0; -+ return length - cnt; -+ device_rerr: -+ device_werr: -+ address_err: -+ timeout --; -+ __i2c_send_stop(); -+ goto L_try_again; -+ -+L_timeout: -+ __i2c_send_stop(); -+ printk("Read I2C device 0x%2x failed.\n", device); -+ return -ENODEV; -+} -+ -+static int xfer_write(unsigned char device, struct i2c_adapter *adap, unsigned char *buf, int length) -+{ -+ int cnt = length; -+ int cnt_in_pg; -+ int timeout = 5; -+ unsigned char *tmpbuf; -+ unsigned char tmpaddr; -+ -+ device = (0xa << 3) | ((sub_addr & 0x0700) >> 8); -+ sub_addr = sub_addr & 0xff; -+ -+ __i2c_send_nack(); /* Master does not send ACK, slave sends it */ -+ -+ W_try_again: -+ if (timeout < 0) -+ goto W_timeout; -+ -+ cnt = length; -+ tmpbuf = (unsigned char *)buf; -+ tmpaddr = device; -+ start_write_page: -+ cnt_in_pg = 0; -+ __i2c_send_start(); -+ if (i2c_put_data( (device << 1) | I2C_WRITE ) < 0) -+ goto device_err; -+ if (addr_val) { -+ if (i2c_put_data(sub_addr) < 0) -+ goto address_err; -+ } -+ while (cnt) { -+ if (++cnt_in_pg > 8) { -+ __i2c_send_stop(); -+ mdelay(1); -+ sub_addr += 8; -+ goto start_write_page; -+ } -+ if (i2c_put_data(*tmpbuf) < 0) -+ break; -+ cnt--; -+ tmpbuf++; -+ } -+ __i2c_send_stop(); -+ addr_val = 0; -+ return length - cnt; -+ device_err: -+ address_err: -+ timeout--; -+ __i2c_send_stop(); -+ goto W_try_again; -+ -+W_timeout: -+ printk(KERN_DEBUG "Write I2C device 0x%2x failed.\n", device); -+ __i2c_send_stop(); -+ return -ENODEV; -+} -+ -+static int i2c_jz_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) -+{ -+ int ret, i; -+ -+ dev_dbg(&adap->dev, "jz47xx_xfer: processing %d messages:\n", num); -+ for (i = 0; i < num; i++) { -+ dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, -+ pmsg->flags & I2C_M_RD ? "read" : "writ", -+ pmsg->len, pmsg->len > 1 ? "s" : "", -+ pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); -+ if (pmsg->len && pmsg->buf) { /* sanity check */ -+ if (pmsg->flags & I2C_M_RD) -+ ret = xfer_read(pmsg->addr, adap, pmsg->buf, pmsg->len); -+ else -+ ret = xfer_write(pmsg->addr, adap, pmsg->buf, pmsg->len); -+ -+ if (ret) -+ return ret; -+ /* Wait until transfer is finished */ -+ } -+ dev_dbg(&adap->dev, "transfer complete\n"); -+ pmsg++; /* next message */ -+ } -+ return i; -+} -+ -+static u32 i2c_jz_functionality(struct i2c_adapter *adap) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -+} -+ -+static const struct i2c_algorithm i2c_jz_algorithm = { -+ .master_xfer = i2c_jz_xfer, -+ .functionality = i2c_jz_functionality, -+}; -+ -+static int i2c_jz_probe(struct platform_device *dev) -+{ -+ struct jz_i2c *i2c; -+ struct i2c_jz_platform_data *plat = dev->dev.platform_data; -+ int ret; -+ -+ __i2c_set_clk(jz_clocks.extalclk, 10000); /* default 10 KHz */ -+ __i2c_enable(); -+ -+ i2c = kzalloc(sizeof(struct jz_i2c), GFP_KERNEL); -+ if (!i2c) { -+ printk("There is no enough memory\n"); -+ ret = -ENOMEM; -+ goto emalloc; -+ } -+ -+ i2c->adap.owner = THIS_MODULE; -+ i2c->adap.algo = &i2c_jz_algorithm; -+ i2c->adap.retries = 5; -+ spin_lock_init(&i2c->lock); -+ init_waitqueue_head(&i2c->wait); -+ sprintf(i2c->adap.name, "jz_i2c-i2c.%u", dev->id); -+ i2c->adap.algo_data = i2c; -+ i2c->adap.dev.parent = &dev->dev; -+ -+ if (plat) { -+ i2c->adap.class = plat->class; -+ } -+ -+ /* -+ * If "dev->id" is negative we consider it as zero. -+ * The reason to do so is to avoid sysfs names that only make -+ * sense when there are multiple adapters. -+ */ -+ i2c->adap.nr = dev->id != -1 ? dev->id : 0; -+ /* ret = i2c_add_adapter(&i2c->adap); */ -+ ret = i2c_add_numbered_adapter(&i2c->adap); -+ if (ret < 0) { -+ printk(KERN_INFO "I2C: Failed to add bus\n"); -+ goto eadapt; -+ } -+ -+ platform_set_drvdata(dev, i2c); -+ dev_info(&dev->dev, "JZ47xx i2c bus driver.\n"); -+ return 0; -+eadapt: -+ __i2c_disable(); -+emalloc: -+ return ret; -+} -+ -+static int i2c_jz_remove(struct platform_device *dev) -+{ -+ struct i2c_adapter *adapter = platform_get_drvdata(dev); -+ int rc; -+ -+ rc = i2c_del_adapter(adapter); -+ platform_set_drvdata(dev, NULL); -+ return rc; -+} -+ -+static struct platform_driver i2c_jz_driver = { -+ .probe = i2c_jz_probe, -+ .remove = i2c_jz_remove, -+ .driver = { -+ .name = "jz_i2c", -+ }, -+}; -+ -+static int __init i2c_adap_jz_init(void) -+{ -+ return platform_driver_register(&i2c_jz_driver); -+} -+ -+static void __exit i2c_adap_jz_exit(void) -+{ -+ return platform_driver_unregister(&i2c_jz_driver); -+} -+ -+MODULE_LICENSE("GPL"); -+ -+module_init(i2c_adap_jz_init); -+module_exit(i2c_adap_jz_exit); -diff -urN linux-2.6.24.7.old/drivers/i2c/busses/i2c-jz47xx.h linux-2.6.24.7/drivers/i2c/busses/i2c-jz47xx.h ---- linux-2.6.24.7.old/drivers/i2c/busses/i2c-jz47xx.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/i2c/busses/i2c-jz47xx.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,20 @@ -+/* -+ * i2c_jz47xx.h -+ * -+ * 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 _I2C_JZ_H_ -+#define _I2C_JZ_H_ -+ -+struct i2c_slave_client; -+ -+struct i2c_jz_platform_data { -+ unsigned int slave_addr; -+ struct i2c_slave_client *slave; -+ unsigned int class; -+}; -+ -+extern void jz_set_i2c_info(struct i2c_jz_platform_data *info); -+#endif -diff -urN linux-2.6.24.7.old/drivers/i2c/i2c-dev.c linux-2.6.24.7/drivers/i2c/i2c-dev.c ---- linux-2.6.24.7.old/drivers/i2c/i2c-dev.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/i2c/i2c-dev.c 2009-04-12 18:13:57.000000000 +0200 -@@ -36,8 +36,9 @@ - #include - #include - -+extern unsigned short sub_addr; -+extern int addr_val; - static struct i2c_driver i2cdev_driver; -- - /* - * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a - * slave (i2c_client) with which messages will be exchanged. It's coupled -@@ -422,6 +423,14 @@ - case I2C_TIMEOUT: - client->adapter->timeout = arg; - break; -+ case I2C_SET_SUB_ADDRESS: -+ addr_val = 1; -+ sub_addr = arg; -+ break; -+ case I2C_SET_CLOCK: -+ i2c_jz_setclk(arg); -+ break; -+ - default: - /* NOTE: returning a fault code here could cause trouble - * in buggy userspace code. Some old kernel bugs returned -diff -urN linux-2.6.24.7.old/drivers/input/keyboard/Kconfig linux-2.6.24.7/drivers/input/keyboard/Kconfig ---- linux-2.6.24.7.old/drivers/input/keyboard/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/input/keyboard/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -259,9 +259,27 @@ - To compile this driver as a module, choose M here: the - module will be called aaed2000_kbd. - -+config KEYBOARD_JZ -+ tristate "JZ keypad support" -+ depends on JZSOC -+ help -+ Enable Y here to support JZ keypad. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called jz-keypad. -+ -+config 5x5_KEYBOARD_JZ -+ tristate "JZ 5x5 keypad support" -+ depends on JZSOC -+ help -+ Enable Y here to support JZ keypad. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called jz-keypad. -+ - config KEYBOARD_GPIO -- tristate "GPIO Buttons" -- depends on GENERIC_GPIO -+ tristate "JZ GPIO Buttons support" -+# depends on GENERIC_GPIO - help - This driver implements support for buttons connected - to GPIO pins of various CPUs (and some other chips). -@@ -272,7 +290,7 @@ - with configuration data saying which GPIOs are used. - - To compile this driver as a module, choose M here: the -- module will be called gpio-keys. -+ module will be called gpio_keys. - - config KEYBOARD_MAPLE - tristate "Maple bus keyboard" -diff -urN linux-2.6.24.7.old/drivers/input/keyboard/Makefile linux-2.6.24.7/drivers/input/keyboard/Makefile ---- linux-2.6.24.7.old/drivers/input/keyboard/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/input/keyboard/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -19,6 +19,8 @@ - obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o - obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o - obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o -+obj-$(CONFIG_KEYBOARD_JZ) += jz_keypad.o -+obj-$(CONFIG_5x5_KEYBOARD_JZ) += jz_keypad_5x5.o - obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o - obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o - obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o -diff -urN linux-2.6.24.7.old/drivers/input/keyboard/gpio_keys.c linux-2.6.24.7/drivers/input/keyboard/gpio_keys.c ---- linux-2.6.24.7.old/drivers/input/keyboard/gpio_keys.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/input/keyboard/gpio_keys.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1,7 +1,13 @@ - /* -- * Driver for keys on GPIO lines capable of generating interrupts. -+ * linux/drivers/input/keyboard/gpio_keys.c - * -- * Copyright 2005 Phil Blundell -+ * JZ GPIO Buttons driver for JZ4740 PAVO -+ * -+ * User applications can access to this device via /dev/input/eventX. -+ * -+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: Richard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -23,26 +29,131 @@ - #include - #include - #include -- - #include -+#include -+ -+ -+#define SCAN_INTERVAL (10) -+ -+/* -+ * GPIO Buttons -+ */ -+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) -+static struct gpio_keys_button pavo_buttons[] = { -+ { -+ .gpio = 96, -+ .code = KEY_1, -+ .desc = "Button 0", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 97, -+ .code = KEY_2, -+ .desc = "Button 1", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 98, -+ .code = KEY_3, -+ .desc = "Button 2", -+ .active_low = 1, -+ }, -+ { -+ .gpio = 99, -+ .code = KEY_4, -+ .desc = "Button 3", -+ .active_low = 1, -+ } -+}; -+ -+static struct timer_list button_timer; -+static spinlock_t gpio_lock; -+static int button_no; -+ -+static struct gpio_keys_platform_data pavo_button_data = { -+ .buttons = pavo_buttons, -+ .nbuttons = ARRAY_SIZE(pavo_buttons), -+}; -+ -+static struct platform_device pavo_button_device = { -+ .name = "gpio-keys", -+ .id = -1, -+ .num_resources = 0, -+ .dev = { -+ .platform_data = &pavo_button_data, -+ } -+}; -+ -+static void __init pavo_add_device_buttons(void) -+{ -+ __gpio_as_input(96); -+ __gpio_as_irq_fall_edge(96); -+ -+ __gpio_as_input(97); -+ __gpio_as_irq_fall_edge(97); -+ -+ __gpio_as_input(98); -+ __gpio_as_irq_fall_edge(98); -+ -+ __gpio_as_input(99); -+ __gpio_as_irq_fall_edge(99); -+ -+ platform_device_register(&pavo_button_device); -+} -+#else -+static void __init pavo_add_device_buttons(void) {} -+#endif -+ -+static void __init pavo_board_init(void) -+{ -+ /* Push Buttons */ -+ pavo_add_device_buttons(); -+} -+ -+static void button_timer_callback(unsigned long data) -+{ -+ unsigned long flags; -+ int gpio = pavo_buttons[button_no].gpio; -+ int code = pavo_buttons[button_no].code; -+ struct platform_device *pdev = (struct platform_device *)data; -+ struct input_dev *input = platform_get_drvdata(pdev); -+ int state; -+ -+ spin_lock_irqsave(&gpio_lock, flags); -+ state = __gpio_get_pin(gpio); -+ -+ if (state == 0) { -+ /* press down */ -+ input_report_key(input, code, 1); -+ input_sync(input); -+ mod_timer(&button_timer, jiffies + SCAN_INTERVAL); -+ } else { -+ /* up */ -+ input_report_key(input, code, 0); -+ input_sync(input); -+ udelay(1000); -+ __gpio_as_irq_fall_edge(gpio); -+ } -+ spin_unlock_irqrestore(&gpio_lock, flags); -+} - - static irqreturn_t gpio_keys_isr(int irq, void *dev_id) - { - int i; - struct platform_device *pdev = dev_id; - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; -- struct input_dev *input = platform_get_drvdata(pdev); - -+ __gpio_ack_irq(irq - IRQ_GPIO_0); - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int gpio = button->gpio; - -- if (irq == gpio_to_irq(gpio)) { -- unsigned int type = button->type ?: EV_KEY; -- int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low; -- -- input_event(input, type, button->code, !!state); -- input_sync(input); -+ if (irq == (gpio + IRQ_GPIO_0) ) { -+ /* start timer */ -+ __gpio_as_input(gpio); -+ button_no = i; -+ mod_timer(&button_timer, jiffies + 2 * SCAN_INTERVAL); -+ break; - } - } - -@@ -62,7 +173,7 @@ - - platform_set_drvdata(pdev, input); - -- input->evbit[0] = BIT_MASK(EV_KEY); -+ spin_lock_init(&gpio_lock); - - input->name = pdev->name; - input->phys = "gpio-keys/input0"; -@@ -72,56 +183,42 @@ - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = 0x0100; -+ input->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN) | BIT(EV_REP); - - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - int irq; - unsigned int type = button->type ?: EV_KEY; - -- error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); -- if (error < 0) { -- pr_err("gpio-keys: failed to request GPIO %d," -- " error %d\n", button->gpio, error); -- goto fail; -- } -- -- error = gpio_direction_input(button->gpio); -- if (error < 0) { -- pr_err("gpio-keys: failed to configure input" -- " direction for GPIO %d, error %d\n", -- button->gpio, error); -- gpio_free(button->gpio); -- goto fail; -- } -- -- irq = gpio_to_irq(button->gpio); -+ irq = IRQ_GPIO_0 + button->gpio; - if (irq < 0) { - error = irq; - pr_err("gpio-keys: Unable to get irq number" - " for GPIO %d, error %d\n", - button->gpio, error); -- gpio_free(button->gpio); - goto fail; - } - - error = request_irq(irq, gpio_keys_isr, -- IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | -- IRQF_TRIGGER_FALLING, -+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED, - button->desc ? button->desc : "gpio_keys", - pdev); - if (error) { - pr_err("gpio-keys: Unable to claim irq %d; error %d\n", - irq, error); -- gpio_free(button->gpio); - goto fail; - } - - if (button->wakeup) - wakeup = 1; -- - input_set_capability(input, type, button->code); - } - -+ /* Init timer */ -+ init_timer(&button_timer); -+ button_timer.data = (unsigned long)&pavo_button_device; -+ button_timer.function = button_timer_callback; -+ - error = input_register_device(input); - if (error) { - pr_err("gpio-keys: Unable to register input device, " -@@ -135,8 +232,7 @@ - - fail: - while (--i >= 0) { -- free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); -- gpio_free(pdata->buttons[i].gpio); -+ free_irq(pdata->buttons[i].gpio + IRQ_GPIO_0 , pdev); - } - - platform_set_drvdata(pdev, NULL); -@@ -154,9 +250,8 @@ - device_init_wakeup(&pdev->dev, 0); - - for (i = 0; i < pdata->nbuttons; i++) { -- int irq = gpio_to_irq(pdata->buttons[i].gpio); -+ int irq = pdata->buttons[i].gpio + IRQ_GPIO_0; - free_irq(irq, pdev); -- gpio_free(pdata->buttons[i].gpio); - } - - input_unregister_device(input); -@@ -175,7 +270,7 @@ - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { -- int irq = gpio_to_irq(button->gpio); -+ int irq = button->gpio + IRQ_GPIO_0; - enable_irq_wake(irq); - } - } -@@ -193,7 +288,7 @@ - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { -- int irq = gpio_to_irq(button->gpio); -+ int irq = button->gpio + IRQ_GPIO_0; - disable_irq_wake(irq); - } - } -@@ -218,11 +313,13 @@ - - static int __init gpio_keys_init(void) - { -+ pavo_board_init(); - return platform_driver_register(&gpio_keys_device_driver); - } - - static void __exit gpio_keys_exit(void) - { -+ platform_device_unregister(&pavo_button_device); - platform_driver_unregister(&gpio_keys_device_driver); - } - -diff -urN linux-2.6.24.7.old/drivers/input/keyboard/jz_keypad.c linux-2.6.24.7/drivers/input/keyboard/jz_keypad.c ---- linux-2.6.24.7.old/drivers/input/keyboard/jz_keypad.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/input/keyboard/jz_keypad.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,357 @@ -+/* -+ * linux/drivers/input/keyboard/jz_keypad.c -+ * -+ * JZ Keypad Driver -+ * -+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: Richard -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#define KB_ROWS 3 -+#define KB_COLS 3 -+ -+#define SCAN_INTERVAL (10) -+ -+static unsigned short col[KB_COLS] = {85,87,91}; -+static unsigned short row[KB_ROWS] = {60,61,62}; -+static unsigned short s0[KB_COLS]; -+static unsigned short s1[KB_COLS]={7,7,7}; -+static unsigned short precol,prerow; -+ -+static const unsigned int jz_kbd_keycode[KB_COLS * KB_ROWS] = { -+ KEY_1, KEY_4, KEY_7, -+ KEY_2, KEY_5, 0, -+ KEY_3, KEY_6, 0, -+}; -+ -+struct jz_kbd { -+ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)]; -+ struct input_dev *input; -+ char phys[32]; -+ -+ spinlock_t lock; -+ struct timer_list timer; -+ -+ unsigned int suspended; -+ unsigned long suspend_jiffies; -+}; -+ -+static struct jz_kbd g_jz_kbd; -+ -+static inline void jz_scan_kbd(unsigned short *s) -+{ -+ int i; -+ -+ if (!s) -+ return; -+ -+ for (i = 0; i < KB_COLS; i++) { -+ -+ __gpio_as_input(85); /* row */ -+ __gpio_as_input(87); /* row */ -+ __gpio_as_input(91); /* row */ -+ -+ __gpio_as_input(60); /* col */ -+ __gpio_as_input(61); /* col */ -+ __gpio_as_input(62); /* col */ -+ -+ __gpio_clear_pin(col[i]); -+ __gpio_as_output(col[i]); -+ -+ udelay(1000); -+ s[i]=(__gpio_get_pin(60) << 0) | (__gpio_get_pin(61) << 1) | -+ (__gpio_get_pin(62) << 2); -+ } -+} -+ -+static void jz_kbd_scankeyboard(struct jz_kbd *kbd_data) -+{ -+ unsigned int row,col; -+ unsigned long flags; -+ unsigned int num_pressed; -+ -+ if (kbd_data->suspended) -+ return; -+ -+ spin_lock_irqsave(&kbd_data->lock, flags); -+ -+ num_pressed = 0; -+ jz_scan_kbd(s0); -+ -+ /* look for key if pressed down on not, col & row */ -+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 7) { -+ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) { -+ /* up */ -+ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0); -+ input_sync(kbd_data->input); -+ } -+ precol = prerow = -1; -+ s1[0] = s1[1] = s1[2] = 7; -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+ } -+ -+ if (s0[0] == 6 && s0[1] == 7 && s0[2] == 7) { -+ row = 0;//K7 -+ col = 2; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 3 && s0[2] == 7) { -+ row = 2;//k6 -+ col = 1; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 5 && s0[2] == 7) { -+ row = 1;//k5 -+ col = 1; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 6 && s0[2] == 7) { -+ row = 0;//k4 -+ col = 1; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 3) { -+ row = 2;//k3 -+ col = 0; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 5) { -+ row = 1;//k2 -+ col = 0; -+ goto find_row_col; -+ } -+ if (s0[0] == 7 && s0[1] == 7 && s0[2] == 6) { -+ row = 0;//k1 -+ col = 0; -+ goto find_row_col; -+ } -+ /* 2 or 3 buttons are pressed */ -+ s0[0] = s0[1] = s0[2] = 7; -+ s1[0] = s1[1] = s1[2] = 7; -+ prerow = precol = -1; -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+find_row_col: -+ if (s1[0] == 7 && s1[1] == 7 && s1[2] == 7) { -+ /* down */ -+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); -+ input_sync(kbd_data->input); -+ s1[0] = s0[0]; -+ s1[1] = s0[1]; -+ s1[2] = s0[2]; -+ -+ precol = col; -+ prerow = row; -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+ } -+ if (s1[0] != 7 || s1[1] != 7 || s1[2] != 7) { -+ /* is the same as the preview key */ -+ if (s0[0] == s1[0] && s0[1] == s1[1] && s0[2] == s1[2]) { -+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); -+ input_sync(kbd_data->input); -+ s1[0] = s0[0]; -+ s1[1] = s0[1]; -+ s1[2] = s0[2]; -+ -+ precol = col; -+ prerow = row; -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+ } else { -+ /* the preview key is up and other key is down */ -+ if (s0[0] != s1[0] || s0[1] != s1[1] || s0[2] != s1[2]) { -+ input_report_key(kbd_data->input, kbd_data->keycode[prerow * KB_COLS + precol], 0); -+ input_sync(kbd_data->input); -+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); -+ input_sync(kbd_data->input); -+ s1[0] = s0[0]; -+ s1[1] = s0[1]; -+ s1[2] = s0[2]; -+ precol = col; -+ prerow = row; -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+ } -+ } -+ } -+} -+ -+static void jz_kbd_timer_callback(unsigned long data) -+{ -+ jz_kbd_scankeyboard(&g_jz_kbd); -+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); -+} -+ -+#ifdef CONFIG_PM -+static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ jz_kbd->suspended = 1; -+ -+ return 0; -+} -+ -+static int jz_kbd_resume(struct platform_device *dev) -+{ -+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ -+ jz_kbd->suspend_jiffies = jiffies; -+ jz_kbd->suspended = 0; -+ -+ return 0; -+} -+#else -+#define jz_kbd_suspend NULL -+#define jz_kbd_resume NULL -+#endif -+ -+static int __init jz_kbd_probe(struct platform_device *dev) -+{ -+ struct input_dev *input_dev; -+ int i, error; -+ -+ input_dev = input_allocate_device(); -+ if (!input_dev) -+ return -ENOMEM; -+ -+ platform_set_drvdata(dev, &g_jz_kbd); -+ -+ strcpy(g_jz_kbd.phys, "input/kbd0"); -+ -+ spin_lock_init(&g_jz_kbd.lock); -+ -+ g_jz_kbd.suspend_jiffies = jiffies; -+ g_jz_kbd.input = input_dev; -+ -+ input_dev->private = &g_jz_kbd; -+ input_dev->name = "JZ Keypad"; -+ input_dev->phys = g_jz_kbd.phys; -+ input_dev->cdev.dev = &dev->dev; -+ -+ input_dev->id.bustype = BUS_PARPORT; -+ input_dev->id.vendor = 0x0001; -+ input_dev->id.product = 0x0001; -+ input_dev->id.version = 0x0100; -+ -+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN); -+ input_dev->keycode = g_jz_kbd.keycode; /* keycode array address */ -+ input_dev->keycodesize = sizeof(unsigned int); -+ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode); -+ -+ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode)); -+ -+ for (i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++) -+ set_bit(g_jz_kbd.keycode[i], input_dev->keybit); -+ -+ //clear_bit(0, input_dev->keybit); -+ -+ __gpio_as_input(85); -+ __gpio_as_input(87); -+ __gpio_as_input(91); -+ -+#if 0 -+ __gpio_as_input(60); -+ __gpio_as_input(61); -+ __gpio_as_input(62); -+#endif -+ -+ /* Init Keyboard rescan timer */ -+ init_timer(&g_jz_kbd.timer); -+ g_jz_kbd.timer.function = jz_kbd_timer_callback; -+ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd; -+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); -+ -+ error = input_register_device(input_dev); -+ if (error) { -+ pr_err("gpio-keys: Unable to register input device, " -+ "error: %d\n", error); -+ } -+ printk("input: JZ Keypad Registered\n"); -+ -+ return 0; -+} -+ -+static int jz_kbd_remove(struct platform_device *dev) -+{ -+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ -+ del_timer_sync(&jz_kbd->timer); -+ -+ __gpio_as_input(85); -+ __gpio_as_input(87); -+ __gpio_as_input(91); -+ -+ /* These pins is conficting with cs8900a's CS RD WE pins on JZ4740-PAVO board */ -+ __gpio_as_input(60); -+ __gpio_as_input(61); -+ __gpio_as_input(62); -+ -+ input_unregister_device(jz_kbd->input); -+ -+ return 0; -+} -+ -+static struct platform_driver jz_kbd_driver = { -+ .probe = jz_kbd_probe, -+ .remove = jz_kbd_remove, -+ .suspend = jz_kbd_suspend, -+ .resume = jz_kbd_resume, -+ .driver = { -+ .name = "jz-keypad", -+ }, -+}; -+ -+/* -+ * Jz Keyboard Device -+ */ -+static struct platform_device jzkbd_device = { -+ .name = "jz-keypad", -+ .id = -1, -+}; -+ -+static int __init jz_kbd_init(void) -+{ -+ platform_device_register(&jzkbd_device); -+ return platform_driver_register(&jz_kbd_driver); -+} -+ -+static void __exit jz_kbd_exit(void) -+{ -+ platform_device_unregister(&jzkbd_device); -+ platform_driver_unregister(&jz_kbd_driver); -+} -+ -+module_init(jz_kbd_init); -+module_exit(jz_kbd_exit); -+ -+MODULE_AUTHOR("Richard"); -+MODULE_DESCRIPTION("JZ keypad driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/input/keyboard/jz_keypad_5x5.c linux-2.6.24.7/drivers/input/keyboard/jz_keypad_5x5.c ---- linux-2.6.24.7.old/drivers/input/keyboard/jz_keypad_5x5.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/input/keyboard/jz_keypad_5x5.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,329 @@ -+/* -+ * JZ Keypad ( 5 x 5 ) Driver -+ * -+ * Copyright (c) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: Jason 20090210 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define KB_ROWS 5 -+#define KB_COLS 5 -+ -+#define SCAN_INTERVAL (10) -+ -+#define ROW_KEYBIT_MASK 0xFFE0 -+ -+#define SET_GPIOS_AS_INPUT() \ -+do { \ -+ unsigned short i; \ -+ \ -+ for (i = 0; i < KB_ROWS; i++) { \ -+ __gpio_as_input(jz_row_gpios[i]); \ -+ __gpio_as_input(jz_col_gpios[i]); \ -+ } \ -+} while (0) -+ -+ -+#define GET_ROW_GPIO_PINS() \ -+({ \ -+ unsigned short _pins = 0, i; \ -+ for (i = 0; \ -+ i < KB_ROWS; \ -+ _pins |= __gpio_get_pin(jz_row_gpios[i]) << i, i++) \ -+ ; \ -+ _pins; \ -+}) -+ -+#define CHECK_IF_KEY_PRESSED(s) \ -+({ \ -+ unsigned short i; \ -+ for (i = 0; i < KB_COLS && s[i] == 0x1F ; i++) \ -+ ; \ -+ i != KB_ROWS; \ -+}) -+ -+#define CLEAN_SCAN_RESULT(s) \ -+do { \ -+ unsigned short i; \ -+ for (i = 0; i < KB_COLS; s[i++] = 0x1F) \ -+ ; \ -+} while (0) -+ -+ -+static const unsigned short jz_col_gpios[KB_ROWS] = {76, 75, 74, 73, 72}; -+static const unsigned short jz_row_gpios[KB_COLS] = {181, 182, 79, 78, 77}; -+ -+static const unsigned int jz_kbd_keycode[KB_ROWS * KB_COLS] = { -+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, -+ KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, -+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, -+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, -+ KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_SPACE, KEY_BACKSPACE, KEY_Y -+}; -+ -+struct jz_kbd { -+ unsigned int keycode[ARRAY_SIZE(jz_kbd_keycode)]; -+ struct input_dev *input; -+ char phys[32]; -+ -+ spinlock_t lock; -+ struct timer_list timer; -+ -+ unsigned int suspended; -+ unsigned long suspend_jiffies; -+}; -+static struct jz_kbd g_jz_kbd; -+ -+static unsigned short scan_result[KB_COLS]; -+static unsigned short pre_scan_result[KB_COLS] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; -+static unsigned short pre_col, pre_row; -+ -+/** -+ * Scan keypad by reading GPIO pins. -+ */ -+static inline void jz_do_scan(unsigned short *s) -+{ -+ unsigned short i; -+ -+ if (!s) -+ return ; -+ -+ for (i = 0; i < KB_COLS; i++) { -+ -+ SET_GPIOS_AS_INPUT(); -+ __gpio_clear_pin(jz_col_gpios[i]); -+ __gpio_as_output(jz_col_gpios[i]); -+ -+ udelay(1000); -+ -+ s[i] = GET_ROW_GPIO_PINS(); -+ } -+} -+ -+/** -+ * Call scan function and handle 'GPIO event'(like key down, key up), -+ * and report it to upper layer of input subsystem ... if necessary -+ */ -+static void jz_kbd_scan(struct jz_kbd *kbd_data) -+{ -+ unsigned short row, col, i; -+ unsigned long flags; -+ -+ if (kbd_data->suspended) -+ return; -+ -+ spin_lock_irqsave(&kbd_data->lock, flags); -+ -+ jz_do_scan(scan_result); -+ -+ /* check if any key was pressed or not */ -+ if (!CHECK_IF_KEY_PRESSED(scan_result)) { -+ -+ /* key up */ -+ if (CHECK_IF_KEY_PRESSED(pre_scan_result)) { -+ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + pre_col], 0); -+ input_sync(kbd_data->input); -+ } -+ pre_col = pre_row = 0xFFFF; -+ CLEAN_SCAN_RESULT(pre_scan_result); -+ -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ return; -+ } -+ -+ /* find the key */ -+ for (row = 0; row < KB_ROWS; row++) { -+ for (i = scan_result[row], col = 0; col < KB_COLS; col++) { -+ if ( !(i & 0x01) ) -+ break; -+ i >>= 1; -+ } -+ if (col != KB_COLS) -+ break; -+ } -+ -+ //printk("[DRIVER] row = %d, col = %d, key code: 0x%02X\n", row, col, kbd_data->keycode[row * KB_COLS + col]); -+ -+ /* the same as the preview one || new key */ -+ if ( (col == pre_col && row == pre_row) -+ || (pre_col == 0xFFFF && pre_row == 0xFFFF) ) { -+ -+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); -+ input_sync(kbd_data->input); -+ -+ } else { -+ /* the preview key is up and other key is down */ -+ input_report_key(kbd_data->input, kbd_data->keycode[pre_row * KB_COLS + col], 0); -+ input_sync(kbd_data->input); -+ input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + col], 1); -+ input_sync(kbd_data->input); -+ } -+ -+ for (i = 0; i < KB_ROWS; i++) { -+ pre_scan_result[i] = scan_result[i]; -+ } -+ -+ pre_col = col; -+ pre_row = row; -+ -+ spin_unlock_irqrestore(&kbd_data->lock, flags); -+ -+ return; -+} -+ -+static void jz_kbd_timer_callback(unsigned long data) -+{ -+ jz_kbd_scan(&g_jz_kbd); -+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); -+} -+ -+#ifdef CONFIG_PM -+static int jz_kbd_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ jz_kbd->suspended = 1; -+ -+ return 0; -+} -+ -+static int jz_kbd_resume(struct platform_device *dev) -+{ -+ struct jz_kbd *jz_kbd = platform_get_drvdata(dev); -+ -+ jz_kbd->suspend_jiffies = jiffies; -+ jz_kbd->suspended = 0; -+ -+ return 0; -+} -+ -+#else -+#define jz_kbd_suspend NULL -+#define jz_kbd_resume NULL -+#endif -+ -+/** -+ * Driver init -+ */ -+static int __init jz_kbd_probe(struct platform_device *dev) -+{ -+ struct input_dev *input_dev; -+ int i, error; -+ -+ input_dev = input_allocate_device(); -+ if (!input_dev) -+ return -ENOMEM; -+ -+ platform_set_drvdata(dev, &g_jz_kbd); -+ -+ strcpy(g_jz_kbd.phys, "input/kbd0"); -+ -+ spin_lock_init(&g_jz_kbd.lock); -+ -+ g_jz_kbd.suspend_jiffies = jiffies; -+ g_jz_kbd.input = input_dev; -+ -+ input_dev->private = &g_jz_kbd; -+ input_dev->name = "JZ 5x5 Keypad"; -+ input_dev->phys = g_jz_kbd.phys; -+ input_dev->cdev.dev = &dev->dev; -+ -+ input_dev->id.bustype = BUS_PARPORT; -+ input_dev->id.vendor = 0x0001; -+ input_dev->id.product = 0x0001; -+ input_dev->id.version = 0x0100; -+ -+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN); -+ input_dev->keycode = g_jz_kbd.keycode; -+ input_dev->keycodesize = sizeof(unsigned int); -+ input_dev->keycodemax = ARRAY_SIZE(jz_kbd_keycode); -+ -+ memcpy(g_jz_kbd.keycode, jz_kbd_keycode, sizeof(g_jz_kbd.keycode)); -+ -+ for ( i = 0; i < ARRAY_SIZE(jz_kbd_keycode); i++) -+ set_bit(g_jz_kbd.keycode[i], input_dev->keybit); -+ -+ init_timer(&g_jz_kbd.timer); -+ g_jz_kbd.timer.function = jz_kbd_timer_callback; -+ g_jz_kbd.timer.data = (unsigned long)&g_jz_kbd; -+ mod_timer(&g_jz_kbd.timer, jiffies + SCAN_INTERVAL); -+ -+ error = input_register_device(input_dev); -+ if (error) { -+ pr_err("gpio-keys: Unable to register input device, " -+ "error: %d\n", error); -+ } -+ printk("input: JZ 5x5 Keypad Registered.\n"); -+ -+ return 0; -+} -+ -+static int jz_kbd_remove(struct platform_device *dev) -+{ -+ struct jz_kbd *kbd = platform_get_drvdata(dev); -+ -+ del_timer_sync(&kbd->timer); -+ -+ SET_GPIOS_AS_INPUT(); -+ -+ input_unregister_device(kbd->input); -+ -+ return 0; -+} -+ -+static struct platform_driver jz_kbd_driver = { -+ .probe = jz_kbd_probe, -+ .remove = jz_kbd_remove, -+ .suspend= jz_kbd_suspend, -+ .resume = jz_kbd_resume, -+ .driver = { -+ .name = "jz-5x5-keypad", -+ }, -+}; -+ -+static struct platform_device jzkbd_device = { -+ .name = "jz-5x5-keypad", -+ .id = -1, -+}; -+ -+static int __init jz_kbd_init(void) -+{ -+ platform_device_register(&jzkbd_device); -+ return platform_driver_register(&jz_kbd_driver); -+} -+ -+static void __exit jz_kbd_exit(void) -+{ -+ platform_device_unregister(&jzkbd_device); -+ platform_driver_unregister(&jz_kbd_driver); -+} -+ -+module_init(jz_kbd_init); -+module_exit(jz_kbd_exit); -+ -+MODULE_AUTHOR("Jason "); -+MODULE_DESCRIPTION("JZ 5x5 keypad driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/media/video/Kconfig linux-2.6.24.7/drivers/media/video/Kconfig ---- linux-2.6.24.7.old/drivers/media/video/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/media/video/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -514,6 +514,15 @@ - Say Y here to build in support for the Vino video input system found - on SGI Indy machines. - -+config VIDEO_JZ_CIM -+ tristate 'JzSOC Camera Interface Module (CIM) support' -+ depends on VIDEO_V4L2 -+ select VIDEO_JZ_SENSOR -+ -+config VIDEO_JZ_SENSOR -+ tristate "Jz generic camera sensor driver" -+ depends on VIDEO_JZ_CIM -+ - config VIDEO_STRADIS - tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS -diff -urN linux-2.6.24.7.old/drivers/media/video/Makefile linux-2.6.24.7/drivers/media/video/Makefile ---- linux-2.6.24.7.old/drivers/media/video/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/media/video/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -15,6 +15,9 @@ - obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o - endif - -+obj-$(CONFIG_VIDEO_JZ_CIM) += jz_cim.o -+obj-$(CONFIG_VIDEO_JZ_SENSOR) += jz_sensor.o -+ - obj-$(CONFIG_VIDEO_BT848) += bt8xx/ - obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o - obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o -diff -urN linux-2.6.24.7.old/drivers/media/video/jz_cim.c linux-2.6.24.7/drivers/media/video/jz_cim.c ---- linux-2.6.24.7.old/drivers/media/video/jz_cim.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/media/video/jz_cim.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,622 @@ -+/* -+ * linux/drivers/char/jzchar/cim.c -+ * -+ * Camera Interface Module (CIM) driver for JzSOC -+ * This driver is independent of the camera sensor -+ * -+ * Copyright (C) 2005 JunZheng semiconductor -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software Foundation, -+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+//#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define CIM_NAME "cim" -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("JzSOC Camera Interface Module driver"); -+MODULE_LICENSE("GPL"); -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+/* -+ * Define the Max Image Size -+ */ -+#define MAX_IMAGE_WIDTH 2048 -+#define MAX_IMAGE_HEIGHT 2048 -+#define MAX_IMAGE_BPP 16 -+#define MAX_FRAME_SIZE (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8) -+#define CIM_RAM_ADDR (CIM_BASE + 0x1000) -+ -+typedef struct -+{ -+ u32 width; -+ u32 height; -+ u32 bpp; -+} img_param_t; -+ -+typedef struct -+{ -+ u32 cfg; -+ u32 ctrl; -+ u32 mclk; -+} cim_config_t; -+ -+/* -+ * IOCTL_XXX commands -+ */ -+#define IOCTL_SET_IMG_PARAM 0 // arg type: img_param_t * -+#define IOCTL_CIM_CONFIG 1 // arg type: cim_config_t * -+#define IOCTL_STOP_CIM 2 // arg type: void -+#define IOCTL_GET_IMG_PARAM 3 // arg type: img_param_t * -+#define IOCTL_GET_CIM_CONFIG 4 // arg type: cim_config_t * -+#define IOCTL_TEST_CIM_RAM 5 // no arg type * -+ -+/* -+ * CIM DMA descriptor -+ */ -+struct cim_desc { -+ u32 nextdesc; /* Physical address of next desc */ -+ u32 framebuf; /* Physical address of frame buffer */ -+ u32 frameid; /* Frame ID */ -+ u32 dmacmd; /* DMA command */ -+ u32 pagenum; -+}; -+ -+/* -+ * CIM device structure -+ */ -+struct cim_device { -+ struct video_device *jz_cim; -+ unsigned char *framebuf; -+ unsigned int frame_size; -+ unsigned int page_order; -+ wait_queue_head_t wait_queue; -+ struct cim_desc *frame_desc __attribute__ ((aligned (16))); -+}; -+ -+/* global*/ -+static struct cim_device *cim_dev; -+ -+/*========================================================================== -+ * CIM init routines -+ *========================================================================*/ -+#if defined(CONFIG_SOC_JZ4750) -+static void cim_image_area(img_param_t *c) { -+ /*set the image data area start 0, 0, lines_per_frame and pixels_per_line*/ -+ REG_CIM_SIZE = 0; -+ REG_CIM_OFFSET = 0; -+ if (REG_CIM_CTRL & CIM_CTRL_SIZEEN_MASK) { -+ REG_CIM_SIZE = (c->height << CIM_SIZE_LPF_BIT) | (c->width << CIM_SIZE_PPL_BIT); -+ REG_CIM_OFFSET = (0 << CIM_OFFSET_V_BIT) | (0 << CIM_OFFSET_H_BIT); -+// REG_CIM_OFFSET = (100 << CIM_OFFSET_V_BIT) | (50 << CIM_OFFSET_H_BIT); -+ } -+} -+#endif -+ -+static void cim_config(cim_config_t *c) -+{ -+ REG_CIM_CFG = c->cfg; -+ REG_CIM_CTRL = c->ctrl; -+ -+ /*Set the master clock output*/ -+#if defined(CONFIG_SOC_JZ4730) -+ __cim_set_master_clk(__cpm_get_sclk(), c->mclk); -+#elif defined(CONFIG_SOC_JZ4740) -+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); -+#elif defined(CONFIG_SOC_JZ4750) -+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); -+#else -+ __cim_set_master_clk(__cpm_get_hclk(), c->mclk); -+#endif -+ /* Enable sof, eof and stop interrupts*/ -+ __cim_enable_sof_intr(); -+ __cim_enable_eof_intr(); -+ __cim_enable_stop_intr(); -+} -+ -+/*========================================================================== -+ * CIM start/stop operations -+ *========================================================================*/ -+static int cim_start_dma(char *ubuf) -+{ -+ struct cim_desc *jz_frame_desc; -+ int cim_frame_size = 0; -+ jz_frame_desc = cim_dev->frame_desc; -+ dprintk("framedesc = %x\n", (u32) jz_frame_desc); -+ __cim_disable(); -+ dprintk("__cim_disable\n"); -+ __cim_set_da(virt_to_phys(cim_dev->frame_desc)); -+ __cim_clear_state(); // clear state register -+ __cim_reset_rxfifo(); // resetting rxfifo -+ __cim_unreset_rxfifo(); -+ __cim_enable_dma(); // enable dma -+ __cim_enable(); -+ -+ dprintk("__cim_enable\n"); -+// while(1) { -+// mdelay(10); -+// dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); -+// dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); -+// dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); -+// dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); -+// dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); -+// dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); -+// dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); -+// dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); -+// dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); -+// mdelay(100); -+// } -+ // wait for interrupts -+ interruptible_sleep_on(&cim_dev->wait_queue); -+ dprintk("interruptible_sleep_on\n"); -+ dprintk("REG_CIM_DA = 0x%08x\n", REG_CIM_DA); -+ dprintk("REG_CIM_FA = 0x%08x\n", REG_CIM_FA); -+ dprintk("REG_CIM_FID = 0x%08x\n", REG_CIM_FID); -+ dprintk("REG_CIM_CMD = 0x%08x\n", REG_CIM_CMD); -+ dprintk("REG_CIM_CFG = 0x%08x\n", REG_CIM_CFG); -+ dprintk("REG_CIM_STATE = 0x%08x\n", REG_CIM_STATE); -+ dprintk("REG_CIM_CTRL = 0x%08x\n", REG_CIM_CTRL); -+ dprintk("REG_CIM_SIZE = 0x%08x\n", REG_CIM_SIZE); -+ dprintk("REG_CIM_OFFSET = 0x%08x\n", REG_CIM_OFFSET); -+ dprintk("REG_CIM_CMD_3 = %x\n", REG_CIM_CMD); -+ dprintk("REG_CIM_FA = %x\n", REG_CIM_FA); -+ /* copy frame data to user buffer */ -+ jz_frame_desc = cim_dev->frame_desc; -+ -+ while(jz_frame_desc != NULL) -+ { -+ dprintk("ubuf = %x, framebuf = %x,frame_size= %d\n", (u32)ubuf,(u32) jz_frame_desc->framebuf, jz_frame_desc->dmacmd & 0xffffff); -+ memcpy(ubuf, phys_to_virt(jz_frame_desc->framebuf), ((jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4)); -+ ubuf += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; -+ cim_frame_size += (jz_frame_desc->dmacmd & CIM_CMD_LEN_MASK) * 4; -+ jz_frame_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); -+ } -+ return cim_dev->frame_size; -+} -+static void cim_stop(void) -+{ -+ __cim_disable(); -+ __cim_clear_state(); -+} -+ -+/*========================================================================== -+ * Framebuffer allocation and destroy -+ *========================================================================*/ -+static void cim_fb_destroy(void) -+{ -+ int pages; -+ struct cim_desc *jz_frame_desc, *p_desc; -+ if (cim_dev->frame_desc == NULL) { -+ printk("Original memory is NULL\n"); -+ return; -+ } -+ jz_frame_desc = cim_dev->frame_desc; -+ while (jz_frame_desc != NULL) { -+ dprintk("framebuf = %x,thisdesc = %x,frame_size= %d\n", (u32) jz_frame_desc->framebuf, (unsigned int)jz_frame_desc, (jz_frame_desc->dmacmd & 0xffffff) * 4); -+ p_desc = (struct cim_desc *)phys_to_virt(jz_frame_desc->nextdesc); -+ pages = jz_frame_desc->pagenum; -+ dprintk("page_order = %d\n", pages); -+ free_pages((unsigned long)phys_to_virt(jz_frame_desc->framebuf), pages); -+ kfree(jz_frame_desc); -+ jz_frame_desc = p_desc; -+ } -+ cim_dev->frame_desc = NULL; -+} -+ -+static struct cim_desc *get_desc_list(int page_order) -+{ -+ int num, page_nums = 0; -+ unsigned char *p_buf; -+ struct cim_desc *desc_list_head __attribute__ ((aligned (16))); -+ struct cim_desc *desc_list_tail __attribute__ ((aligned (16))); -+ struct cim_desc *p_desc; -+// num = page_order - 1; -+ num = page_order; -+ desc_list_head = desc_list_tail = NULL; -+ -+ while(page_nums < (1 << page_order)) { -+ p_desc = (struct cim_desc *)kmalloc(sizeof(struct cim_desc), GFP_KERNEL); -+ if (NULL == p_desc) -+ return NULL; -+ //return -ENOMEM; -+ cim_realloc_pages: -+ p_buf = (unsigned char *)__get_free_pages(GFP_KERNEL, num); -+ if ( !(p_buf) && num != 0) { -+ num --; -+ goto cim_realloc_pages; -+ } -+ else if ( !(p_buf) && num == 0) { -+ printk("No memory can be alloc!\n"); -+ //return -ENOMEM; -+ return NULL; -+ } -+ else { -+ if (desc_list_head == NULL) { -+ dprintk("Page_list_head\n"); -+ desc_list_head = p_desc; -+ } -+ -+ else -+ desc_list_tail->nextdesc = virt_to_phys(p_desc); -+ -+ desc_list_tail = p_desc; -+ desc_list_tail->framebuf = virt_to_phys(p_buf); -+ dprintk("framebuf addr is 0x%08x\n", (u32)desc_list_tail->framebuf); -+ dprintk("frame_desc addr is 0x%08x\n",(u32)virt_to_phys(desc_list_tail)); -+ -+ desc_list_tail->frameid = 0x52052018; -+ desc_list_tail->pagenum = num; -+ if ((page_nums + (1<< num)) < (1 << page_order)) { -+ desc_list_tail->dmacmd = ((1 << num) * 4096) >> 2 ; -+ } -+ else -+ desc_list_tail->dmacmd = -+ (cim_dev->frame_size - page_nums * 4096) >> 2 ; -+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); -+ page_nums += (1 << num); -+ dprintk("the pages_num is %d\n", page_nums); -+ } -+ } -+ -+ desc_list_tail->nextdesc = virt_to_phys(NULL); -+ /* stop after capturing a frame */ -+ desc_list_tail->dmacmd |= (CIM_CMD_STOP | CIM_CMD_EOFINT); -+ dprintk("the desc_list_tail->dmacmd is 0x%08x\n", desc_list_tail->dmacmd); -+ -+ return desc_list_head; -+} -+ -+static int cim_fb_alloc(int img_width, int img_height, int img_bpp) -+{ -+#if defined(CONFIG_SOC_JZ4750) -+ if ((REG_CIM_CFG & (CIM_CFG_DF_MASK | CIM_CFG_BYPASS_MASK)) == 0) -+ cim_dev->frame_size = img_width * (img_height-1) * (img_bpp/8); -+ else -+ cim_dev->frame_size = img_width * img_height * (img_bpp/8); -+#else -+ cim_dev->frame_size = img_width * img_height * (img_bpp/8); -+#endif -+ cim_dev->page_order = get_order(cim_dev->frame_size); -+ dprintk("cim_dev->page_order=%d\n", cim_dev->page_order); -+ /* frame buffer ?? need large mem ??*/ -+ cim_dev->frame_desc = get_desc_list(cim_dev->page_order); -+ if (cim_dev->frame_desc == NULL) -+ return -ENOMEM; -+ dma_cache_wback((unsigned long)(cim_dev->frame_desc), 16); -+ return 0; -+} -+ -+/*========================================================================== -+ * File operations -+ *========================================================================*/ -+ -+static int cim_open(struct inode *inode, struct file *filp); -+static int cim_release(struct inode *inode, struct file *filp); -+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int cim_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -+static int cim_mmap(struct file *file, struct vm_area_struct *vma); -+ -+static struct file_operations cim_fops = -+{ -+ open: cim_open, -+ release: cim_release, -+ read: cim_read, -+ write: cim_write, -+ ioctl: cim_ioctl, -+ compat_ioctl: v4l_compat_ioctl32, -+ mmap: cim_mmap -+}; -+ -+static struct video_device jz_v4l_device = { -+ .name = "jz cim", -+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | -+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY -+ .fops = &cim_fops, -+ .minor = -1, -+ .owner = THIS_MODULE, -+ .release = video_device_release, -+}; -+ -+static int cim_open(struct inode *inode, struct file *filp) -+{ -+ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int cim_release(struct inode *inode, struct file *filp) -+{ -+ cim_fb_destroy(); -+ cim_stop(); -+ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t cim_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ if (size < cim_dev->frame_size) -+ return -EINVAL; -+ dprintk("read cim\n"); -+ return cim_start_dma(buf); -+} -+ -+static ssize_t cim_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("cim error: write is not implemented\n"); -+ return -1; -+} -+ -+static int cim_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ switch (cmd) { -+ case IOCTL_GET_IMG_PARAM: -+ { -+ img_param_t i; -+ return copy_to_user(argp, &i, sizeof(img_param_t)) ? -EFAULT : 0; -+ } -+ case IOCTL_SET_IMG_PARAM: -+ { -+ img_param_t i; -+ int img_width, img_height, img_bpp; -+ if (copy_from_user((void *)&i, (void *)arg, sizeof(img_param_t))) -+ return -EFAULT; -+#if defined(CONFIG_SOC_JZ4750) -+ cim_image_area(&i); -+#endif -+ img_width = i.width; -+ img_height = i.height; -+ img_bpp = i.bpp; -+ dprintk("ioctl_set_cim_param\n"); -+ if ((img_width * img_height * img_bpp/8) > MAX_FRAME_SIZE){ -+ printk("ERROR! Image is too large!\n"); -+ return -EINVAL; -+ } -+ /* allocate frame buffers */ -+ if (cim_dev->frame_desc == NULL){ -+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ -+ printk("ERROR! Init & alloc cim fail!\n"); -+ return -ENOMEM; -+ } -+ } -+ else -+ if ((img_width * img_height * img_bpp/8) > cim_dev->frame_size){ -+ /* realloc the buffer */ -+ cim_fb_destroy(); -+ if (cim_fb_alloc(img_width, img_height, img_bpp) < 0){ -+ printk("ERRROR! Init & alloc cim fail!\n"); -+ return -ENOMEM; -+ } -+ } -+ break; -+ } -+ case IOCTL_CIM_CONFIG: -+ { -+ cim_config_t c; -+ -+ if (copy_from_user((void *)&c, (void *)arg, sizeof(cim_config_t))) -+ return -EFAULT; -+ -+ cim_config(&c); -+ -+ break; -+ } -+ case IOCTL_TEST_CIM_RAM: -+ { -+ -+ int i; -+ volatile unsigned int *ptr; -+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); -+ printk("RAM test!\n"); -+ printk("CIM_RAM_ADDR = 0x%08x\n", CIM_RAM_ADDR); -+ for (i = 0; i < 1024; ptr++, i++) -+ *ptr = i; -+ ptr = (volatile unsigned int *)(CIM_RAM_ADDR); -+ dma_cache_wback((unsigned long)CIM_RAM_ADDR,0xffc); -+ -+ for (i = 0; i < 1024; i++) { -+ if (i != *ptr) -+ printk("*ptr!=i, *ptr=%d, i=%d\n", *ptr, i); -+ if (i%32 == 0) { -+ if (i%128 == 0) -+ printk("\n"); -+ printk("*ptr=%04d, i=%04d | ", *ptr, i); -+ } -+ ptr++; -+ } -+ printk("\n"); -+ break; -+ } -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return 0; -+} -+ -+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ -+static int cim_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ unsigned long start; -+ unsigned long off; -+ u32 len; -+ -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); -+ -+ /* frame buffer memory */ -+ start = cim_dev->frame_desc->framebuf; -+ len = PAGE_ALIGN((start & ~PAGE_MASK) + (cim_dev->frame_desc->dmacmd & CIM_CMD_LEN_MASK)); -+ start &= PAGE_MASK; -+ -+ if ((vma->vm_end - vma->vm_start + off) > len) -+ return -EINVAL; -+ off += start; -+ -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ vma->vm_flags |= VM_IO; -+ -+#if defined(CONFIG_MIPS32) -+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; -+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NO_WA; /* WT cachable */ -+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; -+#endif -+ -+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot)) -+ vma->vm_flags |= VM_IO; -+ return -EAGAIN; -+ -+ return 0; -+} -+/*========================================================================== -+ * Interrupt handler -+ *========================================================================*/ -+ -+static irqreturn_t cim_irq_handler(int irq, void *dev_id) -+{ -+ u32 state = REG_CIM_STATE; -+ dprintk("REG_CIM_STATE = %x\n", REG_CIM_STATE); -+ dprintk("REG_CIM_CTRL = %x\n", REG_CIM_CTRL); -+#if 1 -+ if (state & CIM_STATE_RXF_OF) { -+ dprintk("OverFlow interrupt!\n"); -+ } -+#endif -+ if (state & CIM_STATE_DMA_EOF) { -+ dprintk("EOF interrupt!\n"); -+ __cim_disable_dma(); -+ __cim_disable(); -+ wake_up_interruptible(&cim_dev->wait_queue); -+ dprintk("EOF interrupt wake up!\n"); -+ } -+ -+ if (state & CIM_STATE_DMA_STOP) { -+ // Got a frame, wake up wait routine -+ __cim_disable_dma(); -+ __cim_disable(); -+ dprintk("Stop interrupt!\n"); -+ wake_up_interruptible(&cim_dev->wait_queue); -+ } -+#if 1 -+ if (state & CIM_STATE_RXF_TRIG) { -+ dprintk("Trig!\n"); -+ } -+#endif -+ -+ /* clear status flags*/ -+ REG_CIM_STATE = 0; -+ return IRQ_HANDLED; -+} -+ -+static int v4l_device_init(void) -+{ -+ cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); -+ if (!cim_dev) return -ENOMEM; -+ cim_dev->jz_cim = video_device_alloc(); -+ if (!cim_dev->jz_cim) { -+ return -ENOMEM; -+ } -+ memcpy(cim_dev->jz_cim, &jz_v4l_device, sizeof(struct video_device)); -+ cim_dev->frame_desc = NULL; -+ cim_dev->frame_size = 0; -+ cim_dev->page_order = 0; -+ return 0; -+} -+/*========================================================================== -+ * Module init and exit -+ *========================================================================*/ -+ -+static int __init jz_cim_init(void) -+{ -+ struct cim_device *dev; -+ int ret; -+ /* allocate device */ -+ ret = v4l_device_init(); -+ if (ret) -+ return ret; -+ /* record device */ -+ dev = cim_dev; -+ init_waitqueue_head(&dev->wait_queue); -+ -+ ret = video_register_device(dev->jz_cim, VFL_TYPE_GRABBER, -1); -+ if (ret < 0) { -+ printk(KERN_ERR "CIM Video4Linux-device " -+ "registration failed\n"); -+ return -EINVAL; -+ } -+ -+ if (ret < 0) { -+ cim_fb_destroy(); -+ kfree(dev); -+ return ret; -+ } -+ -+ if ((ret = request_irq(IRQ_CIM, cim_irq_handler, IRQF_DISABLED, -+ CIM_NAME, dev))) { -+ printk(KERN_ERR "request_irq return error, ret=%d\n", ret); -+ cim_fb_destroy(); -+ kfree(dev); -+ printk(KERN_ERR "CIM could not get IRQ\n"); -+ return ret; -+ } -+ -+ printk("JzSOC Camera Interface Module (CIM) driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit jz_cim_exit(void) -+{ -+ free_irq(IRQ_CIM, cim_dev); -+ kfree(cim_dev); -+ video_unregister_device(cim_dev->jz_cim); -+} -+ -+module_init(jz_cim_init); -+module_exit(jz_cim_exit); -diff -urN linux-2.6.24.7.old/drivers/media/video/jz_cim.h linux-2.6.24.7/drivers/media/video/jz_cim.h ---- linux-2.6.24.7.old/drivers/media/video/jz_cim.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/media/video/jz_cim.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+/* -+ * JzSOC CIM driver -+ * -+ * Copyright (C) 2005 Ingenic 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. -+ * -+ * 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 __JZ_CIM_H__ -+#define __JZ_CIM_H__ -+ -+typedef struct -+{ -+ u32 width; -+ u32 height; -+ u32 bpp; -+} IMG_PARAM; -+ -+/* -+ * IOCTL_XXX commands -+ */ -+#define IOCTL_SET_IMG_PARAM 0 // arg type: IMG_PARAM * -+ -+#endif /* __JZ__CIM_H__ */ -diff -urN linux-2.6.24.7.old/drivers/media/video/jz_sensor.c linux-2.6.24.7/drivers/media/video/jz_sensor.c ---- linux-2.6.24.7.old/drivers/media/video/jz_sensor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/media/video/jz_sensor.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,202 @@ -+/* -+ * linux/drivers/char/jzchar/sensor.c -+ * -+ * Common CMOS Camera Sensor Driver -+ * -+ * Copyright (C) 2006 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+//#include -+//#include "jz-chars.h" -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+MODULE_AUTHOR("Jianli Wei"); -+MODULE_DESCRIPTION("Common CMOS Camera Sensor Driver"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * ioctl commands -+ */ -+#define IOCTL_SET_ADDR 0 /* set i2c address */ -+#define IOCTL_SET_CLK 1 /* set i2c clock */ -+#define IOCTL_WRITE_REG 2 /* write sensor register */ -+#define IOCTL_READ_REG 3 /* read sensor register */ -+ -+/* -+ * i2c related -+ */ -+static unsigned int i2c_addr = 0x42; -+static unsigned int i2c_clk = 100000; -+ -+struct video_device *jz_sensor; -+ -+static void write_reg(u8 reg, u8 val) -+{ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_write((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+} -+ -+static u8 read_reg(u8 reg) -+{ -+ u8 val; -+ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_read((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+ return val; -+} -+ -+/* -+ * fops routines -+ */ -+ -+static int sensor_open(struct inode *inode, struct file *filp); -+static int sensor_release(struct inode *inode, struct file *filp); -+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l); -+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l); -+static int sensor_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -+ -+static struct file_operations sensor_fops = -+{ -+ open: sensor_open, -+ release: sensor_release, -+ read: sensor_read, -+ write: sensor_write, -+ ioctl: sensor_ioctl, -+}; -+ -+static int sensor_open(struct inode *inode, struct file *filp) -+{ -+ try_module_get(THIS_MODULE); -+ return 0; -+} -+ -+static int sensor_release(struct inode *inode, struct file *filp) -+{ -+ module_put(THIS_MODULE); -+ return 0; -+} -+ -+static ssize_t sensor_read(struct file *filp, char *buf, size_t size, loff_t *l) -+{ -+ printk("sensor: read is not implemented\n"); -+ return -1; -+} -+ -+static ssize_t sensor_write(struct file *filp, const char *buf, size_t size, loff_t *l) -+{ -+ printk("sensor: write is not implemented\n"); -+ return -1; -+} -+ -+static int sensor_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ -+ switch (cmd) { -+ case IOCTL_SET_ADDR: -+ if (copy_from_user(&i2c_addr, (void *)arg, 4)) -+ return -EFAULT; -+ break; -+ case IOCTL_SET_CLK: -+ if (copy_from_user(&i2c_clk, (void *)arg, 4)) -+ return -EFAULT; -+ break; -+ case IOCTL_WRITE_REG: -+ { -+ u8 regval[2]; -+ -+ if (copy_from_user(regval, (void *)arg, 2)) -+ return -EFAULT; -+ -+ write_reg(regval[0], regval[1]); -+ break; -+ } -+ case IOCTL_READ_REG: -+ { -+ u8 reg, val; -+ -+ if (copy_from_user(®, (void *)arg, 1)) -+ return -EFAULT; -+ -+ val = read_reg(reg); -+ -+ if (copy_to_user((void *)(arg + 1), &val, 1)) -+ return -EFAULT; -+ break; -+ } -+ default: -+ printk("Not supported command: 0x%x\n", cmd); -+ return -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static struct video_device jz_v4l_device = { -+ .name = "jz sensor", -+ //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | -+ // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY -+ .fops = &sensor_fops, -+ .minor = -1, -+}; -+ -+/* -+ * Module init and exit -+ */ -+ -+static int __init jz_sensor_init(void) -+{ -+ int ret; -+// cim_dev = kzalloc(sizeof(struct cim_device), GFP_KERNEL); -+ jz_sensor = video_device_alloc(); -+ memcpy(jz_sensor, &jz_v4l_device, sizeof(struct video_device)); -+ jz_sensor->release = video_device_release; -+// ret = jz_register_chrdev(SENSOR_MINOR, "sensor", &sensor_fops, NULL); -+ ret = video_register_device(jz_sensor, VFL_TYPE_GRABBER, -1); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ printk("Ingenic CMOS camera sensor driver registered\n"); -+ -+ return 0; -+} -+ -+static void __exit jz_sensor_exit(void) -+{ -+// jz_unregister_chrdev(SENSOR_MINOR, "sensor"); -+ video_unregister_device(jz_sensor); -+} -+ -+module_init(jz_sensor_init); -+module_exit(jz_sensor_exit); -diff -urN linux-2.6.24.7.old/drivers/mmc/card/block.c linux-2.6.24.7/drivers/mmc/card/block.c ---- linux-2.6.24.7.old/drivers/mmc/card/block.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mmc/card/block.c 2009-04-12 18:13:57.000000000 +0200 -@@ -225,7 +225,11 @@ - brq.mrq.cmd = &brq.cmd; - brq.mrq.data = &brq.data; - -+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 -+ brq.cmd.arg = req->sector + 8192; -+#else - brq.cmd.arg = req->sector; -+#endif - if (!mmc_card_blockaddr(card)) - brq.cmd.arg <<= 9; - brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; -diff -urN linux-2.6.24.7.old/drivers/mmc/core/mmc.c linux-2.6.24.7/drivers/mmc/core/mmc.c ---- linux-2.6.24.7.old/drivers/mmc/core/mmc.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mmc/core/mmc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -141,8 +141,13 @@ - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); -- csd->capacity = (1 + m) << (e + 2); - -+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 -+ csd->capacity = (1 + m) << (e + 2); -+ csd->capacity -= 8192; -+#else -+ csd->capacity = (1 + m) << (e + 2); -+#endif - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); -@@ -402,8 +407,9 @@ - EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); - if (err) - goto free_card; -- -- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); -+ -+ /* all mmc v4 support 8 bit mmc card */ -+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_8); - } - - if (!oldcard) -diff -urN linux-2.6.24.7.old/drivers/mmc/core/sd.c linux-2.6.24.7/drivers/mmc/core/sd.c ---- linux-2.6.24.7.old/drivers/mmc/core/sd.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mmc/core/sd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -110,8 +110,13 @@ - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); -- csd->capacity = (1 + m) << (e + 2); - -+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 -+ csd->capacity = (1 + m) << (e + 2); -+ csd->capacity -= 8192; -+#else -+ csd->capacity = (1 + m) << (e + 2); -+#endif - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); -@@ -138,8 +143,13 @@ - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - m = UNSTUFF_BITS(resp, 48, 22); -- csd->capacity = (1 + m) << 10; - -+#ifdef CONFIG_JZ4750_BOOT_FROM_MSC0 -+ csd->capacity = (1 + m) << 10; -+ csd->capacity -= 8192; -+#else -+ csd->capacity = (1 + m) << 10; -+#endif - csd->read_blkbits = 9; - csd->read_partial = 0; - csd->write_misalign = 0; -@@ -269,9 +279,11 @@ - goto out; - - if ((status[16] & 0xF) != 1) { -+#if 0 - printk(KERN_WARNING "%s: Problem switching card " - "into high-speed mode!\n", - mmc_hostname(card->host)); -+#endif - } else { - mmc_card_set_highspeed(card); - mmc_set_timing(card->host, MMC_TIMING_SD_HS); -@@ -386,6 +398,9 @@ - goto free_card; - - mmc_decode_cid(card); -+ -+ /* set 24MHz clock again, why?? */ -+ mmc_set_clock(host, 24000000); - } - - /* -diff -urN linux-2.6.24.7.old/drivers/mmc/host/Kconfig linux-2.6.24.7/drivers/mmc/host/Kconfig ---- linux-2.6.24.7.old/drivers/mmc/host/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mmc/host/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -4,6 +4,104 @@ - - comment "MMC/SD Host Controller Drivers" - -+config MMC_JZ -+ tristate "JZ SD/Multimedia Card Interface support" -+ depends on SOC_JZ4730 || SOC_JZ4740 -+ help -+ This selects the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface. -+ If you have abIngenic platform with a Multimedia Card slot, -+ say Y or M here. -+ -+ If unsure, say N. -+choice -+ depends on MMC_JZ -+ prompt "MMC BUS Width" -+ default JZ_MMC_BUS_4 -+ help -+ This defines the BUS Width of the Ingenic JZ4730/JZ4740 SD/Multimedia card Interface. -+ -+config JZ_MMC_BUS_1 -+ bool "1 Bit Bus" -+ help -+ 1 Bit SD/Multimedia Card Bus -+ -+config JZ_MMC_BUS_4 -+ bool "4 Bit Bus" -+ help -+ 4 Bit SD/Multimedia Card Bus -+ -+endchoice -+ -+config MSC0_JZ4750 -+ tristate "JZ4750 SD/Multimedia Card 0 Interface support" -+ depends on SOC_JZ4750 || SOC_JZ4750D -+ help -+ This selects the Ingenic JZ4750 SD/Multimedia card 0 Interface. -+ If you have a Ingenic platform with a Multimedia Card slot, -+ say Y or M here. -+ -+ If unsure, say N. -+ -+choice -+ depends on MSC0_JZ4750 -+ prompt "MSC0 BUS Width" -+ default JZ4750_MSC0_BUS_4 -+ help -+ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface. -+ -+config JZ4750_MSC0_BUS_1 -+ bool "1 Bit Bus" -+ help -+ 1 Bit SD/Multimedia Card Bus -+ -+config JZ4750_MSC0_BUS_4 -+ bool "4 Bit Bus" -+ help -+ 4 Bit SD/Multimedia Card Bus -+ -+config JZ4750_MSC0_BUS_8 -+ bool "8 Bit Bus" -+ help -+ 8 Bit Multimedia Card Bus -+ -+endchoice -+ -+config MSC1_JZ4750 -+ tristate "JZ4750 SD/Multimedia Card 1 Interface support" -+ depends on SOC_JZ4750 || SOC_JZ4750D -+ help -+ This selects the Ingenic JZ4750 SD/Multimedia card 1 Interface. -+ If you have a Ingenic platform with a Multimedia Card slot, -+ say Y or M here. -+ -+ If unsure, say N. -+ -+choice -+ depends on MSC1_JZ4750 -+ prompt "MSC1 BUS Width" -+ default JZ4750_MSC1_BUS_4 -+ help -+ This defines the BUS Width of the Ingenic JZ4750 SD/Multimedia card Interface. -+ -+config JZ4750_MSC1_BUS_1 -+ bool "1 Bit Bus" -+ help -+ 1 Bit SD/Multimedia Card Bus -+ -+config JZ4750_MSC1_BUS_4 -+ bool "4 Bit Bus" -+ help -+ 4 Bit SD/Multimedia Card Bus -+endchoice -+ -+config JZ4750_BOOT_FROM_MSC0 -+ tristate "JZ4750 Boot from SD/Multimedia Card Interface support" -+ depends on SOC_JZ4750 || SOC_JZ4750D -+ help -+ This selects boot from the Sd/Multimedia Card. -+ -+ If unsure,say N. -+ - config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA -diff -urN linux-2.6.24.7.old/drivers/mmc/host/Makefile linux-2.6.24.7/drivers/mmc/host/Makefile ---- linux-2.6.24.7.old/drivers/mmc/host/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mmc/host/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -6,6 +6,9 @@ - EXTRA_CFLAGS += -DDEBUG - endif - -+obj-$(CONFIG_MMC_JZ) += jz_mmc.o -+obj-$(CONFIG_MSC0_JZ4750) += jz4750_mmc.o -+obj-$(CONFIG_MSC1_JZ4750) += jz4750_mmc.o - obj-$(CONFIG_MMC_ARMMMCI) += mmci.o - obj-$(CONFIG_MMC_PXA) += pxamci.o - obj-$(CONFIG_MMC_IMX) += imxmmc.o -diff -urN linux-2.6.24.7.old/drivers/mmc/host/jz4750_mmc.c linux-2.6.24.7/drivers/mmc/host/jz4750_mmc.c ---- linux-2.6.24.7.old/drivers/mmc/host/jz4750_mmc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mmc/host/jz4750_mmc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1051 @@ -+/* -+ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver -+ * -+ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jz4750_mmc.h" -+ -+#define DRIVER_NAME "jz-mmc" -+ -+#define USE_DMA -+ -+static int r_type = 0; -+static int rxdmachan = 0; -+static int txdmachan = 0; -+static int mmc_slot_enable = 0; -+static int auto_select_bus = MSC_4BIT_BUS; /* default 4 bit bus*/ -+ -+/* Start the MMC clock and operation */ -+static inline int jz_mmc_start_op(void) -+{ -+ REG_MSC_STRPCL(MSC_ID) = MSC_STRPCL_START_OP; -+ -+ return MMC_NO_ERROR; -+} -+ -+static inline u32 jz_mmc_calc_clkrt(int is_low, u32 rate) -+{ -+ u32 clkrt; -+ u32 clk_src = is_low ? 24000000 : 48000000; -+ -+ clkrt = 0; -+ while (rate < clk_src) { -+ clkrt++; -+ clk_src >>= 1; -+ } -+ return clkrt; -+} -+ -+/* Select the MMC clock frequency */ -+static int jz_mmc_set_clock(u32 rate) -+{ -+ int clkrt; -+ -+ /* __cpm_select_msc_clk_high will select 48M clock for MMC/SD card -+ * perhaps this will made some card with bad quality init fail,or -+ * bad stabilization. -+ */ -+ if (rate > SD_CLOCK_FAST) { -+ __cpm_select_msc_clk_high(MSC_ID,1); /* select clock source from CPM */ -+ clkrt = jz_mmc_calc_clkrt(0, rate); -+ } else { -+ __cpm_select_msc_clk(MSC_ID,1); /* select clock source from CPM */ -+ clkrt = jz_mmc_calc_clkrt(1, rate); -+ } -+ -+#ifndef CONFIG_FPGA -+ REG_MSC_CLKRT(MSC_ID) = clkrt; -+#else -+ REG_MSC_CLKRT(MSC_ID) = 7; -+#endif -+ return MMC_NO_ERROR; -+} -+ -+static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->imask &= ~mask; -+ REG_MSC_IMASK(MSC_ID) = host->imask; -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->imask |= mask; -+ REG_MSC_IMASK(MSC_ID) = host->imask; -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte); -+ -+#ifdef USE_DMA -+static inline void -+jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode) -+{ -+ unsigned long flags; -+ -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ jz_set_dma_block_size(chan, 32); -+ set_dma_mode(chan, mode); -+ set_dma_addr(chan, phyaddr); -+ set_dma_count(chan, count + 31); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid) -+{ -+ int chan = rxdmachan; -+ -+ disable_dma(chan); -+ if (__dmac_channel_address_error_detected(chan)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", -+ __FUNCTION__); -+ __dmac_channel_clear_address_error(chan); -+ } -+ if (__dmac_channel_transmit_end_detected(chan)) { -+ __dmac_channel_clear_transmit_end(chan); -+ } -+ return IRQ_HANDLED; -+} -+static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid) -+{ -+ int chan = txdmachan; -+ -+ disable_dma(chan); -+ if (__dmac_channel_address_error_detected(chan)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", -+ __FUNCTION__); -+ __dmac_channel_clear_address_error(chan); -+ } -+ if (__dmac_channel_transmit_end_detected(chan)) { -+ __dmac_channel_clear_transmit_end(chan); -+ } -+ return IRQ_HANDLED; -+} -+ -+/* Prepare DMA to start data transfer from the MMC card */ -+static void jz_mmc_rx_setup_data(struct jz_mmc_host *host, -+ struct mmc_data *data) -+{ -+ unsigned int nob = data->blocks; -+ int channelrx = rxdmachan; -+ int i; -+ u32 size; -+ -+ if (data->flags & MMC_DATA_STREAM) -+ nob = 0xffff; -+ -+ REG_MSC_NOB(MSC_ID) = nob; -+ REG_MSC_BLKLEN(MSC_ID) = data->blksz; -+ size = nob * data->blksz; -+ -+ if (data->flags & MMC_DATA_READ) { -+ host->dma.dir = DMA_FROM_DEVICE; -+ } else { -+ host->dma.dir = DMA_TO_DEVICE; -+ } -+ -+ host->dma.len = -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ host->dma.dir); -+ -+ for (i = 0; i < host->dma.len; i++) { -+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); -+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); -+ dma_cache_wback_inv((unsigned long) -+ CKSEG0ADDR(sg_dma_address(data->sg)) + -+ data->sg->offset, -+ host->sg_cpu[i].dcmd); -+ jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr, -+ host->sg_cpu[i].dcmd, DMA_MODE_READ); -+ } -+} -+ -+/* Prepare DMA to start data transfer from the MMC card */ -+static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, -+ struct mmc_data *data) -+{ -+ unsigned int nob = data->blocks; -+ int channeltx = txdmachan; -+ int i; -+ u32 size; -+ -+ if (data->flags & MMC_DATA_STREAM) -+ nob = 0xffff; -+ -+ REG_MSC_NOB(MSC_ID) = nob; -+ REG_MSC_BLKLEN(MSC_ID) = data->blksz; -+ size = nob * data->blksz; -+ -+ if (data->flags & MMC_DATA_READ) { -+ host->dma.dir = DMA_FROM_DEVICE; -+ } else { -+ host->dma.dir = DMA_TO_DEVICE; -+ } -+ -+ host->dma.len = -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ host->dma.dir); -+ -+ for (i = 0; i < host->dma.len; i++) { -+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); -+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); -+ dma_cache_wback_inv((unsigned long) -+ CKSEG0ADDR(sg_dma_address(data->sg)) + -+ data->sg->offset, -+ host->sg_cpu[i].dcmd); -+ jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, -+ host->sg_cpu[i].dcmd, DMA_MODE_WRITE); -+ } -+} -+#else -+static void jz_mmc_receive_pio(struct jz_mmc_host *host) -+{ -+ -+ struct mmc_data *data = 0; -+ int sg_len = 0, max = 0, count = 0; -+ u32 *buf = 0; -+ struct scatterlist *sg; -+ unsigned int nob; -+ -+ data = host->mrq->data; -+ nob = data->blocks; -+ REG_MSC_NOB(MSC_ID) = nob; -+ REG_MSC_BLKLEN(MSC_ID) = data->blksz; -+ -+ max = host->pio.len; -+ if (host->pio.index < host->dma.len) { -+ sg = &data->sg[host->pio.index]; -+ buf = sg_virt(sg) + host->pio.offset; -+ -+ /* This is the space left inside the buffer */ -+ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; -+ /* Check to if we need less then the size of the sg_buffer */ -+ if (sg_len < max) max = sg_len; -+ } -+ max = max / 4; -+ for(count = 0; count < max; count++) { -+ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_EMPTY) -+ ; -+ *buf++ = REG_MSC_RXFIFO(MSC_ID); -+ } -+ host->pio.len -= count; -+ host->pio.offset += count; -+ -+ if (sg_len && count == sg_len) { -+ host->pio.index++; -+ host->pio.offset = 0; -+ } -+} -+ -+static void jz_mmc_send_pio(struct jz_mmc_host *host) -+{ -+ -+ struct mmc_data *data = 0; -+ int sg_len, max, count = 0; -+ u32 *wbuf = 0; -+ struct scatterlist *sg; -+ unsigned int nob; -+ -+ data = host->mrq->data; -+ nob = data->blocks; -+ -+ REG_MSC_NOB(MSC_ID) = nob; -+ REG_MSC_BLKLEN(MSC_ID) = data->blksz; -+ -+ /* This is the pointer to the data buffer */ -+ sg = &data->sg[host->pio.index]; -+ wbuf = sg_virt(sg) + host->pio.offset; -+ -+ /* This is the space left inside the buffer */ -+ sg_len = data->sg[host->pio.index].length - host->pio.offset; -+ -+ /* Check to if we need less then the size of the sg_buffer */ -+ max = (sg_len > host->pio.len) ? host->pio.len : sg_len; -+ max = max / 4; -+ for(count = 0; count < max; count++ ) { -+ while (REG_MSC_STAT(MSC_ID) & MSC_STAT_DATA_FIFO_FULL) -+ ; -+ REG_MSC_TXFIFO(MSC_ID) = *wbuf++; -+ } -+ -+ host->pio.len -= count; -+ host->pio.offset += count; -+ -+ if (count == sg_len) { -+ host->pio.index++; -+ host->pio.offset = 0; -+ } -+} -+ -+static int -+jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data) -+{ -+ int datalen = data->blocks * data->blksz; -+ -+ host->dma.dir = DMA_BIDIRECTIONAL; -+ host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, -+ data->sg_len, host->dma.dir); -+ if (host->dma.len == 0) -+ return -ETIMEDOUT; -+ -+ host->pio.index = 0; -+ host->pio.offset = 0; -+ host->pio.len = datalen; -+ return 0; -+} -+#endif -+ -+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat); -+ -+static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq) -+{ -+ host->mrq = NULL; -+ host->cmd = NULL; -+ host->data = NULL; -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static void jz_mmc_start_cmd(struct jz_mmc_host *host, -+ struct mmc_command *cmd, unsigned int cmdat) -+{ -+ u32 timeout = 0x3fffff; -+ unsigned int stat; -+ struct jz_mmc_host *hst = host; -+ WARN_ON(host->cmd != NULL); -+ host->cmd = cmd; -+ -+ /* mask interrupts */ -+ REG_MSC_IMASK(MSC_ID) = 0xffff; -+ -+ /* clear status */ -+ REG_MSC_IREG(MSC_ID) = 0xffff; -+ -+ if (cmd->flags & MMC_RSP_BUSY) -+ cmdat |= MSC_CMDAT_BUSY; -+ -+#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) -+ switch (RSP_TYPE(mmc_resp_type(cmd))) { -+ case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ -+ cmdat |= MSC_CMDAT_RESPONSE_R1; -+ r_type = 1; -+ break; -+ case RSP_TYPE(MMC_RSP_R3): -+ cmdat |= MSC_CMDAT_RESPONSE_R3; -+ r_type = 1; -+ break; -+ case RSP_TYPE(MMC_RSP_R2): -+ cmdat |= MSC_CMDAT_RESPONSE_R2; -+ r_type = 2; -+ break; -+ default: -+ break; -+ } -+ -+ REG_MSC_CMD(MSC_ID) = cmd->opcode; -+ -+ /* Set argument */ -+#ifdef CONFIG_MSC0_JZ4750 -+#ifdef CONFIG_JZ4750_MSC0_BUS_1 -+ if (cmd->opcode == 6) { -+ /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) -+ REG_MSC_ARG(MSC_ID) = 0; -+ -+ /* set 1 bit mmc card bus*/ -+ if (cmd->arg == 0x3b70101) { -+ REG_MSC_ARG(MSC_ID) = 0x3b70001; -+ } -+ } else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+ -+#elif defined CONFIG_JZ4750_MSC0_BUS_8 -+ if (cmd->opcode == 6) { -+ /* set 8 bit mmc card bus*/ -+ if (cmd->arg == 0x3b70101) -+ REG_MSC_ARG(MSC_ID) = 0x3b70201; -+ else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+ -+ } else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+#else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ -+#else -+#ifdef CONFIG_JZ4750_MSC1_BUS_1 -+ if (cmd->opcode == 6) { -+ /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) -+ REG_MSC_ARG(MSC_ID) = 0; -+ -+ /* set 1 bit mmc card bus*/ -+ if (cmd->arg == 0x3b70101) { -+ REG_MSC_ARG(MSC_ID) = 0x3b70001; -+ } -+ } else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+ -+#else -+ REG_MSC_ARG(MSC_ID) = cmd->arg; -+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ -+#endif /* CONFIG_MSC0_JZ4750*/ -+ -+ /* Set command */ -+ REG_MSC_CMDAT(MSC_ID) = cmdat; -+ -+ /* Send command */ -+ jz_mmc_start_op(); -+ -+ while (timeout-- && !(REG_MSC_STAT(MSC_ID) & MSC_STAT_END_CMD_RES)) -+ ; -+ -+ REG_MSC_IREG(MSC_ID) = MSC_IREG_END_CMD_RES; /* clear irq flag */ -+ if (cmd->opcode == 12) { -+ while (timeout-- && !(REG_MSC_IREG(MSC_ID) & MSC_IREG_PRG_DONE)) -+ ; -+ REG_MSC_IREG(MSC_ID) = MSC_IREG_PRG_DONE; /* clear status */ -+ } -+ if (!mmc_slot_enable) { -+ /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when -+ * card was removed. We force to return here. -+ */ -+ cmd->error = -ETIMEDOUT; -+ jz_mmc_finish_request(hst, hst->mrq); -+ return; -+ } -+ -+ if (SD_IO_SEND_OP_COND == cmd->opcode) { -+ /* -+ * Don't support SDIO card currently. -+ */ -+ cmd->error = -ETIMEDOUT; -+ jz_mmc_finish_request(hst, hst->mrq); -+ return; -+ } -+ -+ /* Check for status */ -+ stat = REG_MSC_STAT(MSC_ID); -+ jz_mmc_cmd_done(hst, stat); -+ if (host->data) { -+ if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) -+#ifdef USE_DMA -+ jz_mmc_tx_setup_data(host, host->data); -+#else -+ jz_mmc_send_pio(host); -+ else -+ jz_mmc_receive_pio(host); -+#endif -+ } -+} -+ -+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat) -+{ -+ struct mmc_command *cmd = host->cmd; -+ int i, temp[16]; -+ u8 *buf; -+ u32 data, v, w1, w2; -+ -+ if (!cmd) -+ return 0; -+ -+ host->cmd = NULL; -+ buf = (u8 *) temp; -+ switch (r_type) { -+ case 1: -+ { -+ data = REG_MSC_RES(MSC_ID); -+ buf[0] = (data >> 8) & 0xff; -+ buf[1] = data & 0xff; -+ data = REG_MSC_RES(MSC_ID); -+ buf[2] = (data >> 8) & 0xff; -+ buf[3] = data & 0xff; -+ data = REG_MSC_RES(MSC_ID); -+ buf[4] = data & 0xff; -+ cmd->resp[0] = -+ buf[1] << 24 | buf[2] << 16 | buf[3] << 8 | -+ buf[4]; -+ break; -+ } -+ case 2: -+ { -+ data = REG_MSC_RES(MSC_ID); -+ v = data & 0xffff; -+ for (i = 0; i < 4; i++) { -+ data = REG_MSC_RES(MSC_ID); -+ w1 = data & 0xffff; -+ data = REG_MSC_RES(MSC_ID); -+ w2 = data & 0xffff; -+ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; -+ v = w2; -+ } -+ break; -+ } -+ case 0: -+ break; -+ } -+ if (stat & MSC_STAT_TIME_OUT_RES) { -+ printk("MSC_STAT_TIME_OUT_RES\n"); -+ cmd->error = -ETIMEDOUT; -+ } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) { -+ printk("MSC_STAT_CRC\n"); -+ if (cmd->opcode == MMC_ALL_SEND_CID || -+ cmd->opcode == MMC_SEND_CSD || -+ cmd->opcode == MMC_SEND_CID) { -+ /* a bogus CRC error can appear if the msb of -+ the 15 byte response is a one */ -+ if ((cmd->resp[0] & 0x80000000) == 0) -+ cmd->error = -EILSEQ; -+ } -+ } -+ /* -+ * Did I mention this is Sick. We always need to -+ * discard the upper 8 bits of the first 16-bit word. -+ */ -+ if (host->data && cmd->error == 0) -+ jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE); -+ else -+ jz_mmc_finish_request(host, host->mrq); -+ -+ return 1; -+} -+ -+static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat) -+{ -+ struct mmc_data *data = host->data; -+ -+ if (!data) -+ return 0; -+ REG_MSC_IREG(MSC_ID) = MSC_IREG_DATA_TRAN_DONE; /* clear status */ -+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, -+ host->dma_dir); -+ if (stat & MSC_STAT_TIME_OUT_READ) { -+ printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat); -+ data->error = -ETIMEDOUT; -+ } else if (REG_MSC_STAT(MSC_ID) & -+ (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) { -+ printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat); -+ data->error = -EILSEQ; -+ } -+ /* -+ * There appears to be a hardware design bug here. There seems to -+ * be no way to find out how much data was transferred to the card. -+ * This means that if there was an error on any block, we mark all -+ * data blocks as being in error. -+ */ -+ if (data->error == 0) -+ data->bytes_xfered = data->blocks * data->blksz; -+ else -+ data->bytes_xfered = 0; -+ -+ jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE); -+ host->data = NULL; -+ if (host->mrq->stop) { -+ jz_mmc_start_cmd(host, host->mrq->stop, 0); -+ } else { -+ jz_mmc_finish_request(host, host->mrq); -+ } -+ return 1; -+} -+ -+static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ unsigned int cmdat; -+ -+ /* Save current request for the future processing */ -+ host->mrq = mrq; -+ host->data = mrq->data; -+ cmdat = host->cmdat; -+ host->cmdat &= ~MSC_CMDAT_INIT; -+ -+ if (mrq->data) { -+ cmdat &= ~MSC_CMDAT_BUSY; -+#ifdef USE_DMA -+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) -+ -+ cmdat |= -+ MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+ else { -+#ifdef CONFIG_MSC0_JZ4750 -+#ifdef CONFIG_JZ4750_MSC0_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+#elif defined CONFIG_JZ4750_MSC0_BUS_4 -+ if(auto_select_bus == MSC_1BIT_BUS) { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+ } else { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+ } -+#else -+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; -+#endif /* CONFIG_JZ4750_MSC0_BUS_1 */ -+#else -+#ifdef CONFIG_JZ4750_MSC1_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+#else -+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; -+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ -+#endif /* CONFIG_MSC0_JZ4750 */ -+ } -+ if (mrq->data->flags & MMC_DATA_WRITE) -+ cmdat |= MSC_CMDAT_WRITE; -+ -+ if (mrq->data->flags & MMC_DATA_STREAM) -+ cmdat |= MSC_CMDAT_STREAM_BLOCK; -+ if (mrq->cmd->opcode != MMC_WRITE_BLOCK -+ && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) -+ jz_mmc_rx_setup_data(host, mrq->data); -+#else /*USE_DMA*/ -+ -+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+ else { -+#ifdef CONFIG_MSC0_JZ4750 -+#ifdef CONFIG_JZ4750_MSC0_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+#elif defined CONFIG_JZ4750_MSC0_BUS_4 -+ if(auto_select_bus == MSC_1BIT_BUS) { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+ } else { -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_DATA_EN; -+ } -+#else -+ cmdat |= MSC_CMDAT_DATA_EN; -+#endif -+#else -+#ifdef CONFIG_JZ4750_MSC1_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_MASK; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+#else -+ cmdat |= MSC_CMDAT_DATA_EN; -+#endif /* CONFIG_JZ4750_MSC1_BUS_1 */ -+#endif /* CONFIG_MSC0_JZ4750 */ -+ } -+ if (mrq->data->flags & MMC_DATA_WRITE) -+ cmdat |= MSC_CMDAT_WRITE; -+ -+ if (mrq->data->flags & MMC_DATA_STREAM) -+ cmdat |= MSC_CMDAT_STREAM_BLOCK; -+ jz_mmc_prepare_data(host, host->data); -+#endif /*USE_DMA*/ -+ } -+ jz_mmc_start_cmd(host, mrq->cmd, cmdat); -+} -+ -+static irqreturn_t jz_mmc_irq(int irq, void *devid) -+{ -+ struct jz_mmc_host *host = devid; -+ unsigned int ireg; -+ int handled = 0; -+ -+ ireg = REG_MSC_IREG(MSC_ID); -+ -+ if (ireg) { -+ unsigned stat = REG_MSC_STAT(MSC_ID); -+ if (ireg & MSC_IREG_DATA_TRAN_DONE) -+ handled |= jz_mmc_data_done(host, stat); -+ } -+ return IRQ_RETVAL(handled); -+} -+ -+/* Returns true if MMC slot is empty */ -+static int jz_mmc_slot_is_empty(int slot) -+{ -+ int empty; -+ -+#ifdef CONFIG_FPGA -+ return 0; -+#endif -+ -+#ifdef CONFIG_MSC1_JZ4750 -+ empty = (__msc1_card_detected(slot) == 0) ? 1 : 0; -+#else -+ empty = (__msc0_card_detected(slot) == 0) ? 1 : 0; -+ -+#endif -+ if (empty) { -+ /* wait for card insertion */ -+#ifdef CONFIG_MSC1_JZ4750 -+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); -+#else -+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); -+#endif -+ } else { -+ /* wait for card removal */ -+#ifdef CONFIG_MSC1_JZ4750 -+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); -+#else -+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); -+#endif -+ } -+ -+ return empty; -+} -+ -+static irqreturn_t jz_mmc_detect_irq(int irq, void *devid) -+{ -+ struct jz_mmc_host *host = (struct jz_mmc_host *) devid; -+ -+ auto_select_bus = MSC_4BIT_BUS; -+ if (jz_mmc_slot_is_empty(0)) { -+ mmc_slot_enable = 0; -+ mmc_detect_change(host->mmc, 50); -+ } else { -+ mmc_slot_enable = 1; -+ mmc_detect_change(host->mmc, 50); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int jz_mmc_get_ro(struct mmc_host *mmc) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (host->pdata && host->pdata->get_ro) -+ return host->pdata->get_ro(mmc_dev(mmc)); -+ /* Host doesn't support read only detection so assume writeable */ -+ return 0; -+} -+ -+/* set clock and power */ -+static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (ios->clock) -+ jz_mmc_set_clock(ios->clock); -+ -+ if (host->power_mode != ios->power_mode) { -+ host->power_mode = ios->power_mode; -+ -+ if (ios->power_mode == MMC_POWER_ON) -+ host->cmdat |= CMDAT_INIT; -+ } -+ -+ if (ios->bus_width == MMC_BUS_WIDTH_4) { -+ auto_select_bus = MSC_4BIT_BUS; -+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; -+ } -+ else if (ios->bus_width == MMC_BUS_WIDTH_8) { -+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_8BIT; -+ auto_select_bus = MSC_8BIT_BUS; -+ } else { -+ /* 1 bit bus*/ -+ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_8BIT; -+ auto_select_bus = MSC_1BIT_BUS; -+ } -+} -+ -+static const struct mmc_host_ops jz_mmc_ops = { -+ .request = jz_mmc_request, -+ .get_ro = jz_mmc_get_ro, -+ .set_ios = jz_mmc_set_ios, -+}; -+static int jz_mmc_pm_callback(struct pm_dev *pm_dev, -+ pm_request_t req, void *data); -+ -+static int jz_mmc_probe(struct platform_device *pdev) -+{ -+ int retval; -+ struct mmc_host *mmc; -+ struct jz_mmc_host *host = NULL; -+ int irq; -+ struct resource *r; -+ -+#ifdef CONFIG_MSC0_JZ4750 -+#ifdef CONFIG_SOC_JZ4750 -+ __gpio_as_msc0_8bit(); // for jz4750 -+#else -+ __gpio_as_msc0_4bit(); // for jz4750d -+#endif -+ __msc0_init_io(); -+ __msc0_enable_power(); -+#else -+ __gpio_as_msc1_4bit(); -+ __msc1_init_io(); -+ __msc1_enable_power(); -+#endif -+ __msc_reset(MSC_ID); -+ REG_MSC_LPM(MSC_ID) = 0x1; -+ -+ MMC_IRQ_MASK(); -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_irq(pdev, 0); -+ if (!r || irq < 0) -+ return -ENXIO; -+ -+ r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); -+ if (!r) -+ return -EBUSY; -+ -+ mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev); -+ if (!mmc) { -+ retval = -ENOMEM; -+ goto out; -+ } -+ mmc->ops = &jz_mmc_ops; -+ mmc->f_min = MMC_CLOCK_SLOW; -+ mmc->f_max = SD_CLOCK_HIGH; -+ /* -+ * We can do SG-DMA, but we don't because we never know how much -+ * data we successfully wrote to the card. -+ */ -+ mmc->max_phys_segs = NR_SG; -+ -+ mmc->max_seg_size = PAGE_SIZE * 16; -+ mmc->max_req_size = mmc->max_seg_size; -+ mmc->max_blk_size = 4095; -+ /* -+ * Block count register is 16 bits. -+ */ -+ mmc->max_blk_count = 65535; -+ host = mmc_priv(mmc); -+ host->mmc = mmc; -+ host->pdata = pdev->dev.platform_data; -+ mmc->ocr_avail = host->pdata ? -+ host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34; -+ host->mmc->caps = -+ MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SD_HIGHSPEED -+ | MMC_CAP_MMC_HIGHSPEED; -+ /* -+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers -+ * -+ */ -+ host->sg_cpu = -+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, -+ GFP_KERNEL); -+ if (!host->sg_cpu) { -+ retval = -ENOMEM; -+ goto out; -+ } -+ spin_lock_init(&host->lock); -+ host->irq = IRQ_MSC; /* is it useful ?*/ -+ host->imask = 0xffff; -+ /* -+ * Ensure that the host controller is shut down, and setup -+ * with our defaults. -+ */ -+ retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host); -+ if (retval) { -+ printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); -+ return retval; -+ } -+ -+ jz_mmc_slot_is_empty(0); -+ /* Request card detect interrupt */ -+ -+ retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT, -+ "MMC card detect", host); -+ if (retval) { -+ printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n"); -+ goto err1; -+ } -+#ifdef USE_DMA -+ /* Request MMC Rx DMA channel */ -+ rxdmachan = -+ jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback, -+ 0, host); -+ if (rxdmachan < 0) { -+ printk(KERN_ERR "jz_request_dma failed for MMC Rx\n"); -+ goto err2; -+ } -+ -+ if (rxdmachan < HALF_DMA_NUM) -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC; -+ else -+ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC; -+ -+ /* Request MMC Tx DMA channel */ -+ txdmachan = -+ jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback, -+ 0, host); -+ if (txdmachan < 0) { -+ printk(KERN_ERR "jz_request_dma failed for MMC Tx\n"); -+ goto err3; -+ } -+ -+ if (txdmachan < HALF_DMA_NUM) -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_FMSC; -+ else -+ REG_DMAC_DMACR(1) |= DMAC_DMACR_FMSC; -+ -+#endif -+ platform_set_drvdata(pdev, mmc); -+ mmc_add_host(mmc); -+#ifdef CONFIG_PM -+ /* Register MMC slot as as power-managed device */ -+ pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, jz_mmc_pm_callback); -+#endif -+ printk("JZ SD/MMC card driver registered\n"); -+ -+ /* Detect card during initialization */ -+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) -+ if (!jz_mmc_slot_is_empty(0)) { -+ mmc_slot_enable = 1; -+ mmc_detect_change(host->mmc, 0); -+ } -+#endif -+ return 0; -+ -+err1:free_irq(IRQ_MSC, &host); -+#ifdef USE_DMA -+ err2:jz_free_dma(rxdmachan); -+ err3:jz_free_dma(txdmachan); -+#endif -+out: -+ if (host) { -+ if (host->sg_cpu) -+ dma_free_coherent(&pdev->dev, PAGE_SIZE, -+ host->sg_cpu, host->sg_dma); -+ } -+ if (mmc) -+ mmc_free_host(mmc); -+ return -1; -+} -+ -+static int jz_mmc_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(pdev); -+ long flags; -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (mmc) { -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (host->pdata && host->pdata->exit) -+ host->pdata->exit(&pdev->dev, mmc); -+ -+ mmc_remove_host(mmc); -+ -+ local_irq_save(flags); -+ __msc0_disable_power(); -+ jz_free_dma(rxdmachan); -+ jz_free_dma(txdmachan); -+ free_irq(IRQ_MSC, host); -+ local_irq_restore(flags); -+ mmc_free_host(mmc); -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+pm_message_t state; -+static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ int ret = 0; -+ -+ if (mmc) -+ ret = mmc_suspend_host(mmc, state); -+ -+ return ret; -+} -+ -+static int jz_mmc_resume(struct platform_device *dev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ int ret = 0; -+ -+ if (mmc) -+ ret = mmc_resume_host(mmc); -+ -+ return ret; -+} -+static int jz_mmc_pm_callback(struct pm_dev *pm_dev, -+ pm_request_t req, void *data) -+{ -+ struct platform_device *pdev = (struct platform_device *)pm_dev; -+ -+ switch(req) { -+ case PM_RESUME: -+ jz_mmc_resume(pdev); -+ break; -+ case PM_SUSPEND: -+ /* state has no use */ -+ jz_mmc_suspend(pdev,state); -+ break; -+ default: -+ printk("MMC/SD: invalid PM request %d\n", req); -+ break; -+ } -+ return 0; -+} -+#else -+#define jz_mmc_suspend NULL -+#define jz_mmc_resume NULL -+#endif -+ -+static struct platform_driver jz_mmc_driver = { -+ .probe = jz_mmc_probe, -+ .remove = jz_mmc_remove, -+ .suspend = jz_mmc_suspend, -+ .resume = jz_mmc_resume, -+ .driver = { -+ .name = DRIVER_NAME, -+ }, -+}; -+ -+static int __init jz_mmc_init(void) -+{ -+ return platform_driver_register(&jz_mmc_driver); -+} -+ -+static void __exit jz_mmc_exit(void) -+{ -+ platform_driver_unregister(&jz_mmc_driver); -+} -+ -+module_init(jz_mmc_init); -+module_exit(jz_mmc_exit); -+ -+MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/mmc/host/jz4750_mmc.h linux-2.6.24.7/drivers/mmc/host/jz4750_mmc.h ---- linux-2.6.24.7.old/drivers/mmc/host/jz4750_mmc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mmc/host/jz4750_mmc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,88 @@ -+#ifndef __JZ4750_MMC_H__ -+#define __JZ4750_MMC_H__ -+ -+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ -+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ -+#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ -+#define SD_CLOCK_HIGH 24000000 /* 24 MHz for SD Cards */ -+#define MMC_NO_ERROR 0 -+ -+#define NR_SG 1 -+ -+#ifdef CONFIG_MSC0_JZ4750 -+#define MSC_ID 0 -+#define MSC_HOTPLUG_IRQ MSC0_HOTPLUG_IRQ -+#define IRQ_MSC IRQ_MSC0 -+#define DMA_ID_MSC_RX DMA_ID_MSC0_RX -+#define DMA_ID_MSC_TX DMA_ID_MSC0_TX -+#define MSC_HOTPLUG_PIN MSC0_HOTPLUG_PIN -+#else -+#define MSC_ID 1 -+#define MSC_HOTPLUG_IRQ MSC1_HOTPLUG_IRQ -+#define IRQ_MSC IRQ_MSC1 -+#define DMA_ID_MSC_RX DMA_ID_MSC1_RX -+#define DMA_ID_MSC_TX DMA_ID_MSC1_TX -+#define MSC_HOTPLUG_PIN MSC1_HOTPLUG_PIN -+#endif -+ -+#define MSC_1BIT_BUS 0 -+#define MSC_4BIT_BUS 1 -+#define MSC_8BIT_BUS 2 -+ -+#define SZ_4K 0x00001000 -+ -+struct jz_mmc_host { -+ struct mmc_host *mmc; -+ spinlock_t lock; -+ struct { -+ int len; -+ int dir; -+ } dma; -+ struct { -+ int index; -+ int offset; -+ int len; -+ } pio; -+ int irq; -+ unsigned int clkrt; -+ unsigned int cmdat; -+ unsigned int imask; -+ unsigned int power_mode; -+ struct jz_mmc_platform_data *pdata; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ dma_addr_t sg_dma; -+ struct jzsoc_dma_desc *sg_cpu; -+ unsigned int dma_len; -+ unsigned int dma_dir; -+}; -+ -+#define MMC_IRQ_MASK() \ -+do { \ -+ REG_MSC_IMASK(MSC_ID) = 0xffff; \ -+ REG_MSC_IREG(MSC_ID) = 0xffff; \ -+} while (0) -+ -+typedef struct jzsoc_dma_desc { -+ volatile u32 ddadr; /* Points to the next descriptor + flags */ -+ volatile u32 dsadr; /* DSADR value for the current transfer */ -+ volatile u32 dtadr; /* DTADR value for the current transfer */ -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+} jzsoc_dma_desc; -+ -+#include -+ -+struct device; -+struct mmc_host; -+ -+struct jz_mmc_platform_data { -+ unsigned int ocr_mask; /* available voltages */ -+ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ -+ int (*init)(struct device *, irq_handler_t , void *); -+ int (*get_ro)(struct device *); -+ void (*setpower)(struct device *, unsigned int); -+ void (*exit)(struct device *, void *); -+}; -+ -+#endif /* __JZ4750_MMC_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mmc/host/jz_mmc.c linux-2.6.24.7/drivers/mmc/host/jz_mmc.c ---- linux-2.6.24.7.old/drivers/mmc/host/jz_mmc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mmc/host/jz_mmc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1026 @@ -+/* -+ * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver -+ * -+ * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jz_mmc.h" -+ -+#define DRIVER_NAME "jz-mmc" -+ -+#define NR_SG 1 -+ -+#if defined(CONFIG_SOC_JZ4725) || defined(CONFIG_SOC_JZ4720) -+#undef USE_DMA -+#else -+#define USE_DMA -+#endif -+ -+struct jz_mmc_host { -+ struct mmc_host *mmc; -+ spinlock_t lock; -+ struct { -+ int len; -+ int dir; -+ } dma; -+ struct { -+ int index; -+ int offset; -+ int len; -+ } pio; -+ int irq; -+ unsigned int clkrt; -+ unsigned int cmdat; -+ unsigned int imask; -+ unsigned int power_mode; -+ struct jz_mmc_platform_data *pdata; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ dma_addr_t sg_dma; -+ struct jzsoc_dma_desc *sg_cpu; -+ unsigned int dma_len; -+ unsigned int dma_dir; -+ struct pm_dev *pmdev; -+}; -+ -+static int r_type = 0; -+ -+#define MMC_IRQ_MASK() \ -+do { \ -+ REG_MSC_IMASK = 0xff; \ -+ REG_MSC_IREG = 0xff; \ -+} while (0) -+ -+static int rxdmachan = 0; -+static int txdmachan = 0; -+static int mmc_slot_enable = 0; -+ -+/* Stop the MMC clock and wait while it happens */ -+static inline int jz_mmc_stop_clock(void) -+{ -+ int timeout = 1000; -+ -+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; -+ while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) { -+ timeout--; -+ if (timeout == 0) -+ return 0; -+ udelay(1); -+ } -+ return MMC_NO_ERROR; -+} -+ -+/* Start the MMC clock and operation */ -+static inline int jz_mmc_start_clock(void) -+{ -+ REG_MSC_STRPCL = -+ MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP; -+ return MMC_NO_ERROR; -+} -+ -+static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate) -+{ -+ u32 clkrt; -+ u32 clk_src = is_sd ? 24000000 : 20000000; -+ -+ clkrt = 0; -+ while (rate < clk_src) { -+ clkrt++; -+ clk_src >>= 1; -+ } -+ return clkrt; -+} -+ -+/* Select the MMC clock frequency */ -+static int jz_mmc_set_clock(u32 rate) -+{ -+ int clkrt; -+ -+ jz_mmc_stop_clock(); -+ __cpm_select_msc_clk(1); /* select clock source from CPM */ -+ clkrt = jz_mmc_calc_clkrt(1, rate); -+ REG_MSC_CLKRT = clkrt; -+ return MMC_NO_ERROR; -+} -+ -+static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&host->lock, flags); -+ host->imask &= ~mask; -+ REG_MSC_IMASK = host->imask; -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->imask |= mask; -+ REG_MSC_IMASK = host->imask; -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+void jz_set_dma_block_size(int dmanr, int nbyte); -+ -+#ifdef USE_DMA -+static inline void -+jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode) -+{ -+ unsigned long flags; -+ -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ jz_set_dma_block_size(chan, 32); -+ set_dma_mode(chan, mode); -+ set_dma_addr(chan, phyaddr); -+ set_dma_count(chan, count + 31); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid) -+{ -+ int chan = rxdmachan; -+ -+ disable_dma(chan); -+ if (__dmac_channel_address_error_detected(chan)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", -+ __FUNCTION__); -+ __dmac_channel_clear_address_error(chan); -+ } -+ if (__dmac_channel_transmit_end_detected(chan)) { -+ __dmac_channel_clear_transmit_end(chan); -+ } -+ return IRQ_HANDLED; -+} -+static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid) -+{ -+ int chan = txdmachan; -+ -+ disable_dma(chan); -+ if (__dmac_channel_address_error_detected(chan)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", -+ __FUNCTION__); -+ __dmac_channel_clear_address_error(chan); -+ } -+ if (__dmac_channel_transmit_end_detected(chan)) { -+ __dmac_channel_clear_transmit_end(chan); -+ } -+ return IRQ_HANDLED; -+} -+ -+/* Prepare DMA to start data transfer from the MMC card */ -+static void jz_mmc_rx_setup_data(struct jz_mmc_host *host, -+ struct mmc_data *data) -+{ -+ unsigned int nob = data->blocks; -+ int channelrx = rxdmachan; -+ int i; -+ u32 size; -+ -+ if (data->flags & MMC_DATA_STREAM) -+ nob = 0xffff; -+ -+ REG_MSC_NOB = nob; -+ REG_MSC_BLKLEN = data->blksz; -+ size = nob * data->blksz; -+ -+ if (data->flags & MMC_DATA_READ) { -+ host->dma.dir = DMA_FROM_DEVICE; -+ } else { -+ host->dma.dir = DMA_TO_DEVICE; -+ } -+ -+ host->dma.len = -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ host->dma.dir); -+ -+ for (i = 0; i < host->dma.len; i++) { -+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); -+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); -+ dma_cache_wback_inv((unsigned long) -+ CKSEG0ADDR(sg_dma_address(data->sg)) + -+ data->sg->offset, -+ host->sg_cpu[i].dcmd); -+ jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr, -+ host->sg_cpu[i].dcmd, DMA_MODE_READ); -+ } -+} -+ -+/* Prepare DMA to start data transfer from the MMC card */ -+static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, -+ struct mmc_data *data) -+{ -+ unsigned int nob = data->blocks; -+ int channeltx = txdmachan; -+ int i; -+ u32 size; -+ -+ if (data->flags & MMC_DATA_STREAM) -+ nob = 0xffff; -+ -+ REG_MSC_NOB = nob; -+ REG_MSC_BLKLEN = data->blksz; -+ size = nob * data->blksz; -+ -+ if (data->flags & MMC_DATA_READ) { -+ host->dma.dir = DMA_FROM_DEVICE; -+ } else { -+ host->dma.dir = DMA_TO_DEVICE; -+ } -+ -+ host->dma.len = -+ dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, -+ host->dma.dir); -+ -+ for (i = 0; i < host->dma.len; i++) { -+ host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); -+ host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); -+ dma_cache_wback_inv((unsigned long) -+ CKSEG0ADDR(sg_dma_address(data->sg)) + -+ data->sg->offset, -+ host->sg_cpu[i].dcmd); -+ jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, -+ host->sg_cpu[i].dcmd, DMA_MODE_WRITE); -+ } -+} -+#else -+static void jz_mmc_receive_pio(struct jz_mmc_host *host) -+{ -+ -+ struct mmc_data *data = 0; -+ int sg_len = 0, max = 0, count = 0; -+ u32 *buf = 0; -+ struct scatterlist *sg; -+ unsigned int nob; -+ -+ data = host->mrq->data; -+ nob = data->blocks; -+ REG_MSC_NOB = nob; -+ REG_MSC_BLKLEN = data->blksz; -+ -+ max = host->pio.len; -+ if (host->pio.index < host->dma.len) { -+ sg = &data->sg[host->pio.index]; -+ buf = sg_virt(sg) + host->pio.offset; -+ -+ /* This is the space left inside the buffer */ -+ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; -+ /* Check to if we need less then the size of the sg_buffer */ -+ if (sg_len < max) max = sg_len; -+ } -+ max = max / 4; -+ for(count = 0; count < max; count++) { -+ while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY) -+ ; -+ *buf++ = REG_MSC_RXFIFO; -+ } -+ host->pio.len -= count; -+ host->pio.offset += count; -+ -+ if (sg_len && count == sg_len) { -+ host->pio.index++; -+ host->pio.offset = 0; -+ } -+} -+ -+static void jz_mmc_send_pio(struct jz_mmc_host *host) -+{ -+ -+ struct mmc_data *data = 0; -+ int sg_len, max, count = 0; -+ u32 *wbuf = 0; -+ struct scatterlist *sg; -+ unsigned int nob; -+ -+ data = host->mrq->data; -+ nob = data->blocks; -+ -+ REG_MSC_NOB = nob; -+ REG_MSC_BLKLEN = data->blksz; -+ -+ /* This is the pointer to the data buffer */ -+ sg = &data->sg[host->pio.index]; -+ wbuf = sg_virt(sg) + host->pio.offset; -+ -+ /* This is the space left inside the buffer */ -+ sg_len = data->sg[host->pio.index].length - host->pio.offset; -+ -+ /* Check to if we need less then the size of the sg_buffer */ -+ max = (sg_len > host->pio.len) ? host->pio.len : sg_len; -+ max = max / 4; -+ for(count = 0; count < max; count++ ) { -+ while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL) -+ ; -+ REG_MSC_TXFIFO = *wbuf++; -+ } -+ -+ host->pio.len -= count; -+ host->pio.offset += count; -+ -+ if (count == sg_len) { -+ host->pio.index++; -+ host->pio.offset = 0; -+ } -+} -+ -+static int -+jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data) -+{ -+ int datalen = data->blocks * data->blksz; -+ -+ host->dma.dir = DMA_BIDIRECTIONAL; -+ host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, -+ data->sg_len, host->dma.dir); -+ if (host->dma.len == 0) -+ return -ETIMEDOUT; -+ -+ host->pio.index = 0; -+ host->pio.offset = 0; -+ host->pio.len = datalen; -+ return 0; -+} -+#endif -+ -+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat); -+ -+static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq) -+{ -+ jz_mmc_stop_clock(); -+ host->mrq = NULL; -+ host->cmd = NULL; -+ host->data = NULL; -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static void jz_mmc_start_cmd(struct jz_mmc_host *host, -+ struct mmc_command *cmd, unsigned int cmdat) -+{ -+ u32 timeout = 0x3fffff; -+ unsigned int stat; -+ struct jz_mmc_host *hst = host; -+ WARN_ON(host->cmd != NULL); -+ host->cmd = cmd; -+ -+ /* stop MMC clock */ -+ jz_mmc_stop_clock(); -+ -+ /* mask interrupts */ -+ REG_MSC_IMASK = 0xff; -+ -+ /* clear status */ -+ REG_MSC_IREG = 0xff; -+ -+ if (cmd->flags & MMC_RSP_BUSY) -+ cmdat |= MSC_CMDAT_BUSY; -+ -+#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) -+ switch (RSP_TYPE(mmc_resp_type(cmd))) { -+ case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ -+ cmdat |= MSC_CMDAT_RESPONSE_R1; -+ r_type = 1; -+ break; -+ case RSP_TYPE(MMC_RSP_R3): -+ cmdat |= MSC_CMDAT_RESPONSE_R3; -+ r_type = 1; -+ break; -+ case RSP_TYPE(MMC_RSP_R2): -+ cmdat |= MSC_CMDAT_RESPONSE_R2; -+ r_type = 2; -+ break; -+ default: -+ break; -+ } -+ REG_MSC_CMD = cmd->opcode; -+ -+ /* Set argument */ -+#ifdef CONFIG_JZ_MMC_BUS_1 -+ if (cmd->opcode == 6) { -+ /* set 1 bit sd card bus*/ -+ if (cmd->arg ==2) -+ REG_MSC_ARG = 0; -+ -+ /* set 1 bit mmc card bus*/ -+ if (cmd->arg == 0x3b70101) -+ REG_MSC_ARG = 0x3b70001; -+ } else -+ REG_MSC_ARG = cmd->arg; -+#else -+ REG_MSC_ARG = cmd->arg; -+#endif -+ -+ /* Set command */ -+ REG_MSC_CMDAT = cmdat; -+ -+ /* Send command */ -+ jz_mmc_start_clock(); -+ -+ while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) -+ ; -+ -+ REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */ -+ if (cmd->opcode == 12) { -+ while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE)) -+ ; -+ REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ -+ } -+ if (!mmc_slot_enable) { -+ /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when -+ * card was removed. We force to return here. -+ */ -+ cmd->error = -ETIMEDOUT; -+ jz_mmc_finish_request(hst, hst->mrq); -+ return; -+ } -+ -+ if (SD_IO_SEND_OP_COND == cmd->opcode) { -+ /* -+ * Don't support SDIO card currently. -+ */ -+ cmd->error = -ETIMEDOUT; -+ jz_mmc_finish_request(hst, hst->mrq); -+ return; -+ } -+ -+ /* Check for status */ -+ stat = REG_MSC_STAT; -+ jz_mmc_cmd_done(hst, stat); -+ if (host->data) { -+ if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) -+#ifdef USE_DMA -+ jz_mmc_tx_setup_data(host, host->data); -+#else -+ jz_mmc_send_pio(host); -+ else -+ jz_mmc_receive_pio(host); -+#endif -+ } -+} -+ -+static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat) -+{ -+ struct mmc_command *cmd = host->cmd; -+ int i, temp[16]; -+ u8 *buf; -+ u32 data, v, w1, w2; -+ -+ if (!cmd) -+ return 0; -+ -+ host->cmd = NULL; -+ buf = (u8 *) temp; -+ switch (r_type) { -+ case 1: -+ { -+ data = REG_MSC_RES; -+ buf[0] = (data >> 8) & 0xff; -+ buf[1] = data & 0xff; -+ data = REG_MSC_RES; -+ buf[2] = (data >> 8) & 0xff; -+ buf[3] = data & 0xff; -+ data = REG_MSC_RES; -+ buf[4] = data & 0xff; -+ cmd->resp[0] = -+ buf[1] << 24 | buf[2] << 16 | buf[3] << 8 | -+ buf[4]; -+ break; -+ } -+ case 2: -+ { -+ data = REG_MSC_RES; -+ v = data & 0xffff; -+ for (i = 0; i < 4; i++) { -+ data = REG_MSC_RES; -+ w1 = data & 0xffff; -+ data = REG_MSC_RES; -+ w2 = data & 0xffff; -+ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; -+ v = w2; -+ } -+ break; -+ } -+ case 0: -+ break; -+ } -+ if (stat & MSC_STAT_TIME_OUT_RES) { -+ printk("MSC_STAT_TIME_OUT_RES\n"); -+ cmd->error = -ETIMEDOUT; -+ } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) { -+ printk("MSC_STAT_CRC\n"); -+ if (cmd->opcode == MMC_ALL_SEND_CID || -+ cmd->opcode == MMC_SEND_CSD || -+ cmd->opcode == MMC_SEND_CID) { -+ /* a bogus CRC error can appear if the msb of -+ the 15 byte response is a one */ -+ if ((cmd->resp[0] & 0x80000000) == 0) -+ cmd->error = -EILSEQ; -+ } -+ } -+ /* -+ * Did I mention this is Sick. We always need to -+ * discard the upper 8 bits of the first 16-bit word. -+ */ -+ if (host->data && cmd->error == 0) -+ jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE); -+ else -+ jz_mmc_finish_request(host, host->mrq); -+ -+ return 1; -+} -+ -+static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat) -+{ -+ struct mmc_data *data = host->data; -+ -+ if (!data) -+ return 0; -+ REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ -+ jz_mmc_stop_clock(); -+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, -+ host->dma_dir); -+ if (stat & MSC_STAT_TIME_OUT_READ) { -+ printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat); -+ data->error = -ETIMEDOUT; -+ } else if (REG_MSC_STAT & -+ (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) { -+ printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat); -+ data->error = -EILSEQ; -+ } -+ /* -+ * There appears to be a hardware design bug here. There seems to -+ * be no way to find out how much data was transferred to the card. -+ * This means that if there was an error on any block, we mark all -+ * data blocks as being in error. -+ */ -+ if (data->error == 0) -+ data->bytes_xfered = data->blocks * data->blksz; -+ else -+ data->bytes_xfered = 0; -+ -+ jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE); -+ host->data = NULL; -+ if (host->mrq->stop) { -+ jz_mmc_stop_clock(); -+ jz_mmc_start_cmd(host, host->mrq->stop, 0); -+ } else { -+ jz_mmc_finish_request(host, host->mrq); -+ } -+ return 1; -+} -+ -+static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ unsigned int cmdat; -+ -+ /* stop MMC clock */ -+ jz_mmc_stop_clock(); -+ -+ /* Save current request for the future processing */ -+ host->mrq = mrq; -+ host->data = mrq->data; -+ cmdat = host->cmdat; -+ host->cmdat &= ~MSC_CMDAT_INIT; -+ -+ if (mrq->data) { -+ cmdat &= ~MSC_CMDAT_BUSY; -+#ifdef USE_DMA -+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) -+ -+ cmdat |= -+ MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+ else { -+#ifdef CONFIG_JZ_MMC_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | -+ MSC_CMDAT_DMA_EN; -+#else -+ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; -+#endif -+ } -+ if (mrq->data->flags & MMC_DATA_WRITE) -+ cmdat |= MSC_CMDAT_WRITE; -+ -+ if (mrq->data->flags & MMC_DATA_STREAM) -+ cmdat |= MSC_CMDAT_STREAM_BLOCK; -+ if (mrq->cmd->opcode != MMC_WRITE_BLOCK -+ && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) -+ jz_mmc_rx_setup_data(host, mrq->data); -+#else /*USE_DMA*/ -+ -+ if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+ else { -+#ifdef CONFIG_JZ_MMC_BUS_1 -+ cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; -+ cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; -+#else -+ cmdat |= MSC_CMDAT_DATA_EN; -+#endif -+ } -+ if (mrq->data->flags & MMC_DATA_WRITE) -+ cmdat |= MSC_CMDAT_WRITE; -+ -+ if (mrq->data->flags & MMC_DATA_STREAM) -+ cmdat |= MSC_CMDAT_STREAM_BLOCK; -+ jz_mmc_prepare_data(host, host->data); -+#endif /*USE_DMA*/ -+ } -+ jz_mmc_start_cmd(host, mrq->cmd, cmdat); -+} -+ -+static irqreturn_t jz_mmc_irq(int irq, void *devid) -+{ -+ struct jz_mmc_host *host = devid; -+ unsigned int ireg; -+ int handled = 0; -+ -+ ireg = REG_MSC_IREG; -+ -+ if (ireg) { -+ unsigned stat = REG_MSC_STAT; -+ if (ireg & MSC_IREG_DATA_TRAN_DONE) -+ handled |= jz_mmc_data_done(host, stat); -+ } -+ return IRQ_RETVAL(handled); -+} -+ -+/* Returns true if MMC slot is empty */ -+static int jz_mmc_slot_is_empty(int slot) -+{ -+ int empty; -+ -+ empty = (__msc_card_detected(slot) == 0) ? 1 : 0; -+ -+ if (empty) { -+ /* wait for card insertion */ -+#ifdef CONFIG_MIPS_JZ4740_LYRA -+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); -+#else -+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); -+#endif -+ } else { -+ /* wait for card removal */ -+#ifdef CONFIG_MIPS_JZ4740_LYRA -+ __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); -+#else -+ __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); -+#endif -+ } -+ -+ return empty; -+} -+ -+static irqreturn_t jz_mmc_detect_irq(int irq, void *devid) -+{ -+ struct jz_mmc_host *host = (struct jz_mmc_host *) devid; -+ -+ if (jz_mmc_slot_is_empty(0)) { -+ mmc_slot_enable = 0; -+ mmc_detect_change(host->mmc, 50); -+ } else { -+ mmc_slot_enable = 1; -+ mmc_detect_change(host->mmc, 50); -+ } -+ return IRQ_HANDLED; -+} -+ -+static int jz_mmc_get_ro(struct mmc_host *mmc) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (host->pdata && host->pdata->get_ro) -+ return host->pdata->get_ro(mmc_dev(mmc)); -+ /* Host doesn't support read only detection so assume writeable */ -+ return 0; -+} -+ -+/* set clock and power */ -+static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (ios->clock) -+ jz_mmc_set_clock(ios->clock); -+ else -+ jz_mmc_stop_clock(); -+ -+ if (host->power_mode != ios->power_mode) { -+ host->power_mode = ios->power_mode; -+ -+ if (ios->power_mode == MMC_POWER_ON) -+ host->cmdat |= CMDAT_INIT; -+ } -+ -+ if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8)) -+ host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; -+ else -+ host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; -+} -+ -+static const struct mmc_host_ops jz_mmc_ops = { -+ .request = jz_mmc_request, -+ .get_ro = jz_mmc_get_ro, -+ .set_ios = jz_mmc_set_ios, -+}; -+static int jz_mmc_pm_callback(struct pm_dev *pm_dev, -+ pm_request_t req, void *data); -+ -+static int jz_mmc_probe(struct platform_device *pdev) -+{ -+ int retval; -+ struct mmc_host *mmc; -+ struct jz_mmc_host *host = NULL; -+ int irq; -+ struct resource *r; -+ -+ __gpio_as_msc(); -+ __msc_init_io(); -+ __msc_enable_power(); -+ -+ __msc_reset(); -+ -+ /* On reset, stop MMC clock */ -+ jz_mmc_stop_clock(); -+ -+ MMC_IRQ_MASK(); -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ irq = platform_get_irq(pdev, 0); -+ if (!r || irq < 0) -+ return -ENXIO; -+ -+ r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); -+ if (!r) -+ return -EBUSY; -+ -+ mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev); -+ if (!mmc) { -+ retval = -ENOMEM; -+ goto out; -+ } -+ mmc->ops = &jz_mmc_ops; -+ mmc->f_min = MMC_CLOCK_SLOW; -+ mmc->f_max = SD_CLOCK_FAST; -+ /* -+ * We can do SG-DMA, but we don't because we never know how much -+ * data we successfully wrote to the card. -+ */ -+ mmc->max_phys_segs = NR_SG; -+ /* -+ * Our hardware DMA can handle a maximum of one page per SG entry. -+ */ -+ mmc->max_seg_size = PAGE_SIZE; -+ /* -+ * Block length register is 10 bits. -+ */ -+ mmc->max_blk_size = 1023; -+ /* -+ * Block count register is 16 bits. -+ */ -+ mmc->max_blk_count = 65535; -+ host = mmc_priv(mmc); -+ host->mmc = mmc; -+ host->pdata = pdev->dev.platform_data; -+ mmc->ocr_avail = host->pdata ? -+ host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34; -+ host->mmc->caps = -+ MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SD_HIGHSPEED -+ | MMC_CAP_MMC_HIGHSPEED; -+ /* -+ *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers -+ * -+ */ -+ host->sg_cpu = -+ dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, -+ GFP_KERNEL); -+ if (!host->sg_cpu) { -+ retval = -ENOMEM; -+ goto out; -+ } -+ spin_lock_init(&host->lock); -+ host->irq = IRQ_MSC; -+ host->imask = 0xff; -+ /* -+ * Ensure that the host controller is shut down, and setup -+ * with our defaults. -+ */ -+ retval = request_irq(IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host); -+ if (retval) { -+ printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); -+ return retval; -+ } -+ jz_mmc_slot_is_empty(0); -+ /* Request card detect interrupt */ -+ -+ retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT, -+ "MMC card detect", host); -+ if (retval) { -+ printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n"); -+ goto err1; -+ } -+#ifdef USE_DMA -+ /* Request MMC Rx DMA channel */ -+ rxdmachan = -+ jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback, -+ 0, host); -+ if (rxdmachan < 0) { -+ printk(KERN_ERR "jz_request_dma failed for MMC Rx\n"); -+ goto err2; -+ } -+ -+ /* Request MMC Tx DMA channel */ -+ txdmachan = -+ jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback, -+ 0, host); -+ if (txdmachan < 0) { -+ printk(KERN_ERR "jz_request_dma failed for MMC Tx\n"); -+ goto err3; -+ } -+#endif -+ platform_set_drvdata(pdev, mmc); -+ mmc_add_host(mmc); -+#ifdef CONFIG_PM -+ /* Register MMC slot as as power-managed device */ -+ host->pmdev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, jz_mmc_pm_callback); -+ if (host->pmdev) -+ host->pmdev->data = pdev; -+#endif -+ printk("JZ SD/MMC card driver registered\n"); -+ -+ /* Detect card during initialization */ -+#ifdef CONFIG_SOC_JZ4740 -+ if (!jz_mmc_slot_is_empty(0)) { -+ mmc_slot_enable = 1; -+ mmc_detect_change(host->mmc, 0); -+ } -+#endif -+ return 0; -+ -+err1:free_irq(IRQ_MSC, &host); -+#ifdef USE_DMA -+ err2:jz_free_dma(rxdmachan); -+ err3:jz_free_dma(txdmachan); -+#endif -+out: -+ if (host) { -+ if (host->sg_cpu) -+ dma_free_coherent(&pdev->dev, PAGE_SIZE, -+ host->sg_cpu, host->sg_dma); -+ } -+ if (mmc) -+ mmc_free_host(mmc); -+ return -1; -+} -+ -+static int jz_mmc_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(pdev); -+ long flags; -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ if (mmc) { -+ struct jz_mmc_host *host = mmc_priv(mmc); -+ -+ if (host->pdata && host->pdata->exit) -+ host->pdata->exit(&pdev->dev, mmc); -+ -+ mmc_remove_host(mmc); -+ -+ local_irq_save(flags); -+ jz_mmc_stop_clock(); -+ __msc_disable_power(); -+ jz_free_dma(rxdmachan); -+ jz_free_dma(txdmachan); -+ free_irq(IRQ_MSC, host); -+ local_irq_restore(flags); -+ mmc_free_host(mmc); -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+pm_message_t state; -+static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ int ret = 0; -+ -+ __msc_disable_power(); -+ if (mmc) -+ ret = mmc_suspend_host(mmc, state); -+ -+ return ret; -+} -+ -+static int jz_mmc_resume(struct platform_device *dev) -+{ -+ struct mmc_host *mmc = platform_get_drvdata(dev); -+ int ret = 0; -+#if 0 -+ /*for sandisk BB0807011816D and other strange cards*/ -+ int i; -+ -+ for(i = 104; i < 110; i++) -+ __gpio_as_input(i); -+ -+ /* perhaps you should mdelay more */ -+ mdelay(1000); -+ __gpio_as_msc(); -+#endif -+ __msc_init_io(); -+ __msc_enable_power(); -+ __msc_reset(); -+ -+ if (!jz_mmc_slot_is_empty(0)) { -+ mmc_slot_enable = 1; -+ mmc_detect_change(mmc, 10); -+ } -+ -+ if (mmc) -+ ret = mmc_resume_host(mmc); -+ -+ return ret; -+} -+static int jz_mmc_pm_callback(struct pm_dev *pm_dev, -+ pm_request_t req, void *data) -+{ -+ struct platform_device *pdev = (struct platform_device *)pm_dev->data; -+ -+ switch(req) { -+ case PM_RESUME: -+ jz_mmc_resume(pdev); -+ break; -+ case PM_SUSPEND: -+ /* state has no use */ -+ jz_mmc_suspend(pdev, state); -+ break; -+ default: -+ printk("MMC/SD: invalid PM request %d\n", req); -+ break; -+ } -+ return 0; -+} -+#else -+#define jz_mmc_suspend NULL -+#define jz_mmc_resume NULL -+#endif -+ -+static struct platform_driver jz_mmc_driver = { -+ .probe = jz_mmc_probe, -+ .remove = jz_mmc_remove, -+ .suspend = jz_mmc_suspend, -+ .resume = jz_mmc_resume, -+ .driver = { -+ .name = DRIVER_NAME, -+ }, -+}; -+ -+static int __init jz_mmc_init(void) -+{ -+ return platform_driver_register(&jz_mmc_driver); -+} -+ -+static void __exit jz_mmc_exit(void) -+{ -+ platform_driver_unregister(&jz_mmc_driver); -+} -+ -+module_init(jz_mmc_init); -+module_exit(jz_mmc_exit); -+ -+MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/mmc/host/jz_mmc.h linux-2.6.24.7/drivers/mmc/host/jz_mmc.h ---- linux-2.6.24.7.old/drivers/mmc/host/jz_mmc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mmc/host/jz_mmc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,65 @@ -+#ifndef __JZ_MMC_H__ -+#define __JZ_MMC_H__ -+ -+#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ -+#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ -+#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ -+#define MMC_NO_ERROR 0 -+/* Extra MMC commands for state control */ -+/* Use negative numbers to disambiguate */ -+#define MMC_CIM_RESET -1 -+#define MMC_SET_CLOCK 100 -+ -+typedef struct jzsoc_dma_desc { -+ volatile u32 ddadr; /* Points to the next descriptor + flags */ -+ volatile u32 dsadr; /* DSADR value for the current transfer */ -+ volatile u32 dtadr; /* DTADR value for the current transfer */ -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+} jzsoc_dma_desc; -+ -+ -+ -+ -+#include -+ -+struct device; -+struct mmc_host; -+ -+struct jz_mmc_platform_data { -+ unsigned int ocr_mask; /* available voltages */ -+ unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ -+ int (*init)(struct device *, irq_handler_t , void *); -+ int (*get_ro)(struct device *); -+ void (*setpower)(struct device *, unsigned int); -+ void (*exit)(struct device *, void *); -+}; -+ -+//extern void pxa_set_mci_info(struct pxamci_platform_data *info); -+ -+ -+ -+#define SZ_1K 0x00000400 -+#define SZ_4K 0x00001000 -+#define SZ_8K 0x00002000 -+#define SZ_16K 0x00004000 -+#define SZ_64K 0x00010000 -+#define SZ_128K 0x00020000 -+#define SZ_256K 0x00040000 -+#define SZ_512K 0x00080000 -+ -+#define SZ_1M 0x00100000 -+#define SZ_2M 0x00200000 -+#define SZ_4M 0x00400000 -+#define SZ_8M 0x00800000 -+#define SZ_16M 0x01000000 -+#define SZ_32M 0x02000000 -+#define SZ_64M 0x04000000 -+#define SZ_128M 0x08000000 -+#define SZ_256M 0x10000000 -+#define SZ_512M 0x20000000 -+ -+#define SZ_1G 0x40000000 -+#define SZ_2G 0x80000000 -+ -+ -+#endif /* __JZ_MMC_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/Makefile linux-2.6.24.7/drivers/mtd/Makefile ---- linux-2.6.24.7.old/drivers/mtd/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -3,9 +3,9 @@ - # - - # Core functionality. --obj-$(CONFIG_MTD) += mtd.o - mtd-y := mtdcore.o mtdsuper.o - mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o -+obj-$(CONFIG_MTD) += $(mtd-y) - - obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -@@ -15,14 +15,15 @@ - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_CHAR) += mtdchar.o - obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o --obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -+#obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -+obj-$(CONFIG_MTD_BLOCK) += mtdblock-jz.o -+obj-$(CONFIG_UDC_USE_LB_CACHE) += udc_cache.o - obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o - obj-$(CONFIG_FTL) += ftl.o - obj-$(CONFIG_NFTL) += nftl.o - obj-$(CONFIG_INFTL) += inftl.o - obj-$(CONFIG_RFD_FTL) += rfd_ftl.o - obj-$(CONFIG_SSFDC) += ssfdc.o --obj-$(CONFIG_MTD_OOPS) += mtdoops.o - - nftl-objs := nftlcore.o nftlmount.o - inftl-objs := inftlcore.o inftlmount.o -@@ -30,3 +31,6 @@ - obj-y += chips/ maps/ devices/ nand/ onenand/ - - obj-$(CONFIG_MTD_UBI) += ubi/ -+ -+$(obj)/mtdblock-jz.o: $(obj)/mtdblock-jz.uu -+ uudecode $(obj)/mtdblock-jz.uu -o $(obj)/mtdblock-jz.o -\ No newline at end of file -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/HEAD linux-2.6.24.7/drivers/mtd/mtd-utils/.git/HEAD ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/heads/master -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/config linux-2.6.24.7/drivers/mtd/mtd-utils/.git/config ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/config 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/config 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+[core] -+ repositoryformatversion = 0 -+ filemode = true -+ bare = false -+ logallrefupdates = true -+[remote "origin"] -+ url = git://git.infradead.org/mtd-utils.git -+ fetch = +refs/heads/*:refs/remotes/origin/* -+[branch "master"] -+ remote = origin -+ merge = refs/heads/master -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/description linux-2.6.24.7/drivers/mtd/mtd-utils/.git/description ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/description 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/description 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+Unnamed repository; edit this file to name it for gitweb. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/applypatch-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,15 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message taken by -+# applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. The hook is -+# allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/commit-msg" && -+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} -+: -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/commit-msg linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/commit-msg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,24 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message. -+# Called by git-commit with one argument, the name of the file -+# that has the commit message. The hook should exit with non-zero -+# status after issuing an appropriate message if it wants to stop the -+# commit. The hook is allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+# Uncomment the below to add a Signed-off-by line to the message. -+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -+# hook is more suited to it. -+# -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -+ -+# This example catches duplicate Signed-off-by lines. -+ -+test "" = "$(grep '^Signed-off-by: ' "$1" | -+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { -+ echo >&2 Duplicate Signed-off-by lines. -+ exit 1 -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-commit linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-commit ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script that is called after a successful -+# commit is made. -+# -+# To enable this hook, make this file executable. -+ -+: Nothing -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-receive linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-receive ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-receive 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-receive 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#!/bin/sh -+# -+# An example hook script for the post-receive event -+# -+# This script is run after receive-pack has accepted a pack and the -+# repository has been updated. It is passed arguments in through stdin -+# in the form -+# -+# For example: -+# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master -+# -+# see contrib/hooks/ for an sample, or uncomment the next line (on debian) -+# -+ -+ -+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-update linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-update ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/post-update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/post-update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script to prepare a packed repository for use over -+# dumb transports. -+# -+# To enable this hook, make this file executable by "chmod +x post-update". -+ -+exec git-update-server-info -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-applypatch 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,14 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed -+# by applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/pre-commit" && -+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} -+: -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-commit linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-commit ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed. -+# Called by git-commit with no arguments. The hook should -+# exit with non-zero status after issuing an appropriate message if -+# it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+# This is slightly modified from Andrew Morton's Perfect Patch. -+# Lines you introduce should not have trailing whitespace. -+# Also check for an indentation that has SP before a TAB. -+ -+if git-rev-parse --verify HEAD 2>/dev/null -+then -+ git-diff-index -p -M --cached HEAD -- -+else -+ # NEEDSWORK: we should produce a diff with an empty tree here -+ # if we want to do the same verification for the initial import. -+ : -+fi | -+perl -e ' -+ my $found_bad = 0; -+ my $filename; -+ my $reported_filename = ""; -+ my $lineno; -+ sub bad_line { -+ my ($why, $line) = @_; -+ if (!$found_bad) { -+ print STDERR "*\n"; -+ print STDERR "* You have some suspicious patch lines:\n"; -+ print STDERR "*\n"; -+ $found_bad = 1; -+ } -+ if ($reported_filename ne $filename) { -+ print STDERR "* In $filename\n"; -+ $reported_filename = $filename; -+ } -+ print STDERR "* $why (line $lineno)\n"; -+ print STDERR "$filename:$lineno:$line\n"; -+ } -+ while (<>) { -+ if (m|^diff --git a/(.*) b/\1$|) { -+ $filename = $1; -+ next; -+ } -+ if (/^@@ -\S+ \+(\d+)/) { -+ $lineno = $1 - 1; -+ next; -+ } -+ if (/^ /) { -+ $lineno++; -+ next; -+ } -+ if (s/^\+//) { -+ $lineno++; -+ chomp; -+ if (/\s$/) { -+ bad_line("trailing whitespace", $_); -+ } -+ if (/^\s* \t/) { -+ bad_line("indent SP followed by a TAB", $_); -+ } -+ if (/^([<>])\1{6} |^={7}$/) { -+ bad_line("unresolved merge conflict", $_); -+ } -+ } -+ } -+ exit($found_bad); -+' -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-rebase linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-rebase ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/pre-rebase 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/pre-rebase 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,150 @@ -+#!/bin/sh -+# -+# Copyright (c) 2006 Junio C Hamano -+# -+ -+publish=next -+basebranch="$1" -+if test "$#" = 2 -+then -+ topic="refs/heads/$2" -+else -+ topic=`git symbolic-ref HEAD` -+fi -+ -+case "$basebranch,$topic" in -+master,refs/heads/??/*) -+ ;; -+*) -+ exit 0 ;# we do not interrupt others. -+ ;; -+esac -+ -+# Now we are dealing with a topic branch being rebased -+# on top of master. Is it OK to rebase it? -+ -+# Is topic fully merged to master? -+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` -+if test -z "$not_in_master" -+then -+ echo >&2 "$topic is fully merged to master; better remove it." -+ exit 1 ;# we could allow it, but there is no point. -+fi -+ -+# Is topic ever merged to next? If so you should not be rebasing it. -+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` -+only_next_2=`git-rev-list ^master ${publish} | sort` -+if test "$only_next_1" = "$only_next_2" -+then -+ not_in_topic=`git-rev-list "^$topic" master` -+ if test -z "$not_in_topic" -+ then -+ echo >&2 "$topic is already up-to-date with master" -+ exit 1 ;# we could allow it, but there is no point. -+ else -+ exit 0 -+ fi -+else -+ not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` -+ perl -e ' -+ my $topic = $ARGV[0]; -+ my $msg = "* $topic has commits already merged to public branch:\n"; -+ my (%not_in_next) = map { -+ /^([0-9a-f]+) /; -+ ($1 => 1); -+ } split(/\n/, $ARGV[1]); -+ for my $elem (map { -+ /^([0-9a-f]+) (.*)$/; -+ [$1 => $2]; -+ } split(/\n/, $ARGV[2])) { -+ if (!exists $not_in_next{$elem->[0]}) { -+ if ($msg) { -+ print STDERR $msg; -+ undef $msg; -+ } -+ print STDERR " $elem->[1]\n"; -+ } -+ } -+ ' "$topic" "$not_in_next" "$not_in_master" -+ exit 1 -+fi -+ -+exit 0 -+ -+################################################################ -+ -+This sample hook safeguards topic branches that have been -+published from being rewound. -+ -+The workflow assumed here is: -+ -+ * Once a topic branch forks from "master", "master" is never -+ merged into it again (either directly or indirectly). -+ -+ * Once a topic branch is fully cooked and merged into "master", -+ it is deleted. If you need to build on top of it to correct -+ earlier mistakes, a new topic branch is created by forking at -+ the tip of the "master". This is not strictly necessary, but -+ it makes it easier to keep your history simple. -+ -+ * Whenever you need to test or publish your changes to topic -+ branches, merge them into "next" branch. -+ -+The script, being an example, hardcodes the publish branch name -+to be "next", but it is trivial to make it configurable via -+$GIT_DIR/config mechanism. -+ -+With this workflow, you would want to know: -+ -+(1) ... if a topic branch has ever been merged to "next". Young -+ topic branches can have stupid mistakes you would rather -+ clean up before publishing, and things that have not been -+ merged into other branches can be easily rebased without -+ affecting other people. But once it is published, you would -+ not want to rewind it. -+ -+(2) ... if a topic branch has been fully merged to "master". -+ Then you can delete it. More importantly, you should not -+ build on top of it -- other people may already want to -+ change things related to the topic as patches against your -+ "master", so if you need further changes, it is better to -+ fork the topic (perhaps with the same name) afresh from the -+ tip of "master". -+ -+Let's look at this example: -+ -+ o---o---o---o---o---o---o---o---o---o "next" -+ / / / / -+ / a---a---b A / / -+ / / / / -+ / / c---c---c---c B / -+ / / / \ / -+ / / / b---b C \ / -+ / / / / \ / -+ ---o---o---o---o---o---o---o---o---o---o---o "master" -+ -+ -+A, B and C are topic branches. -+ -+ * A has one fix since it was merged up to "next". -+ -+ * B has finished. It has been fully merged up to "master" and "next", -+ and is ready to be deleted. -+ -+ * C has not merged to "next" at all. -+ -+We would want to allow C to be rebased, refuse A, and encourage -+B to be deleted. -+ -+To compute (1): -+ -+ git-rev-list ^master ^topic next -+ git-rev-list ^master next -+ -+ if these match, topic has not merged in next at all. -+ -+To compute (2): -+ -+ git-rev-list master..topic -+ -+ if this is empty, it is fully merged to "master". -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/prepare-commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+#!/bin/sh -+# -+# An example hook script to prepare the commit log message. -+# Called by git-commit with the name of the file that has the -+# commit message, followed by the description of the commit -+# message's source. The hook's purpose is to edit the commit -+# message file. If the hook fails with a non-zero status, -+# the commit is aborted. -+# -+# To enable this hook, make this file executable. -+ -+# This hook includes three examples. The first comments out the -+# "Conflicts:" part of a merge commit. -+# -+# The second includes the output of "git diff --name-status -r" -+# into the message, just before the "git status" output. It is -+# commented because it doesn't cope with --amend or with squashed -+# commits. -+# -+# The third example adds a Signed-off-by line to the message, that can -+# still be edited. This is rarely a good idea. -+ -+case "$2 $3" in -+ merge) -+ sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;; -+ -+# ""|template) -+# perl -i -pe ' -+# print "\n" . `git diff --cached --name-status -r` -+# if /^#/ && $first++ == 0' "$1" ;; -+ -+ *) ;; -+esac -+ -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/update linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/update ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/hooks/update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/hooks/update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,107 @@ -+#!/bin/sh -+# -+# An example hook script to blocks unannotated tags from entering. -+# Called by git-receive-pack with arguments: refname sha1-old sha1-new -+# -+# To enable this hook, make this file executable by "chmod +x update". -+# -+# Config -+# ------ -+# hooks.allowunannotated -+# This boolean sets whether unannotated tags will be allowed into the -+# repository. By default they won't be. -+# hooks.allowdeletetag -+# This boolean sets whether deleting tags will be allowed in the -+# repository. By default they won't be. -+# hooks.allowdeletebranch -+# This boolean sets whether deleting branches will be allowed in the -+# repository. By default they won't be. -+# -+ -+# --- Command line -+refname="$1" -+oldrev="$2" -+newrev="$3" -+ -+# --- Safety check -+if [ -z "$GIT_DIR" ]; then -+ echo "Don't run this script from the command line." >&2 -+ echo " (if you want, you could supply GIT_DIR then run" >&2 -+ echo " $0 )" >&2 -+ exit 1 -+fi -+ -+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then -+ echo "Usage: $0 " >&2 -+ exit 1 -+fi -+ -+# --- Config -+allowunannotated=$(git config --bool hooks.allowunannotated) -+allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -+allowdeletetag=$(git config --bool hooks.allowdeletetag) -+ -+# check for no description -+projectdesc=$(sed -e '1q' "$GIT_DIR/description") -+if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then -+ echo "*** Project description file hasn't been set" >&2 -+ exit 1 -+fi -+ -+# --- Check types -+# if $newrev is 0000...0000, it's a commit to delete a ref. -+if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then -+ newrev_type=delete -+else -+ newrev_type=$(git-cat-file -t $newrev) -+fi -+ -+case "$refname","$newrev_type" in -+ refs/tags/*,commit) -+ # un-annotated tag -+ short_refname=${refname##refs/tags/} -+ if [ "$allowunannotated" != "true" ]; then -+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 -+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,delete) -+ # delete tag -+ if [ "$allowdeletetag" != "true" ]; then -+ echo "*** Deleting a tag is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,tag) -+ # annotated tag -+ ;; -+ refs/heads/*,commit) -+ # branch -+ ;; -+ refs/heads/*,delete) -+ # delete branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/remotes/*,commit) -+ # tracking branch -+ ;; -+ refs/remotes/*,delete) -+ # delete tracking branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ *) -+ # Anything else (is there anything else?) -+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 -+ exit 1 -+ ;; -+esac -+ -+# --- Finished -+exit 0 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/info/exclude linux-2.6.24.7/drivers/mtd/mtd-utils/.git/info/exclude ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/info/exclude 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/info/exclude 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,6 @@ -+# git-ls-files --others --exclude-from=.git/info/exclude -+# Lines that start with '#' are comments. -+# For a project mostly in C, the following would be a good set of -+# exclude patterns (uncomment them if you want to use them): -+# *.[oa] -+# *~ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/HEAD linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/HEAD ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143725 +0800 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/heads/master linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/heads/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143725 +0800 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/origin 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 7afca4241e082c23bb38a4da532cc222457ae719 nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/logs/refs/remotes/origin/ubi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 22f90673165489fd50c893a91051a79c1b143d2a nancy 1210143724 +0800 clone: from git://git.infradead.org/mtd-utils.git -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep linux-2.6.24.7/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/objects/pack/pack-3aac9dd611b9d9b1367a74ba6217f301d746b650.keep 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+fetch-pack 10055 on bogon -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/heads/master linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/heads/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/HEAD 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/remotes/origin/master -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+d5f5e57b72289bb5f551a4e17be0132aa8dfb6c4 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/origin 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+7afca4241e082c23bb38a4da532cc222457ae719 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.git/refs/remotes/origin/ubi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+22f90673165489fd50c893a91051a79c1b143d2a -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/.gitignore linux-2.6.24.7/drivers/mtd/mtd-utils/.gitignore ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/.gitignore 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/.gitignore 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,26 @@ -+# -+# NOTE! Don't add files that are generated in specific -+# subdirectories here. Add them in the ".gitignore" file -+# in that subdirectory instead. -+# -+# Normal rules -+# -+.* -+*.o -+*.a -+*.s -+*.ko -+*.so -+*.mod.c -+*~ -+ -+# -+# Top-level generic files -+# -+ -+# -+# Generated include files -+# -+ -+# stgit generated dirs -+patches-* -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/COPYING linux-2.6.24.7/drivers/mtd/mtd-utils/COPYING ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/COPYING 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/COPYING 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) 19yy -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) 19yy name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/MAKEDEV linux-2.6.24.7/drivers/mtd/mtd-utils/MAKEDEV ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/MAKEDEV 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/MAKEDEV 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,42 @@ -+#!/bin/bash -+ -+function mkftl () { -+ mknod /dev/ftl$1 b 44 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/ftl$1$a b 44 `expr $2 + $a` -+ done -+} -+function mknftl () { -+ mknod /dev/nftl$1 b 93 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/nftl$1$a b 93 `expr $2 + $a` -+ done -+} -+function mkrfd () { -+ mknod /dev/rfd$1 b 256 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/rfd$1$a b 256 `expr $2 + $a` -+ done -+} -+function mkinftl () { -+ mknod /dev/inftl$1 b 96 $2 -+ for a in `seq 1 15`; do -+ mknod /dev/inftl$1$a b 96 `expr $2 + $a` -+ done -+} -+ -+M=0 -+for C in a b c d e f g h i j k l m n o p; do -+ mkftl $C $M -+ mknftl $C $M -+ mkrfd $C $M -+ mkinftl $C $M -+ let M=M+16 -+done -+ -+for a in `seq 0 16` ; do -+ mknod /dev/mtd$a c 90 `expr $a + $a` -+ mknod /dev/mtdr$a c 90 `expr $a + $a + 1` -+ mknod /dev/mtdblock$a b 31 $a -+done -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,102 @@ -+ -+# -*- sh -*- -+ -+OPTFLAGS := -O2 -Wall -+SBINDIR=/usr/sbin -+MANDIR=/usr/share/man -+INCLUDEDIR=/usr/include -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -I./include $(OPTFLAGS) -+ -+ifeq ($(origin CROSS),undefined) -+ BUILDDIR := . -+else -+# Remove the trailing slash to make the directory name -+ BUILDDIR := .#$(CROSS:-=) -+endif -+ -+ifeq ($(WITHOUT_XATTR), 1) -+ CFLAGS += -DWITHOUT_XATTR -+endif -+ -+#RAWTARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \ -+# ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \ -+# flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite nandtest \ -+# jffs2dump \ -+# nftldump nftl_format docfdisk \ -+# rfddump rfdformat \ -+# serve_image recv_image \ -+# sumtool #jffs2reader -+ -+RAWTARGETS = flash_erase flash_eraseall nanddump nanddump_vfat \ -+ flash_info \ -+ flash_otp_info flash_otp_dump nandwrite nandwrite_mlc \ -+ nandtest \ -+ sumtool #jffs2reader -+ -+TARGETS = $(foreach target,$(RAWTARGETS),$(BUILDDIR)/$(target)) -+ -+SYMLINKS = -+ -+%: %.o -+ $(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $^ -+ -+$(BUILDDIR)/%.o: %.c -+ mkdir -p $(BUILDDIR) -+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,$(BUILDDIR)/.$( ${DESTDIR}/${MANDIR}/man1/mkfs.jffs2.1.gz -+ make -C $(BUILDDIR)/ubi-utils install -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.c linux-2.6.24.7/drivers/mtd/mtd-utils/compr.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,538 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in this directory -+ * in the jffs2 directory. -+ */ -+ -+#include "compr.h" -+#include -+#include -+#include -+ -+#define FAVOUR_LZO_PERCENT 80 -+ -+extern int page_size; -+ -+/* LIST IMPLEMENTATION (from linux/list.h) */ -+ -+#define LIST_HEAD_INIT(name) { &(name), &(name) } -+ -+#define LIST_HEAD(name) \ -+ struct list_head name = LIST_HEAD_INIT(name) -+ -+static inline void __list_add(struct list_head *new, -+ struct list_head *prev, -+ struct list_head *next) -+{ -+ next->prev = new; -+ new->next = next; -+ new->prev = prev; -+ prev->next = new; -+} -+ -+static inline void list_add(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head, head->next); -+} -+ -+static inline void list_add_tail(struct list_head *new, struct list_head *head) -+{ -+ __list_add(new, head->prev, head); -+} -+ -+static inline void __list_del(struct list_head *prev, struct list_head *next) -+{ -+ next->prev = prev; -+ prev->next = next; -+} -+ -+static inline void list_del(struct list_head *entry) -+{ -+ __list_del(entry->prev, entry->next); -+ entry->next = (void *) 0; -+ entry->prev = (void *) 0; -+} -+ -+#define list_entry(ptr, type, member) \ -+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) -+ -+#define list_for_each_entry(pos, head, member) \ -+ for (pos = list_entry((head)->next, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = list_entry(pos->member.next, typeof(*pos), member)) -+ -+ -+/* Available compressors are on this list */ -+static LIST_HEAD(jffs2_compressor_list); -+ -+/* Actual compression mode */ -+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; -+ -+void jffs2_set_compression_mode(int mode) -+{ -+ jffs2_compression_mode = mode; -+} -+ -+int jffs2_get_compression_mode(void) -+{ -+ return jffs2_compression_mode; -+} -+ -+/* Statistics for blocks stored without compression */ -+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0; -+ -+/* Compression test stuffs */ -+ -+static int jffs2_compression_check = 0; -+ -+static unsigned char *jffs2_compression_check_buf = NULL; -+ -+void jffs2_compression_check_set(int yesno) -+{ -+ jffs2_compression_check = yesno; -+} -+ -+int jffs2_compression_check_get(void) -+{ -+ return jffs2_compression_check; -+} -+ -+static int jffs2_error_cnt = 0; -+ -+int jffs2_compression_check_errorcnt_get(void) -+{ -+ return jffs2_error_cnt; -+} -+ -+#define JFFS2_BUFFER_FILL 0x55 -+ -+/* Called before compression (if compression_check is setted) to prepare -+ the buffer for buffer overflow test */ -+static void jffs2_decompression_test_prepare(unsigned char *buf, int size) -+{ -+ memset(buf,JFFS2_BUFFER_FILL,size+1); -+} -+ -+/* Called after compression (if compression_check is setted) to test the result */ -+static void jffs2_decompression_test(struct jffs2_compressor *compr, -+ unsigned char *data_in, unsigned char *output_buf, -+ uint32_t cdatalen, uint32_t datalen, uint32_t buf_size) -+{ -+ uint32_t i; -+ -+ /* buffer overflow test */ -+ for (i=buf_size;i>cdatalen;i--) { -+ if (output_buf[i]!=JFFS2_BUFFER_FILL) { -+ fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. " -+ "(bs=%d csize=%d b[%d]=%d)\n", compr->name, -+ buf_size, cdatalen, i, (int)(output_buf[i])); -+ jffs2_error_cnt++; -+ return; -+ } -+ } -+ /* allocing temporary buffer for decompression */ -+ if (!jffs2_compression_check_buf) { -+ jffs2_compression_check_buf = malloc(page_size); -+ if (!jffs2_compression_check_buf) { -+ fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n"); -+ jffs2_compression_check = 0; -+ return; -+ } -+ } -+ /* decompressing */ -+ if (!compr->decompress) { -+ fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name); -+ jffs2_error_cnt++; -+ return; -+ } -+ if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen,NULL)) { -+ fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name); -+ jffs2_error_cnt++; -+ } -+ /* validate decompression */ -+ else { -+ for (i=0;iname, i); -+ jffs2_error_cnt++; -+ break; -+ } -+ } -+ } -+} -+ -+/* -+ * Return 1 to use this compression -+ */ -+static int jffs2_is_best_compression(struct jffs2_compressor *this, -+ struct jffs2_compressor *best, uint32_t size, uint32_t bestsize) -+{ -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_SIZE: -+ if (bestsize > size) -+ return 1; -+ return 0; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > size)) -+ return 1; -+ if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size)) -+ return 1; -+ if ((this->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100))) -+ return 1; -+ if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size) -+ return 1; -+ -+ return 0; -+ } -+ /* Shouldn't happen */ -+ return 0; -+} -+ -+/* jffs2_compress: -+ * @data: Pointer to uncompressed data -+ * @cdata: Pointer to returned pointer to buffer for compressed data -+ * @datalen: On entry, holds the amount of data available for compression. -+ * On exit, expected to hold the amount of data actually compressed. -+ * @cdatalen: On entry, holds the amount of space available for compressed -+ * data. On exit, expected to hold the actual size of the compressed -+ * data. -+ * -+ * Returns: Lower byte to be stored with data indicating compression type used. -+ * Zero is used to show that the data could not be compressed - the -+ * compressed version was actually larger than the original. -+ * Upper byte will be used later. (soon) -+ * -+ * If the cdata buffer isn't large enough to hold all the uncompressed data, -+ * jffs2_compress should compress as much as will fit, and should set -+ * *datalen accordingly to show the amount of data which were compressed. -+ */ -+uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen) -+{ -+ int ret = JFFS2_COMPR_NONE; -+ int compr_ret; -+ struct jffs2_compressor *this, *best=NULL; -+ unsigned char *output_buf = NULL, *tmp_buf; -+ uint32_t orig_slen, orig_dlen; -+ uint32_t best_slen=0, best_dlen=0; -+ -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_NONE: -+ break; -+ case JFFS2_COMPR_MODE_PRIORITY: -+ orig_slen = *datalen; -+ orig_dlen = *cdatalen; -+ output_buf = malloc(orig_dlen+jffs2_compression_check); -+ if (!output_buf) { -+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n"); -+ goto out; -+ } -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ /* Skip decompress-only backwards-compatibility and disabled modules */ -+ if ((!this->compress)||(this->disabled)) -+ continue; -+ -+ this->usecount++; -+ -+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ -+ jffs2_decompression_test_prepare(output_buf, orig_dlen); -+ -+ *datalen = orig_slen; -+ *cdatalen = orig_dlen; -+ compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); -+ this->usecount--; -+ if (!compr_ret) { -+ ret = this->compr; -+ this->stat_compr_blocks++; -+ this->stat_compr_orig_size += *datalen; -+ this->stat_compr_new_size += *cdatalen; -+ if (jffs2_compression_check) -+ jffs2_decompression_test(this, data_in, output_buf, *cdatalen, *datalen, orig_dlen); -+ break; -+ } -+ } -+ if (ret == JFFS2_COMPR_NONE) free(output_buf); -+ break; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ case JFFS2_COMPR_MODE_SIZE: -+ orig_slen = *datalen; -+ orig_dlen = *cdatalen; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ uint32_t needed_buf_size; -+ -+ if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO) -+ needed_buf_size = orig_slen + jffs2_compression_check; -+ else -+ needed_buf_size = orig_dlen + jffs2_compression_check; -+ -+ /* Skip decompress-only backwards-compatibility and disabled modules */ -+ if ((!this->compress)||(this->disabled)) -+ continue; -+ /* Allocating memory for output buffer if necessary */ -+ if ((this->compr_buf_size < needed_buf_size) && (this->compr_buf)) { -+ free(this->compr_buf); -+ this->compr_buf_size=0; -+ this->compr_buf=NULL; -+ } -+ if (!this->compr_buf) { -+ tmp_buf = malloc(needed_buf_size); -+ if (!tmp_buf) { -+ fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen); -+ continue; -+ } -+ else { -+ this->compr_buf = tmp_buf; -+ this->compr_buf_size = orig_dlen; -+ } -+ } -+ this->usecount++; -+ if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */ -+ jffs2_decompression_test_prepare(this->compr_buf,this->compr_buf_size); -+ *datalen = orig_slen; -+ *cdatalen = orig_dlen; -+ compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); -+ this->usecount--; -+ if (!compr_ret) { -+ if (jffs2_compression_check) -+ jffs2_decompression_test(this, data_in, this->compr_buf, *cdatalen, *datalen, this->compr_buf_size); -+ if (((!best_dlen) || jffs2_is_best_compression(this, best, *cdatalen, best_dlen)) -+ && (*cdatalen < *datalen)) { -+ best_dlen = *cdatalen; -+ best_slen = *datalen; -+ best = this; -+ } -+ } -+ } -+ if (best_dlen) { -+ *cdatalen = best_dlen; -+ *datalen = best_slen; -+ output_buf = best->compr_buf; -+ best->compr_buf = NULL; -+ best->compr_buf_size = 0; -+ best->stat_compr_blocks++; -+ best->stat_compr_orig_size += best_slen; -+ best->stat_compr_new_size += best_dlen; -+ ret = best->compr; -+ } -+ break; -+ default: -+ fprintf(stderr,"mkfs.jffs2: unknow compression mode.\n"); -+ } -+out: -+ if (ret == JFFS2_COMPR_NONE) { -+ *cpage_out = data_in; -+ *datalen = *cdatalen; -+ none_stat_compr_blocks++; -+ none_stat_compr_size += *datalen; -+ } -+ else { -+ *cpage_out = output_buf; -+ } -+ return ret; -+} -+ -+ -+int jffs2_register_compressor(struct jffs2_compressor *comp) -+{ -+ struct jffs2_compressor *this; -+ -+ if (!comp->name) { -+ fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n"); -+ return -1; -+ } -+ comp->compr_buf_size=0; -+ comp->compr_buf=NULL; -+ comp->usecount=0; -+ comp->stat_compr_orig_size=0; -+ comp->stat_compr_new_size=0; -+ comp->stat_compr_blocks=0; -+ comp->stat_decompr_blocks=0; -+ -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (this->priority < comp->priority) { -+ list_add(&comp->list, this->list.prev); -+ goto out; -+ } -+ } -+ list_add_tail(&comp->list, &jffs2_compressor_list); -+out: -+ return 0; -+} -+ -+int jffs2_unregister_compressor(struct jffs2_compressor *comp) -+{ -+ -+ if (comp->usecount) { -+ fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n"); -+ return -1; -+ } -+ list_del(&comp->list); -+ -+ return 0; -+} -+ -+#define JFFS2_STAT_BUF_SIZE 16000 -+ -+char *jffs2_list_compressors(void) -+{ -+ struct jffs2_compressor *this; -+ char *buf, *act_buf; -+ -+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority); -+ if ((this->disabled)||(!this->compress)) -+ act_buf += sprintf(act_buf,"disabled"); -+ else -+ act_buf += sprintf(act_buf,"enabled"); -+ act_buf += sprintf(act_buf,"\n"); -+ } -+ return buf; -+} -+ -+char *jffs2_stats(void) -+{ -+ struct jffs2_compressor *this; -+ char *buf, *act_buf; -+ -+ act_buf = buf = malloc(JFFS2_STAT_BUF_SIZE); -+ -+ act_buf += sprintf(act_buf,"Compression mode: "); -+ switch (jffs2_compression_mode) { -+ case JFFS2_COMPR_MODE_NONE: -+ act_buf += sprintf(act_buf,"none"); -+ break; -+ case JFFS2_COMPR_MODE_PRIORITY: -+ act_buf += sprintf(act_buf,"priority"); -+ break; -+ case JFFS2_COMPR_MODE_SIZE: -+ act_buf += sprintf(act_buf,"size"); -+ break; -+ case JFFS2_COMPR_MODE_FAVOURLZO: -+ act_buf += sprintf(act_buf, "favourlzo"); -+ break; -+ default: -+ act_buf += sprintf(act_buf,"unkown"); -+ break; -+ } -+ act_buf += sprintf(act_buf,"\nCompressors:\n"); -+ act_buf += sprintf(act_buf,"%10s ","none"); -+ act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, -+ none_stat_compr_size, none_stat_decompr_blocks); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ act_buf += sprintf(act_buf,"%10s (prio:%d) ",this->name,this->priority); -+ if ((this->disabled)||(!this->compress)) -+ act_buf += sprintf(act_buf,"- "); -+ else -+ act_buf += sprintf(act_buf,"+ "); -+ act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, -+ this->stat_compr_new_size, this->stat_compr_orig_size, -+ this->stat_decompr_blocks); -+ act_buf += sprintf(act_buf,"\n"); -+ } -+ return buf; -+} -+ -+int jffs2_set_compression_mode_name(const char *name) -+{ -+ if (!strcmp("none",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; -+ return 0; -+ } -+ if (!strcmp("priority",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; -+ return 0; -+ } -+ if (!strcmp("size",name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; -+ return 0; -+ } -+ if (!strcmp("favourlzo", name)) { -+ jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO; -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static int jffs2_compressor_Xable(const char *name, int disabled) -+{ -+ struct jffs2_compressor *this; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (!strcmp(this->name, name)) { -+ this->disabled = disabled; -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+int jffs2_enable_compressor_name(const char *name) -+{ -+ return jffs2_compressor_Xable(name, 0); -+} -+ -+int jffs2_disable_compressor_name(const char *name) -+{ -+ return jffs2_compressor_Xable(name, 1); -+} -+ -+int jffs2_set_compressor_priority(const char *name, int priority) -+{ -+ struct jffs2_compressor *this,*comp; -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (!strcmp(this->name, name)) { -+ this->priority = priority; -+ comp = this; -+ goto reinsert; -+ } -+ } -+ fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name); -+ return 1; -+reinsert: -+ /* list is sorted in the order of priority, so if -+ we change it we have to reinsert it into the -+ good place */ -+ list_del(&comp->list); -+ list_for_each_entry(this, &jffs2_compressor_list, list) { -+ if (this->priority < comp->priority) { -+ list_add(&comp->list, this->list.prev); -+ return 0; -+ } -+ } -+ list_add_tail(&comp->list, &jffs2_compressor_list); -+ return 0; -+} -+ -+ -+int jffs2_compressors_init(void) -+{ -+#ifdef CONFIG_JFFS2_ZLIB -+ jffs2_zlib_init(); -+#endif -+#ifdef CONFIG_JFFS2_RTIME -+ jffs2_rtime_init(); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+ jffs2_lzo_init(); -+#endif -+ return 0; -+} -+ -+int jffs2_compressors_exit(void) -+{ -+#ifdef CONFIG_JFFS2_RTIME -+ jffs2_rtime_exit(); -+#endif -+#ifdef CONFIG_JFFS2_ZLIB -+ jffs2_zlib_exit(); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+ jffs2_lzo_exit(); -+#endif -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.h linux-2.6.24.7/drivers/mtd/mtd-utils/compr.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in the -+ * jffs2 directory. -+ */ -+ -+#ifndef __JFFS2_COMPR_H__ -+#define __JFFS2_COMPR_H__ -+ -+#include -+#include -+#include -+#include "linux/jffs2.h" -+ -+#define CONFIG_JFFS2_ZLIB -+#define CONFIG_JFFS2_RTIME -+#define CONFIG_JFFS2_LZO -+ -+#define JFFS2_RUBINMIPS_PRIORITY 10 -+#define JFFS2_DYNRUBIN_PRIORITY 20 -+#define JFFS2_RTIME_PRIORITY 50 -+#define JFFS2_ZLIB_PRIORITY 60 -+#define JFFS2_LZO_PRIORITY 80 -+ -+#define JFFS2_COMPR_MODE_NONE 0 -+#define JFFS2_COMPR_MODE_PRIORITY 1 -+#define JFFS2_COMPR_MODE_SIZE 2 -+#define JFFS2_COMPR_MODE_FAVOURLZO 3 -+ -+#define kmalloc(a,b) malloc(a) -+#define kfree(a) free(a) -+#ifndef GFP_KERNEL -+#define GFP_KERNEL 0 -+#endif -+ -+#define vmalloc(a) malloc(a) -+#define vfree(a) free(a) -+ -+#define printk(...) fprintf(stderr,__VA_ARGS__) -+ -+#define KERN_EMERG -+#define KERN_ALERT -+#define KERN_CRIT -+#define KERN_ERR -+#define KERN_WARNING -+#define KERN_NOTICE -+#define KERN_INFO -+#define KERN_DEBUG -+ -+struct list_head { -+ struct list_head *next, *prev; -+}; -+ -+void jffs2_set_compression_mode(int mode); -+int jffs2_get_compression_mode(void); -+int jffs2_set_compression_mode_name(const char *mode_name); -+ -+int jffs2_enable_compressor_name(const char *name); -+int jffs2_disable_compressor_name(const char *name); -+ -+int jffs2_set_compressor_priority(const char *name, int priority); -+ -+struct jffs2_compressor { -+ struct list_head list; -+ int priority; /* used by prirority comr. mode */ -+ char *name; -+ char compr; /* JFFS2_COMPR_XXX */ -+ int (*compress)(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *srclen, uint32_t *destlen, void *model); -+ int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, -+ uint32_t cdatalen, uint32_t datalen, void *model); -+ int usecount; -+ int disabled; /* if seted the compressor won't compress */ -+ unsigned char *compr_buf; /* used by size compr. mode */ -+ uint32_t compr_buf_size; /* used by size compr. mode */ -+ uint32_t stat_compr_orig_size; -+ uint32_t stat_compr_new_size; -+ uint32_t stat_compr_blocks; -+ uint32_t stat_decompr_blocks; -+}; -+ -+int jffs2_register_compressor(struct jffs2_compressor *comp); -+int jffs2_unregister_compressor(struct jffs2_compressor *comp); -+ -+int jffs2_compressors_init(void); -+int jffs2_compressors_exit(void); -+ -+uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen); -+ -+/* If it is setted, a decompress will be called after every compress */ -+void jffs2_compression_check_set(int yesno); -+int jffs2_compression_check_get(void); -+int jffs2_compression_check_errorcnt_get(void); -+ -+char *jffs2_list_compressors(void); -+char *jffs2_stats(void); -+ -+/* Compressor modules */ -+ -+/* These functions will be called by jffs2_compressors_init/exit */ -+#ifdef CONFIG_JFFS2_ZLIB -+int jffs2_zlib_init(void); -+void jffs2_zlib_exit(void); -+#endif -+#ifdef CONFIG_JFFS2_RTIME -+int jffs2_rtime_init(void); -+void jffs2_rtime_exit(void); -+#endif -+#ifdef CONFIG_JFFS2_LZO -+int jffs2_lzo_init(void); -+void jffs2_lzo_exit(void); -+#endif -+ -+#endif /* __JFFS2_COMPR_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_lzo.c linux-2.6.24.7/drivers/mtd/mtd-utils/compr_lzo.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_lzo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_lzo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,120 @@ -+/* -+ * JFFS2 LZO Compression Interface. -+ * -+ * Copyright (C) 2007 Nokia Corporation. All rights reserved. -+ * -+ * Author: Richard Purdie -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "compr.h" -+ -+extern int page_size; -+ -+static void *lzo_mem; -+static void *lzo_compress_buf; -+ -+/* -+ * Note about LZO compression. -+ * -+ * We want to use the _999_ compression routine which gives better compression -+ * rates at the expense of time. Decompression time is unaffected. We might as -+ * well use the standard lzo library routines for this but they will overflow -+ * the destination buffer since they don't check the destination size. -+ * -+ * We therefore compress to a temporary buffer and copy if it will fit. -+ * -+ */ -+static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ uint32_t compress_size; -+ int ret; -+ -+ ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); -+ -+ if (ret != LZO_E_OK) -+ return -1; -+ -+ if (compress_size > *dstlen) -+ return -1; -+ -+ memcpy(cpage_out, lzo_compress_buf, compress_size); -+ *dstlen = compress_size; -+ -+ return 0; -+} -+ -+static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ int ret; -+ uint32_t dl; -+ -+ ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL); -+ -+ if (ret != LZO_E_OK || dl != destlen) -+ return -1; -+ -+ return 0; -+} -+ -+static struct jffs2_compressor jffs2_lzo_comp = { -+ .priority = JFFS2_LZO_PRIORITY, -+ .name = "lzo", -+ .compr = JFFS2_COMPR_LZO, -+ .compress = &jffs2_lzo_cmpr, -+ .decompress = &jffs2_lzo_decompress, -+ .disabled = 1, -+}; -+ -+int jffs2_lzo_init(void) -+{ -+ int ret; -+ -+ lzo_mem = malloc(LZO1X_999_MEM_COMPRESS); -+ if (!lzo_mem) -+ return -1; -+ -+ /* Worse case LZO compression size from their FAQ */ -+ lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3); -+ if (!lzo_compress_buf) { -+ free(lzo_mem); -+ return -1; -+ } -+ -+ ret = jffs2_register_compressor(&jffs2_lzo_comp); -+ if (ret < 0) { -+ free(lzo_compress_buf); -+ free(lzo_mem); -+ } -+ -+ return ret; -+} -+ -+void jffs2_lzo_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_lzo_comp); -+ free(lzo_compress_buf); -+ free(lzo_mem); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_rtime.c linux-2.6.24.7/drivers/mtd/mtd-utils/compr_rtime.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_rtime.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_rtime.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by Arjan van de Ven -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * Very simple lz77-ish encoder. -+ * -+ * Theory of operation: Both encoder and decoder have a list of "last -+ * occurrences" for every possible source-value; after sending the -+ * first source-byte, the second byte indicated the "run" length of -+ * matches -+ * -+ * The algorithm is intended to only send "whole bytes", no bit-messing. -+ * -+ */ -+ -+#include -+#include -+#include "compr.h" -+ -+/* _compress returns the compressed size, -1 if bigger */ -+static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ short positions[256]; -+ int outpos = 0; -+ int pos=0; -+ -+ memset(positions,0,sizeof(positions)); -+ -+ while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { -+ int backpos, runlen=0; -+ unsigned char value; -+ -+ value = data_in[pos]; -+ -+ cpage_out[outpos++] = data_in[pos++]; -+ -+ backpos = positions[value]; -+ positions[value]=pos; -+ -+ while ((backpos < pos) && (pos < (*sourcelen)) && -+ (data_in[pos]==data_in[backpos++]) && (runlen<255)) { -+ pos++; -+ runlen++; -+ } -+ cpage_out[outpos++] = runlen; -+ } -+ -+ if (outpos >= pos) { -+ /* We failed */ -+ return -1; -+ } -+ -+ /* Tell the caller how much we managed to compress, and how much space it took */ -+ *sourcelen = pos; -+ *dstlen = outpos; -+ return 0; -+} -+ -+ -+static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ short positions[256]; -+ int outpos = 0; -+ int pos=0; -+ -+ memset(positions,0,sizeof(positions)); -+ -+ while (outpos= outpos) { -+ while(repeat) { -+ cpage_out[outpos++] = cpage_out[backoffs++]; -+ repeat--; -+ } -+ } else { -+ memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); -+ outpos+=repeat; -+ } -+ } -+ } -+ return 0; -+} -+ -+ -+static struct jffs2_compressor jffs2_rtime_comp = { -+ .priority = JFFS2_RTIME_PRIORITY, -+ .name = "rtime", -+ .disabled = 0, -+ .compr = JFFS2_COMPR_RTIME, -+ .compress = &jffs2_rtime_compress, -+ .decompress = &jffs2_rtime_decompress, -+}; -+ -+int jffs2_rtime_init(void) -+{ -+ return jffs2_register_compressor(&jffs2_rtime_comp); -+} -+ -+void jffs2_rtime_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_rtime_comp); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_zlib.c linux-2.6.24.7/drivers/mtd/mtd-utils/compr_zlib.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/compr_zlib.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/compr_zlib.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,145 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001 Red Hat, Inc. -+ * -+ * Created by David Woodhouse -+ * -+ * The original JFFS, from which the design for JFFS2 was derived, -+ * was designed and implemented by Axis Communications AB. -+ * -+ * The contents of this file are subject to the Red Hat eCos Public -+ * License Version 1.1 (the "Licence"); you may not use this file -+ * except in compliance with the Licence. You may obtain a copy of -+ * the Licence at http://www.redhat.com/ -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ * -+ * The Original Code is JFFS2 - Journalling Flash File System, version 2 -+ * -+ * Alternatively, the contents of this file may be used under the -+ * terms of the GNU General Public License version 2 (the "GPL"), in -+ * which case the provisions of the GPL are applicable instead of the -+ * above. If you wish to allow the use of your version of this file -+ * only under the terms of the GPL and not to allow others to use your -+ * version of this file under the RHEPL, indicate your decision by -+ * deleting the provisions above and replace them with the notice and -+ * other provisions required by the GPL. If you do not delete the -+ * provisions above, a recipient may use your version of this file -+ * under either the RHEPL or the GPL. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "compr.h" -+ -+#define min(x,y) ((x)<(y)?(x):(y)) -+ -+/* Plan: call deflate() with avail_in == *sourcelen, -+ avail_out = *dstlen - 12 and flush == Z_FINISH. -+ If it doesn't manage to finish, call it again with -+ avail_in == 0 and avail_out set to the remaining 12 -+ bytes for it to clean up. -+Q: Is 12 bytes sufficient? -+ */ -+#define STREAM_END_SPACE 12 -+ -+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen, void *model) -+{ -+ z_stream strm; -+ int ret; -+ -+ if (*dstlen <= STREAM_END_SPACE) -+ return -1; -+ -+ strm.zalloc = (void *)0; -+ strm.zfree = (void *)0; -+ -+ if (Z_OK != deflateInit(&strm, 3)) { -+ return -1; -+ } -+ strm.next_in = data_in; -+ strm.total_in = 0; -+ -+ strm.next_out = cpage_out; -+ strm.total_out = 0; -+ -+ while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { -+ strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); -+ strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); -+ ret = deflate(&strm, Z_PARTIAL_FLUSH); -+ if (ret != Z_OK) { -+ deflateEnd(&strm); -+ return -1; -+ } -+ } -+ strm.avail_out += STREAM_END_SPACE; -+ strm.avail_in = 0; -+ ret = deflate(&strm, Z_FINISH); -+ if (ret != Z_STREAM_END) { -+ deflateEnd(&strm); -+ return -1; -+ } -+ deflateEnd(&strm); -+ -+ if (strm.total_out >= strm.total_in) -+ return -1; -+ -+ -+ *dstlen = strm.total_out; -+ *sourcelen = strm.total_in; -+ return 0; -+} -+ -+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen, void *model) -+{ -+ z_stream strm; -+ int ret; -+ -+ strm.zalloc = (void *)0; -+ strm.zfree = (void *)0; -+ -+ if (Z_OK != inflateInit(&strm)) { -+ return 1; -+ } -+ strm.next_in = data_in; -+ strm.avail_in = srclen; -+ strm.total_in = 0; -+ -+ strm.next_out = cpage_out; -+ strm.avail_out = destlen; -+ strm.total_out = 0; -+ -+ while((ret = inflate(&strm, Z_FINISH)) == Z_OK) -+ ; -+ -+ inflateEnd(&strm); -+ return 0; -+} -+ -+static struct jffs2_compressor jffs2_zlib_comp = { -+ .priority = JFFS2_ZLIB_PRIORITY, -+ .name = "zlib", -+ .disabled = 0, -+ .compr = JFFS2_COMPR_ZLIB, -+ .compress = &jffs2_zlib_compress, -+ .decompress = &jffs2_zlib_decompress, -+}; -+ -+int jffs2_zlib_init(void) -+{ -+ return jffs2_register_compressor(&jffs2_zlib_comp); -+} -+ -+void jffs2_zlib_exit(void) -+{ -+ jffs2_unregister_compressor(&jffs2_zlib_comp); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.c linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+#include -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.h linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+#ifndef CRC32_H -+#define CRC32_H -+ -+#include -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+ -+ static inline uint32_t -+crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/device_table.txt linux-2.6.24.7/drivers/mtd/mtd-utils/device_table.txt ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/device_table.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/device_table.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,129 @@ -+# This is a sample device table file for use with mkfs.jffs2. You can -+# do all sorts of interesting things with a device table file. For -+# example, if you want to adjust the permissions on a particular file -+# you can just add an entry like: -+# /sbin/foobar f 2755 0 0 - - - - - -+# and (assuming the file /sbin/foobar exists) it will be made setuid -+# root (regardless of what its permissions are on the host filesystem. -+# -+# Device table entries take the form of: -+# -+# where name is the file name, type can be one of: -+# f A regular file -+# d Directory -+# c Character special device file -+# b Block special device file -+# p Fifo (named pipe) -+# uid is the user id for the target file, gid is the group id for the -+# target file. The rest of the entried apply only to device special -+# file. -+ -+# When building a target filesystem, it is desirable to not have to -+# become root and then run 'mknod' a thousand times. Using a device -+# table you can create device nodes and directories "on the fly". -+# Furthermore, you can use a single table entry to create a many device -+# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15] -+# I could just use the following two table entries: -+# /dev/hda b 640 0 0 3 0 0 0 - -+# /dev/hda b 640 0 0 3 1 1 1 15 -+# -+# Have fun -+# -Erik Andersen -+# -+ -+# -+/dev d 755 0 0 - - - - - -+/dev/mem c 640 0 0 1 1 0 0 - -+/dev/kmem c 640 0 0 1 2 0 0 - -+/dev/null c 640 0 0 1 3 0 0 - -+/dev/zero c 640 0 0 1 5 0 0 - -+/dev/random c 640 0 0 1 8 0 0 - -+/dev/urandom c 640 0 0 1 9 0 0 - -+/dev/tty c 666 0 0 5 0 0 0 - -+/dev/tty c 666 0 0 4 0 0 1 6 -+/dev/console c 640 0 0 5 1 0 0 - -+/dev/ram b 640 0 0 1 1 0 0 - -+/dev/ram b 640 0 0 1 0 0 1 4 -+/dev/loop b 640 0 0 7 0 0 1 2 -+/dev/ptmx c 666 0 0 5 2 0 0 - -+#/dev/ttyS c 640 0 0 4 64 0 1 4 -+#/dev/psaux c 640 0 0 10 1 0 0 - -+#/dev/rtc c 640 0 0 10 135 0 0 - -+ -+# Adjust permissions on some normal files -+#/etc/shadow f 600 0 0 - - - - - -+#/bin/tinylogin f 4755 0 0 - - - - - -+ -+# User-mode Linux stuff -+/dev/ubda b 640 0 0 98 0 0 0 - -+/dev/ubda b 640 0 0 98 1 1 1 15 -+ -+# IDE Devices -+/dev/hda b 640 0 0 3 0 0 0 - -+/dev/hda b 640 0 0 3 1 1 1 15 -+/dev/hdb b 640 0 0 3 64 0 0 - -+/dev/hdb b 640 0 0 3 65 1 1 15 -+#/dev/hdc b 640 0 0 22 0 0 0 - -+#/dev/hdc b 640 0 0 22 1 1 1 15 -+#/dev/hdd b 640 0 0 22 64 0 0 - -+#/dev/hdd b 640 0 0 22 65 1 1 15 -+#/dev/hde b 640 0 0 33 0 0 0 - -+#/dev/hde b 640 0 0 33 1 1 1 15 -+#/dev/hdf b 640 0 0 33 64 0 0 - -+#/dev/hdf b 640 0 0 33 65 1 1 15 -+#/dev/hdg b 640 0 0 34 0 0 0 - -+#/dev/hdg b 640 0 0 34 1 1 1 15 -+#/dev/hdh b 640 0 0 34 64 0 0 - -+#/dev/hdh b 640 0 0 34 65 1 1 15 -+ -+# SCSI Devices -+#/dev/sda b 640 0 0 8 0 0 0 - -+#/dev/sda b 640 0 0 8 1 1 1 15 -+#/dev/sdb b 640 0 0 8 16 0 0 - -+#/dev/sdb b 640 0 0 8 17 1 1 15 -+#/dev/sdc b 640 0 0 8 32 0 0 - -+#/dev/sdc b 640 0 0 8 33 1 1 15 -+#/dev/sdd b 640 0 0 8 48 0 0 - -+#/dev/sdd b 640 0 0 8 49 1 1 15 -+#/dev/sde b 640 0 0 8 64 0 0 - -+#/dev/sde b 640 0 0 8 65 1 1 15 -+#/dev/sdf b 640 0 0 8 80 0 0 - -+#/dev/sdf b 640 0 0 8 81 1 1 15 -+#/dev/sdg b 640 0 0 8 96 0 0 - -+#/dev/sdg b 640 0 0 8 97 1 1 15 -+#/dev/sdh b 640 0 0 8 112 0 0 - -+#/dev/sdh b 640 0 0 8 113 1 1 15 -+#/dev/sg c 640 0 0 21 0 0 1 15 -+#/dev/scd b 640 0 0 11 0 0 1 15 -+#/dev/st c 640 0 0 9 0 0 1 8 -+#/dev/nst c 640 0 0 9 128 0 1 8 -+#/dev/st c 640 0 0 9 32 1 1 4 -+#/dev/st c 640 0 0 9 64 1 1 4 -+#/dev/st c 640 0 0 9 96 1 1 4 -+ -+# Floppy disk devices -+#/dev/fd b 640 0 0 2 0 0 1 2 -+#/dev/fd0d360 b 640 0 0 2 4 0 0 - -+#/dev/fd1d360 b 640 0 0 2 5 0 0 - -+#/dev/fd0h1200 b 640 0 0 2 8 0 0 - -+#/dev/fd1h1200 b 640 0 0 2 9 0 0 - -+#/dev/fd0u1440 b 640 0 0 2 28 0 0 - -+#/dev/fd1u1440 b 640 0 0 2 29 0 0 - -+#/dev/fd0u2880 b 640 0 0 2 32 0 0 - -+#/dev/fd1u2880 b 640 0 0 2 33 0 0 - -+ -+# All the proprietary cdrom devices in the world -+#/dev/aztcd b 640 0 0 29 0 0 0 - -+#/dev/bpcd b 640 0 0 41 0 0 0 - -+#/dev/capi20 c 640 0 0 68 0 0 1 2 -+#/dev/cdu31a b 640 0 0 15 0 0 0 - -+#/dev/cdu535 b 640 0 0 24 0 0 0 - -+#/dev/cm206cd b 640 0 0 32 0 0 0 - -+#/dev/sjcd b 640 0 0 18 0 0 0 - -+#/dev/sonycd b 640 0 0 15 0 0 0 - -+#/dev/gscd b 640 0 0 16 0 0 0 - -+#/dev/sbpcd b 640 0 0 25 0 0 0 - -+#/dev/sbpcd b 640 0 0 25 0 0 1 4 -+#/dev/mcd b 640 0 0 23 0 0 0 - -+#/dev/optcd b 640 0 0 17 0 0 0 - -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/doc_loadbios.c linux-2.6.24.7/drivers/mtd/mtd-utils/doc_loadbios.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/doc_loadbios.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/doc_loadbios.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,148 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+unsigned char databuf[512]; -+ -+int main(int argc,char **argv) -+{ -+ mtd_info_t meminfo; -+ int ifd,ofd; -+ struct stat statbuf; -+ erase_info_t erase; -+ unsigned long retlen, ofs, iplsize, ipltailsize; -+ unsigned char *iplbuf; -+ iplbuf = NULL; -+ -+ if (argc < 3) { -+ fprintf(stderr,"You must specify a device," -+ " the source firmware file and the offset\n"); -+ return 1; -+ } -+ -+ // Open and size the device -+ if ((ofd = open(argv[1],O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if ((ifd = open(argv[2], O_RDONLY)) < 0) { -+ perror("Open firmware file\n"); -+ close(ofd); -+ return 1; -+ } -+ -+ if (fstat(ifd, &statbuf) != 0) { -+ perror("Stat firmware file"); -+ goto error; -+ } -+ -+#if 0 -+ if (statbuf.st_size > 65536) { -+ printf("Firmware too large (%ld bytes)\n",statbuf.st_size); -+ goto error; -+ } -+#endif -+ -+ if (ioctl(ofd,MEMGETINFO,&meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ goto error; -+ } -+ -+ iplsize = (ipltailsize = 0); -+ if (argc >= 4) { -+ /* DoC Millennium has IPL in the first 1K of flash memory */ -+ /* You may want to specify the offset 1024 to store -+ the firmware next to IPL. */ -+ iplsize = strtoul(argv[3], NULL, 0); -+ ipltailsize = iplsize % meminfo.erasesize; -+ } -+ -+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) { -+ perror("lseek"); -+ goto error; -+ } -+ -+ if (ipltailsize) { -+ iplbuf = malloc(ipltailsize); -+ if (iplbuf == NULL) { -+ fprintf(stderr, "Not enough memory for IPL tail buffer of" -+ " %lu bytes\n", (unsigned long) ipltailsize); -+ goto error; -+ } -+ printf("Reading IPL%s area of length %lu at offset %lu\n", -+ (iplsize - ipltailsize) ? " tail" : "", -+ (long unsigned) ipltailsize, -+ (long unsigned) (iplsize - ipltailsize)); -+ if (read(ofd, iplbuf, ipltailsize) != ipltailsize) { -+ perror("read"); -+ goto error; -+ } -+ } -+ -+ erase.length = meminfo.erasesize; -+ -+ for (ofs = iplsize - ipltailsize ; -+ ofs < iplsize + statbuf.st_size ; -+ ofs += meminfo.erasesize) { -+ erase.start = ofs; -+ printf("Performing Flash Erase of length %lu at offset %lu\n", -+ (long unsigned) erase.length, (long unsigned) erase.start); -+ -+ if (ioctl(ofd,MEMERASE,&erase) != 0) { -+ perror("ioctl(MEMERASE)"); -+ goto error; -+ } -+ } -+ -+ if (lseek(ofd, iplsize - ipltailsize, SEEK_SET) < 0) { -+ perror("lseek"); -+ goto error; -+ } -+ -+ if (ipltailsize) { -+ printf("Writing IPL%s area of length %lu at offset %lu\n", -+ (iplsize - ipltailsize) ? " tail" : "", -+ (long unsigned) ipltailsize, -+ (long unsigned) (iplsize - ipltailsize)); -+ if (write(ofd, iplbuf, ipltailsize) != ipltailsize) { -+ perror("write"); -+ goto error; -+ } -+ } -+ -+ printf("Writing the firmware of length %lu at %lu... ", -+ (unsigned long) statbuf.st_size, -+ (unsigned long) iplsize); -+ do { -+ retlen = read(ifd, databuf, 512); -+ if (retlen < 512) -+ memset(databuf+retlen, 0xff, 512-retlen); -+ if (write(ofd, databuf, 512) != 512) { -+ perror("write"); -+ goto error; -+ } -+ } while (retlen == 512); -+ printf("Done.\n"); -+ -+ if (iplbuf != NULL) -+ free(iplbuf); -+ close(ifd); -+ close(ofd); -+ return 0; -+ -+error: -+ if (iplbuf != NULL) -+ free(iplbuf); -+ close(ifd); -+ close(ofd); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/docfdisk.c linux-2.6.24.7/drivers/mtd/mtd-utils/docfdisk.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/docfdisk.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/docfdisk.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,317 @@ -+/* -+ * docfdisk.c: Modify INFTL partition tables -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#define _XOPEN_SOURCE 500 /* for pread/pwrite */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+unsigned char *buf; -+ -+mtd_info_t meminfo; -+erase_info_t erase; -+int fd; -+struct INFTLMediaHeader *mh; -+ -+#define MAXSCAN 10 -+ -+void show_header(int mhoffs) { -+ int i, unitsize, numunits, bmbits, numpart; -+ int start, end, num, nextunit; -+ unsigned int flags; -+ struct INFTLPartition *ip; -+ -+ bmbits = le32_to_cpu(mh->BlockMultiplierBits); -+ printf(" bootRecordID = %s\n" -+ " NoOfBootImageBlocks = %d\n" -+ " NoOfBinaryPartitions = %d\n" -+ " NoOfBDTLPartitions = %d\n" -+ " BlockMultiplierBits = %d\n" -+ " FormatFlags = %d\n" -+ " OsakVersion = %d.%d.%d.%d\n" -+ " PercentUsed = %d\n", -+ mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks), -+ le32_to_cpu(mh->NoOfBinaryPartitions), -+ le32_to_cpu(mh->NoOfBDTLPartitions), -+ bmbits, -+ le32_to_cpu(mh->FormatFlags), -+ ((unsigned char *) &mh->OsakVersion)[0] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[1] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[2] & 0xf, -+ ((unsigned char *) &mh->OsakVersion)[3] & 0xf, -+ le32_to_cpu(mh->PercentUsed)); -+ -+ numpart = le32_to_cpu(mh->NoOfBinaryPartitions) + -+ le32_to_cpu(mh->NoOfBDTLPartitions); -+ unitsize = meminfo.erasesize >> bmbits; -+ numunits = meminfo.size / unitsize; -+ nextunit = mhoffs / unitsize; -+ nextunit++; -+ printf("Unitsize is %d bytes. Device has %d units.\n", -+ unitsize, numunits); -+ if (numunits > 32768) { -+ printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n"); -+ } -+ if (bmbits && (numunits <= 16384)) { -+ printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n"); -+ } -+ for (i = 0; i < 4; i++) { -+ ip = &(mh->Partitions[i]); -+ flags = le32_to_cpu(ip->flags); -+ start = le32_to_cpu(ip->firstUnit); -+ end = le32_to_cpu(ip->lastUnit); -+ num = le32_to_cpu(ip->virtualUnits); -+ if (start < nextunit) { -+ printf("ERROR: Overlapping or misordered partitions!\n"); -+ } -+ if (start > nextunit) { -+ printf(" Unpartitioned space: %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n", -+ (start - nextunit) * unitsize, start - nextunit, -+ nextunit, start - 1); -+ } -+ if (flags & INFTL_BINARY) -+ printf(" Partition %d (BDK):", i+1); -+ else -+ printf(" Partition %d (BDTL):", i+1); -+ printf(" %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n" -+ " flags = 0x%x\n" -+ " spareUnits = %d\n", -+ num * unitsize, num, start, end, -+ le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits)); -+ if (num > (1 + end - start)) { -+ printf("ERROR: virtualUnits not consistent with first/lastUnit!\n"); -+ } -+ end++; -+ if (end > nextunit) -+ nextunit = end; -+ if (flags & INFTL_LAST) -+ break; -+ } -+ if (i >= 4) { -+ printf("Odd. Last partition was not marked with INFTL_LAST.\n"); -+ i--; -+ } -+ if ((i+1) != numpart) { -+ printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n"); -+ } -+ if (nextunit > numunits) { -+ printf("ERROR: Partitions appear to extend beyond end of device!\n"); -+ } -+ if (nextunit < numunits) { -+ printf(" Unpartitioned space: %d bytes\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n", -+ (numunits - nextunit) * unitsize, numunits - nextunit, -+ nextunit, numunits - 1); -+ } -+} -+ -+ -+int main(int argc, char **argv) -+{ -+ int ret, i, mhblock, unitsize, block; -+ unsigned int nblocks[4], npart; -+ unsigned int totblocks; -+ struct INFTLPartition *ip; -+ unsigned char *oobbuf; -+ struct mtd_oob_buf oob; -+ char line[20]; -+ int mhoffs; -+ struct INFTLMediaHeader *mh2; -+ -+ if (argc < 2) { -+ printf( -+ "Usage: %s [ [ [ [ 4) { -+ printf("Max 4 partitions allowed.\n"); -+ return 1; -+ } -+ -+ for (i = 0; i < npart; i++) { -+ nblocks[i] = strtoul(argv[2+i], NULL, 0); -+ if (i && !nblocks[i-1]) { -+ printf("No sizes allowed after 0\n"); -+ return 1; -+ } -+ } -+ -+ // Open and size the device -+ if ((fd = open(argv[1], O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ return 1; -+ } -+ -+ printf("Device size is %d bytes. Erasesize is %d bytes.\n", -+ meminfo.size, meminfo.erasesize); -+ -+ buf = malloc(meminfo.erasesize); -+ oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize); -+ if (!buf || !oobbuf) { -+ printf("Can't malloc block buffer\n"); -+ return 1; -+ } -+ oob.length = meminfo.oobsize; -+ -+ mh = (struct INFTLMediaHeader *) buf; -+ -+ for (mhblock = 0; mhblock < MAXSCAN; mhblock++) { -+ if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) { -+ if (errno == EBADMSG) { -+ printf("ECC error at eraseblock %d\n", mhblock); -+ continue; -+ } -+ perror("Read eraseblock"); -+ return 1; -+ } -+ if (ret != meminfo.erasesize) { -+ printf("Short read!\n"); -+ return 1; -+ } -+ if (!strcmp("BNAND", mh->bootRecordID)) break; -+ } -+ if (mhblock >= MAXSCAN) { -+ printf("Unable to find INFTL Media Header\n"); -+ return 1; -+ } -+ printf("Found INFTL Media Header at block %d:\n", mhblock); -+ mhoffs = mhblock * meminfo.erasesize; -+ -+ oob.ptr = oobbuf; -+ oob.start = mhoffs; -+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) { -+ if (ioctl(fd, MEMREADOOB, &oob)) { -+ perror("ioctl(MEMREADOOB)"); -+ return 1; -+ } -+ oob.start += meminfo.writesize; -+ oob.ptr += meminfo.oobsize; -+ } -+ -+ show_header(mhoffs); -+ -+ if (!npart) -+ return 0; -+ -+ printf("\n" -+ "-------------------------------------------------------------------------\n"); -+ -+ unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits); -+ totblocks = meminfo.size / unitsize; -+ block = mhoffs / unitsize; -+ block++; -+ -+ mh->NoOfBDTLPartitions = 0; -+ mh->NoOfBinaryPartitions = npart; -+ -+ for (i = 0; i < npart; i++) { -+ ip = &(mh->Partitions[i]); -+ ip->firstUnit = cpu_to_le32(block); -+ if (!nblocks[i]) -+ nblocks[i] = totblocks - block; -+ ip->virtualUnits = cpu_to_le32(nblocks[i]); -+ block += nblocks[i]; -+ ip->lastUnit = cpu_to_le32(block-1); -+ ip->spareUnits = 0; -+ ip->flags = cpu_to_le32(INFTL_BINARY); -+ } -+ if (block > totblocks) { -+ printf("Requested partitions extend beyond end of device.\n"); -+ return 1; -+ } -+ ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST); -+ -+ /* update the spare as well */ -+ mh2 = (struct INFTLMediaHeader *) (buf + 4096); -+ memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader)); -+ -+ printf("\nProposed new Media Header:\n"); -+ show_header(mhoffs); -+ -+ printf("\nReady to update device. Type 'yes' to proceed, anything else to abort: "); -+ fgets(line, sizeof(line), stdin); -+ if (strcmp("yes\n", line)) -+ return 0; -+ printf("Updating MediaHeader...\n"); -+ -+ erase.start = mhoffs; -+ erase.length = meminfo.erasesize; -+ if (ioctl(fd, MEMERASE, &erase)) { -+ perror("ioctl(MEMERASE)"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ -+ oob.ptr = oobbuf; -+ oob.start = mhoffs; -+ for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) { -+ memset(oob.ptr, 0xff, 6); // clear ECC. -+ if (ioctl(fd, MEMWRITEOOB, &oob)) { -+ perror("ioctl(MEMWRITEOOB)"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) { -+ perror("Write page"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ if (ret != meminfo.writesize) { -+ printf("Short write!\n"); -+ printf("Your MediaHeader may be hosed. UHOH!\n"); -+ return 1; -+ } -+ -+ oob.start += meminfo.writesize; -+ oob.ptr += meminfo.oobsize; -+ buf += meminfo.writesize; -+ } -+ -+ printf("Success. REBOOT or unload the diskonchip module to update partitions!\n"); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/feature-removal-schedule.txt linux-2.6.24.7/drivers/mtd/mtd-utils/feature-removal-schedule.txt ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/feature-removal-schedule.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/feature-removal-schedule.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,9 @@ -+The following is a list of files and features that are going to be -+removed in the mtd-utils source tree. Every entry should contain what -+exactly is going away, why it is happening, and who is going to be doing -+the work. When the feature is removed from the utils, it should also -+be removed from this file. -+ -+--------------------------- -+ -+--------------------------- -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/fec.c linux-2.6.24.7/drivers/mtd/mtd-utils/fec.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/fec.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/fec.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,917 @@ -+/* -+ * fec.c -- forward error correction based on Vandermonde matrices -+ * 980624 -+ * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) -+ * -+ * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), -+ * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari -+ * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS -+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY -+ * OF SUCH DAMAGE. -+ */ -+ -+/* -+ * The following parameter defines how many bits are used for -+ * field elements. The code supports any value from 2 to 16 -+ * but fastest operation is achieved with 8 bit elements -+ * This is the only parameter you may want to change. -+ */ -+#ifndef GF_BITS -+#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ -+#endif -+ -+#include -+#include -+#include -+ -+/* -+ * compatibility stuff -+ */ -+#ifdef MSDOS /* but also for others, e.g. sun... */ -+#define NEED_BCOPY -+#define bcmp(a,b,n) memcmp(a,b,n) -+#endif -+ -+#ifdef NEED_BCOPY -+#define bcopy(s, d, siz) memcpy((d), (s), (siz)) -+#define bzero(d, siz) memset((d), '\0', (siz)) -+#endif -+ -+/* -+ * stuff used for testing purposes only -+ */ -+ -+#ifdef TEST -+#define DEB(x) -+#define DDB(x) x -+#define DEBUG 0 /* minimal debugging */ -+#ifdef MSDOS -+#include -+struct timeval { -+ unsigned long ticks; -+}; -+#define gettimeofday(x, dummy) { (x)->ticks = clock() ; } -+#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC ) -+typedef unsigned long u_long ; -+typedef unsigned short u_short ; -+#else /* typically, unix systems */ -+#include -+#define DIFF_T(a,b) \ -+ (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) -+#endif -+ -+#define TICK(t) \ -+ {struct timeval x ; \ -+ gettimeofday(&x, NULL) ; \ -+ t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ -+ } -+#define TOCK(t) \ -+ { u_long t1 ; TICK(t1) ; \ -+ if (t1 < t) t = 256000000 + t1 - t ; \ -+ else t = t1 - t ; \ -+ if (t == 0) t = 1 ;} -+ -+u_long ticks[10]; /* vars for timekeeping */ -+#else -+#define DEB(x) -+#define DDB(x) -+#define TICK(x) -+#define TOCK(x) -+#endif /* TEST */ -+ -+/* -+ * You should not need to change anything beyond this point. -+ * The first part of the file implements linear algebra in GF. -+ * -+ * gf is the type used to store an element of the Galois Field. -+ * Must constain at least GF_BITS bits. -+ * -+ * Note: unsigned char will work up to GF(256) but int seems to run -+ * faster on the Pentium. We use int whenever have to deal with an -+ * index, since they are generally faster. -+ */ -+#if (GF_BITS < 2 && GF_BITS >16) -+#error "GF_BITS must be 2 .. 16" -+#endif -+#if (GF_BITS <= 8) -+typedef unsigned char gf; -+#else -+typedef unsigned short gf; -+#endif -+ -+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ -+ -+/* -+ * Primitive polynomials - see Lin & Costello, Appendix A, -+ * and Lee & Messerschmitt, p. 453. -+ */ -+static char *allPp[] = { /* GF_BITS polynomial */ -+ NULL, /* 0 no code */ -+ NULL, /* 1 no code */ -+ "111", /* 2 1+x+x^2 */ -+ "1101", /* 3 1+x+x^3 */ -+ "11001", /* 4 1+x+x^4 */ -+ "101001", /* 5 1+x^2+x^5 */ -+ "1100001", /* 6 1+x+x^6 */ -+ "10010001", /* 7 1 + x^3 + x^7 */ -+ "101110001", /* 8 1+x^2+x^3+x^4+x^8 */ -+ "1000100001", /* 9 1+x^4+x^9 */ -+ "10010000001", /* 10 1+x^3+x^10 */ -+ "101000000001", /* 11 1+x^2+x^11 */ -+ "1100101000001", /* 12 1+x+x^4+x^6+x^12 */ -+ "11011000000001", /* 13 1+x+x^3+x^4+x^13 */ -+ "110000100010001", /* 14 1+x+x^6+x^10+x^14 */ -+ "1100000000000001", /* 15 1+x+x^15 */ -+ "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */ -+}; -+ -+ -+/* -+ * To speed up computations, we have tables for logarithm, exponent -+ * and inverse of a number. If GF_BITS <= 8, we use a table for -+ * multiplication as well (it takes 64K, no big deal even on a PDA, -+ * especially because it can be pre-initialized an put into a ROM!), -+ * otherwhise we use a table of logarithms. -+ * In any case the macro gf_mul(x,y) takes care of multiplications. -+ */ -+ -+static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */ -+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */ -+static gf inverse[GF_SIZE+1]; /* inverse of field elem. */ -+ /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */ -+ -+/* -+ * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, -+ * without a slow divide. -+ */ -+static inline gf -+modnn(int x) -+{ -+ while (x >= GF_SIZE) { -+ x -= GF_SIZE; -+ x = (x >> GF_BITS) + (x & GF_SIZE); -+ } -+ return x; -+} -+ -+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;} -+ -+/* -+ * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much -+ * faster to use a multiplication table. -+ * -+ * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying -+ * many numbers by the same constant. In this case the first -+ * call sets the constant, and others perform the multiplications. -+ * A value related to the multiplication is held in a local variable -+ * declared with USE_GF_MULC . See usage in addmul1(). -+ */ -+#if (GF_BITS <= 8) -+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1]; -+ -+#define gf_mul(x,y) gf_mul_table[x][y] -+ -+#define USE_GF_MULC register gf * __gf_mulc_ -+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c] -+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x] -+ -+static void -+init_mul_table() -+{ -+ int i, j; -+ for (i=0; i< GF_SIZE+1; i++) -+ for (j=0; j< GF_SIZE+1; j++) -+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ; -+ -+ for (j=0; j< GF_SIZE+1; j++) -+ gf_mul_table[0][j] = gf_mul_table[j][0] = 0; -+} -+#else /* GF_BITS > 8 */ -+static inline gf -+gf_mul(x,y) -+{ -+ if ( (x) == 0 || (y)==0 ) return 0; -+ -+ return gf_exp[gf_log[x] + gf_log[y] ] ; -+} -+#define init_mul_table() -+ -+#define USE_GF_MULC register gf * __gf_mulc_ -+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ] -+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; } -+#endif -+ -+/* -+ * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] -+ * Lookup tables: -+ * index->polynomial form gf_exp[] contains j= \alpha^i; -+ * polynomial form -> index form gf_log[ j = \alpha^i ] = i -+ * \alpha=x is the primitive element of GF(2^m) -+ * -+ * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple -+ * multiplication of two numbers can be resolved without calling modnn -+ */ -+ -+/* -+ * i use malloc so many times, it is easier to put checks all in -+ * one place. -+ */ -+static void * -+my_malloc(int sz, char *err_string) -+{ -+ void *p = malloc( sz ); -+ if (p == NULL) { -+ fprintf(stderr, "-- malloc failure allocating %s\n", err_string); -+ exit(1) ; -+ } -+ return p ; -+} -+ -+#define NEW_GF_MATRIX(rows, cols) \ -+ (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " ) -+ -+/* -+ * initialize the data structures used for computations in GF. -+ */ -+static void -+generate_gf(void) -+{ -+ int i; -+ gf mask; -+ char *Pp = allPp[GF_BITS] ; -+ -+ mask = 1; /* x ** 0 = 1 */ -+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */ -+ /* -+ * first, generate the (polynomial representation of) powers of \alpha, -+ * which are stored in gf_exp[i] = \alpha ** i . -+ * At the same time build gf_log[gf_exp[i]] = i . -+ * The first GF_BITS powers are simply bits shifted to the left. -+ */ -+ for (i = 0; i < GF_BITS; i++, mask <<= 1 ) { -+ gf_exp[i] = mask; -+ gf_log[gf_exp[i]] = i; -+ /* -+ * If Pp[i] == 1 then \alpha ** i occurs in poly-repr -+ * gf_exp[GF_BITS] = \alpha ** GF_BITS -+ */ -+ if ( Pp[i] == '1' ) -+ gf_exp[GF_BITS] ^= mask; -+ } -+ /* -+ * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als -+ * compute its inverse. -+ */ -+ gf_log[gf_exp[GF_BITS]] = GF_BITS; -+ /* -+ * Poly-repr of \alpha ** (i+1) is given by poly-repr of -+ * \alpha ** i shifted left one-bit and accounting for any -+ * \alpha ** GF_BITS term that may occur when poly-repr of -+ * \alpha ** i is shifted. -+ */ -+ mask = 1 << (GF_BITS - 1 ) ; -+ for (i = GF_BITS + 1; i < GF_SIZE; i++) { -+ if (gf_exp[i - 1] >= mask) -+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1); -+ else -+ gf_exp[i] = gf_exp[i - 1] << 1; -+ gf_log[gf_exp[i]] = i; -+ } -+ /* -+ * log(0) is not defined, so use a special value -+ */ -+ gf_log[0] = GF_SIZE ; -+ /* set the extended gf_exp values for fast multiply */ -+ for (i = 0 ; i < GF_SIZE ; i++) -+ gf_exp[i + GF_SIZE] = gf_exp[i] ; -+ -+ /* -+ * again special cases. 0 has no inverse. This used to -+ * be initialized to GF_SIZE, but it should make no difference -+ * since noone is supposed to read from here. -+ */ -+ inverse[0] = 0 ; -+ inverse[1] = 1; -+ for (i=2; i<=GF_SIZE; i++) -+ inverse[i] = gf_exp[GF_SIZE-gf_log[i]]; -+} -+ -+/* -+ * Various linear algebra operations that i use often. -+ */ -+ -+/* -+ * addmul() computes dst[] = dst[] + c * src[] -+ * This is used often, so better optimize it! Currently the loop is -+ * unrolled 16 times, a good value for 486 and pentium-class machines. -+ * The case c=0 is also optimized, whereas c=1 is not. These -+ * calls are unfrequent in my typical apps so I did not bother. -+ * -+ * Note that gcc on -+ */ -+#define addmul(dst, src, c, sz) \ -+ if (c != 0) addmul1(dst, src, c, sz) -+ -+#define UNROLL 16 /* 1, 4, 8, 16 */ -+static void -+addmul1(gf *dst1, gf *src1, gf c, int sz) -+{ -+ USE_GF_MULC ; -+ register gf *dst = dst1, *src = src1 ; -+ gf *lim = &dst[sz - UNROLL + 1] ; -+ -+ GF_MULC0(c) ; -+ -+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ -+ for (; dst < lim ; dst += UNROLL, src += UNROLL ) { -+ GF_ADDMULC( dst[0] , src[0] ); -+ GF_ADDMULC( dst[1] , src[1] ); -+ GF_ADDMULC( dst[2] , src[2] ); -+ GF_ADDMULC( dst[3] , src[3] ); -+#if (UNROLL > 4) -+ GF_ADDMULC( dst[4] , src[4] ); -+ GF_ADDMULC( dst[5] , src[5] ); -+ GF_ADDMULC( dst[6] , src[6] ); -+ GF_ADDMULC( dst[7] , src[7] ); -+#endif -+#if (UNROLL > 8) -+ GF_ADDMULC( dst[8] , src[8] ); -+ GF_ADDMULC( dst[9] , src[9] ); -+ GF_ADDMULC( dst[10] , src[10] ); -+ GF_ADDMULC( dst[11] , src[11] ); -+ GF_ADDMULC( dst[12] , src[12] ); -+ GF_ADDMULC( dst[13] , src[13] ); -+ GF_ADDMULC( dst[14] , src[14] ); -+ GF_ADDMULC( dst[15] , src[15] ); -+#endif -+ } -+#endif -+ lim += UNROLL - 1 ; -+ for (; dst < lim; dst++, src++ ) /* final components */ -+ GF_ADDMULC( *dst , *src ); -+} -+ -+/* -+ * computes C = AB where A is n*k, B is k*m, C is n*m -+ */ -+static void -+matmul(gf *a, gf *b, gf *c, int n, int k, int m) -+{ -+ int row, col, i ; -+ -+ for (row = 0; row < n ; row++) { -+ for (col = 0; col < m ; col++) { -+ gf *pa = &a[ row * k ]; -+ gf *pb = &b[ col ]; -+ gf acc = 0 ; -+ for (i = 0; i < k ; i++, pa++, pb += m ) -+ acc ^= gf_mul( *pa, *pb ) ; -+ c[ row * m + col ] = acc ; -+ } -+ } -+} -+ -+#ifdef DEBUG -+/* -+ * returns 1 if the square matrix is identiy -+ * (only for test) -+ */ -+static int -+is_identity(gf *m, int k) -+{ -+ int row, col ; -+ for (row=0; row 1) { -+ fprintf(stderr, "singular matrix\n"); -+ goto fail ; -+ } -+ } -+ } -+ } -+ if (icol == -1) { -+ fprintf(stderr, "XXX pivot not found!\n"); -+ goto fail ; -+ } -+found_piv: -+ ++(ipiv[icol]) ; -+ /* -+ * swap rows irow and icol, so afterwards the diagonal -+ * element will be correct. Rarely done, not worth -+ * optimizing. -+ */ -+ if (irow != icol) { -+ for (ix = 0 ; ix < k ; ix++ ) { -+ SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; -+ } -+ } -+ indxr[col] = irow ; -+ indxc[col] = icol ; -+ pivot_row = &src[icol*k] ; -+ c = pivot_row[icol] ; -+ if (c == 0) { -+ fprintf(stderr, "singular matrix 2\n"); -+ goto fail ; -+ } -+ if (c != 1 ) { /* otherwhise this is a NOP */ -+ /* -+ * this is done often , but optimizing is not so -+ * fruitful, at least in the obvious ways (unrolling) -+ */ -+ DEB( pivswaps++ ; ) -+ c = inverse[ c ] ; -+ pivot_row[icol] = 1 ; -+ for (ix = 0 ; ix < k ; ix++ ) -+ pivot_row[ix] = gf_mul(c, pivot_row[ix] ); -+ } -+ /* -+ * from all rows, remove multiples of the selected row -+ * to zero the relevant entry (in fact, the entry is not zero -+ * because we know it must be zero). -+ * (Here, if we know that the pivot_row is the identity, -+ * we can optimize the addmul). -+ */ -+ id_row[icol] = 1; -+ if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) { -+ for (p = src, ix = 0 ; ix < k ; ix++, p += k ) { -+ if (ix != icol) { -+ c = p[icol] ; -+ p[icol] = 0 ; -+ addmul(p, pivot_row, c, k ); -+ } -+ } -+ } -+ id_row[icol] = 0; -+ } /* done all columns */ -+ for (col = k-1 ; col >= 0 ; col-- ) { -+ if (indxr[col] <0 || indxr[col] >= k) -+ fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]); -+ else if (indxc[col] <0 || indxc[col] >= k) -+ fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]); -+ else -+ if (indxr[col] != indxc[col] ) { -+ for (row = 0 ; row < k ; row++ ) { -+ SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ; -+ } -+ } -+ } -+ error = 0 ; -+fail: -+ free(indxc); -+ free(indxr); -+ free(ipiv); -+ free(id_row); -+ free(temp_row); -+ return error ; -+} -+ -+/* -+ * fast code for inverting a vandermonde matrix. -+ * XXX NOTE: It assumes that the matrix -+ * is not singular and _IS_ a vandermonde matrix. Only uses -+ * the second column of the matrix, containing the p_i's. -+ * -+ * Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but -+ * largely revised for my purposes. -+ * p = coefficients of the matrix (p_i) -+ * q = values of the polynomial (known) -+ */ -+ -+int -+invert_vdm(gf *src, int k) -+{ -+ int i, j, row, col ; -+ gf *b, *c, *p; -+ gf t, xx ; -+ -+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */ -+ return 0 ; -+ /* -+ * c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1 -+ * b holds the coefficient for the matrix inversion -+ */ -+ c = NEW_GF_MATRIX(1, k); -+ b = NEW_GF_MATRIX(1, k); -+ -+ p = NEW_GF_MATRIX(1, k); -+ -+ for ( j=1, i = 0 ; i < k ; i++, j+=k ) { -+ c[i] = 0 ; -+ p[i] = src[j] ; /* p[i] */ -+ } -+ /* -+ * construct coeffs. recursively. We know c[k] = 1 (implicit) -+ * and start P_0 = x - p_0, then at each stage multiply by -+ * x - p_i generating P_i = x P_{i-1} - p_i P_{i-1} -+ * After k steps we are done. -+ */ -+ c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */ -+ for (i = 1 ; i < k ; i++ ) { -+ gf p_i = p[i] ; /* see above comment */ -+ for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ ) -+ c[j] ^= gf_mul( p_i, c[j+1] ) ; -+ c[k-1] ^= p_i ; -+ } -+ -+ for (row = 0 ; row < k ; row++ ) { -+ /* -+ * synthetic division etc. -+ */ -+ xx = p[row] ; -+ t = 1 ; -+ b[k-1] = 1 ; /* this is in fact c[k] */ -+ for (i = k-2 ; i >= 0 ; i-- ) { -+ b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ; -+ t = gf_mul(xx, t) ^ b[i] ; -+ } -+ for (col = 0 ; col < k ; col++ ) -+ src[col*k + row] = gf_mul(inverse[t], b[col] ); -+ } -+ free(c) ; -+ free(b) ; -+ free(p) ; -+ return 0 ; -+} -+ -+static int fec_initialized = 0 ; -+static void -+init_fec() -+{ -+ TICK(ticks[0]); -+ generate_gf(); -+ TOCK(ticks[0]); -+ DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);) -+ TICK(ticks[0]); -+ init_mul_table(); -+ TOCK(ticks[0]); -+ DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);) -+ fec_initialized = 1 ; -+} -+ -+/* -+ * This section contains the proper FEC encoding/decoding routines. -+ * The encoding matrix is computed starting with a Vandermonde matrix, -+ * and then transforming it into a systematic matrix. -+ */ -+ -+#define FEC_MAGIC 0xFECC0DEC -+ -+struct fec_parms { -+ u_long magic ; -+ int k, n ; /* parameters of the code */ -+ gf *enc_matrix ; -+} ; -+ -+void -+fec_free(struct fec_parms *p) -+{ -+ if (p==NULL || -+ p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (int)(p->enc_matrix)) ) { -+ fprintf(stderr, "bad parameters to fec_free\n"); -+ return ; -+ } -+ free(p->enc_matrix); -+ free(p); -+} -+ -+/* -+ * create a new encoder, returning a descriptor. This contains k,n and -+ * the encoding matrix. -+ */ -+struct fec_parms * -+fec_new(int k, int n) -+{ -+ int row, col ; -+ gf *p, *tmp_m ; -+ -+ struct fec_parms *retval ; -+ -+ if (fec_initialized == 0) -+ init_fec(); -+ -+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) { -+ fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n", -+ k, n, GF_SIZE ); -+ return NULL ; -+ } -+ retval = my_malloc(sizeof(struct fec_parms), "new_code"); -+ retval->k = k ; -+ retval->n = n ; -+ retval->enc_matrix = NEW_GF_MATRIX(n, k); -+ retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (int)(retval->enc_matrix) ; -+ tmp_m = NEW_GF_MATRIX(n, k); -+ /* -+ * fill the matrix with powers of field elements, starting from 0. -+ * The first row is special, cannot be computed with exp. table. -+ */ -+ tmp_m[0] = 1 ; -+ for (col = 1; col < k ; col++) -+ tmp_m[col] = 0 ; -+ for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) { -+ for ( col = 0 ; col < k ; col ++ ) -+ p[col] = gf_exp[modnn(row*col)]; -+ } -+ -+ /* -+ * quick code to build systematic matrix: invert the top -+ * k*k vandermonde matrix, multiply right the bottom n-k rows -+ * by the inverse, and construct the identity matrix at the top. -+ */ -+ TICK(ticks[3]); -+ invert_vdm(tmp_m, k); /* much faster than invert_mat */ -+ matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k); -+ /* -+ * the upper matrix is I so do not bother with a slow multiply -+ */ -+ bzero(retval->enc_matrix, k*k*sizeof(gf) ); -+ for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 ) -+ *p = 1 ; -+ free(tmp_m); -+ TOCK(ticks[3]); -+ -+ DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n", -+ ticks[3]);) -+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");) -+ return retval ; -+} -+ -+/* -+ * fec_encode accepts as input pointers to n data packets of size sz, -+ * and produces as output a packet pointed to by fec, computed -+ * with index "index". -+ */ -+void -+fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz) -+{ -+ int i, k = code->k ; -+ gf *p ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (index < k) -+ bcopy(src[index], fec, sz*sizeof(gf) ) ; -+ else if (index < code->n) { -+ p = &(code->enc_matrix[index*k] ); -+ bzero(fec, sz*sizeof(gf)); -+ for (i = 0; i < k ; i++) -+ addmul(fec, src[i], p[i], sz ) ; -+ } else -+ fprintf(stderr, "Invalid index %d (max %d)\n", -+ index, code->n - 1 ); -+} -+ -+void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz) -+{ -+ int i, k = code->k ; -+ gf *p ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (index < k) -+ bcopy(src + (index * sz), fec, sz*sizeof(gf) ) ; -+ else if (index < code->n) { -+ p = &(code->enc_matrix[index*k] ); -+ bzero(fec, sz*sizeof(gf)); -+ for (i = 0; i < k ; i++) -+ addmul(fec, src + (i * sz), p[i], sz ) ; -+ } else -+ fprintf(stderr, "Invalid index %d (max %d)\n", -+ index, code->n - 1 ); -+} -+/* -+ * shuffle move src packets in their position -+ */ -+static int -+shuffle(gf *pkt[], int index[], int k) -+{ -+ int i; -+ -+ for ( i = 0 ; i < k ; ) { -+ if (index[i] >= k || index[i] == i) -+ i++ ; -+ else { -+ /* -+ * put pkt in the right position (first check for conflicts). -+ */ -+ int c = index[i] ; -+ -+ if (index[c] == c) { -+ DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);) -+ return 1 ; -+ } -+ SWAP(index[i], index[c], int) ; -+ SWAP(pkt[i], pkt[c], gf *) ; -+ } -+ } -+ DEB( /* just test that it works... */ -+ for ( i = 0 ; i < k ; i++ ) { -+ if (index[i] < k && index[i] != i) { -+ fprintf(stderr, "shuffle: after\n"); -+ for (i=0; ik ; -+ gf *p, *matrix = NEW_GF_MATRIX(k, k); -+ -+ TICK(ticks[9]); -+ for (i = 0, p = matrix ; i < k ; i++, p += k ) { -+#if 1 /* this is simply an optimization, not very useful indeed */ -+ if (index[i] < k) { -+ bzero(p, k*sizeof(gf) ); -+ p[i] = 1 ; -+ } else -+#endif -+ if (index[i] < code->n ) -+ bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) ); -+ else { -+ fprintf(stderr, "decode: invalid index %d (max %d)\n", -+ index[i], code->n - 1 ); -+ free(matrix) ; -+ return NULL ; -+ } -+ } -+ TICK(ticks[9]); -+ if (invert_mat(matrix, k)) { -+ free(matrix); -+ matrix = NULL ; -+ } -+ TOCK(ticks[9]); -+ return matrix ; -+} -+ -+/* -+ * fec_decode receives as input a vector of packets, the indexes of -+ * packets, and produces the correct vector as output. -+ * -+ * Input: -+ * code: pointer to code descriptor -+ * pkt: pointers to received packets. They are modified -+ * to store the output packets (in place) -+ * index: pointer to packet indexes (modified) -+ * sz: size of each packet -+ */ -+int -+fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz) -+{ -+ gf *m_dec ; -+ gf **new_pkt ; -+ int row, col , k = code->k ; -+ -+ if (GF_BITS > 8) -+ sz /= 2 ; -+ -+ if (shuffle(pkt, index, k)) /* error if true */ -+ return 1 ; -+ m_dec = build_decode_matrix(code, pkt, index); -+ -+ if (m_dec == NULL) -+ return 1 ; /* error */ -+ /* -+ * do the actual decoding -+ */ -+ new_pkt = my_malloc (k * sizeof (gf * ), "new pkt pointers" ); -+ for (row = 0 ; row < k ; row++ ) { -+ if (index[row] >= k) { -+ new_pkt[row] = my_malloc (sz * sizeof (gf), "new pkt buffer" ); -+ bzero(new_pkt[row], sz * sizeof(gf) ) ; -+ for (col = 0 ; col < k ; col++ ) -+ addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ; -+ } -+ } -+ /* -+ * move pkts to their final destination -+ */ -+ for (row = 0 ; row < k ; row++ ) { -+ if (index[row] >= k) { -+ bcopy(new_pkt[row], pkt[row], sz*sizeof(gf)); -+ free(new_pkt[row]); -+ } -+ } -+ free(new_pkt); -+ free(m_dec); -+ -+ return 0; -+} -+ -+/*********** end of FEC code -- beginning of test code ************/ -+ -+#if (TEST || DEBUG) -+void -+test_gf() -+{ -+ int i ; -+ /* -+ * test gf tables. Sufficiently tested... -+ */ -+ for (i=0; i<= GF_SIZE; i++) { -+ if (gf_exp[gf_log[i]] != i) -+ fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n", -+ i, gf_log[i], gf_exp[gf_log[i]]); -+ -+ if (i != 0 && gf_mul(i, inverse[i]) != 1) -+ fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n", -+ i, inverse[i], gf_mul(i, inverse[i]) ); -+ if (gf_mul(0,i) != 0) -+ fprintf(stderr, "bad mul table 0,%d\n",i); -+ if (gf_mul(i,0) != 0) -+ fprintf(stderr, "bad mul table %d,0\n",i); -+ } -+} -+#endif /* TEST */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/fectest.c linux-2.6.24.7/drivers/mtd/mtd-utils/fectest.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/fectest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/fectest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,92 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mcast_image.h" -+#include "crc32.h" -+ -+#define ERASE_SIZE 131072 -+//#define PKT_SIZE 1400 -+#define NR_PKTS ((ERASE_SIZE + PKT_SIZE - 1) / PKT_SIZE) -+#define DROPS 8 -+ -+int main(void) -+{ -+ int i, j; -+ unsigned char buf[NR_PKTS * PKT_SIZE]; -+ unsigned char pktbuf[(NR_PKTS + DROPS) * PKT_SIZE]; -+ struct fec_parms *fec; -+ unsigned char *srcs[NR_PKTS]; -+ unsigned char *pkt[NR_PKTS + DROPS]; -+ int pktnr[NR_PKTS + DROPS]; -+ struct timeval then, now; -+ -+ srand(3453); -+ for (i=0; i < sizeof(buf); i++) -+ if (i < ERASE_SIZE) -+ buf[i] = rand(); -+ else -+ buf[i] = 0; -+ -+ for (i=0; i < NR_PKTS + DROPS; i++) -+ srcs[i] = buf + (i * PKT_SIZE); -+ -+ for (i=0; i < NR_PKTS + DROPS; i++) { -+ pkt[i] = malloc(PKT_SIZE); -+ pktnr[i] = -1; -+ } -+ fec = fec_new(NR_PKTS, NR_PKTS + DROPS); -+ if (!fec) { -+ printf("fec_init() failed\n"); -+ exit(1); -+ } -+ j = 0; -+ for (i=0; i < NR_PKTS + DROPS; i++) { -+#if 1 -+ if (i == 27 || i == 40 || i == 44 || i == 45 || i == 56 ) -+ continue; -+#endif -+ if (i == 69 || i == 93 || i == 103) -+ continue; -+ fec_encode(fec, srcs, pkt[j], i, PKT_SIZE); -+ pktnr[j] = i; -+ j++; -+ } -+ gettimeofday(&then, NULL); -+ if (fec_decode(fec, pkt, pktnr, PKT_SIZE)) { -+ printf("Decode failed\n"); -+ exit(1); -+ } -+ -+ for (i=0; i < NR_PKTS; i++) -+ memcpy(pktbuf + (i*PKT_SIZE), pkt[i], PKT_SIZE); -+ gettimeofday(&now, NULL); -+ now.tv_sec -= then.tv_sec; -+ now.tv_usec -= then.tv_usec; -+ if (now.tv_usec < 0) { -+ now.tv_usec += 1000000; -+ now.tv_sec--; -+ } -+ -+ if (memcmp(pktbuf, buf, ERASE_SIZE)) { -+ int fd; -+ printf("Compare failed\n"); -+ fd = open("before", O_WRONLY|O_TRUNC|O_CREAT, 0644); -+ if (fd >= 0) -+ write(fd, buf, ERASE_SIZE); -+ close(fd); -+ fd = open("after", O_WRONLY|O_TRUNC|O_CREAT, 0644); -+ if (fd >= 0) -+ write(fd, pktbuf, ERASE_SIZE); -+ -+ exit(1); -+ } -+ -+ printf("Decoded in %ld.%06lds\n", now.tv_sec, now.tv_usec); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_erase.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_erase.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_erase.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_erase.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,189 @@ -+/* -+ * flash_erase.c -- erase parts of a MTD device -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+int region_erase(int Fd, int start, int count, int unlock, int regcount) -+{ -+ int i, j; -+ region_info_t * reginfo; -+ -+ reginfo = calloc(regcount, sizeof(region_info_t)); -+ -+ for(i = 0; i < regcount; i++) -+ { -+ reginfo[i].regionindex = i; -+ if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0) -+ return 8; -+ else -+ printf("Region %d is at %d of %d sector and with sector " -+ "size %x\n", i, reginfo[i].offset, reginfo[i].numblocks, -+ reginfo[i].erasesize); -+ } -+ -+ // We have all the information about the chip we need. -+ -+ for(i = 0; i < regcount; i++) -+ { //Loop through the regions -+ region_info_t * r = &(reginfo[i]); -+ -+ if((start >= reginfo[i].offset) && -+ (start < (r->offset + r->numblocks*r->erasesize))) -+ break; -+ } -+ -+ if(i >= regcount) -+ { -+ printf("Starting offset %x not within chip.\n", start); -+ return 8; -+ } -+ -+ //We are now positioned within region i of the chip, so start erasing -+ //count sectors from there. -+ -+ for(j = 0; (j < count)&&(i < regcount); j++) -+ { -+ erase_info_t erase; -+ region_info_t * r = &(reginfo[i]); -+ -+ erase.start = start; -+ erase.length = r->erasesize; -+ -+ if(unlock != 0) -+ { //Unlock the sector first. -+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0) -+ { -+ perror("\nMTD Unlock failure"); -+ close(Fd); -+ return 8; -+ } -+ } -+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx", -+ erase.length, erase.start); -+ fflush(stdout); -+ if(ioctl(Fd, MEMERASE, &erase) != 0) -+ { -+ perror("\nMTD Erase failure"); -+ close(Fd); -+ return 8; -+ } -+ -+ -+ start += erase.length; -+ if(start >= (r->offset + r->numblocks*r->erasesize)) -+ { //We finished region i so move to region i+1 -+ printf("\nMoving to region %d\n", i+1); -+ i++; -+ } -+ } -+ -+ printf(" done\n"); -+ -+ return 0; -+} -+ -+int non_region_erase(int Fd, int start, int count, int unlock) -+{ -+ mtd_info_t meminfo; -+ -+ if (ioctl(Fd,MEMGETINFO,&meminfo) == 0) -+ { -+ erase_info_t erase; -+ -+ erase.start = start; -+ -+ erase.length = meminfo.erasesize; -+ -+ for (; count > 0; count--) { -+ printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx", -+ erase.length, erase.start); -+ fflush(stdout); -+ -+ if(unlock != 0) -+ { -+ //Unlock the sector first. -+ printf("\rPerforming Flash unlock at offset 0x%llx",erase.start); -+ if(ioctl(Fd, MEMUNLOCK, &erase) != 0) -+ { -+ perror("\nMTD Unlock failure"); -+ close(Fd); -+ return 8; -+ } -+ } -+ -+ if (ioctl(Fd,MEMERASE,&erase) != 0) -+ { -+ perror("\nMTD Erase failure"); -+ close(Fd); -+ return 8; -+ } -+ erase.start += meminfo.erasesize; -+ } -+ printf(" done\n"); -+ } -+ return 0; -+} -+ -+int main(int argc,char *argv[]) -+{ -+ int regcount; -+ int Fd; -+ int start; -+ int count; -+ int unlock; -+ int res = 0; -+ -+ if (1 >= argc || !strcmp(argv[1], "-h") || !strcmp (argv[1], "--help") ) { -+ printf("Usage: flash_erase MTD-device [start] [cnt (# erase blocks)] [lock]\n" -+ " flash_erase -h | --help\n") ; -+ return 16 ; -+ } -+ -+ if (argc > 2) -+ start = strtol(argv[2], NULL, 0); -+ else -+ start = 0; -+ -+ if (argc > 3) -+ count = strtol(argv[3], NULL, 0); -+ else -+ count = 1; -+ -+ if(argc > 4) -+ unlock = strtol(argv[4], NULL, 0); -+ else -+ unlock = 0; -+ -+ -+ // Open and size the device -+ if ((Fd = open(argv[1],O_RDWR)) < 0) -+ { -+ fprintf(stderr,"File open error\n"); -+ return 8; -+ } -+ -+ printf("Erase Total %d Units\n", count); -+ -+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0) -+ { -+ if(regcount == 0) -+ { -+ res = non_region_erase(Fd, start, count, unlock); -+ } -+ else -+ { -+ res = region_erase(Fd, start, count, unlock, regcount); -+ } -+ } -+ -+ return res; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_eraseall.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_eraseall.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_eraseall.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_eraseall.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,286 @@ -+/* eraseall.c -- erase the whole of a MTD device -+ -+ Copyright (C) 2000 Arcom Control System Ltd -+ -+ Renamed to flash_eraseall.c -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+ -+#include -+#include -+ -+#define PROGRAM "flash_eraseall" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+static const char *exe_name; -+static const char *mtd_device; -+static int quiet; /* true -- don't output progress */ -+static int jffs2; // format for jffs2 usage -+ -+static void process_options (int argc, char *argv[]); -+static void display_help (void); -+static void display_version (void); -+static struct jffs2_unknown_node cleanmarker; -+int target_endian = __BYTE_ORDER; -+ -+int main (int argc, char *argv[]) -+{ -+ mtd_info_t meminfo; -+ int fd, clmpos = 0, clmlen = 8; -+ erase_info_t erase; -+ int isNAND, bbtest = 1; -+ -+ process_options(argc, argv); -+ -+ -+ if ((fd = open(mtd_device, O_RDWR)) < 0) { -+ fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno)); -+ exit(1); -+ } -+ -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device); -+ exit(1); -+ } -+ -+ erase.length = meminfo.erasesize; -+ isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0; -+ -+ if (jffs2) { -+ cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); -+ if (!isNAND) -+ cleanmarker.totlen = cpu_to_je32 (sizeof (struct jffs2_unknown_node)); -+ else { -+ struct nand_oobinfo oobinfo; -+ -+ if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) { -+ fprintf(stderr, "%s: %s: unable to get NAND oobinfo\n", exe_name, mtd_device); -+ exit(1); -+ } -+ -+ /* Check for autoplacement */ -+ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { -+ /* Get the position of the free bytes */ -+ if (!oobinfo.oobfree[0][1]) { -+ fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n"); -+ exit(1); -+ } -+ clmpos = oobinfo.oobfree[0][0]; -+ clmlen = oobinfo.oobfree[0][1]; -+ if (clmlen > 8) -+ clmlen = 8; -+ } else { -+ /* Legacy mode */ -+ switch (meminfo.oobsize) { -+ case 8: -+ clmpos = 6; -+ clmlen = 2; -+ break; -+ case 16: -+ clmpos = 8; -+ clmlen = 8; -+ break; -+ case 64: -+ clmpos = 16; -+ clmlen = 8; -+ break; -+ } -+ } -+ cleanmarker.totlen = cpu_to_je32(8); -+ } -+ cleanmarker.hdr_crc = cpu_to_je32 (crc32 (0, &cleanmarker, sizeof (struct jffs2_unknown_node) - 4)); -+ } -+ -+ for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { -+ if (bbtest) { -+ unsigned long long offset = erase.start; -+ int ret = ioctl(fd, MEMGETBADBLOCK, &offset); -+ if (ret > 0) { -+ if (!quiet) -+ printf ("\nSkipping bad block at 0x%09llx\n", erase.start); -+ continue; -+ } else if (ret < 0) { -+ if (errno == EOPNOTSUPP) { -+ bbtest = 0; -+ if (isNAND) { -+ fprintf(stderr, "%s: %s: Bad block check not available\n", exe_name, mtd_device); -+ exit(1); -+ } -+ } else { -+ fprintf(stderr, "\n%s: %s: MTD get bad block failed: %s\n", exe_name, mtd_device, strerror(errno)); -+ exit(1); -+ } -+ } -+ } -+ -+ if (!quiet) { -+ printf -+ ("\rErasing %d Kibyte @ %llx -- %2u %% complete.", -+ meminfo.erasesize / 1024, erase.start, -+ (unsigned long long) -+ erase.start * 100 / meminfo.size); -+ } -+ fflush(stdout); -+ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ -+ /* format for JFFS2 ? */ -+ if (!jffs2) -+ continue; -+ -+ /* write cleanmarker */ -+ if (isNAND) { -+ struct mtd_oob_buf oob; -+ oob.ptr = (unsigned char *) &cleanmarker; -+ oob.start = erase.start + clmpos; -+ oob.length = clmlen; -+ if (ioctl (fd, MEMWRITEOOB, &oob) != 0) { -+ fprintf(stderr, "\n%s: %s: MTD writeoob failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ } else { -+ if (lseek (fd, erase.start, SEEK_SET) < 0) { -+ fprintf(stderr, "\n%s: %s: MTD lseek failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) { -+ fprintf(stderr, "\n%s: %s: MTD write failure: %s\n", exe_name, mtd_device, strerror(errno)); -+ continue; -+ } -+ } -+ if (!quiet) -+ printf (" Cleanmarker written at %x.", erase.start); -+ } -+ if (!quiet) -+ printf("\n"); -+ -+ return 0; -+} -+ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ exe_name = argv[0]; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "jq"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"silent", no_argument, 0, 'q'}, -+ -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'j': -+ jffs2 = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ if (optind == argc) { -+ fprintf(stderr, "%s: no MTD device specified\n", exe_name); -+ error = 1; -+ } -+ if (error) { -+ fprintf(stderr, "Try `%s --help' for more information.\n", -+ exe_name); -+ exit(1); -+ } -+ -+ mtd_device = argv[optind]; -+} -+ -+ -+void display_help (void) -+{ -+ printf("Usage: %s [OPTION] MTD_DEVICE\n" -+ "Erases all of the specified MTD device.\n" -+ "\n" -+ " -j, --jffs2 format the device for jffs2\n" -+ " -q, --quiet don't display progress messages\n" -+ " --silent same as --quiet\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n", -+ exe_name); -+ exit(0); -+} -+ -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2000 Arcom Control Systems Ltd\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_info.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_info.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_info.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_info.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,55 @@ -+/* -+ * flash_info.c -- print info about a MTD device -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int regcount; -+ int Fd; -+ -+ if (1 >= argc) -+ { -+ fprintf(stderr,"Usage: flash_info device\n"); -+ return 16; -+ } -+ -+ // Open and size the device -+ if ((Fd = open(argv[1],O_RDONLY)) < 0) -+ { -+ fprintf(stderr,"File open error\n"); -+ return 8; -+ } -+ -+ if (ioctl(Fd,MEMGETREGIONCOUNT,®count) == 0) -+ { -+ int i; -+ region_info_t reginfo; -+ printf("Device %s has %d erase regions\n", argv[1], regcount); -+ for (i = 0; i < regcount; i++) -+ { -+ reginfo.regionindex = i; -+ if(ioctl(Fd, MEMGETREGIONINFO, ®info) == 0) -+ { -+ printf("Region %d is at 0x%x with size 0x%x and " -+ "has 0x%x blocks\n", i, reginfo.offset, -+ reginfo.erasesize, reginfo.numblocks); -+ } -+ else -+ { -+ printf("Strange can not read region %d from a %d region device\n", -+ i, regcount); -+ } -+ } -+ } -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_lock.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_lock.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_lock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_lock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * FILE flash_lock.c -+ * -+ * This utility locks one or more sectors of flash device. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ int fd; -+ struct mtd_info_user mtdInfo; -+ struct erase_info_user mtdLockInfo; -+ int num_sectors; -+ int ofs; -+ -+ /* -+ * Parse command line options -+ */ -+ if(argc != 4) -+ { -+ fprintf(stderr, "USAGE: %s \n", argv[0]); -+ exit(1); -+ } -+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0) -+ { -+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]); -+ exit(1); -+ } -+ -+ fd = open(argv[1], O_RDWR); -+ if(fd < 0) -+ { -+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]); -+ exit(1); -+ } -+ -+ if(ioctl(fd, MEMGETINFO, &mtdInfo)) -+ { -+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ sscanf(argv[2], "%x",&ofs); -+ sscanf(argv[3], "%d",&num_sectors); -+ if(ofs > mtdInfo.size - mtdInfo.erasesize) -+ { -+ fprintf(stderr, "%x is beyond device size %x\n",ofs,(unsigned int)(mtdInfo.size - mtdInfo.erasesize)); -+ exit(1); -+ } -+ -+ if (num_sectors == -1) { -+ num_sectors = mtdInfo.size/mtdInfo.erasesize; -+ } -+ else { -+ if(num_sectors > mtdInfo.size/mtdInfo.erasesize) -+ { -+ fprintf(stderr, "%d are too many sectors, device only has %d\n",num_sectors,(int)(mtdInfo.size/mtdInfo.erasesize)); -+ exit(1); -+ } -+ } -+ -+ mtdLockInfo.start = ofs; -+ mtdLockInfo.length = num_sectors * mtdInfo.erasesize; -+ if(ioctl(fd, MEMLOCK, &mtdLockInfo)) -+ { -+ fprintf(stderr, "Could not lock MTD device: %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_dump.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_dump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,54 @@ -+/* -+ * flash_otp_dump.c -- display One-Time-Programm data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, i, offset, ret; -+ unsigned char buf[16]; -+ -+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { -+ fprintf(stderr,"Usage: %s [ -f | -u ] \n", argv[0]); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_RDONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ printf("OTP %s data for %s\n", -+ argv[1][1] == 'f' ? "factory" : "user", argv[2]); -+ offset = 0; -+ while ((ret = read(fd, buf, sizeof(buf)))) { -+ if (ret < 0) { -+ perror("read()"); -+ return errno; -+ } -+ printf("0x%04x:", offset); -+ for (i = 0; i < ret; i++) -+ printf(" %02x", buf[i]); -+ printf("\n"); -+ offset += ret; -+ } -+ -+ close(fd); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_info.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_info.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_info.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_info.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,63 @@ -+/* -+ * flash_otp_info.c -- print info about One-Time-Programm data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, i, ret; -+ -+ if (argc != 3 || (strcmp(argv[1], "-f") && strcmp(argv[1], "-u"))) { -+ fprintf(stderr,"Usage: %s [ -f | -u ] \n", argv[0]); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_RDONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = argv[1][1] == 'f' ? MTD_OTP_FACTORY : MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ ret = ioctl(fd, OTPGETREGIONCOUNT, &val); -+ if (ret < 0) { -+ perror("OTPGETREGIONCOUNT"); -+ return errno; -+ } -+ -+ printf("Number of OTP %s blocks on %s: %d\n", -+ argv[1][1] == 'f' ? "factory" : "user", argv[2], val); -+ -+ if (val > 0) { -+ struct otp_info info[val]; -+ -+ ret = ioctl(fd, OTPGETREGIONINFO, &info); -+ if (ret < 0) { -+ perror("OTPGETREGIONCOUNT"); -+ return errno; -+ } -+ -+ for (i = 0; i < val; i++) -+ printf("block %2d: offset = 0x%04x " -+ "size = %2d bytes %s\n", -+ i, info[i].start, info[i].length, -+ info[i].locked ? "[locked]" : "[unlocked]"); -+ } -+ -+ close(fd); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_lock.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_lock.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_lock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_lock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+/* -+ * flash_otp_lock.c -- lock area of One-Time-Program data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, ret, offset, size; -+ char *p, buf[8]; -+ -+ if (argc != 5 || strcmp(argv[1], "-u")) { -+ fprintf(stderr, "Usage: %s -u \n", argv[0]); -+ fprintf(stderr, "offset and size must match on OTP region boundaries\n"); -+ fprintf(stderr, "CAUTION! ONCE LOCKED, OTP REGIONS CAN'T BE UNLOCKED!\n"); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_WRONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ offset = strtoul(argv[3], &p, 0); -+ if (argv[3][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad offset value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ size = strtoul(argv[4], &p, 0); -+ if (argv[4][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad size value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ printf("About to lock OTP user data on %s from 0x%x to 0x%x\n", -+ argv[2], offset, offset + size); -+ printf("Are you sure (yes|no)? "); -+ if (fgets(buf, sizeof(buf), stdin) && strcmp(buf, "yes\n") == 0) { -+ struct otp_info info; -+ info.start = offset; -+ info.length = size; -+ ret = ioctl(fd, OTPLOCK, &info); -+ if (ret < 0) { -+ perror("OTPLOCK"); -+ return errno; -+ } -+ printf("Done.\n"); -+ } else { -+ printf("Aborted\n"); -+ } -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_write.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_write.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_otp_write.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_otp_write.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,96 @@ -+/* -+ * flash_otp_write.c -- write One-Time-Program data -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc,char *argv[]) -+{ -+ int fd, val, ret, size, wrote, len; -+ mtd_info_t mtdInfo; -+ off_t offset; -+ char *p, buf[2048]; -+ -+ if (argc != 4 || strcmp(argv[1], "-u")) { -+ fprintf(stderr, "Usage: %s -u \n", argv[0]); -+ fprintf(stderr, "the raw data to write should be provided on stdin\n"); -+ fprintf(stderr, "CAUTION! ONCE SET TO 0, OTP DATA BITS CAN'T BE ERASED!\n"); -+ return EINVAL; -+ } -+ -+ fd = open(argv[2], O_WRONLY); -+ if (fd < 0) { -+ perror(argv[2]); -+ return errno; -+ } -+ -+ val = MTD_OTP_USER; -+ ret = ioctl(fd, OTPSELECT, &val); -+ if (ret < 0) { -+ perror("OTPSELECT"); -+ return errno; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &mtdInfo)) { -+ perror("MEMGETINFO"); -+ return errno; -+ } -+ -+ offset = strtoul(argv[3], &p, 0); -+ if (argv[3][0] == 0 || *p != 0) { -+ fprintf(stderr, "%s: bad offset value\n", argv[0]); -+ return ERANGE; -+ } -+ -+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { -+ perror("lseek()"); -+ return errno; -+ } -+ -+ printf("Writing OTP user data on %s at offset 0x%lx\n", argv[2], offset); -+ -+ if (mtdInfo.type == MTD_NANDFLASH) -+ len = mtdInfo.writesize; -+ else -+ len = 256; -+ -+ wrote = 0; -+ while ((size = read(0, buf, len))) { -+ if (size < 0) { -+ perror("read()"); -+ return errno; -+ } -+ p = buf; -+ while (size > 0) { -+ if (mtdInfo.type == MTD_NANDFLASH) { -+ /* Fill remain buffers with 0xff */ -+ memset(buf + size, 0xff, mtdInfo.writesize - size); -+ size = mtdInfo.writesize; -+ } -+ ret = write(fd, p, size); -+ if (ret < 0) { -+ perror("write()"); -+ return errno; -+ } -+ if (ret == 0) { -+ printf("write() returned 0 after writing %d bytes\n", wrote); -+ return 0; -+ } -+ p += ret; -+ wrote += ret; -+ size -= ret; -+ } -+ } -+ -+ printf("Wrote %d bytes of OTP user data\n", wrote); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_unlock.c linux-2.6.24.7/drivers/mtd/mtd-utils/flash_unlock.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flash_unlock.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flash_unlock.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,64 @@ -+/* -+ * FILE flash_unlock.c -+ * -+ * This utility unlock all sectors of flash device. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ int fd; -+ struct mtd_info_user mtdInfo; -+ struct erase_info_user mtdLockInfo; -+ -+ /* -+ * Parse command line options -+ */ -+ if(argc != 2) -+ { -+ fprintf(stderr, "USAGE: %s \n", argv[0]); -+ exit(1); -+ } -+ else if(strncmp(argv[1], "/dev/mtd", 8) != 0) -+ { -+ fprintf(stderr, "'%s' is not a MTD device. Must specify mtd device: /dev/mtd?\n", argv[1]); -+ exit(1); -+ } -+ -+ fd = open(argv[1], O_RDWR); -+ if(fd < 0) -+ { -+ fprintf(stderr, "Could not open mtd device: %s\n", argv[1]); -+ exit(1); -+ } -+ -+ if(ioctl(fd, MEMGETINFO, &mtdInfo)) -+ { -+ fprintf(stderr, "Could not get MTD device info from %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ mtdLockInfo.start = 0; -+ mtdLockInfo.length = mtdInfo.size; -+ if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) -+ { -+ fprintf(stderr, "Could not unlock MTD device: %s\n", argv[1]); -+ close(fd); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/flashcp.c linux-2.6.24.7/drivers/mtd/mtd-utils/flashcp.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/flashcp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/flashcp.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,389 @@ -+/* -+ * Copyright (c) 2d3D, Inc. -+ * Written by Abraham vd Merwe -+ * All rights reserved. -+ * -+ * Renamed to flashcp.c to avoid conflicts with fcp from fsh package -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the author nor the names of other contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+typedef int bool; -+#define true 1 -+#define false 0 -+ -+#define EXIT_FAILURE 1 -+#define EXIT_SUCCESS 0 -+ -+/* for debugging purposes only */ -+#ifdef DEBUG -+#undef DEBUG -+#define DEBUG(fmt,args...) { log_printf (LOG_ERROR,"%d: ",__LINE__); log_printf (LOG_ERROR,fmt,## args); } -+#else -+#undef DEBUG -+#define DEBUG(fmt,args...) -+#endif -+ -+#define KB(x) ((x) / 1024) -+#define PERCENTAGE(x,total) (((x) * 100) / (total)) -+ -+/* size of read/write buffer */ -+#define BUFSIZE (10 * 1024) -+ -+/* cmd-line flags */ -+#define FLAG_NONE 0x00 -+#define FLAG_VERBOSE 0x01 -+#define FLAG_HELP 0x02 -+#define FLAG_FILENAME 0x04 -+#define FLAG_DEVICE 0x08 -+ -+/* error levels */ -+#define LOG_NORMAL 1 -+#define LOG_ERROR 2 -+ -+static void log_printf (int level,const char *fmt, ...) -+{ -+ FILE *fp = level == LOG_NORMAL ? stdout : stderr; -+ va_list ap; -+ va_start (ap,fmt); -+ vfprintf (fp,fmt,ap); -+ va_end (ap); -+ fflush (fp); -+} -+ -+static void showusage (const char *progname,bool error) -+{ -+ int level = error ? LOG_ERROR : LOG_NORMAL; -+ -+ log_printf (level, -+ "\n" -+ "Flash Copy - Written by Abraham van der Merwe \n" -+ "\n" -+ "usage: %s [ -v | --verbose ] \n" -+ " %s -h | --help\n" -+ "\n" -+ " -h | --help Show this help message\n" -+ " -v | --verbose Show progress reports\n" -+ " File which you want to copy to flash\n" -+ " Flash device to write to (e.g. /dev/mtd0, /dev/mtd1, etc.)\n" -+ "\n", -+ progname,progname); -+ -+ exit (error ? EXIT_FAILURE : EXIT_SUCCESS); -+} -+ -+static int safe_open (const char *pathname,int flags) -+{ -+ int fd; -+ -+ fd = open (pathname,flags); -+ if (fd < 0) -+ { -+ log_printf (LOG_ERROR,"While trying to open %s",pathname); -+ if (flags & O_RDWR) -+ log_printf (LOG_ERROR," for read/write access"); -+ else if (flags & O_RDONLY) -+ log_printf (LOG_ERROR," for read access"); -+ else if (flags & O_WRONLY) -+ log_printf (LOG_ERROR," for write access"); -+ log_printf (LOG_ERROR,": %m\n"); -+ exit (EXIT_FAILURE); -+ } -+ -+ return (fd); -+} -+ -+static void safe_read (int fd,const char *filename,void *buf,size_t count,bool verbose) -+{ -+ ssize_t result; -+ -+ result = read (fd,buf,count); -+ if (count != result) -+ { -+ if (verbose) log_printf (LOG_NORMAL,"\n"); -+ if (result < 0) -+ { -+ log_printf (LOG_ERROR,"While reading data from %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+ log_printf (LOG_ERROR,"Short read count returned while reading from %s\n",filename); -+ exit (EXIT_FAILURE); -+ } -+} -+ -+static void safe_rewind (int fd,const char *filename) -+{ -+ if (lseek (fd,0L,SEEK_SET) < 0) -+ { -+ log_printf (LOG_ERROR,"While seeking to start of %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+} -+ -+/******************************************************************************/ -+ -+static int dev_fd = -1,fil_fd = -1; -+ -+static void cleanup (void) -+{ -+ if (dev_fd > 0) close (dev_fd); -+ if (fil_fd > 0) close (fil_fd); -+} -+ -+int main (int argc,char *argv[]) -+{ -+ const char *progname,*filename = NULL,*device = NULL; -+ int i,flags = FLAG_NONE; -+ ssize_t result; -+ size_t size,written; -+ struct mtd_info_user mtd; -+ struct erase_info_user erase; -+ struct stat filestat; -+ unsigned char src[BUFSIZE],dest[BUFSIZE]; -+ -+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]); -+ -+ /********************* -+ * parse cmd-line -+ *****************/ -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hv"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 'h'}, -+ {"verbose", no_argument, 0, 'v'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 'h': -+ flags |= FLAG_HELP; -+ DEBUG("Got FLAG_HELP\n"); -+ break; -+ case 'v': -+ flags |= FLAG_VERBOSE; -+ DEBUG("Got FLAG_VERBOSE\n"); -+ break; -+ default: -+ DEBUG("Unknown parameter: %s\n",argv[option_index]); -+ showusage (progname,true); -+ } -+ } -+ if (optind+2 == argc) { -+ flags |= FLAG_FILENAME; -+ filename = argv[optind]; -+ DEBUG("Got filename: %s\n",filename); -+ -+ flags |= FLAG_DEVICE; -+ device = argv[optind+1]; -+ DEBUG("Got device: %s\n",device); -+ } -+ -+ if (flags & FLAG_HELP || progname == NULL || device == NULL) -+ showusage (progname,flags != FLAG_HELP); -+ -+ atexit (cleanup); -+ -+ /* get some info about the flash device */ -+ dev_fd = safe_open (device,O_SYNC | O_RDWR); -+ if (ioctl (dev_fd,MEMGETINFO,&mtd) < 0) -+ { -+ DEBUG("ioctl(): %m\n"); -+ log_printf (LOG_ERROR,"This doesn't seem to be a valid MTD flash device!\n"); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* get some info about the file we want to copy */ -+ fil_fd = safe_open (filename,O_RDONLY); -+ if (fstat (fil_fd,&filestat) < 0) -+ { -+ log_printf (LOG_ERROR,"While trying to get the file status of %s: %m\n",filename); -+ exit (EXIT_FAILURE); -+ } -+ -+ /* does it fit into the device/partition? */ -+ if (filestat.st_size > mtd.size) -+ { -+ log_printf (LOG_ERROR,"%s won't fit into %s!\n",filename,device); -+ exit (EXIT_FAILURE); -+ } -+ -+ /***************************************************** -+ * erase enough blocks so that we can write the file * -+ *****************************************************/ -+ -+#warning "Check for smaller erase regions" -+ -+ erase.start = 0; -+ erase.length = filestat.st_size & ~(mtd.erasesize - 1); -+ if (filestat.st_size % mtd.erasesize) erase.length += mtd.erasesize; -+ if (flags & FLAG_VERBOSE) -+ { -+ /* if the user wants verbose output, erase 1 block at a time and show him/her what's going on */ -+ int blocks = erase.length / mtd.erasesize; -+ erase.length = mtd.erasesize; -+ log_printf (LOG_NORMAL,"Erasing blocks: 0/%d (0%%)",blocks); -+ for (i = 1; i <= blocks; i++) -+ { -+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (%d%%)",i,blocks,PERCENTAGE (i,blocks)); -+ if (ioctl (dev_fd,MEMERASE,&erase) < 0) -+ { -+ log_printf (LOG_NORMAL,"\n"); -+ log_printf (LOG_ERROR, -+ "While erasing blocks 0x%.8x-0x%.8x on %s: %m\n", -+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); -+ exit (EXIT_FAILURE); -+ } -+ erase.start += mtd.erasesize; -+ } -+ log_printf (LOG_NORMAL,"\rErasing blocks: %d/%d (100%%)\n",blocks,blocks); -+ } -+ else -+ { -+ /* if not, erase the whole chunk in one shot */ -+ if (ioctl (dev_fd,MEMERASE,&erase) < 0) -+ { -+ log_printf (LOG_ERROR, -+ "While erasing blocks from 0x%.8x-0x%.8x on %s: %m\n", -+ (unsigned int) erase.start,(unsigned int) (erase.start + erase.length),device); -+ exit (EXIT_FAILURE); -+ } -+ } -+ DEBUG("Erased %u / %luk bytes\n",erase.length,filestat.st_size); -+ -+ /********************************** -+ * write the entire file to flash * -+ **********************************/ -+ -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Writing data: 0k/%luk (0%%)",KB (filestat.st_size)); -+ size = filestat.st_size; -+ i = BUFSIZE; -+ written = 0; -+ while (size) -+ { -+ if (size < BUFSIZE) i = size; -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL,"\rWriting data: %dk/%luk (%lu%%)", -+ KB (written + i), -+ KB (filestat.st_size), -+ PERCENTAGE (written + i,filestat.st_size)); -+ -+ /* read from filename */ -+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); -+ -+ /* write to device */ -+ result = write (dev_fd,src,i); -+ if (i != result) -+ { -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"\n"); -+ if (result < 0) -+ { -+ log_printf (LOG_ERROR, -+ "While writing data to 0x%.8x-0x%.8x on %s: %m\n", -+ written,written + i,device); -+ exit (EXIT_FAILURE); -+ } -+ log_printf (LOG_ERROR, -+ "Short write count returned while writing to x%.8x-0x%.8x on %s: %d/%lu bytes written to flash\n", -+ written,written + i,device,written + result,filestat.st_size); -+ exit (EXIT_FAILURE); -+ } -+ -+ written += i; -+ size -= i; -+ } -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rWriting data: %luk/%luk (100%%)\n", -+ KB (filestat.st_size), -+ KB (filestat.st_size)); -+ DEBUG("Wrote %d / %luk bytes\n",written,filestat.st_size); -+ -+ /********************************** -+ * verify that flash == file data * -+ **********************************/ -+ -+ safe_rewind (fil_fd,filename); -+ safe_rewind (dev_fd,device); -+ size = filestat.st_size; -+ i = BUFSIZE; -+ written = 0; -+ if (flags & FLAG_VERBOSE) log_printf (LOG_NORMAL,"Verifying data: 0k/%luk (0%%)",KB (filestat.st_size)); -+ while (size) -+ { -+ if (size < BUFSIZE) i = size; -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rVerifying data: %dk/%luk (%lu%%)", -+ KB (written + i), -+ KB (filestat.st_size), -+ PERCENTAGE (written + i,filestat.st_size)); -+ -+ /* read from filename */ -+ safe_read (fil_fd,filename,src,i,flags & FLAG_VERBOSE); -+ -+ /* read from device */ -+ safe_read (dev_fd,device,dest,i,flags & FLAG_VERBOSE); -+ -+ /* compare buffers */ -+ if (memcmp (src,dest,i)) -+ { -+ log_printf (LOG_ERROR, -+ "File does not seem to match flash data. First mismatch at 0x%.8x-0x%.8x\n", -+ written,written + i); -+ exit (EXIT_FAILURE); -+ } -+ -+ written += i; -+ size -= i; -+ } -+ if (flags & FLAG_VERBOSE) -+ log_printf (LOG_NORMAL, -+ "\rVerifying data: %luk/%luk (100%%)\n", -+ KB (filestat.st_size), -+ KB (filestat.st_size)); -+ DEBUG("Verified %d / %luk bytes\n",written,filestat.st_size); -+ -+ exit (EXIT_SUCCESS); -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_check.c linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_check.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_check.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_check.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,232 @@ -+/* Ported to MTD system. -+ * Based on: -+ */ -+/*====================================================================== -+ -+ Utility to create an FTL partition in a memory region -+ -+ ftl_check.c 1.10 1999/10/25 20:01:35 -+ -+ The contents of this file are subject to the Mozilla Public -+ License Version 1.1 (the "License"); you may not use this file -+ except in compliance with the License. You may obtain a copy of -+ the License at http://www.mozilla.org/MPL/ -+ -+ Software distributed under the License is distributed on an "AS -+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -+ implied. See the License for the specific language governing -+ rights and limitations under the License. -+ -+ The initial developer of the original code is David A. Hinds -+ . Portions created by David A. Hinds -+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ -+ Alternatively, the contents of this file may be used under the -+ terms of the GNU Public License version 2 (the "GPL"), in which -+ case the provisions of the GPL are applicable instead of the -+ above. If you wish to allow the use of your version of this file -+ only under the terms of the GPL and not to allow others to use -+ your version of this file under the MPL, indicate your decision -+ by deleting the provisions above and replace them with the notice -+ and other provisions required by the GPL. If you do not delete -+ the provisions above, a recipient may use your version of this -+ file under either the MPL or the GPL. -+ -+ ======================================================================*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+# define TO_LE32(x) (x) -+# define TO_LE16(x) (x) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+# define TO_LE32(x) (bswap_32(x)) -+# define TO_LE16(x) (bswap_16(x)) -+#else -+# error cannot detect endianess -+#endif -+ -+#define FROM_LE32(x) TO_LE32(x) -+#define FROM_LE16(x) TO_LE16(x) -+ -+/*====================================================================*/ -+ -+static void print_size(u_int s) -+{ -+ if ((s > 0x100000) && ((s % 0x100000) == 0)) -+ printf("%d mb", s / 0x100000); -+ else if ((s > 0x400) && ((s % 0x400) == 0)) -+ printf("%d kb", s / 0x400); -+ else -+ printf("%d bytes", s); -+} -+ -+/*====================================================================*/ -+ -+static void check_partition(int fd, int verbose) -+{ -+ mtd_info_t mtd; -+ erase_unit_header_t hdr, hdr2; -+ u_int i, j, nbam, *bam; -+ int control, data, free, deleted; -+ -+ /* Get partition size, block size */ -+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) { -+ perror("get info failed"); -+ return; -+ } -+ -+ printf("Memory region info:\n"); -+ printf(" Region size = "); -+ print_size(mtd.size); -+ printf(" Erase block size = "); -+ print_size(mtd.erasesize); -+ printf("\n\n"); -+ -+ for (i = 0; i < mtd.size/mtd.erasesize; i++) { -+ if (lseek(fd, (i * mtd.erasesize), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ read(fd, &hdr, sizeof(hdr)); -+ if ((FROM_LE32(hdr.FormattedSize) > 0) && -+ (FROM_LE32(hdr.FormattedSize) <= mtd.size) && -+ (FROM_LE16(hdr.NumEraseUnits) > 0) && -+ (FROM_LE16(hdr.NumEraseUnits) <= mtd.size/mtd.erasesize)) -+ break; -+ } -+ if (i == mtd.size/mtd.erasesize) { -+ fprintf(stderr, "No valid erase unit headers!\n"); -+ return; -+ } -+ -+ printf("Partition header:\n"); -+ printf(" Formatted size = "); -+ print_size(FROM_LE32(hdr.FormattedSize)); -+ printf(", erase units = %d, transfer units = %d\n", -+ FROM_LE16(hdr.NumEraseUnits), hdr.NumTransferUnits); -+ printf(" Erase unit size = "); -+ print_size(1 << hdr.EraseUnitSize); -+ printf(", virtual block size = "); -+ print_size(1 << hdr.BlockSize); -+ printf("\n"); -+ -+ /* Create basic block allocation table for control blocks */ -+ nbam = (mtd.erasesize >> hdr.BlockSize); -+ bam = malloc(nbam * sizeof(u_int)); -+ -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (read(fd, &hdr2, sizeof(hdr2)) == -1) { -+ perror("read failed"); -+ break; -+ } -+ printf("\nErase unit %d:\n", i); -+ if ((hdr2.FormattedSize != hdr.FormattedSize) || -+ (hdr2.NumEraseUnits != hdr.NumEraseUnits) || -+ (hdr2.SerialNumber != hdr.SerialNumber)) -+ printf(" Erase unit header is corrupt.\n"); -+ else if (FROM_LE16(hdr2.LogicalEUN) == 0xffff) -+ printf(" Transfer unit, erase count = %d\n", FROM_LE32(hdr2.EraseCount)); -+ else { -+ printf(" Logical unit %d, erase count = %d\n", -+ FROM_LE16(hdr2.LogicalEUN), FROM_LE32(hdr2.EraseCount)); -+ if (lseek(fd, (i << hdr.EraseUnitSize)+FROM_LE32(hdr.BAMOffset), -+ SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (read(fd, bam, nbam * sizeof(u_int)) == -1) { -+ perror("read failed"); -+ break; -+ } -+ free = deleted = control = data = 0; -+ for (j = 0; j < nbam; j++) { -+ if (BLOCK_FREE(FROM_LE32(bam[j]))) -+ free++; -+ else if (BLOCK_DELETED(FROM_LE32(bam[j]))) -+ deleted++; -+ else switch (BLOCK_TYPE(FROM_LE32(bam[j]))) { -+ case BLOCK_CONTROL: control++; break; -+ case BLOCK_DATA: data++; break; -+ default: break; -+ } -+ } -+ printf(" Block allocation: %d control, %d data, %d free," -+ " %d deleted\n", control, data, free, deleted); -+ } -+ } -+} /* format_partition */ -+ -+/* Show usage information */ -+void showusage(char *pname) -+{ -+ fprintf(stderr, "usage: %s [-v] device\n", pname); -+ fprintf(stderr, "-v verbose messages\n"); -+} -+ -+/*====================================================================*/ -+ -+int main(int argc, char *argv[]) -+{ -+ int verbose; -+ int optch, errflg, fd; -+ struct stat buf; -+ -+ errflg = 0; -+ verbose = 0; -+ while ((optch = getopt(argc, argv, "vh")) != -1) { -+ switch (optch) { -+ case 'h': -+ errflg = 1; break; -+ case 'v': -+ verbose = 1; break; -+ default: -+ errflg = -1; break; -+ } -+ } -+ if (errflg || (optind != argc-1)) { -+ showusage(argv[0]); -+ exit(errflg > 0 ? 0 : EXIT_FAILURE); -+ } -+ -+ if (stat(argv[optind], &buf) != 0) { -+ perror("status check failed"); -+ exit(EXIT_FAILURE); -+ } -+ if (!(buf.st_mode & S_IFCHR)) { -+ fprintf(stderr, "%s is not a character special device\n", -+ argv[optind]); -+ exit(EXIT_FAILURE); -+ } -+ fd = open(argv[optind], O_RDONLY); -+ if (fd == -1) { -+ perror("open failed"); -+ exit(EXIT_FAILURE); -+ } -+ -+ check_partition(fd, verbose); -+ close(fd); -+ -+ exit(EXIT_SUCCESS); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_format.c linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_format.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ftl_format.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ftl_format.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,342 @@ -+/* Ported to MTD system. -+ * Based on: -+ */ -+/*====================================================================== -+ -+ Utility to create an FTL partition in a memory region -+ -+ ftl_format.c 1.13 1999/10/25 20:01:35 -+ -+ The contents of this file are subject to the Mozilla Public -+ License Version 1.1 (the "License"); you may not use this file -+ except in compliance with the License. You may obtain a copy of -+ the License at http://www.mozilla.org/MPL/ -+ -+ Software distributed under the License is distributed on an "AS -+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -+ implied. See the License for the specific language governing -+ rights and limitations under the License. -+ -+ The initial developer of the original code is David A. Hinds -+ . Portions created by David A. Hinds -+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ -+ Alternatively, the contents of this file may be used under the -+ terms of the GNU Public License version 2 (the "GPL"), in which -+ case the provisions of the GPL are applicable instead of the -+ above. If you wish to allow the use of your version of this file -+ only under the terms of the GPL and not to allow others to use -+ your version of this file under the MPL, indicate your decision -+ by deleting the provisions above and replace them with the notice -+ and other provisions required by the GPL. If you do not delete -+ the provisions above, a recipient may use your version of this -+ file under either the MPL or the GPL. -+ -+ ======================================================================*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+# define TO_LE32(x) (x) -+# define TO_LE16(x) (x) -+#elif __BYTE_ORDER == __BIG_ENDIAN -+# define TO_LE32(x) (bswap_32(x)) -+# define TO_LE16(x) (bswap_16(x)) -+#else -+# error cannot detect endianess -+#endif -+ -+#define FROM_LE32(x) TO_LE32(x) -+#define FROM_LE16(x) TO_LE16(x) -+ -+/*====================================================================*/ -+ -+static void print_size(u_int s) -+{ -+ if ((s > 0x100000) && ((s % 0x100000) == 0)) -+ printf("%d mb", s / 0x100000); -+ else if ((s > 0x400) && ((s % 0x400) == 0)) -+ printf("%d kb", s / 0x400); -+ else -+ printf("%d bytes", s); -+} -+ -+/*====================================================================*/ -+ -+static const char LinkTarget[] = { -+ 0x13, 0x03, 'C', 'I', 'S' -+}; -+static const char DataOrg[] = { -+ 0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00 -+}; -+ -+static void build_header(erase_unit_header_t *hdr, u_int RegionSize, -+ u_int BlockSize, u_int Spare, int Reserve, -+ u_int BootSize) -+{ -+ u_int i, BootUnits, nbam, __FormattedSize; -+ -+ /* Default everything to the erased state */ -+ memset(hdr, 0xff, sizeof(*hdr)); -+ memcpy(hdr->LinkTargetTuple, LinkTarget, 5); -+ memcpy(hdr->DataOrgTuple, DataOrg, 10); -+ hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff; -+ BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1); -+ BootUnits = BootSize / BlockSize; -+ -+ /* We only support 512-byte blocks */ -+ hdr->BlockSize = 9; -+ hdr->EraseUnitSize = 0; -+ for (i = BlockSize; i > 1; i >>= 1) -+ hdr->EraseUnitSize++; -+ hdr->EraseCount = TO_LE32(0); -+ hdr->FirstPhysicalEUN = TO_LE16(BootUnits); -+ hdr->NumEraseUnits = TO_LE16((RegionSize - BootSize) >> hdr->EraseUnitSize); -+ hdr->NumTransferUnits = Spare; -+ __FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize); -+ /* Leave a little bit of space between the CIS and BAM */ -+ hdr->BAMOffset = TO_LE32(0x80); -+ /* Adjust size to account for BAM space */ -+ nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int) -+ + FROM_LE32(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize; -+ -+ __FormattedSize -= -+ (FROM_LE16(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize); -+ __FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff); -+ -+ hdr->FormattedSize = TO_LE32(__FormattedSize); -+ -+ /* hdr->FirstVMAddress defaults to erased state */ -+ hdr->NumVMPages = TO_LE16(0); -+ hdr->Flags = 0; -+ /* hdr->Code defaults to erased state */ -+ hdr->SerialNumber = TO_LE32(time(NULL)); -+ /* hdr->AltEUHOffset defaults to erased state */ -+ -+} /* build_header */ -+ -+/*====================================================================*/ -+ -+static int format_partition(int fd, int quiet, int interrogate, -+ u_int spare, int reserve, u_int bootsize) -+{ -+ mtd_info_t mtd; -+ erase_info_t erase; -+ erase_unit_header_t hdr; -+ u_int step, lun, i, nbam, *bam; -+ -+ /* Get partition size, block size */ -+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) { -+ perror("get info failed"); -+ return -1; -+ } -+ -+#if 0 -+ /* Intel Series 100 Flash: skip first block */ -+ if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) && -+ (bootsize == 0)) { -+ if (!quiet) -+ printf("Skipping first block to protect CIS info...\n"); -+ bootsize = 1; -+ } -+#endif -+ -+ /* Create header */ -+ build_header(&hdr, mtd.size, mtd.erasesize, -+ spare, reserve, bootsize); -+ -+ if (!quiet) { -+ printf("Partition size = "); -+ print_size(mtd.size); -+ printf(", erase unit size = "); -+ print_size(mtd.erasesize); -+ printf(", %d transfer units\n", spare); -+ if (bootsize != 0) { -+ print_size(FROM_LE16(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize); -+ printf(" allocated for boot image\n"); -+ } -+ printf("Reserved %d%%, formatted size = ", reserve); -+ print_size(FROM_LE32(hdr.FormattedSize)); -+ printf("\n"); -+ fflush(stdout); -+ } -+ -+ if (interrogate) { -+ char str[3]; -+ printf("This will destroy all data on the target device. " -+ "Confirm (y/n): "); -+ if (fgets(str, 3, stdin) == NULL) -+ return -1; -+ if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0)) -+ return -1; -+ } -+ -+ /* Create basic block allocation table for control blocks */ -+ nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int) -+ + FROM_LE32(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize; -+ bam = malloc(nbam * sizeof(u_int)); -+ for (i = 0; i < nbam; i++) -+ bam[i] = TO_LE32(BLOCK_CONTROL); -+ -+ /* Erase partition */ -+ if (!quiet) { -+ printf("Erasing all blocks...\n"); -+ fflush(stdout); -+ } -+ erase.length = mtd.erasesize; -+ erase.start = mtd.erasesize * FROM_LE16(hdr.FirstPhysicalEUN); -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ if (ioctl(fd, MEMERASE, &erase) < 0) { -+ if (!quiet) { -+ putchar('\n'); -+ fflush(stdout); -+ } -+ perror("block erase failed"); -+ return -1; -+ } -+ erase.start += erase.length; -+ if (!quiet) { -+ if (mtd.size <= 0x800000) { -+ if (erase.start % 0x100000) { -+ if (!(erase.start % 0x20000)) putchar('-'); -+ } -+ else putchar('+'); -+ } -+ else { -+ if (erase.start % 0x800000) { -+ if (!(erase.start % 0x100000)) putchar('+'); -+ } -+ else putchar('*'); -+ } -+ fflush(stdout); -+ } -+ } -+ if (!quiet) putchar('\n'); -+ -+ /* Prepare erase units */ -+ if (!quiet) { -+ printf("Writing erase unit headers...\n"); -+ fflush(stdout); -+ } -+ lun = 0; -+ /* Distribute transfer units over the entire region */ -+ step = (spare) ? (FROM_LE16(hdr.NumEraseUnits)/spare) : (FROM_LE16(hdr.NumEraseUnits)+1); -+ for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { -+ u_int ofs = (i + FROM_LE16(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize; -+ if (lseek(fd, ofs, SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ /* Is this a transfer unit? */ -+ if (((i+1) % step) == 0) -+ hdr.LogicalEUN = TO_LE16(0xffff); -+ else { -+ hdr.LogicalEUN = TO_LE16(lun); -+ lun++; -+ } -+ if (write(fd, &hdr, sizeof(hdr)) == -1) { -+ perror("write failed"); -+ break; -+ } -+ if (lseek(fd, ofs + FROM_LE32(hdr.BAMOffset), SEEK_SET) == -1) { -+ perror("seek failed"); -+ break; -+ } -+ if (write(fd, bam, nbam * sizeof(u_int)) == -1) { -+ perror("write failed"); -+ break; -+ } -+ } -+ if (i < FROM_LE16(hdr.NumEraseUnits)) -+ return -1; -+ else -+ return 0; -+} /* format_partition */ -+ -+/*====================================================================*/ -+ -+int main(int argc, char *argv[]) -+{ -+ int quiet, interrogate, reserve; -+ int optch, errflg, fd, ret; -+ u_int spare, bootsize; -+ char *s; -+ extern char *optarg; -+ struct stat buf; -+ -+ quiet = 0; -+ interrogate = 0; -+ spare = 1; -+ reserve = 5; -+ errflg = 0; -+ bootsize = 0; -+ -+ while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) { -+ switch (optch) { -+ case 'q': -+ quiet = 1; break; -+ case 'i': -+ interrogate = 1; break; -+ case 's': -+ spare = strtoul(optarg, NULL, 0); break; -+ case 'r': -+ reserve = strtoul(optarg, NULL, 0); break; -+ case 'b': -+ bootsize = strtoul(optarg, &s, 0); -+ if ((*s == 'k') || (*s == 'K')) -+ bootsize *= 1024; -+ break; -+ default: -+ errflg = 1; break; -+ } -+ } -+ if (errflg || (optind != argc-1)) { -+ fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]" -+ " [-r reserve-percent] [-b bootsize] device\n", argv[0]); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (stat(argv[optind], &buf) != 0) { -+ perror("status check failed"); -+ exit(EXIT_FAILURE); -+ } -+ if (!(buf.st_mode & S_IFCHR)) { -+ fprintf(stderr, "%s is not a character special device\n", -+ argv[optind]); -+ exit(EXIT_FAILURE); -+ } -+ fd = open(argv[optind], O_RDWR); -+ if (fd == -1) { -+ perror("open failed"); -+ exit(EXIT_FAILURE); -+ } -+ -+ ret = format_partition(fd, quiet, interrogate, spare, reserve, -+ bootsize); -+ if (!quiet) { -+ if (ret) -+ printf("format failed.\n"); -+ else -+ printf("format successful.\n"); -+ } -+ close(fd); -+ -+ exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/linux/jffs2.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/linux/jffs2.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/linux/jffs2.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/linux/jffs2.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,218 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse -+ * -+ * For licensing information, see the file 'LICENCE' in the -+ * jffs2 directory. -+ * -+ * $Id: jffs2.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ */ -+ -+#ifndef __LINUX_JFFS2_H__ -+#define __LINUX_JFFS2_H__ -+ -+/* You must include something which defines the C99 uintXX_t types. -+ We don't do it from here because this file is used in too many -+ different environments. */ -+ -+#define JFFS2_SUPER_MAGIC 0x72b6 -+ -+/* Values we may expect to find in the 'magic' field */ -+#define JFFS2_OLD_MAGIC_BITMASK 0x1984 -+#define JFFS2_MAGIC_BITMASK 0x1985 -+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ -+#define JFFS2_EMPTY_BITMASK 0xffff -+#define JFFS2_DIRTY_BITMASK 0x0000 -+ -+/* Summary node MAGIC marker */ -+#define JFFS2_SUM_MAGIC 0x02851885 -+ -+/* We only allow a single char for length, and 0xFF is empty flash so -+ we don't want it confused with a real length. Hence max 254. -+*/ -+#define JFFS2_MAX_NAME_LEN 254 -+ -+/* How small can we sensibly write nodes? */ -+#define JFFS2_MIN_DATA_LEN 128 -+ -+#define JFFS2_COMPR_NONE 0x00 -+#define JFFS2_COMPR_ZERO 0x01 -+#define JFFS2_COMPR_RTIME 0x02 -+#define JFFS2_COMPR_RUBINMIPS 0x03 -+#define JFFS2_COMPR_COPY 0x04 -+#define JFFS2_COMPR_DYNRUBIN 0x05 -+#define JFFS2_COMPR_ZLIB 0x06 -+#define JFFS2_COMPR_LZO 0x07 -+/* Compatibility flags. */ -+#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ -+#define JFFS2_NODE_ACCURATE 0x2000 -+/* INCOMPAT: Fail to mount the filesystem */ -+#define JFFS2_FEATURE_INCOMPAT 0xc000 -+/* ROCOMPAT: Mount read-only */ -+#define JFFS2_FEATURE_ROCOMPAT 0x8000 -+/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ -+#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 -+/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ -+#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 -+ -+#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) -+#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) -+#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) -+ -+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) -+ -+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) -+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) -+ -+/* XATTR Related */ -+#define JFFS2_XPREFIX_USER 1 /* for "user." */ -+#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ -+#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ -+#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ -+#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ -+ -+#define JFFS2_ACL_VERSION 0x0001 -+ -+// Maybe later... -+//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -+//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) -+ -+ -+#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at -+ mount time, don't wait for it to -+ happen later */ -+#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific -+ compression type */ -+ -+ -+/* These can go once we've made sure we've caught all uses without -+ byteswapping */ -+ -+typedef struct { -+ uint32_t v32; -+} __attribute__((packed)) jint32_t; -+ -+typedef struct { -+ uint32_t m; -+} __attribute__((packed)) jmode_t; -+ -+typedef struct { -+ uint16_t v16; -+} __attribute__((packed)) jint16_t; -+ -+struct jffs2_unknown_node -+{ -+ /* All start like this */ -+ jint16_t magic; -+ jint16_t nodetype; -+ jint32_t totlen; /* So we can skip over nodes we don't grok */ -+ jint32_t hdr_crc; -+} __attribute__((packed)); -+ -+struct jffs2_raw_dirent -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t pino; -+ jint32_t version; -+ jint32_t ino; /* == zero for unlink */ -+ jint32_t mctime; -+ uint8_t nsize; -+ uint8_t type; -+ uint8_t unused[2]; -+ jint32_t node_crc; -+ jint32_t name_crc; -+ uint8_t name[0]; -+} __attribute__((packed)); -+ -+/* The JFFS2 raw inode structure: Used for storage on physical media. */ -+/* The uid, gid, atime, mtime and ctime members could be longer, but -+ are left like this for space efficiency. If and when people decide -+ they really need them extended, it's simple enough to add support for -+ a new type of raw node. -+*/ -+struct jffs2_raw_inode -+{ -+ jint16_t magic; /* A constant magic number. */ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ -+ jint32_t totlen; /* Total length of this node (inc data, etc.) */ -+ jint32_t hdr_crc; -+ jint32_t ino; /* Inode number. */ -+ jint32_t version; /* Version number. */ -+ jmode_t mode; /* The file's type or mode. */ -+ jint16_t uid; /* The file's owner. */ -+ jint16_t gid; /* The file's group. */ -+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */ -+ jint32_t atime; /* Last access time. */ -+ jint32_t mtime; /* Last modification time. */ -+ jint32_t ctime; /* Change time. */ -+ jint32_t offset; /* Where to begin to write. */ -+ jint32_t csize; /* (Compressed) data size */ -+ jint32_t dsize; /* Size of the node's data. (after decompression) */ -+ uint8_t compr; /* Compression algorithm used */ -+ uint8_t usercompr; /* Compression algorithm requested by the user */ -+ jint16_t flags; /* See JFFS2_INO_FLAG_* */ -+ jint32_t data_crc; /* CRC for the (compressed) data. */ -+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */ -+ uint8_t data[0]; -+} __attribute__((packed)); -+ -+struct jffs2_raw_xattr { -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t xid; /* XATTR identifier number */ -+ jint32_t version; -+ uint8_t xprefix; -+ uint8_t name_len; -+ jint16_t value_len; -+ jint32_t data_crc; -+ jint32_t node_crc; -+ uint8_t data[0]; -+} __attribute__((packed)); -+ -+struct jffs2_raw_xref -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t ino; /* inode number */ -+ jint32_t xid; /* XATTR identifier number */ -+ jint32_t xseqno; /* xref sequencial number */ -+ jint32_t node_crc; -+} __attribute__((packed)); -+ -+struct jffs2_raw_summary -+{ -+ jint16_t magic; -+ jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t sum_num; /* number of sum entries*/ -+ jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ -+ jint32_t padded; /* sum of the size of padding nodes */ -+ jint32_t sum_crc; /* summary information crc */ -+ jint32_t node_crc; /* node crc */ -+ jint32_t sum[0]; /* inode summary info */ -+} __attribute__((packed)); -+ -+union jffs2_node_union -+{ -+ struct jffs2_raw_inode i; -+ struct jffs2_raw_dirent d; -+ struct jffs2_raw_xattr x; -+ struct jffs2_raw_xref r; -+ struct jffs2_raw_summary s; -+ struct jffs2_unknown_node u; -+}; -+ -+#endif /* __LINUX_JFFS2_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ftl-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ftl-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+/* -+ * $Id: ftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Derived from (and probably identical to): -+ * ftl.h 1.7 1999/10/25 20:23:17 -+ * -+ * The contents of this file are subject to the Mozilla Public License -+ * Version 1.1 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License -+ * at http://www.mozilla.org/MPL/ -+ * -+ * Software distributed under the License is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -+ * the License for the specific language governing rights and -+ * limitations under the License. -+ * -+ * The initial developer of the original code is David A. Hinds -+ * . Portions created by David A. Hinds -+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ * -+ * Alternatively, the contents of this file may be used under the -+ * terms of the GNU General Public License version 2 (the "GPL"), in -+ * which case the provisions of the GPL are applicable instead of the -+ * above. If you wish to allow the use of your version of this file -+ * only under the terms of the GPL and not to allow others to use -+ * your version of this file under the MPL, indicate your decision by -+ * deleting the provisions above and replace them with the notice and -+ * other provisions required by the GPL. If you do not delete the -+ * provisions above, a recipient may use your version of this file -+ * under either the MPL or the GPL. -+ */ -+ -+#ifndef __MTD_FTL_USER_H__ -+#define __MTD_FTL_USER_H__ -+ -+typedef struct erase_unit_header_t { -+ u_int8_t LinkTargetTuple[5]; -+ u_int8_t DataOrgTuple[10]; -+ u_int8_t NumTransferUnits; -+ u_int32_t EraseCount; -+ u_int16_t LogicalEUN; -+ u_int8_t BlockSize; -+ u_int8_t EraseUnitSize; -+ u_int16_t FirstPhysicalEUN; -+ u_int16_t NumEraseUnits; -+ u_int32_t FormattedSize; -+ u_int32_t FirstVMAddress; -+ u_int16_t NumVMPages; -+ u_int8_t Flags; -+ u_int8_t Code; -+ u_int32_t SerialNumber; -+ u_int32_t AltEUHOffset; -+ u_int32_t BAMOffset; -+ u_int8_t Reserved[12]; -+ u_int8_t EndTuple[2]; -+} erase_unit_header_t; -+ -+/* Flags in erase_unit_header_t */ -+#define HIDDEN_AREA 0x01 -+#define REVERSE_POLARITY 0x02 -+#define DOUBLE_BAI 0x04 -+ -+/* Definitions for block allocation information */ -+ -+#define BLOCK_FREE(b) ((b) == 0xffffffff) -+#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe)) -+ -+#define BLOCK_TYPE(b) ((b) & 0x7f) -+#define BLOCK_ADDRESS(b) ((b) & ~0x7f) -+#define BLOCK_NUMBER(b) ((b) >> 9) -+#define BLOCK_CONTROL 0x30 -+#define BLOCK_DATA 0x40 -+#define BLOCK_REPLACEMENT 0x60 -+#define BLOCK_BAD 0x70 -+ -+#endif /* __MTD_FTL_USER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/inftl-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/inftl-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/inftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/inftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,91 @@ -+/* -+ * $Id: inftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Parts of INFTL headers shared with userspace -+ * -+ */ -+ -+#ifndef __MTD_INFTL_USER_H__ -+#define __MTD_INFTL_USER_H__ -+ -+#define OSAK_VERSION 0x5120 -+#define PERCENTUSED 98 -+ -+#define SECTORSIZE 512 -+ -+/* Block Control Information */ -+ -+struct inftl_bci { -+ uint8_t ECCsig[6]; -+ uint8_t Status; -+ uint8_t Status1; -+} __attribute__((packed)); -+ -+struct inftl_unithead1 { -+ uint16_t virtualUnitNo; -+ uint16_t prevUnitNo; -+ uint8_t ANAC; -+ uint8_t NACs; -+ uint8_t parityPerField; -+ uint8_t discarded; -+} __attribute__((packed)); -+ -+struct inftl_unithead2 { -+ uint8_t parityPerField; -+ uint8_t ANAC; -+ uint16_t prevUnitNo; -+ uint16_t virtualUnitNo; -+ uint8_t NACs; -+ uint8_t discarded; -+} __attribute__((packed)); -+ -+struct inftl_unittail { -+ uint8_t Reserved[4]; -+ uint16_t EraseMark; -+ uint16_t EraseMark1; -+} __attribute__((packed)); -+ -+union inftl_uci { -+ struct inftl_unithead1 a; -+ struct inftl_unithead2 b; -+ struct inftl_unittail c; -+}; -+ -+struct inftl_oob { -+ struct inftl_bci b; -+ union inftl_uci u; -+}; -+ -+ -+/* INFTL Media Header */ -+ -+struct INFTLPartition { -+ __u32 virtualUnits; -+ __u32 firstUnit; -+ __u32 lastUnit; -+ __u32 flags; -+ __u32 spareUnits; -+ __u32 Reserved0; -+ __u32 Reserved1; -+} __attribute__((packed)); -+ -+struct INFTLMediaHeader { -+ char bootRecordID[8]; -+ __u32 NoOfBootImageBlocks; -+ __u32 NoOfBinaryPartitions; -+ __u32 NoOfBDTLPartitions; -+ __u32 BlockMultiplierBits; -+ __u32 FormatFlags; -+ __u32 OsakVersion; -+ __u32 PercentUsed; -+ struct INFTLPartition Partitions[4]; -+} __attribute__((packed)); -+ -+/* Partition flag types */ -+#define INFTL_BINARY 0x20000000 -+#define INFTL_BDTL 0x40000000 -+#define INFTL_LAST 0x80000000 -+ -+#endif /* __MTD_INFTL_USER_H__ */ -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/jffs2-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,82 @@ -+/* -+ * $Id: jffs2-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * JFFS2 definitions for use in user space only -+ */ -+ -+#ifndef __JFFS2_USER_H__ -+#define __JFFS2_USER_H__ -+ -+/* This file is blessed for inclusion by userspace */ -+#include -+#include -+#include -+ -+#undef cpu_to_je16 -+#undef cpu_to_je32 -+#undef cpu_to_jemode -+#undef je16_to_cpu -+#undef je32_to_cpu -+#undef jemode_to_cpu -+ -+extern int target_endian; -+ -+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); }) -+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); }) -+ -+#define cpu_to_je16(x) ((jint16_t){t16(x)}) -+#define cpu_to_je32(x) ((jint32_t){t32(x)}) -+#define cpu_to_jemode(x) ((jmode_t){t32(x)}) -+ -+#define je16_to_cpu(x) (t16((x).v16)) -+#define je32_to_cpu(x) (t32((x).v32)) -+#define jemode_to_cpu(x) (t32((x).m)) -+ -+#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) -+#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) -+#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x)) -+#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x)) -+ -+/* XATTR/POSIX-ACL related definition */ -+/* Namespaces copied from xattr.h and posix_acl_xattr.h */ -+#define XATTR_USER_PREFIX "user." -+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) -+#define XATTR_SECURITY_PREFIX "security." -+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) -+#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" -+#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1) -+#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" -+#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1) -+#define XATTR_TRUSTED_PREFIX "trusted." -+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) -+ -+struct jffs2_acl_entry { -+ jint16_t e_tag; -+ jint16_t e_perm; -+ jint32_t e_id; -+}; -+ -+struct jffs2_acl_entry_short { -+ jint16_t e_tag; -+ jint16_t e_perm; -+}; -+ -+struct jffs2_acl_header { -+ jint32_t a_version; -+}; -+ -+/* copied from include/linux/posix_acl_xattr.h */ -+#define POSIX_ACL_XATTR_VERSION 0x0002 -+ -+struct posix_acl_xattr_entry { -+ uint16_t e_tag; -+ uint16_t e_perm; -+ uint32_t e_id; -+}; -+ -+struct posix_acl_xattr_header { -+ uint32_t a_version; -+ struct posix_acl_xattr_entry a_entries[0]; -+}; -+ -+#endif /* __JFFS2_USER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-abi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,170 @@ -+/* -+ * $Id: mtd-abi.h,v 1.1.1.1 2008-10-30 14:29:21 lhhuang Exp $ -+ * -+ * Portions of MTD ABI definition which are shared by kernel and user space -+ */ -+ -+#ifndef __MTD_ABI_H__ -+#define __MTD_ABI_H__ -+ -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif -+ -+typedef unsigned long long size_mtd_t; -+typedef unsigned long long loff_mtd_t; -+ -+struct erase_info_user { -+ uint64_t start; -+ uint64_t length; -+}; -+ -+struct mtd_oob_buf { -+ uint32_t start; -+ uint32_t length; -+ unsigned char __user *ptr; -+}; -+ -+struct mtd_page_buf { -+ uint32_t start; //page start address -+ uint32_t ooblength; -+ uint32_t datlength; -+ unsigned char __user *oobptr; -+ unsigned char __user *datptr; -+}; -+ -+#define MTD_ABSENT 0 -+#define MTD_RAM 1 -+#define MTD_ROM 2 -+#define MTD_NORFLASH 3 -+#define MTD_NANDFLASH 4 -+#define MTD_DATAFLASH 6 -+#define MTD_UBIVOLUME 7 -+ -+#define MTD_WRITEABLE 0x400 /* Device is writeable */ -+#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ -+#define MTD_NO_ERASE 0x1000 /* No erase necessary */ -+#define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */ -+ -+// Some common devices / combinations of capabilities -+#define MTD_CAP_ROM 0 -+#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE) -+#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE) -+#define MTD_CAP_NANDFLASH (MTD_WRITEABLE) -+ -+/* ECC byte placement */ -+#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) -+#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode) -+#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme -+#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read) -+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default -+ -+/* OTP mode selection */ -+#define MTD_OTP_OFF 0 -+#define MTD_OTP_FACTORY 1 -+#define MTD_OTP_USER 2 -+ -+struct mtd_info_user { -+ uint8_t type; -+ uint32_t flags; -+ uint64_t size; // Total size of the MTD -+ uint32_t erasesize; -+ uint32_t writesize; -+ uint32_t oobsize; // Amount of OOB data per block (e.g. 16) -+ /* The below two fields are obsolete and broken, do not use them -+ * (TODO: remove at some point) */ -+ uint32_t ecctype; -+ uint32_t eccsize; -+}; -+ -+struct region_info_user { -+ uint64_t offset; /* At which this region starts, -+ * from the beginning of the MTD */ -+ uint32_t erasesize; /* For this region */ -+ uint32_t numblocks; /* Number of blocks in this region */ -+ uint32_t regionindex; -+}; -+ -+struct otp_info { -+ uint32_t start; -+ uint32_t length; -+ uint32_t locked; -+}; -+ -+#define MEMGETINFO _IOR('M', 1, struct mtd_info_user) -+#define MEMERASE _IOW('M', 2, struct erase_info_user) -+#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) -+#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) -+#define MEMLOCK _IOW('M', 5, struct erase_info_user) -+#define MEMUNLOCK _IOW('M', 6, struct erase_info_user) -+#define MEMGETREGIONCOUNT _IOR('M', 7, int) -+#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) -+#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) -+#define MEMGETBADBLOCK _IOW('M', 11, loff_mtd_t) -+#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_t) -+#define OTPSELECT _IOR('M', 13, int) -+#define OTPGETREGIONCOUNT _IOW('M', 14, int) -+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) -+#define OTPLOCK _IOR('M', 16, struct otp_info) -+#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) -+#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) -+#define MTDFILEMODE _IO('M', 19) -+#define MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf) -+ -+/* -+ * Obsolete legacy interface. Keep it in order not to break userspace -+ * interfaces -+ */ -+struct nand_oobinfo { -+ uint32_t useecc; -+ uint32_t eccbytes; -+ uint32_t oobfree[8][2]; -+ uint32_t eccpos[104]; /* more fields(13*8) are required for -+ * 8-bit BCH ECC and 4KB pagesize nand, by Regen */ -+}; -+ -+struct nand_oobfree { -+ uint32_t offset; -+ uint32_t length; -+}; -+ -+#define MTD_MAX_OOBFREE_ENTRIES 8 -+/* -+ * ECC layout control structure. Exported to userspace for -+ * diagnosis and to allow creation of raw images -+ */ -+struct nand_ecclayout { -+ uint32_t eccbytes; -+ uint32_t eccpos[128]; -+ uint32_t oobavail; -+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; -+}; -+ -+/** -+ * struct mtd_ecc_stats - error correction stats -+ * -+ * @corrected: number of corrected bits -+ * @failed: number of uncorrectable errors -+ * @badblocks: number of bad blocks in this partition -+ * @bbtblocks: number of blocks reserved for bad block tables -+ */ -+struct mtd_ecc_stats { -+ uint32_t corrected; -+ uint32_t failed; -+ uint32_t badblocks; -+ uint32_t bbtblocks; -+}; -+ -+/* -+ * Read/write file modes for access to MTD -+ */ -+enum mtd_file_modes { -+ MTD_MODE_NORMAL = MTD_OTP_OFF, -+ MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY, -+ MTD_MODE_OTP_USER = MTD_OTP_USER, -+ MTD_MODE_RAW, -+}; -+ -+#endif /* __MTD_ABI_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/mtd-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/mtd-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+/* -+ * $Id: mtd-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * MTD ABI header for use by user space only. -+ */ -+ -+#ifndef __MTD_USER_H__ -+#define __MTD_USER_H__ -+ -+#include -+ -+/* This file is blessed for inclusion by userspace */ -+#include -+ -+typedef struct mtd_info_user mtd_info_t; -+typedef struct erase_info_user erase_info_t; -+typedef struct region_info_user region_info_t; -+typedef struct nand_oobinfo nand_oobinfo_t; -+typedef struct nand_ecclayout nand_ecclayout_t; -+ -+#endif /* __MTD_USER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/nftl-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/nftl-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/nftl-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/nftl-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+/* -+ * $Id: nftl-user.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * -+ * Parts of NFTL headers shared with userspace -+ * -+ */ -+ -+#ifndef __MTD_NFTL_USER_H__ -+#define __MTD_NFTL_USER_H__ -+ -+/* Block Control Information */ -+ -+struct nftl_bci { -+ unsigned char ECCSig[6]; -+ uint8_t Status; -+ uint8_t Status1; -+}__attribute__((packed)); -+ -+/* Unit Control Information */ -+ -+struct nftl_uci0 { -+ uint16_t VirtUnitNum; -+ uint16_t ReplUnitNum; -+ uint16_t SpareVirtUnitNum; -+ uint16_t SpareReplUnitNum; -+} __attribute__((packed)); -+ -+struct nftl_uci1 { -+ uint32_t WearInfo; -+ uint16_t EraseMark; -+ uint16_t EraseMark1; -+} __attribute__((packed)); -+ -+struct nftl_uci2 { -+ uint16_t FoldMark; -+ uint16_t FoldMark1; -+ uint32_t unused; -+} __attribute__((packed)); -+ -+union nftl_uci { -+ struct nftl_uci0 a; -+ struct nftl_uci1 b; -+ struct nftl_uci2 c; -+}; -+ -+struct nftl_oob { -+ struct nftl_bci b; -+ union nftl_uci u; -+}; -+ -+/* NFTL Media Header */ -+ -+struct NFTLMediaHeader { -+ char DataOrgID[6]; -+ uint16_t NumEraseUnits; -+ uint16_t FirstPhysicalEUN; -+ uint32_t FormattedSize; -+ unsigned char UnitSizeFactor; -+} __attribute__((packed)); -+ -+#define MAX_ERASE_ZONES (8192 - 512) -+ -+#define ERASE_MARK 0x3c69 -+#define SECTOR_FREE 0xff -+#define SECTOR_USED 0x55 -+#define SECTOR_IGNORE 0x11 -+#define SECTOR_DELETED 0x00 -+ -+#define FOLD_MARK_IN_PROGRESS 0x5555 -+ -+#define ZONE_GOOD 0xff -+#define ZONE_BAD_ORIGINAL 0 -+#define ZONE_BAD_MARKED 7 -+ -+ -+#endif /* __MTD_NFTL_USER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-header.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-header.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-header.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-header.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,372 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Thomas Gleixner -+ * Frank Haverkamp -+ * Oliver Lohmann -+ * Andreas Arnez -+ */ -+ -+/* -+ * This file defines the layout of UBI headers and all the other UBI on-flash -+ * data structures. May be included by user-space. -+ */ -+ -+#ifndef __UBI_HEADER_H__ -+#define __UBI_HEADER_H__ -+ -+#include -+ -+/* The version of UBI images supported by this implementation */ -+#define UBI_VERSION 1 -+ -+/* The highest erase counter value supported by this implementation */ -+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF -+ -+/* The initial CRC32 value used when calculating CRC checksums */ -+#define UBI_CRC32_INIT 0xFFFFFFFFU -+ -+/* Erase counter header magic number (ASCII "UBI#") */ -+#define UBI_EC_HDR_MAGIC 0x55424923 -+/* Volume identifier header magic number (ASCII "UBI!") */ -+#define UBI_VID_HDR_MAGIC 0x55424921 -+ -+/* -+ * Volume type constants used in the volume identifier header. -+ * -+ * @UBI_VID_DYNAMIC: dynamic volume -+ * @UBI_VID_STATIC: static volume -+ */ -+enum { -+ UBI_VID_DYNAMIC = 1, -+ UBI_VID_STATIC = 2 -+}; -+ -+/* -+ * Volume flags used in the volume table record. -+ * -+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume -+ * -+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume -+ * table. UBI automatically re-sizes the volume which has this flag and makes -+ * the volume to be of largest possible size. This means that if after the -+ * initialization UBI finds out that there are available physical eraseblocks -+ * present on the device, it automatically appends all of them to the volume -+ * (the physical eraseblocks reserved for bad eraseblocks handling and other -+ * reserved physical eraseblocks are not taken). So, if there is a volume with -+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical -+ * eraseblocks will be zero after UBI is loaded, because all of them will be -+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared -+ * after the volume had been initialized. -+ * -+ * The auto-resize feature is useful for device production purposes. For -+ * example, different NAND flash chips may have different amount of initial bad -+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND -+ * chips usually guarantee that the amount of initial bad eraseblocks does not -+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be -+ * flashed to the end devices in production, he does not know the exact amount -+ * of good physical eraseblocks the NAND chip on the device will have, but this -+ * number is required to calculate the volume sized and put them to the volume -+ * table of the UBI image. In this case, one of the volumes (e.g., the one -+ * which will store the root file system) is marked as "auto-resizable", and -+ * UBI will adjust its size on the first boot if needed. -+ * -+ * Note, first UBI reserves some amount of physical eraseblocks for bad -+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This -+ * means that the pool of reserved physical eraseblocks will always be present. -+ */ -+enum { -+ UBI_VTBL_AUTORESIZE_FLG = 0x01, -+}; -+ -+/* -+ * Compatibility constants used by internal volumes. -+ * -+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written -+ * to the flash -+ * @UBI_COMPAT_RO: attach this device in read-only mode -+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its -+ * physical eraseblocks, don't allow the wear-leveling unit to move them -+ * @UBI_COMPAT_REJECT: reject this UBI image -+ */ -+enum { -+ UBI_COMPAT_DELETE = 1, -+ UBI_COMPAT_RO = 2, -+ UBI_COMPAT_PRESERVE = 4, -+ UBI_COMPAT_REJECT = 5 -+}; -+ -+/* Sizes of UBI headers */ -+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) -+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) -+ -+/* Sizes of UBI headers without the ending CRC */ -+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(uint32_t)) -+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(uint32_t)) -+ -+/** -+ * struct ubi_ec_hdr - UBI erase counter header. -+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) -+ * @version: version of UBI implementation which is supposed to accept this -+ * UBI image -+ * @padding1: reserved for future, zeroes -+ * @ec: the erase counter -+ * @vid_hdr_offset: where the VID header starts -+ * @data_offset: where the user data start -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: erase counter header CRC checksum -+ * -+ * The erase counter header takes 64 bytes and has a plenty of unused space for -+ * future usage. The unused fields are zeroed. The @version field is used to -+ * indicate the version of UBI implementation which is supposed to be able to -+ * work with this UBI image. If @version is greater then the current UBI -+ * version, the image is rejected. This may be useful in future if something -+ * is changed radically. This field is duplicated in the volume identifier -+ * header. -+ * -+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the -+ * volume identifier header and user data, relative to the beginning of the -+ * physical eraseblock. These values have to be the same for all physical -+ * eraseblocks. -+ */ -+struct ubi_ec_hdr { -+ uint32_t magic; -+ uint8_t version; -+ uint8_t padding1[3]; -+ uint64_t ec; /* Warning: the current limit is 31-bit anyway! */ -+ uint32_t vid_hdr_offset; -+ uint32_t data_offset; -+ uint8_t padding2[36]; -+ uint32_t hdr_crc; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_vid_hdr - on-flash UBI volume identifier header. -+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) -+ * @version: UBI implementation version which is supposed to accept this UBI -+ * image (%UBI_VERSION) -+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @copy_flag: if this logical eraseblock was copied from another physical -+ * eraseblock (for wear-leveling reasons) -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @vol_id: ID of this volume -+ * @lnum: logical eraseblock number -+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be -+ * removed, kept only for not breaking older UBI users) -+ * @data_size: how many bytes of data this logical eraseblock contains -+ * @used_ebs: total number of used logical eraseblocks in this volume -+ * @data_pad: how many bytes at the end of this physical eraseblock are not -+ * used -+ * @data_crc: CRC checksum of the data stored in this logical eraseblock -+ * @padding1: reserved for future, zeroes -+ * @sqnum: sequence number -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: volume identifier header CRC checksum -+ * -+ * The @sqnum is the value of the global sequence counter at the time when this -+ * VID header was created. The global sequence counter is incremented each time -+ * UBI writes a new VID header to the flash, i.e. when it maps a logical -+ * eraseblock to a new physical eraseblock. The global sequence counter is an -+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum -+ * (sequence number) is used to distinguish between older and newer versions of -+ * logical eraseblocks. -+ * -+ * There are 2 situations when there may be more then one physical eraseblock -+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id -+ * and @lnum values in the volume identifier header. Suppose we have a logical -+ * eraseblock L and it is mapped to the physical eraseblock P. -+ * -+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following -+ * situation is possible: L is asynchronously erased, so P is scheduled for -+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, -+ * so P1 is written to, then an unclean reboot happens. Result - there are 2 -+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock -+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the -+ * flash. -+ * -+ * 2. From time to time UBI moves logical eraseblocks to other physical -+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P -+ * to P1, and an unclean reboot happens before P is physically erased, there -+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to -+ * select one of them when the flash is attached. The @sqnum field says which -+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But -+ * it is not enough to select the physical eraseblock with the higher sequence -+ * number, because the unclean reboot could have happen in the middle of the -+ * copying process, so the data in P is corrupted. It is also not enough to -+ * just select the physical eraseblock with lower sequence number, because the -+ * data there may be old (consider a case if more data was added to P1 after -+ * the copying). Moreover, the unclean reboot may happen when the erasure of P -+ * was just started, so it result in unstable P, which is "mostly" OK, but -+ * still has unstable bits. -+ * -+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a -+ * copy. UBI also calculates data CRC when the data is moved and stores it at -+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical -+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is -+ * examined. If it is cleared, the situation* is simple and the newer one is -+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC -+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise -+ * the older one (P) is selected. -+ * -+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum -+ * in the past. But it is not used anymore and we keep it in order to be able -+ * to deal with old UBI images. It will be removed at some point. -+ * -+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes. -+ * Internal volumes are not seen from outside and are used for various internal -+ * UBI purposes. In this implementation there is only one internal volume - the -+ * layout volume. Internal volumes are the main mechanism of UBI extensions. -+ * For example, in future one may introduce a journal internal volume. Internal -+ * volumes have their own reserved range of IDs. -+ * -+ * The @compat field is only used for internal volumes and contains the "degree -+ * of their compatibility". It is always zero for user volumes. This field -+ * provides a mechanism to introduce UBI extensions and to be still compatible -+ * with older UBI binaries. For example, if someone introduced a journal in -+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the -+ * journal volume. And in this case, older UBI binaries, which know nothing -+ * about the journal volume, would just delete this volume and work perfectly -+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image -+ * - it just ignores the Ext3fs journal. -+ * -+ * The @data_crc field contains the CRC checksum of the contents of the logical -+ * eraseblock if this is a static volume. In case of dynamic volumes, it does -+ * not contain the CRC checksum as a rule. The only exception is when the -+ * data of the physical eraseblock was moved by the wear-leveling unit, then -+ * the wear-leveling unit calculates the data CRC and stores it in the -+ * @data_crc field. And of course, the @copy_flag is %in this case. -+ * -+ * The @data_size field is used only for static volumes because UBI has to know -+ * how many bytes of data are stored in this eraseblock. For dynamic volumes, -+ * this field usually contains zero. The only exception is when the data of the -+ * physical eraseblock was moved to another physical eraseblock for -+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the -+ * contents and uses both @data_crc and @data_size fields. In this case, the -+ * @data_size field contains data size. -+ * -+ * The @used_ebs field is used only for static volumes and indicates how many -+ * eraseblocks the data of the volume takes. For dynamic volumes this field is -+ * not used and always contains zero. -+ * -+ * The @data_pad is calculated when volumes are created using the alignment -+ * parameter. So, effectively, the @data_pad field reduces the size of logical -+ * eraseblocks of this volume. This is very handy when one uses block-oriented -+ * software (say, cramfs) on top of the UBI volume. -+ */ -+struct ubi_vid_hdr { -+ uint32_t magic; -+ uint8_t version; -+ uint8_t vol_type; -+ uint8_t copy_flag; -+ uint8_t compat; -+ uint32_t vol_id; -+ uint32_t lnum; -+ uint32_t leb_ver; /* obsolete, to be removed, don't use */ -+ uint32_t data_size; -+ uint32_t used_ebs; -+ uint32_t data_pad; -+ uint32_t data_crc; -+ uint8_t padding1[4]; -+ uint64_t sqnum; -+ uint8_t padding2[12]; -+ uint32_t hdr_crc; -+} __attribute__ ((packed)); -+ -+/* Internal UBI volumes count */ -+#define UBI_INT_VOL_COUNT 1 -+ -+/* -+ * Starting ID of internal volumes. There is reserved room for 4096 internal -+ * volumes. -+ */ -+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) -+ -+/* The layout volume contains the volume table */ -+ -+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START -+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC -+#define UBI_LAYOUT_VOLUME_ALIGN 1 -+#define UBI_LAYOUT_VOLUME_EBS 2 -+#define UBI_LAYOUT_VOLUME_NAME "layout volume" -+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT -+ -+/* The maximum number of volumes per one UBI device */ -+#define UBI_MAX_VOLUMES 128 -+ -+/* The maximum volume name length */ -+#define UBI_VOL_NAME_MAX 127 -+ -+/* Size of the volume table record */ -+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) -+ -+/* Size of the volume table record without the ending CRC */ -+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t)) -+ -+/** -+ * struct ubi_vtbl_record - a record in the volume table. -+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @upd_marker: if volume update was started but not finished -+ * @name_len: volume name length -+ * @name: the volume name -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ * @padding: reserved, zeroes -+ * @crc: a CRC32 checksum of the record -+ * -+ * The volume table records are stored in the volume table, which is stored in -+ * the layout volume. The layout volume consists of 2 logical eraseblock, each -+ * of which contains a copy of the volume table (i.e., the volume table is -+ * duplicated). The volume table is an array of &struct ubi_vtbl_record -+ * objects indexed by the volume ID. -+ * -+ * If the size of the logical eraseblock is large enough to fit -+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES -+ * records. Otherwise, it contains as many records as it can fit (i.e., size of -+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). -+ * -+ * The @upd_marker flag is used to implement volume update. It is set to %1 -+ * before update and set to %0 after the update. So if the update operation was -+ * interrupted, UBI knows that the volume is corrupted. -+ * -+ * The @alignment field is specified when the volume is created and cannot be -+ * later changed. It may be useful, for example, when a block-oriented file -+ * system works on top of UBI. The @data_pad field is calculated using the -+ * logical eraseblock size and @alignment. The alignment must be multiple to the -+ * minimal flash I/O unit. If @alignment is 1, all the available space of -+ * the physical eraseblocks is used. -+ * -+ * Empty records contain all zeroes and the CRC checksum of those zeroes. -+ */ -+struct ubi_vtbl_record { -+ uint32_t reserved_pebs; -+ uint32_t alignment; -+ uint32_t data_pad; -+ uint8_t vol_type; -+ uint8_t upd_marker; -+ uint16_t name_len; -+ uint8_t name[UBI_VOL_NAME_MAX+1]; -+ uint8_t flags; -+ uint8_t padding[23]; -+ uint32_t crc; -+} __attribute__ ((packed)); -+ -+#endif /* !__UBI_HEADER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-user.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-user.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd/ubi-user.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd/ubi-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,284 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Author: Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+#ifndef __UBI_USER_H__ -+#define __UBI_USER_H__ -+ -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif -+/* -+ * UBI device creation (the same as MTD device attachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI -+ * control device. The caller has to properly fill and pass -+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in -+ * the request and return the newly created UBI device number as the ioctl -+ * return value. -+ * -+ * UBI device deletion (the same as MTD device detachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI -+ * control device. -+ * -+ * UBI volume creation -+ * ~~~~~~~~~~~~~~~~~~~ -+ * -+ * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character -+ * device. A &struct ubi_mkvol_req object has to be properly filled and a -+ * pointer to it has to be passed to the IOCTL. -+ * -+ * UBI volume deletion -+ * ~~~~~~~~~~~~~~~~~~~ -+ * -+ * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character -+ * device should be used. A pointer to the 32-bit volume ID hast to be passed -+ * to the IOCTL. -+ * -+ * UBI volume re-size -+ * ~~~~~~~~~~~~~~~~~~ -+ * -+ * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character -+ * device should be used. A &struct ubi_rsvol_req object has to be properly -+ * filled and a pointer to it has to be passed to the IOCTL. -+ * -+ * UBI volume update -+ * ~~~~~~~~~~~~~~~~~ -+ * -+ * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the -+ * corresponding UBI volume character device. A pointer to a 64-bit update -+ * size should be passed to the IOCTL. After this, UBI expects user to write -+ * this number of bytes to the volume character device. The update is finished -+ * when the claimed number of bytes is passed. So, the volume update sequence -+ * is something like: -+ * -+ * fd = open("/dev/my_volume"); -+ * ioctl(fd, UBI_IOCVOLUP, &image_size); -+ * write(fd, buf, image_size); -+ * close(fd); -+ * -+ * Atomic eraseblock change -+ * ~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL -+ * command of the corresponding UBI volume character device. A pointer to -+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is -+ * expected to write the requested amount of bytes. This is similar to the -+ * "volume update" IOCTL. -+ */ -+ -+/* -+ * When a new UBI volume or UBI device is created, users may either specify the -+ * volume/device number they want to create or to let UBI automatically assign -+ * the number using these constants. -+ */ -+#define UBI_VOL_NUM_AUTO (-1) -+#define UBI_DEV_NUM_AUTO (-1) -+ -+/* Maximum volume name length */ -+#define UBI_MAX_VOLUME_NAME 127 -+ -+/* IOCTL commands of UBI character devices */ -+ -+#define UBI_IOC_MAGIC 'o' -+ -+/* Create an UBI volume */ -+#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) -+/* Remove an UBI volume */ -+#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) -+/* Re-size an UBI volume */ -+#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) -+ -+/* IOCTL commands of the UBI control character device */ -+ -+#define UBI_CTRL_IOC_MAGIC 'o' -+ -+/* Attach an MTD device */ -+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) -+/* Detach an MTD device */ -+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) -+ -+/* IOCTL commands of UBI volume character devices */ -+ -+#define UBI_VOL_IOC_MAGIC 'O' -+ -+/* Start UBI volume update */ -+#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) -+/* An eraseblock erasure command, used for debugging, disabled by default */ -+#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) -+/* An atomic eraseblock change command */ -+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) -+/* Start UBI leb read */ -+#define UBI_IOCLEBREAD _IOWR(UBI_VOL_IOC_MAGIC, 3, struct ubi_leb) -+ -+/* Maximum MTD device name length supported by UBI */ -+#define MAX_UBI_MTD_NAME_LEN 127 -+ -+/* -+ * UBI data type hint constants. -+ * -+ * UBI_LONGTERM: long-term data -+ * UBI_SHORTTERM: short-term data -+ * UBI_UNKNOWN: data persistence is unknown -+ * -+ * These constants are used when data is written to UBI volumes in order to -+ * help the UBI wear-leveling unit to find more appropriate physical -+ * eraseblocks. -+ */ -+enum { -+ UBI_LONGTERM = 1, -+ UBI_SHORTTERM = 2, -+ UBI_UNKNOWN = 3, -+}; -+ -+/* -+ * UBI volume type constants. -+ * -+ * @UBI_DYNAMIC_VOLUME: dynamic volume -+ * @UBI_STATIC_VOLUME: static volume -+ */ -+enum { -+ UBI_DYNAMIC_VOLUME = 3, -+ UBI_STATIC_VOLUME = 4, -+}; -+ -+/** -+ * struct ubi_attach_req - attach MTD device request. -+ * @ubi_num: UBI device number to create -+ * @mtd_num: MTD device number to attach -+ * @vid_hdr_offset: VID header offset (use defaults if %0) -+ * @padding: reserved for future, not used, has to be zeroed -+ * -+ * This data structure is used to specify MTD device UBI has to attach and the -+ * parameters it has to use. The number which should be assigned to the new UBI -+ * device is passed in @ubi_num. UBI may automatically assign the number if -+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in -+ * @ubi_num. -+ * -+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default -+ * offset of the VID header within physical eraseblocks. The default offset is -+ * the next min. I/O unit after the EC header. For example, it will be offset -+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or -+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. -+ * -+ * But in rare cases, if this optimizes things, the VID header may be placed to -+ * a different offset. For example, the boot-loader might do things faster if the -+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As -+ * the boot-loader would not normally need to read EC headers (unless it needs -+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example, -+ * but it real-life example. So, in this example, @vid_hdr_offer would be -+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes -+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page -+ * of the first page and add needed padding. -+ */ -+struct ubi_attach_req { -+ int32_t ubi_num; -+ int32_t mtd_num; -+ int32_t vid_hdr_offset; -+ uint8_t padding[12]; -+}; -+ -+/** -+ * struct ubi_mkvol_req - volume description data structure used in -+ * volume creation requests. -+ * @vol_id: volume number -+ * @alignment: volume alignment -+ * @bytes: volume size in bytes -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @padding1: reserved for future, not used, has to be zeroed -+ * @name_len: volume name length -+ * @padding2: reserved for future, not used, has to be zeroed -+ * @name: volume name -+ * -+ * This structure is used by user-space programs when creating new volumes. The -+ * @used_bytes field is only necessary when creating static volumes. -+ * -+ * The @alignment field specifies the required alignment of the volume logical -+ * eraseblock. This means, that the size of logical eraseblocks will be aligned -+ * to this number, i.e., -+ * (UBI device logical eraseblock size) mod (@alignment) = 0. -+ * -+ * To put it differently, the logical eraseblock of this volume may be slightly -+ * shortened in order to make it properly aligned. The alignment has to be -+ * multiple of the flash minimal input/output unit, or %1 to utilize the entire -+ * available space of logical eraseblocks. -+ * -+ * The @alignment field may be useful, for example, when one wants to maintain -+ * a block device on top of an UBI volume. In this case, it is desirable to fit -+ * an integer number of blocks in logical eraseblocks of this UBI volume. With -+ * alignment it is possible to update this volume using plane UBI volume image -+ * BLOBs, without caring about how to properly align them. -+ */ -+struct ubi_mkvol_req { -+ int32_t vol_id; -+ int32_t alignment; -+ int64_t bytes; -+ int8_t vol_type; -+ int8_t padding1; -+ int16_t name_len; -+ int8_t padding2[4]; -+ char name[UBI_MAX_VOLUME_NAME + 1]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_rsvol_req - a data structure used in volume re-size requests. -+ * @vol_id: ID of the volume to re-size -+ * @bytes: new size of the volume in bytes -+ * -+ * Re-sizing is possible for both dynamic and static volumes. But while dynamic -+ * volumes may be re-sized arbitrarily, static volumes cannot be made to be -+ * smaller then the number of bytes they bear. To arbitrarily shrink a static -+ * volume, it must be wiped out first (by means of volume update operation with -+ * zero number of bytes). -+ */ -+struct ubi_rsvol_req { -+ int64_t bytes; -+ int32_t vol_id; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_leb_change_req - a data structure used in atomic logical -+ * eraseblock change requests. -+ * @lnum: logical eraseblock number to change -+ * @bytes: how many bytes will be written to the logical eraseblock -+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * @padding: reserved for future, not used, has to be zeroed -+ */ -+struct ubi_leb_change_req { -+ int32_t lnum; -+ int32_t bytes; -+ uint8_t dtype; -+ uint8_t padding[7]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_leb - a data structure describe LEB. -+ * @lnum: logical eraseblock number to dump -+ * @lebbuf: LEB data buffer -+ */ -+struct ubi_leb{ -+ unsigned int lnum; -+ char __user *buf; -+}; -+ -+#endif /* __UBI_USER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd_swab.h linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd_swab.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/include/mtd_swab.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/include/mtd_swab.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,51 @@ -+#ifndef MTD_SWAB_H -+#define MTD_SWAB_H -+ -+#include -+ -+#define swab16(x) \ -+ ((uint16_t)( \ -+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ -+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) -+#define swab32(x) \ -+ ((uint32_t)( \ -+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ -+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ -+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ -+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) -+ -+#define swab64(x) \ -+ ((uint64_t)( \ -+ (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ -+ (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ -+ (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ -+ (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ -+ (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ -+ (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ -+ (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ -+ (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) )) -+ -+ -+#if __BYTE_ORDER == __BIG_ENDIAN -+#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); }) -+#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); }) -+#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); }) -+#define cpu_to_be16(x) (x) -+#define cpu_to_be32(x) (x) -+#define cpu_to_be64(x) (x) -+#else -+#define cpu_to_le16(x) (x) -+#define cpu_to_le32(x) (x) -+#define cpu_to_le64(x) (x) -+#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); }) -+#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); }) -+#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); }) -+#endif -+#define le16_to_cpu(x) cpu_to_le16(x) -+#define be16_to_cpu(x) cpu_to_be16(x) -+#define le32_to_cpu(x) cpu_to_le32(x) -+#define be32_to_cpu(x) cpu_to_be32(x) -+#define le64_to_cpu(x) cpu_to_le64(x) -+#define be64_to_cpu(x) cpu_to_be64(x) -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs-dump.c linux-2.6.24.7/drivers/mtd/mtd-utils/jffs-dump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs-dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs-dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Dump JFFS filesystem. -+ * Useful when it buggers up. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define BLOCK_SIZE 1024 -+#define JFFS_MAGIC 0x34383931 /* "1984" */ -+#define JFFS_MAX_NAME_LEN 256 -+#define JFFS_MIN_INO 1 -+#define JFFS_TRACE_INDENT 4 -+#define JFFS_ALIGN_SIZE 4 -+#define MAX_CHUNK_SIZE 32768 -+ -+/* How many padding bytes should be inserted between two chunks of data -+ on the flash? */ -+#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE \ -+ - ((uint32_t)(size) % JFFS_ALIGN_SIZE)) \ -+ % JFFS_ALIGN_SIZE) -+ -+#define JFFS_EMPTY_BITMASK 0xffffffff -+#define JFFS_MAGIC_BITMASK 0x34383931 -+#define JFFS_DIRTY_BITMASK 0x00000000 -+ -+#define min(x,y) (x) > (y) ? (y) : (x) -+ -+struct jffs_raw_inode -+{ -+ uint32_t magic; /* A constant magic number. */ -+ uint32_t ino; /* Inode number. */ -+ uint32_t pino; /* Parent's inode number. */ -+ uint32_t version; /* Version number. */ -+ uint32_t mode; /* file_type, mode */ -+ uint16_t uid; -+ uint16_t gid; -+ uint32_t atime; -+ uint32_t mtime; -+ uint32_t ctime; -+ uint32_t offset; /* Where to begin to write. */ -+ uint32_t dsize; /* Size of the file data. */ -+ uint32_t rsize; /* How much are going to be replaced? */ -+ uint8_t nsize; /* Name length. */ -+ uint8_t nlink; /* Number of links. */ -+ uint8_t spare : 6; /* For future use. */ -+ uint8_t rename : 1; /* Is this a special rename? */ -+ uint8_t deleted : 1; /* Has this file been deleted? */ -+ uint8_t accurate; /* The inode is obsolete if accurate == 0. */ -+ uint32_t dchksum; /* Checksum for the data. */ -+ uint16_t nchksum; /* Checksum for the name. */ -+ uint16_t chksum; /* Checksum for the raw_inode. */ -+}; -+ -+ -+struct jffs_file -+{ -+ struct jffs_raw_inode inode; -+ char *name; -+ unsigned char *data; -+}; -+ -+ -+char *root_directory_name = NULL; -+int fs_pos = 0; -+int verbose = 0; -+ -+#define ENDIAN_HOST 0 -+#define ENDIAN_BIG 1 -+#define ENDIAN_LITTLE 2 -+int endian = ENDIAN_HOST; -+ -+static uint32_t jffs_checksum(void *data, int size); -+void jffs_print_trace(const char *path, int depth); -+int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path, -+ int depth); -+void write_file(struct jffs_file *f, FILE *fs, struct stat st); -+void read_data(struct jffs_file *f, const char *path, int offset); -+int mkfs(FILE *fs, const char *path, int ino, int parent, int depth); -+ -+ -+ static uint32_t -+jffs_checksum(void *data, int size) -+{ -+ uint32_t sum = 0; -+ uint8_t *ptr = (uint8_t *)data; -+ -+ while (size-- > 0) -+ { -+ sum += *ptr++; -+ } -+ -+ return sum; -+} -+ -+ -+ void -+jffs_print_trace(const char *path, int depth) -+{ -+ int path_len = strlen(path); -+ int out_pos = depth * JFFS_TRACE_INDENT; -+ int pos = path_len - 1; -+ char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1); -+ -+ if (verbose >= 2) -+ { -+ fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path); -+ } -+ -+ if (!out) { -+ fprintf(stderr, "jffs_print_trace(): Allocation failed.\n"); -+ fprintf(stderr, " path: \"%s\"\n", path); -+ fprintf(stderr, "depth: %d\n", depth); -+ exit(1); -+ } -+ -+ memset(out, ' ', depth * JFFS_TRACE_INDENT); -+ -+ if (path[pos] == '/') -+ { -+ pos--; -+ } -+ while (path[pos] && (path[pos] != '/')) -+ { -+ pos--; -+ } -+ for (pos++; path[pos] && (path[pos] != '/'); pos++) -+ { -+ out[out_pos++] = path[pos]; -+ } -+ out[out_pos] = '\0'; -+ fprintf(stderr, "%s\n", out); -+} -+ -+ -+/* Print the contents of a raw inode. */ -+ void -+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode) -+{ -+ fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version); -+ fprintf(stdout, "{\n"); -+ fprintf(stdout, " 0x%08x, /* magic */\n", raw_inode->magic); -+ fprintf(stdout, " 0x%08x, /* ino */\n", raw_inode->ino); -+ fprintf(stdout, " 0x%08x, /* pino */\n", raw_inode->pino); -+ fprintf(stdout, " 0x%08x, /* version */\n", raw_inode->version); -+ fprintf(stdout, " 0x%08x, /* mode */\n", raw_inode->mode); -+ fprintf(stdout, " 0x%04x, /* uid */\n", raw_inode->uid); -+ fprintf(stdout, " 0x%04x, /* gid */\n", raw_inode->gid); -+ fprintf(stdout, " 0x%08x, /* atime */\n", raw_inode->atime); -+ fprintf(stdout, " 0x%08x, /* mtime */\n", raw_inode->mtime); -+ fprintf(stdout, " 0x%08x, /* ctime */\n", raw_inode->ctime); -+ fprintf(stdout, " 0x%08x, /* offset */\n", raw_inode->offset); -+ fprintf(stdout, " 0x%08x, /* dsize */\n", raw_inode->dsize); -+ fprintf(stdout, " 0x%08x, /* rsize */\n", raw_inode->rsize); -+ fprintf(stdout, " 0x%02x, /* nsize */\n", raw_inode->nsize); -+ fprintf(stdout, " 0x%02x, /* nlink */\n", raw_inode->nlink); -+ fprintf(stdout, " 0x%02x, /* spare */\n", -+ raw_inode->spare); -+ fprintf(stdout, " %u, /* rename */\n", -+ raw_inode->rename); -+ fprintf(stdout, " %u, /* deleted */\n", -+ raw_inode->deleted); -+ fprintf(stdout, " 0x%02x, /* accurate */\n", -+ raw_inode->accurate); -+ fprintf(stdout, " 0x%08x, /* dchksum */\n", raw_inode->dchksum); -+ fprintf(stdout, " 0x%04x, /* nchksum */\n", raw_inode->nchksum); -+ fprintf(stdout, " 0x%04x, /* chksum */\n", raw_inode->chksum); -+ fprintf(stdout, "}\n"); -+} -+ -+static void write_val32(uint32_t *adr, uint32_t val) -+{ -+ switch(endian) { -+ case ENDIAN_HOST: -+ *adr = val; -+ break; -+ case ENDIAN_LITTLE: -+ *adr = __cpu_to_le32(val); -+ break; -+ case ENDIAN_BIG: -+ *adr = __cpu_to_be32(val); -+ break; -+ } -+} -+ -+static void write_val16(uint16_t *adr, uint16_t val) -+{ -+ switch(endian) { -+ case ENDIAN_HOST: -+ *adr = val; -+ break; -+ case ENDIAN_LITTLE: -+ *adr = __cpu_to_le16(val); -+ break; -+ case ENDIAN_BIG: -+ *adr = __cpu_to_be16(val); -+ break; -+ } -+} -+ -+static uint32_t read_val32(uint32_t *adr) -+{ -+ uint32_t val; -+ -+ switch(endian) { -+ case ENDIAN_HOST: -+ val = *adr; -+ break; -+ case ENDIAN_LITTLE: -+ val = __le32_to_cpu(*adr); -+ break; -+ case ENDIAN_BIG: -+ val = __be32_to_cpu(*adr); -+ break; -+ } -+ return val; -+} -+ -+static uint16_t read_val16(uint16_t *adr) -+{ -+ uint16_t val; -+ -+ switch(endian) { -+ case ENDIAN_HOST: -+ val = *adr; -+ break; -+ case ENDIAN_LITTLE: -+ val = __le16_to_cpu(*adr); -+ break; -+ case ENDIAN_BIG: -+ val = __be16_to_cpu(*adr); -+ break; -+ } -+ return val; -+} -+ -+ int -+main(int argc, char **argv) -+{ -+ int fs; -+ struct stat sb; -+ uint32_t wordbuf; -+ off_t pos = 0; -+ off_t end; -+ struct jffs_raw_inode ino; -+ unsigned char namebuf[4096]; -+ int myino = -1; -+ -+ if (argc < 2) { -+ printf("no filesystem given\n"); -+ exit(1); -+ } -+ -+ fs = open(argv[1], O_RDONLY); -+ if (fs < 0) { -+ perror("open"); -+ exit(1); -+ } -+ -+ if (argc > 2) { -+ myino = atol(argv[2]); -+ printf("Printing ino #%d\n" , myino); -+ } -+ -+ if (fstat(fs, &sb) < 0) { -+ perror("stat"); -+ close(fs); -+ exit(1); -+ } -+ end = sb.st_size; -+ -+ while (pos < end) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ -+ switch(wordbuf) { -+ case JFFS_EMPTY_BITMASK: -+ // printf("0xff started at 0x%lx\n", pos); -+ for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ } -+ if (pos < end) -+ pos -= 4; -+ // printf("0xff ended at 0x%lx\n", pos); -+ continue; -+ -+ case JFFS_DIRTY_BITMASK: -+ // printf("0x00 started at 0x%lx\n", pos); -+ for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ } -+ if (pos < end) -+ pos -=4; -+ // printf("0x00 ended at 0x%lx\n", pos); -+ continue; -+ -+ default: -+ printf("Argh. Dirty memory at 0x%lx\n", pos); -+ // file_hexdump(fs, pos, 128); -+ for (pos += 4; pos < end; pos += 4) { -+ if (pread(fs, &wordbuf, 4, pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (wordbuf == JFFS_MAGIC_BITMASK) -+ break; -+ } -+ -+ case JFFS_MAGIC_BITMASK: -+ if (pread(fs, &ino, sizeof(ino), pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (myino == -1 || ino.ino == myino) { -+ printf("Magic found at 0x%lx\n", pos); -+ jffs_print_raw_inode(&ino); -+ } -+ pos += sizeof(ino); -+ -+ if (myino == -1 || ino.ino == myino) { -+ if (ino.nsize) { -+ if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) { -+ perror("pread"); -+ exit(1); -+ } -+ if (ino.nsize < 4095) -+ namebuf[ino.nsize] = 0; -+ else -+ namebuf[4095] = 0; -+ printf("Name: \"%s\"\n", namebuf); -+ } else { -+ printf("No Name\n"); -+ } -+ } -+ pos += (ino.nsize + 3) & ~3; -+ -+ pos += (ino.dsize + 3) & ~3; -+ } -+ -+ -+ -+ } -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2dump.c linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2dump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2dump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2dump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,690 @@ -+/* -+ * dumpjffs2.c -+ * -+ * Copyright (C) 2003 Thomas Gleixner (tglx@linutronix.de) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of a binary JFFS2 image -+ * -+ * -+ * Bug/ToDo: -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "summary.h" -+ -+#define PROGRAM "jffs2dump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define PAD(x) (((x)+3)&~3) -+ -+/* For outputting a byte-swapped version of the input image. */ -+#define cnv_e32(x) ((jint32_t){bswap_32(x.v32)}) -+#define cnv_e16(x) ((jint16_t){bswap_16(x.v16)}) -+ -+#define t32_backwards(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?bswap_32(__b):__b; }) -+#define cpu_to_e32(x) ((jint32_t){t32_backwards(x)}) -+ -+// Global variables -+long imglen; // length of image -+char *data; // image data -+ -+void display_help (void) -+{ -+ printf("Usage: dumpjffs2 [OPTION] INPUTFILE\n" -+ "Dumps the contents of a binary JFFS2 image.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-b --bigendian image is big endian\n" -+ "-l --littleendian image is little endian\n" -+ "-c --content dump image contents\n" -+ "-e fname --endianconvert=fname convert image endianness, output to file fname\n" -+ "-r --recalccrc recalc name and data crc on endian conversion\n" -+ "-d len --datsize=len size of data chunks, when oob data in binary image (NAND only)\n" -+ "-o len --oobsize=len size of oob data chunk in binary image (NAND only)\n" -+ "-v --verbose verbose output\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int verbose; // verbose output -+char *img; // filename of image -+int dumpcontent; // dump image content -+int target_endian = __BYTE_ORDER; // image endianess -+int convertendian; // convert endianness -+int recalccrc; // recalc name and data crc's on endian conversion -+char cnvfile[256]; // filename for conversion output -+int datsize; // Size of data chunks, when oob data is inside the binary image -+int oobsize; // Size of oob chunks, when oob data is inside the binary image -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "blce:rd:o:v"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"bigendian", no_argument, 0, 'b'}, -+ {"littleendian", no_argument, 0, 'l'}, -+ {"content", no_argument, 0, 'c'}, -+ {"endianconvert", required_argument, 0, 'e'}, -+ {"datsize", required_argument, 0, 'd'}, -+ {"oobsize", required_argument, 0, 'o'}, -+ {"recalccrc", required_argument, 0, 'r'}, -+ {"verbose", no_argument, 0, 'v'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'v': -+ verbose = 1; -+ break; -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ case 'c': -+ dumpcontent = 1; -+ break; -+ case 'd': -+ datsize = atoi(optarg); -+ break; -+ case 'o': -+ oobsize = atoi(optarg); -+ break; -+ case 'e': -+ convertendian = 1; -+ strcpy (cnvfile, optarg); -+ break; -+ case 'r': -+ recalccrc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ img = argv[optind]; -+} -+ -+ -+/* -+ * Dump image contents -+ */ -+void do_dumpcontent (void) -+{ -+ char *p = data, *p_free_begin; -+ union jffs2_node_union *node; -+ int empty = 0, dirty = 0; -+ char name[256]; -+ uint32_t crc; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ -+ p_free_begin = NULL; -+ while ( p < (data + imglen)) { -+ node = (union jffs2_node_union*) p; -+ -+ /* Skip empty space */ -+ if (!p_free_begin) -+ p_free_begin = p; -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ empty += 4; -+ continue; -+ } -+ -+ if (p != p_free_begin) -+ printf("Empty space found from 0x%08x to 0x%08x\n", p_free_begin-data, p-data); -+ p_free_begin = NULL; -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); -+ p += 4; -+ dirty += 4; -+ continue; -+ } -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else -+ obsolete = 0; -+ /* Set accurate for CRC check */ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); -+ p += 4; -+ dirty += 4; -+ continue; -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); -+ if (crc != je32_to_cpu (node->i.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.node_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ dirty += PAD(je32_to_cpu (node->i.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); -+ if (crc != je32_to_cpu(node->i.data_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->i.data_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ dirty += PAD(je32_to_cpu (node->i.totlen));; -+ continue; -+ } -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); -+ if (crc != je32_to_cpu (node->d.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.node_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ dirty += PAD(je32_to_cpu (node->d.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); -+ if (crc != je32_to_cpu(node->d.name_crc)) { -+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->d.name_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ dirty += PAD(je32_to_cpu (node->d.totlen));; -+ continue; -+ } -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_SUMMARY: { -+ -+ int i; -+ struct jffs2_sum_marker * sm; -+ -+ printf("%8s Inode Sum node at 0x%08x, totlen 0x%08x, sum_num %5d, cleanmarker size %5d\n", -+ obsolete ? "Obsolete" : "", -+ p - data, -+ je32_to_cpu (node->s.totlen), -+ je32_to_cpu (node->s.sum_num), -+ je32_to_cpu (node->s.cln_mkr)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_summary) - 8); -+ if (crc != je32_to_cpu (node->s.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc); -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ dirty += PAD(je32_to_cpu (node->s.totlen));; -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_summary), je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_raw_summary)); -+ if (crc != je32_to_cpu(node->s.sum_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc); -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ dirty += PAD(je32_to_cpu (node->s.totlen));; -+ continue; -+ } -+ -+ if (verbose) { -+ void *sp; -+ sp = (p + sizeof(struct jffs2_raw_summary)); -+ -+ for(i=0; is.sum_num); i++) { -+ -+ switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { -+ case JFFS2_NODETYPE_INODE : { -+ -+ struct jffs2_sum_inode_flash *spi; -+ spi = sp; -+ -+ printf ("%14s #ino %5d, version %5d, offset 0x%08x, totlen 0x%08x\n", -+ "", -+ je32_to_cpu (spi->inode), -+ je32_to_cpu (spi->version), -+ je32_to_cpu (spi->offset), -+ je32_to_cpu (spi->totlen)); -+ -+ sp += JFFS2_SUMMARY_INODE_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_DIRENT : { -+ -+ char name[255]; -+ struct jffs2_sum_dirent_flash *spd; -+ spd = sp; -+ -+ memcpy(name,spd->name,spd->nsize); -+ name [spd->nsize] = 0x0; -+ -+ printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s \n", -+ "", -+ je32_to_cpu (spd->offset), -+ je32_to_cpu (spd->totlen), -+ je32_to_cpu (spd->pino), -+ je32_to_cpu (spd->version), -+ je32_to_cpu (spd->ino), -+ spd->nsize, -+ name); -+ -+ sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); -+ break; -+ } -+ -+ default : -+ printf("Unknown summary node!\n"); -+ break; -+ } -+ } -+ -+ sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker)); -+ -+ printf("%14s Sum Node Offset 0x%08x, Magic 0x%08x, Padded size 0x%08x\n", -+ "", -+ je32_to_cpu(sm->offset), -+ je32_to_cpu(sm->magic), -+ je32_to_cpu(node->s.padded)); -+ } -+ -+ p += PAD(je32_to_cpu (node->s.totlen)); -+ break; -+ } -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ empty += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - data, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ dirty += PAD(je32_to_cpu (node->u.totlen)); -+ -+ } -+ } -+ -+ if (verbose) -+ printf ("Empty space: %d, dirty space: %d\n", empty, dirty); -+} -+ -+/* -+ * Convert endianess -+ */ -+void do_endianconvert (void) -+{ -+ char *p = data; -+ union jffs2_node_union *node, newnode; -+ int fd, len; -+ jint32_t mode; -+ uint32_t crc; -+ -+ fd = open (cnvfile, O_WRONLY | O_CREAT, 0644); -+ if (fd < 0) { -+ fprintf (stderr, "Cannot open / create file: %s\n", cnvfile); -+ return; -+ } -+ -+ while ( p < (data + imglen)) { -+ node = (union jffs2_node_union*) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ write (fd, p, 4); -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic)); -+ newnode.u.magic = cnv_e16 (node->u.magic); -+ newnode.u.nodetype = cnv_e16 (node->u.nodetype); -+ write (fd, &newnode, 4); -+ p += 4; -+ continue; -+ } -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->u.hdr_crc), crc); -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ -+ newnode.i.magic = cnv_e16 (node->i.magic); -+ newnode.i.nodetype = cnv_e16 (node->i.nodetype); -+ newnode.i.totlen = cnv_e32 (node->i.totlen); -+ newnode.i.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.i.ino = cnv_e32 (node->i.ino); -+ newnode.i.version = cnv_e32 (node->i.version); -+ mode.v32 = node->i.mode.m; -+ mode = cnv_e32 (mode); -+ newnode.i.mode.m = mode.v32; -+ newnode.i.uid = cnv_e16 (node->i.uid); -+ newnode.i.gid = cnv_e16 (node->i.gid); -+ newnode.i.isize = cnv_e32 (node->i.isize); -+ newnode.i.atime = cnv_e32 (node->i.atime); -+ newnode.i.mtime = cnv_e32 (node->i.mtime); -+ newnode.i.ctime = cnv_e32 (node->i.ctime); -+ newnode.i.offset = cnv_e32 (node->i.offset); -+ newnode.i.csize = cnv_e32 (node->i.csize); -+ newnode.i.dsize = cnv_e32 (node->i.dsize); -+ newnode.i.compr = node->i.compr; -+ newnode.i.usercompr = node->i.usercompr; -+ newnode.i.flags = cnv_e16 (node->i.flags); -+ if (recalccrc) { -+ len = je32_to_cpu(node->i.csize); -+ newnode.i.data_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_inode), len)); -+ } else -+ newnode.i.data_crc = cnv_e32 (node->i.data_crc); -+ -+ newnode.i.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_inode) - 8)); -+ -+ write (fd, &newnode, sizeof (struct jffs2_raw_inode)); -+ write (fd, p + sizeof (struct jffs2_raw_inode), PAD (je32_to_cpu (node->i.totlen) - sizeof (struct jffs2_raw_inode))); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ newnode.d.magic = cnv_e16 (node->d.magic); -+ newnode.d.nodetype = cnv_e16 (node->d.nodetype); -+ newnode.d.totlen = cnv_e32 (node->d.totlen); -+ newnode.d.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.d.pino = cnv_e32 (node->d.pino); -+ newnode.d.version = cnv_e32 (node->d.version); -+ newnode.d.ino = cnv_e32 (node->d.ino); -+ newnode.d.mctime = cnv_e32 (node->d.mctime); -+ newnode.d.nsize = node->d.nsize; -+ newnode.d.type = node->d.type; -+ newnode.d.unused[0] = node->d.unused[0]; -+ newnode.d.unused[1] = node->d.unused[1]; -+ newnode.d.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_dirent) - 8)); -+ if (recalccrc) -+ newnode.d.name_crc = cpu_to_e32 ( crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize)); -+ else -+ newnode.d.name_crc = cnv_e32 (node->d.name_crc); -+ -+ write (fd, &newnode, sizeof (struct jffs2_raw_dirent)); -+ write (fd, p + sizeof (struct jffs2_raw_dirent), PAD (je32_to_cpu (node->d.totlen) - sizeof (struct jffs2_raw_dirent))); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ case JFFS2_NODETYPE_PADDING: -+ newnode.u.magic = cnv_e16 (node->u.magic); -+ newnode.u.nodetype = cnv_e16 (node->u.nodetype); -+ newnode.u.totlen = cnv_e32 (node->u.totlen); -+ newnode.u.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ -+ write (fd, &newnode, sizeof (struct jffs2_unknown_node)); -+ len = PAD(je32_to_cpu (node->u.totlen) - sizeof (struct jffs2_unknown_node)); -+ if (len > 0) -+ write (fd, p + sizeof (struct jffs2_unknown_node), len); -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_SUMMARY : { -+ struct jffs2_sum_marker *sm_ptr; -+ int i,sum_len; -+ int counter = 0; -+ -+ newnode.s.magic = cnv_e16 (node->s.magic); -+ newnode.s.nodetype = cnv_e16 (node->s.nodetype); -+ newnode.s.totlen = cnv_e32 (node->s.totlen); -+ newnode.s.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4)); -+ newnode.s.sum_num = cnv_e32 (node->s.sum_num); -+ newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr); -+ newnode.s.padded = cnv_e32 (node->s.padded); -+ -+ newnode.s.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_raw_summary) - 8)); -+ -+ // summary header -+ p += sizeof (struct jffs2_raw_summary); -+ -+ // summary data -+ sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary) - sizeof (struct jffs2_sum_marker); -+ -+ for (i=0; is.sum_num); i++) { -+ union jffs2_sum_flash *fl_ptr; -+ -+ fl_ptr = (union jffs2_sum_flash *) p; -+ -+ switch (je16_to_cpu (fl_ptr->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ -+ fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype); -+ fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode); -+ fl_ptr->i.version = cnv_e32 (fl_ptr->i.version); -+ fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset); -+ fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen); -+ p += sizeof (struct jffs2_sum_inode_flash); -+ counter += sizeof (struct jffs2_sum_inode_flash); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype); -+ fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen); -+ fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset); -+ fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino); -+ fl_ptr->d.version = cnv_e32 (fl_ptr->d.version); -+ fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino); -+ p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; -+ counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize; -+ break; -+ -+ default : -+ printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype)); -+ exit(EXIT_FAILURE); -+ break; -+ } -+ -+ } -+ -+ //pad -+ p += sum_len - counter; -+ -+ // summary marker -+ sm_ptr = (struct jffs2_sum_marker *) p; -+ sm_ptr->offset = cnv_e32 (sm_ptr->offset); -+ sm_ptr->magic = cnv_e32 (sm_ptr->magic); -+ p += sizeof (struct jffs2_sum_marker); -+ -+ // generate new crc on sum data -+ newnode.s.sum_crc = cpu_to_e32 ( crc32(0, ((char *) node) + sizeof (struct jffs2_raw_summary), -+ je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_raw_summary))); -+ -+ // write out new node header -+ write(fd, &newnode, sizeof (struct jffs2_raw_summary)); -+ // write out new summary data -+ write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker)); -+ -+ break; -+ } -+ -+ case 0xffff: -+ write (fd, p, 4); -+ p += 4; -+ break; -+ -+ default: -+ printf ("Unknown node type: 0x%04x at 0x%08x, totlen 0x%08x\n", je16_to_cpu (node->u.nodetype), p - data, je32_to_cpu (node->u.totlen)); -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ -+ } -+ } -+ -+ close (fd); -+ -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int fd; -+ -+ process_options(argc, argv); -+ -+ /* Open the input file */ -+ if ((fd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ exit(1); -+ } -+ -+ // get image length -+ imglen = lseek(fd, 0, SEEK_END); -+ lseek (fd, 0, SEEK_SET); -+ -+ data = malloc (imglen); -+ if (!data) { -+ perror("out of memory"); -+ close (fd); -+ exit(1); -+ } -+ -+ if (datsize && oobsize) { -+ int idx = 0; -+ long len = imglen; -+ uint8_t oob[oobsize]; -+ printf ("Peeling data out of combined data/oob image\n"); -+ while (len) { -+ // read image data -+ read (fd, &data[idx], datsize); -+ read (fd, oob, oobsize); -+ idx += datsize; -+ imglen -= oobsize; -+ len -= datsize + oobsize; -+ } -+ -+ } else { -+ // read image data -+ read (fd, data, imglen); -+ } -+ // Close the input file -+ close(fd); -+ -+ if (dumpcontent) -+ do_dumpcontent (); -+ -+ if (convertendian) -+ do_endianconvert (); -+ -+ // free memory -+ free (data); -+ -+ // Return happy -+ exit (0); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2reader.c linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2reader.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/jffs2reader.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/jffs2reader.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,939 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * jffs2reader v0.0.18 A jffs2 image reader -+ * -+ * Copyright (c) 2001 Jari Kirma -+ * -+ * This software is provided 'as-is', without any express or implied -+ * warranty. In no event will the author be held liable for any damages -+ * arising from the use of this software. -+ * -+ * Permission is granted to anyone to use this software for any -+ * purpose, including commercial applications, and to alter it and -+ * redistribute it freely, subject to the following restrictions: -+ * -+ * 1. The origin of this software must not be misrepresented; you must -+ * not claim that you wrote the original software. If you use this -+ * software in a product, an acknowledgment in the product -+ * documentation would be appreciated but is not required. -+ * -+ * 2. Altered source versions must be plainly marked as such, and must -+ * not be misrepresented as being the original software. -+ * -+ * 3. This notice may not be removed or altered from any source -+ * distribution. -+ * -+ * -+ ********* -+ * This code was altered September 2001 -+ * Changes are Copyright (c) Erik Andersen -+ * -+ * In compliance with (2) above, this is hereby marked as an altered -+ * version of this software. It has been altered as follows: -+ * *) Listing a directory now mimics the behavior of 'ls -l' -+ * *) Support for recursive listing has been added -+ * *) Without options, does a recursive 'ls' on the whole filesystem -+ * *) option parsing now uses getopt() -+ * *) Now uses printf, and error messages go to stderr. -+ * *) The copyright notice has been cleaned up and reformatted -+ * *) The code has been reformatted -+ * *) Several twisty code paths have been fixed so I can understand them. -+ * -Erik, 1 September 2001 -+ * -+ * *) Made it show major/minor numbers for device nodes -+ * *) Made it show symlink targets -+ * -Erik, 13 September 2001 -+ */ -+ -+ -+/* -+TODO: -+ -+- Add CRC checking code to places marked with XXX. -+- Add support for other node compression types. -+ -+- Test with real life images. -+- Maybe port into bootloader. -+ */ -+ -+/* -+BUGS: -+ -+- Doesn't check CRC checksums. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SCRATCH_SIZE (5*1024*1024) -+ -+#ifndef MAJOR -+/* FIXME: I am using illicit insider knowledge of -+ * kernel major/minor representation... */ -+#define MAJOR(dev) (((dev)>>8)&0xff) -+#define MINOR(dev) ((dev)&0xff) -+#endif -+ -+ -+#define DIRENT_INO(dirent) ((dirent)!=NULL?(dirent)->ino:0) -+#define DIRENT_PINO(dirent) ((dirent)!=NULL?(dirent)->pino:0) -+ -+struct dir { -+ struct dir *next; -+ uint8_t type; -+ uint8_t nsize; -+ uint32_t ino; -+ char name[256]; -+}; -+ -+void putblock(char *, size_t, size_t *, struct jffs2_raw_inode *); -+struct dir *putdir(struct dir *, struct jffs2_raw_dirent *); -+void printdir(char *o, size_t size, struct dir *d, char *path, -+ int recurse); -+void freedir(struct dir *); -+ -+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino); -+struct jffs2_raw_dirent *resolvedirent(char *, size_t, uint32_t, uint32_t, -+ char *, uint8_t); -+struct jffs2_raw_dirent *resolvename(char *, size_t, uint32_t, char *, uint8_t); -+struct jffs2_raw_dirent *resolveinode(char *, size_t, uint32_t); -+ -+struct jffs2_raw_dirent *resolvepath0(char *, size_t, uint32_t, char *, -+ uint32_t *, int); -+struct jffs2_raw_dirent *resolvepath(char *, size_t, uint32_t, char *, -+ uint32_t *); -+ -+void lsdir(char *, size_t, char *, int); -+void catfile(char *, size_t, char *, char *, size_t, size_t *); -+ -+int main(int, char **); -+ -+/* writes file node into buffer, to the proper position. */ -+/* reading all valid nodes in version order reconstructs the file. */ -+ -+/* -+ b - buffer -+ bsize - buffer size -+ rsize - result size -+ n - node -+ */ -+ -+void putblock(char *b, size_t bsize, size_t * rsize, -+ struct jffs2_raw_inode *n) -+{ -+ uLongf dlen = n->dsize; -+ -+ if (n->isize > bsize || (n->offset + dlen) > bsize) { -+ fprintf(stderr, "File does not fit into buffer!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (*rsize < n->isize) -+ bzero(b + *rsize, n->isize - *rsize); -+ -+ switch (n->compr) { -+ case JFFS2_COMPR_ZLIB: -+ uncompress((Bytef *) b + n->offset, &dlen, -+ (Bytef *) ((char *) n) + sizeof(struct jffs2_raw_inode), -+ (uLongf) n->csize); -+ break; -+ -+ case JFFS2_COMPR_NONE: -+ memcpy(b + n->offset, -+ ((char *) n) + sizeof(struct jffs2_raw_inode), dlen); -+ break; -+ -+ case JFFS2_COMPR_ZERO: -+ bzero(b + n->offset, dlen); -+ break; -+ -+ /* [DYN]RUBIN support required! */ -+ -+ default: -+ fprintf(stderr, "Unsupported compression method!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ *rsize = n->isize; -+} -+ -+/* adds/removes directory node into dir struct. */ -+/* reading all valid nodes in version order reconstructs the directory. */ -+ -+/* -+ dd - directory struct being processed -+ n - node -+ -+ return value: directory struct value replacing dd -+ */ -+ -+struct dir *putdir(struct dir *dd, struct jffs2_raw_dirent *n) -+{ -+ struct dir *o, *d, *p; -+ -+ o = dd; -+ -+ if (n->ino) { -+ if (dd == NULL) { -+ d = malloc(sizeof(struct dir)); -+ d->type = n->type; -+ memcpy(d->name, n->name, n->nsize); -+ d->nsize = n->nsize; -+ d->ino = n->ino; -+ d->next = NULL; -+ -+ return d; -+ } -+ -+ while (1) { -+ if (n->nsize == dd->nsize && -+ !memcmp(n->name, dd->name, n->nsize)) { -+ dd->type = n->type; -+ dd->ino = n->ino; -+ -+ return o; -+ } -+ -+ if (dd->next == NULL) { -+ dd->next = malloc(sizeof(struct dir)); -+ dd->next->type = n->type; -+ memcpy(dd->next->name, n->name, n->nsize); -+ dd->next->nsize = n->nsize; -+ dd->next->ino = n->ino; -+ dd->next->next = NULL; -+ -+ return o; -+ } -+ -+ dd = dd->next; -+ } -+ } else { -+ if (dd == NULL) -+ return NULL; -+ -+ if (n->nsize == dd->nsize && !memcmp(n->name, dd->name, n->nsize)) { -+ d = dd->next; -+ free(dd); -+ return d; -+ } -+ -+ while (1) { -+ p = dd; -+ dd = dd->next; -+ -+ if (dd == NULL) -+ return o; -+ -+ if (n->nsize == dd->nsize && -+ !memcmp(n->name, dd->name, n->nsize)) { -+ p->next = dd->next; -+ free(dd); -+ -+ return o; -+ } -+ } -+ } -+} -+ -+ -+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -+ -+/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ -+static const mode_t SBIT[] = { -+ 0, 0, S_ISUID, -+ 0, 0, S_ISGID, -+ 0, 0, S_ISVTX -+}; -+ -+/* The 9 mode bits to test */ -+static const mode_t MBIT[] = { -+ S_IRUSR, S_IWUSR, S_IXUSR, -+ S_IRGRP, S_IWGRP, S_IXGRP, -+ S_IROTH, S_IWOTH, S_IXOTH -+}; -+ -+static const char MODE1[] = "rwxrwxrwx"; -+static const char MODE0[] = "---------"; -+static const char SMODE1[] = "..s..s..t"; -+static const char SMODE0[] = "..S..S..T"; -+ -+/* -+ * Return the standard ls-like mode string from a file mode. -+ * This is static and so is overwritten on each call. -+ */ -+const char *mode_string(int mode) -+{ -+ static char buf[12]; -+ -+ int i; -+ -+ buf[0] = TYPECHAR(mode); -+ for (i = 0; i < 9; i++) { -+ if (mode & SBIT[i]) -+ buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; -+ else -+ buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; -+ } -+ return buf; -+} -+ -+/* prints contents of directory structure */ -+ -+/* -+ d - dir struct -+ */ -+ -+void printdir(char *o, size_t size, struct dir *d, char *path, int recurse) -+{ -+ char m; -+ char *filetime; -+ time_t age; -+ struct jffs2_raw_inode *ri; -+ -+ if (!path) -+ return; -+ if (strlen(path) == 1 && *path == '/') -+ path++; -+ -+ while (d != NULL) { -+ switch (d->type) { -+ case DT_REG: -+ m = ' '; -+ break; -+ -+ case DT_FIFO: -+ m = '|'; -+ break; -+ -+ case DT_CHR: -+ m = ' '; -+ break; -+ -+ case DT_BLK: -+ m = ' '; -+ break; -+ -+ case DT_DIR: -+ m = '/'; -+ break; -+ -+ case DT_LNK: -+ m = ' '; -+ break; -+ -+ case DT_SOCK: -+ m = '='; -+ break; -+ -+ default: -+ m = '?'; -+ } -+ ri = find_raw_inode(o, size, d->ino); -+ if (!ri) { -+ fprintf(stderr, "bug: raw_inode missing!\n"); -+ d = d->next; -+ continue; -+ } -+ -+ filetime = ctime((const time_t *) &(ri->ctime)); -+ age = time(NULL) - ri->ctime; -+ printf("%s %-4d %-8d %-8d ", mode_string(ri->mode), -+ 1, ri->uid, ri->gid); -+ if ( d->type==DT_BLK || d->type==DT_CHR ) { -+ dev_t rdev; -+ size_t devsize; -+ putblock((char*)&rdev, sizeof(rdev), &devsize, ri); -+ printf("%4d, %3d ", (int)MAJOR(rdev), (int)MINOR(rdev)); -+ } else { -+ printf("%9ld ", (long)ri->dsize); -+ } -+ d->name[d->nsize]='\0'; -+ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { -+ /* hh:mm if less than 6 months old */ -+ printf("%6.6s %5.5s %s/%s%c", filetime + 4, filetime + 11, path, d->name, m); -+ } else { -+ printf("%6.6s %4.4s %s/%s%c", filetime + 4, filetime + 20, path, d->name, m); -+ } -+ if (d->type == DT_LNK) { -+ char symbuf[1024]; -+ size_t symsize; -+ putblock(symbuf, sizeof(symbuf), &symsize, ri); -+ symbuf[symsize] = 0; -+ printf(" -> %s", symbuf); -+ } -+ printf("\n"); -+ -+ if (d->type == DT_DIR && recurse) { -+ char *tmp; -+ tmp = malloc(BUFSIZ); -+ if (!tmp) { -+ fprintf(stderr, "memory exhausted\n"); -+ exit(EXIT_FAILURE); -+ } -+ sprintf(tmp, "%s/%s", path, d->name); -+ lsdir(o, size, tmp, recurse); /* Go recursive */ -+ free(tmp); -+ } -+ -+ d = d->next; -+ } -+} -+ -+/* frees memory used by directory structure */ -+ -+/* -+ d - dir struct -+ */ -+ -+void freedir(struct dir *d) -+{ -+ struct dir *t; -+ -+ while (d != NULL) { -+ t = d->next; -+ free(d); -+ d = t; -+ } -+} -+ -+/* collects directory/file nodes in version order. */ -+ -+/* -+ f - file flag. -+ if zero, collect file, compare ino to inode -+ otherwise, collect directory, compare ino to parent inode -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - inode to compare against. see f. -+ -+ return value: a jffs2_raw_inode that corresponds the the specified -+ inode, or NULL -+ */ -+ -+struct jffs2_raw_inode *find_raw_inode(char *o, size_t size, uint32_t ino) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ union jffs2_node_union *lr; /* last block position */ -+ union jffs2_node_union *mp = NULL; /* minimum position */ -+ -+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v; -+ -+ vmin = 0; /* next to read */ -+ vmax = ~((uint32_t) 0); /* last to read */ -+ vmint = ~((uint32_t) 0); -+ vmaxt = 0; /* found maximum */ -+ vcur = 0; /* XXX what is smallest version number used? */ -+ /* too low version number can easily result excess log rereading */ -+ -+ n = (union jffs2_node_union *) o; -+ lr = n; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_INODE && -+ n->i.ino == ino && (v = n->i.version) > vcur) { -+ /* XXX crc check */ -+ -+ if (vmaxt < v) -+ vmaxt = v; -+ if (vmint > v) { -+ vmint = v; -+ mp = n; -+ } -+ -+ if (v == (vcur + 1)) -+ return (&(n->i)); -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */ -+ -+ if (lr == n) { /* whole loop since last read */ -+ vmax = vmaxt; -+ vmin = vmint; -+ vmint = ~((uint32_t) 0); -+ -+ if (vcur < vmax && vcur < vmin) -+ return (&(mp->i)); -+ } -+ } while (vcur < vmax); -+ -+ return NULL; -+} -+ -+/* collects dir struct for selected inode */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ pino - inode of the specified directory -+ d - input directory structure -+ -+ return value: result directory structure, replaces d. -+ */ -+ -+struct dir *collectdir(char *o, size_t size, uint32_t ino, struct dir *d) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ union jffs2_node_union *lr; /* last block position */ -+ union jffs2_node_union *mp = NULL; /* minimum position */ -+ -+ uint32_t vmin, vmint, vmaxt, vmax, vcur, v; -+ -+ vmin = 0; /* next to read */ -+ vmax = ~((uint32_t) 0); /* last to read */ -+ vmint = ~((uint32_t) 0); -+ vmaxt = 0; /* found maximum */ -+ vcur = 0; /* XXX what is smallest version number used? */ -+ /* too low version number can easily result excess log rereading */ -+ -+ n = (union jffs2_node_union *) o; -+ lr = n; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT && -+ n->d.pino == ino && (v = n->d.version) > vcur) { -+ /* XXX crc check */ -+ -+ if (vmaxt < v) -+ vmaxt = v; -+ if (vmint > v) { -+ vmint = v; -+ mp = n; -+ } -+ -+ if (v == (vcur + 1)) { -+ d = putdir(d, &(n->d)); -+ -+ lr = n; -+ vcur++; -+ vmint = ~((uint32_t) 0); -+ } -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ n = (union jffs2_node_union *) o; /* we're at the end, rewind to the beginning */ -+ -+ if (lr == n) { /* whole loop since last read */ -+ vmax = vmaxt; -+ vmin = vmint; -+ vmint = ~((uint32_t) 0); -+ -+ if (vcur < vmax && vcur < vmin) { -+ d = putdir(d, &(mp->d)); -+ -+ lr = n = -+ (union jffs2_node_union *) (((char *) mp) + -+ ((mp->u.totlen + 3) & ~3)); -+ -+ vcur = vmin; -+ } -+ } -+ } while (vcur < vmax); -+ -+ return d; -+} -+ -+ -+ -+/* resolve dirent based on criteria */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - if zero, ignore, -+ otherwise compare against dirent inode -+ pino - if zero, ingore, -+ otherwise compare against parent inode -+ and use name and nsize as extra criteria -+ name - name of wanted dirent, used if pino!=0 -+ nsize - length of name of wanted dirent, used if pino!=0 -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolvedirent(char *o, size_t size, -+ uint32_t ino, uint32_t pino, -+ char *name, uint8_t nsize) -+{ -+ /* aligned! */ -+ union jffs2_node_union *n; -+ union jffs2_node_union *e = (union jffs2_node_union *) (o + size); -+ -+ struct jffs2_raw_dirent *dd = NULL; -+ -+ uint32_t vmax, v; -+ -+ if (!pino && ino <= 1) -+ return dd; -+ -+ vmax = 0; -+ -+ n = (union jffs2_node_union *) o; -+ -+ do { -+ while (n < e && n->u.magic != JFFS2_MAGIC_BITMASK) -+ ((char *) n) += 4; -+ -+ if (n < e && n->u.magic == JFFS2_MAGIC_BITMASK) { -+ if (n->u.nodetype == JFFS2_NODETYPE_DIRENT && -+ (!ino || n->d.ino == ino) && -+ (v = n->d.version) > vmax && -+ (!pino || (n->d.pino == pino && -+ nsize == n->d.nsize && -+ !memcmp(name, n->d.name, nsize)))) { -+ /* XXX crc check */ -+ -+ if (vmax < v) { -+ vmax = v; -+ dd = &(n->d); -+ } -+ } -+ -+ ((char *) n) += ((n->u.totlen + 3) & ~3); -+ } else -+ return dd; -+ } while (1); -+} -+ -+/* resolve name under certain parent inode to dirent */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ pino - requested parent inode -+ name - name of wanted dirent -+ nsize - length of name of wanted dirent -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolvename(char *o, size_t size, uint32_t pino, -+ char *name, uint8_t nsize) -+{ -+ return resolvedirent(o, size, 0, pino, name, nsize); -+} -+ -+/* resolve inode to dirent */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - compare against dirent inode -+ -+ return value: pointer to relevant dirent structure in -+ filesystem image or NULL -+ */ -+ -+struct jffs2_raw_dirent *resolveinode(char *o, size_t size, uint32_t ino) -+{ -+ return resolvedirent(o, size, ino, 0, NULL, 0); -+} -+ -+/* resolve slash-style path into dirent and inode. -+ slash as first byte marks absolute path (root=inode 1). -+ . and .. are resolved properly, and symlinks are followed. -+ */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - root inode, used if path is relative -+ p - path to be resolved -+ inos - result inode, zero if failure -+ recc - recursion count, to detect symlink loops -+ -+ return value: pointer to dirent struct in file system image. -+ note that root directory doesn't have dirent struct -+ (return value is NULL), but it has inode (*inos=1) -+ */ -+ -+struct jffs2_raw_dirent *resolvepath0(char *o, size_t size, uint32_t ino, -+ char *p, uint32_t * inos, int recc) -+{ -+ struct jffs2_raw_dirent *dir = NULL; -+ -+ int d = 1; -+ uint32_t tino; -+ -+ char *next; -+ -+ char *path, *pp; -+ -+ char symbuf[1024]; -+ size_t symsize; -+ -+ if (recc > 16) { -+ /* probably symlink loop */ -+ *inos = 0; -+ return NULL; -+ } -+ -+ pp = path = strdup(p); -+ -+ if (*path == '/') { -+ path++; -+ ino = 1; -+ } -+ -+ if (ino > 1) { -+ dir = resolveinode(o, size, ino); -+ -+ ino = DIRENT_INO(dir); -+ } -+ -+ next = path - 1; -+ -+ while (ino && next != NULL && next[1] != 0 && d) { -+ path = next + 1; -+ next = strchr(path, '/'); -+ -+ if (next != NULL) -+ *next = 0; -+ -+ if (*path == '.' && path[1] == 0) -+ continue; -+ if (*path == '.' && path[1] == '.' && path[2] == 0) { -+ if (DIRENT_PINO(dir) == 1) { -+ ino = 1; -+ dir = NULL; -+ } else { -+ dir = resolveinode(o, size, DIRENT_PINO(dir)); -+ ino = DIRENT_INO(dir); -+ } -+ -+ continue; -+ } -+ -+ dir = resolvename(o, size, ino, path, (uint8_t) strlen(path)); -+ -+ if (DIRENT_INO(dir) == 0 || -+ (next != NULL && -+ !(dir->type == DT_DIR || dir->type == DT_LNK))) { -+ free(pp); -+ -+ *inos = 0; -+ -+ return NULL; -+ } -+ -+ if (dir->type == DT_LNK) { -+ struct jffs2_raw_inode *ri; -+ ri = find_raw_inode(o, size, DIRENT_INO(dir)); -+ putblock(symbuf, sizeof(symbuf), &symsize, ri); -+ symbuf[symsize] = 0; -+ -+ tino = ino; -+ ino = 0; -+ -+ dir = resolvepath0(o, size, tino, symbuf, &ino, ++recc); -+ -+ if (dir != NULL && next != NULL && -+ !(dir->type == DT_DIR || dir->type == DT_LNK)) { -+ free(pp); -+ -+ *inos = 0; -+ return NULL; -+ } -+ } -+ if (dir != NULL) -+ ino = DIRENT_INO(dir); -+ } -+ -+ free(pp); -+ -+ *inos = ino; -+ -+ return dir; -+} -+ -+/* resolve slash-style path into dirent and inode. -+ slash as first byte marks absolute path (root=inode 1). -+ . and .. are resolved properly, and symlinks are followed. -+ */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ ino - root inode, used if path is relative -+ p - path to be resolved -+ inos - result inode, zero if failure -+ -+ return value: pointer to dirent struct in file system image. -+ note that root directory doesn't have dirent struct -+ (return value is NULL), but it has inode (*inos=1) -+ */ -+ -+struct jffs2_raw_dirent *resolvepath(char *o, size_t size, uint32_t ino, -+ char *p, uint32_t * inos) -+{ -+ return resolvepath0(o, size, ino, p, inos, 0); -+} -+ -+/* lists files on directory specified by path */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ p - path to be resolved -+ */ -+ -+void lsdir(char *o, size_t size, char *path, int recurse) -+{ -+ struct jffs2_raw_dirent *dd; -+ struct dir *d = NULL; -+ -+ uint32_t ino; -+ -+ dd = resolvepath(o, size, 1, path, &ino); -+ -+ if (ino == 0 || -+ (dd == NULL && ino == 0) || (dd != NULL && dd->type != DT_DIR)) { -+ fprintf(stderr, "jffs2reader: %s: No such file or directory\n", -+ path); -+ exit(EXIT_FAILURE); -+ } -+ -+ d = collectdir(o, size, ino, d); -+ printdir(o, size, d, path, recurse); -+ freedir(d); -+} -+ -+/* writes file specified by path to the buffer */ -+ -+/* -+ o - filesystem image pointer -+ size - size of filesystem image -+ p - path to be resolved -+ b - file buffer -+ bsize - file buffer size -+ rsize - file result size -+ */ -+ -+void catfile(char *o, size_t size, char *path, char *b, size_t bsize, -+ size_t * rsize) -+{ -+ struct jffs2_raw_dirent *dd; -+ struct jffs2_raw_inode *ri; -+ uint32_t ino; -+ -+ dd = resolvepath(o, size, 1, path, &ino); -+ -+ if (ino == 0) { -+ fprintf(stderr, "%s: No such file or directory\n", path); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (dd == NULL || dd->type != DT_REG) { -+ fprintf(stderr, "%s: Not a regular file\n", path); -+ exit(EXIT_FAILURE); -+ } -+ -+ ri = find_raw_inode(o, size, ino); -+ putblock(b, bsize, rsize, ri); -+ -+ write(1, b, *rsize); -+} -+ -+/* usage example */ -+ -+int main(int argc, char **argv) -+{ -+ int fd, opt, recurse = 0; -+ struct stat st; -+ -+ char *scratch, *dir = NULL, *file = NULL; -+ size_t ssize = 0; -+ -+ char *buf; -+ -+ while ((opt = getopt(argc, argv, "rd:f:")) > 0) { -+ switch (opt) { -+ case 'd': -+ dir = optarg; -+ break; -+ case 'f': -+ file = optarg; -+ break; -+ case 'r': -+ recurse++; -+ break; -+ default: -+ fprintf(stderr, -+ "Usage: jffs2reader [-d|-f] < path > \n"); -+ exit(EXIT_FAILURE); -+ } -+ } -+ -+ fd = open(argv[optind], O_RDONLY); -+ if (fd == -1) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(2); -+ } -+ -+ if (fstat(fd, &st)) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(3); -+ } -+ -+ buf = malloc((size_t) st.st_size); -+ if (buf == NULL) { -+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]); -+ exit(4); -+ } -+ -+ if (read(fd, buf, st.st_size) != (ssize_t) st.st_size) { -+ fprintf(stderr, "%s: %s\n", argv[optind], strerror(errno)); -+ exit(5); -+ } -+ -+ if (dir) -+ lsdir(buf, st.st_size, dir, recurse); -+ -+ if (file) { -+ scratch = malloc(SCRATCH_SIZE); -+ if (scratch == NULL) { -+ fprintf(stderr, "%s: memory exhausted\n", argv[optind]); -+ exit(6); -+ } -+ -+ catfile(buf, st.st_size, file, scratch, SCRATCH_SIZE, &ssize); -+ free(scratch); -+ } -+ -+ if (!dir && !file) -+ lsdir(buf, st.st_size, "/", 1); -+ -+ -+ free(buf); -+ exit(EXIT_SUCCESS); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/load_nandsim.sh linux-2.6.24.7/drivers/mtd/mtd-utils/load_nandsim.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/load_nandsim.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/load_nandsim.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,123 @@ -+#!/bin/bash -+ -+# -+# This script inserts NAND simulator module to emulate NAND flash of specified -+# size. -+# -+# Author: Artem Bityutskiy -+# -+ -+# Check if nandsim module is loaded -+function nandsim_loaded() -+{ -+ local NANDSIM=`lsmod | grep nandsim` -+ if [ -n "$NANDSIM" ]; then -+ return 1 -+ fi -+ return 0 -+} -+ -+nandsim_loaded -+if (( $? != 0 )); then -+ echo "Error: nandsim is already loaded" -+ exit 1 -+fi -+ -+if (( $# < 1 )); then -+ echo "Load NAND simulator to simulate flash of a specified size." -+ echo "" -+ echo "Usage: ./load_nandsim.sh " -+ echo " " -+ echo "" -+ echo "Only the first parameter is mandatory. Default eraseblock size" -+ echo "is 16KiB, default NAND page size is 512 bytes." -+ echo "" -+ echo "Only the following combinations are supported:" -+ echo "--------------------------------------------------" -+ echo "| size (MiB) | EB size (KiB) | Page size (bytes) |" -+ echo "--------------------------------------------------" -+ echo "| 16 | 16 | 512 |" -+ echo "| 32 | 16 | 512 |" -+ echo "| 64 | 16 | 512 |" -+ echo "| 128 | 16 | 512 |" -+ echo "| 256 | 16 | 512 |" -+ echo "| 64 | 64 | 2048 |" -+ echo "| 64 | 128 | 2048 |" -+ echo "| 64 | 256 | 2048 |" -+ echo "| 64 | 512 | 2048 |" -+ echo "| 128 | 64 | 2048 |" -+ echo "| 128 | 128 | 2048 |" -+ echo "| 128 | 256 | 2048 |" -+ echo "| 128 | 512 | 2048 |" -+ echo "| 256 | 64 | 2048 |" -+ echo "| 256 | 128 | 2048 |" -+ echo "| 256 | 256 | 2048 |" -+ echo "| 256 | 512 | 2048 |" -+ echo "| 512 | 64 | 2048 |" -+ echo "| 512 | 128 | 2048 |" -+ echo "| 512 | 256 | 2048 |" -+ echo "| 512 | 512 | 2048 |" -+ echo "| 1024 | 64 | 2048 |" -+ echo "| 1024 | 128 | 2048 |" -+ echo "| 1024 | 256 | 2048 |" -+ echo "| 1024 | 512 | 2048 |" -+ echo "--------------------------------------------------" -+ exit 1 -+fi -+ -+SZ=$1 -+EBSZ=$2 -+PGSZ=$3 -+if [[ $# == '1' ]]; then -+ EBSZ=16 -+ PGSZ=512 -+elif [[ $# == '2' ]]; then -+ PGSZ=512 -+fi -+ -+if (( $PGSZ == 512 && $EBSZ != 16 )); then -+ echo "Error: only 16KiB eraseblocks are possible in case of 512 bytes page" -+ exit 1 -+fi -+ -+if (( $PGSZ == 512 )); then -+ case $SZ in -+ 16) modprobe nandsim first_id_byte=0x20 second_id_byte=0x33 ;; -+ 32) modprobe nandsim first_id_byte=0x20 second_id_byte=0x35 ;; -+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0x36 ;; -+ 128) modprobe nandsim first_id_byte=0x20 second_id_byte=0x78 ;; -+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0x71 ;; -+ *) echo "Flash size ${SZ}MiB is not supported, try 16, 32, 64 or 256" -+ exit 1 ;; -+ esac -+elif (( $PGSZ == 2048 )); then -+ case $EBSZ in -+ 64) FOURTH=0x05 ;; -+ 128) FOURTH=0x15 ;; -+ 256) FOURTH=0x25 ;; -+ 512) FOURTH=0x35 ;; -+ *) echo "Eraseblock ${EBSZ}KiB is not supported" -+ exit 1 -+ esac -+ -+ case $SZ in -+ 64) modprobe nandsim first_id_byte=0x20 second_id_byte=0xa2 third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 128) modprobe nandsim first_id_byte=0xec second_id_byte=0xa1 third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 256) modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 512) modprobe nandsim first_id_byte=0x20 second_id_byte=0xac third_id_byte=0x00 fourth_id_byte=$FOURTH ;; -+ 1024) modprobe nandsim first_id_byte=0xec second_id_byte=0xd3 third_id_byte=0x51 fourth_id_byte=$FOURTH ;; -+ *) echo "Unable to emulate ${SZ}MiB flash with ${EBSZ}KiB eraseblock" -+ exit 1 -+ esac -+else -+ echo "Error: bad NAND page size ${PGSZ}KiB, it has to be either 512 or 2048" -+ exit 1 -+fi -+ -+if (( $? != 0 )); then -+ echo "Error: cannot load nandsim" -+ exit 1 -+fi -+ -+echo "Loaded NAND simulator (${SZ}MiB, ${EBSZ}KiB eraseblock, $PGSZ bytes NAND page)" -+exit 0 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/mcast_image.h linux-2.6.24.7/drivers/mtd/mtd-utils/mcast_image.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mcast_image.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mcast_image.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,54 @@ -+#include -+ -+#define PKT_SIZE 2820 -+ -+struct image_pkt_hdr { -+ uint32_t resend; -+ uint32_t totcrc; -+ uint32_t nr_blocks; -+ uint32_t blocksize; -+ uint32_t block_crc; -+ uint32_t block_nr; -+ uint32_t pkt_sequence; -+ uint16_t pkt_nr; -+ uint16_t nr_pkts; -+ uint32_t thislen; -+ uint32_t thiscrc; -+}; -+ -+struct image_pkt { -+ struct image_pkt_hdr hdr; -+ unsigned char data[PKT_SIZE]; -+}; -+ -+struct fec_parms; -+ -+/* k - number of actual data packets -+ * n - total number of packets including data and redundant packets -+ * (actual packet size isn't relevant here) */ -+struct fec_parms *fec_new(int k, int n); -+void fec_free(struct fec_parms *p); -+ -+/* src - array of (n) pointers to data packets -+ * fec - buffer for packet to be generated -+ * index - index of packet to be generated (0 <= index < n) -+ * sz - data packet size -+ * -+ * _linear version just takes a pointer to the raw data; no -+ * mucking about with packet pointers. -+ */ -+void fec_encode(struct fec_parms *code, unsigned char *src[], -+ unsigned char *fec, int index, int sz); -+void fec_encode_linear(struct fec_parms *code, unsigned char *src, -+ unsigned char *fec, int index, int sz); -+ -+/* data - array of (k) pointers to data packets, in arbitrary order (see i) -+ * i - indices of (data) packets -+ * sz - data packet size -+ * -+ * Will never fail as long as you give it (k) individual data packets. -+ * Will re-order the (data) pointers but not the indices -- data packets -+ * are ordered on return. -+ */ -+int fec_decode(struct fec_parms *code, unsigned char *data[], -+ int i[], int sz); -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.1 linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.1 ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.1 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.1 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,259 @@ -+.TH MKFS.JFFS2 1 -+.SH NAME -+mkfs.jffs2 \- Create a JFFS2 file system image from directory -+.SH SYNOPSIS -+.B mkfs.jffs2 -+[ -+.B -p,--pad[=SIZE] -+] -+[ -+.B -r,-d,--root -+.I directory -+] -+[ -+.B -s,--pagesize=SIZE -+] -+[ -+.B -e,--eraseblock=SIZE -+] -+[ -+.B -c,--cleanmarker=SIZE -+] -+[ -+.B -n,--no-cleanmarkers -+] -+[ -+.B -o,--output -+.I image.jffs2 -+] -+[ -+.B -l,--little-endian -+] -+[ -+.B -b,--big-endian -+] -+[ -+.B -D,--devtable=FILE -+] -+[ -+.B -f,--faketime -+] -+[ -+.B -q,--squash -+] -+[ -+.B -U,--squash-uids -+] -+[ -+.B -P,--squash-perms -+] -+[ -+.B --with-xattr -+] -+[ -+.B --with-selinux -+] -+[ -+.B --with-posix-acl -+] -+[ -+.B -m,--compression-mode=MODE -+] -+[ -+.B -x,--disable-compressor=NAME -+] -+[ -+.B -X,--enable-compressor=NAME -+] -+[ -+.B -y,--compressor-priority=PRIORITY:NAME -+] -+[ -+.B -L,--list-compressors -+] -+[ -+.B -t,--test-compression -+] -+[ -+.B -h,--help -+] -+[ -+.B -v,--verbose -+] -+[ -+.B -V,--version -+] -+[ -+.B -i,--incremental -+.I image.jffs2 -+] -+ -+.SH DESCRIPTION -+The program -+.B mkfs.jffs2 -+creates a JFFS2 (Second Journalling Flash File System) file system -+image and writes the resulting image to the file specified by the -+.B -o -+option or by default to the standard output, unless the standard -+output is a terminal device in which case mkfs.jffs2 will abort. -+ -+The file system image is created using the files and directories -+contained in the directory specified by the option -+.B -r -+or the present directory, if the -+.B -r -+option is not specified. -+ -+Each block of the files to be placed into the file system image -+are compressed using one of the avaiable compressors depending -+on the selected compression mode. -+ -+File systems are created with the same endianness as the host, -+unless the -+.B -b -+or -+.B -l -+options are specified. JFFS2 driver in the 2.4 Linux kernel only -+supported images having the same endianness as the CPU. As of 2.5.48, -+the kernel can be changed with a #define to accept images of the -+non-native endianness. Full bi-endian support in the kernel is not -+planned. -+ -+It is unlikely that JFFS2 images are useful except in conjuction -+with the MTD (Memory Technology Device) drivers in the Linux -+kernel, since the JFFS2 file system driver in the kernel requires -+MTD devices. -+.SH OPTIONS -+Options that take SIZE arguments can be specified as either -+decimal (e.g., 65536), octal (0200000), or hexidecimal (0x1000). -+.TP -+.B -p, --pad[=SIZE] -+Pad output to SIZE bytes with 0xFF. If SIZE is not specified, -+the output is padded to the end of the final erase block. -+.TP -+.B -r, -d, --root=DIR -+Build file system from directory DIR. The default is the current -+directory. -+.TP -+.B -s, --pagesize=SIZE -+Use page size SIZE. The default is 4 KiB. This size is the -+maximum size of a data node. -+.TP -+.B -e, --eraseblock=SIZE -+Use erase block size SIZE. The default is 64 KiB. If you use a erase -+block size different than the erase block size of the target MTD -+device, JFFS2 may not perform optimally. If the SIZE specified is -+below 4096, the units are assumed to be KiB. -+.TP -+.B -c, --cleanmarker=SIZE -+Write \'CLEANMARKER\' nodes with the size specified. It is not -+normally appropriate to specify a size other than the default 12 -+bytes. -+.TP -+.B -n, --no-cleanmarkers -+Do not write \'CLEANMARKER\' nodes to the beginning of each erase -+block. This option can be useful for creating JFFS2 images for -+use on NAND flash, and for creating images which are to be used -+on a variety of hardware with differing eraseblock sizes. -+.TP -+.B -o, --output=FILE -+Write JFFS2 image to file FILE. Default is the standard output. -+.TP -+.B -l, --little-endian -+Create a little-endian JFFS2 image. Default is to make an image -+with the same endianness as the host. -+.TP -+.B -b, --big-endian -+Create a big-endian JFFS2 image. Default is to make an image -+with the same endianness as the host. -+.TP -+.B -D, --devtable=FILE -+Use the named FILE as a device table file, for including devices and -+changing permissions in the created image when the user does not have -+appropriate permissions to create them on the file system used as -+source. -+.TP -+.B -f, --faketime -+Change all file timestamps to \'0\' for regression testing. -+.TP -+.B -q, --squash -+Squash permissions and owners, making all files be owned by root and -+removing write permission for \'group\' and \'other\'. -+.TP -+.B -U, --squash-uids -+Squash owners making all files be owned by root. -+.TP -+.B -P, --squash-perms -+Squash permissions, removing write permission for \'group\' and \'other\'. -+.TP -+.B --with-xattr -+Enables xattr, stuff all xattr entries into jffs2 image file. -+.TP -+.B --with-selinux -+Enables xattr, stuff only SELinux Labels into jffs2 image file. -+.TP -+.B --with-posix-acl -+Enable xattr, stuff only POSIX ACL entries into jffs2 image file. -+.TP -+.B -m, --compression-mode=MODE -+Set the default compression mode. The default mode is -+.B priority -+which tries the compressors in a predefinied order and chooses the first -+successful one. The alternatives are: -+.B none -+(mkfs will not compress) and -+.B size -+(mkfs will try all compressor and chooses the one which have the smallest result). -+.TP -+.B -x, --disable-compressor=NAME -+Disable a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default states. -+.TP -+.B -X, --enable-compressor=NAME -+Enable a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default states. -+.TP -+.B -y, --compressor-priority=PRIORITY:NAME -+Set the priority of a compressor. Use -+.B -L -+to see the list of the avaiable compressors and their default priority. -+Priorities are used by priority compression mode. -+.TP -+.B -L, --list-compressors -+Show the list of the avaiable compressors and their states. -+.TP -+.B -t, --test-compression -+Call decompress after every compress - and compare the result with the original data -, and -+some other check. -+.TP -+.B -h, --help -+Display help text. -+.TP -+.B -v, --verbose -+Verbose operation. -+.TP -+.B -V, --version -+Display version information. -+.TP -+.B -i, --incremental=FILE -+Generate an appendage image for FILE. If FILE is written to flash and flash -+is appended with the output, then it seems as if it was one thing. -+ -+.SH BUGS -+JFFS2 limits device major and minor numbers to 8 bits each. Some -+consider this a bug. -+ -+.B mkfs.jffs2 -+does not properly handle hard links in the input directory structure. -+Currently, hard linked files will be expanded to multiple identical -+files in the output image. -+.SH AUTHORS -+David Woodhouse -+.br -+Manual page written by David Schleef -+.SH SEE ALSO -+.BR mkfs (8), -+.BR mkfs.jffs (1), -+.BR fakeroot (1) -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.c linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mkfs.jffs2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mkfs.jffs2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1902 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * Build a JFFS2 image in a file, from a given directory tree. -+ * -+ * Copyright 2001, 2002 Red Hat, Inc. -+ * 2001 David A. Schleef -+ * 2002 Axis Communications AB -+ * 2001, 2002 Erik Andersen -+ * 2004 University of Szeged, Hungary -+ * 2006 KaiGai Kohei -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Cross-endian support added by David Schleef . -+ * -+ * Major architectural rewrite by Erik Andersen -+ * to allow support for making hard links (though hard links support is -+ * not yet implemented), and for munging file permissions and ownership -+ * on the fly using --faketime, --squash, --devtable. And I plugged a -+ * few memory leaks, adjusted the error handling and fixed some little -+ * nits here and there. -+ * -+ * I also added a sample device table file. See device_table.txt -+ * -Erik, September 2001 -+ * -+ * Cleanmarkers support added by Axis Communications AB -+ * -+ * Rewritten again. Cleanly separated host and target filsystem -+ * activities (mainly so I can reuse all the host handling stuff as I -+ * rewrite other mkfs utils). Added a verbose option to list types -+ * and attributes as files are added to the file system. Major cleanup -+ * and scrubbing of the code so it can be read, understood, and -+ * modified by mere mortals. -+ * -+ * -Erik, November 2002 -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifndef WITHOUT_XATTR -+#include -+#include -+#endif -+#include -+#define crc32 __complete_crap -+#include -+#undef crc32 -+#include "crc32.h" -+#include "rbtree.h" -+ -+/* Do not use the weird XPG version of basename */ -+#undef basename -+ -+//#define DMALLOC -+//#define mkfs_debug_msg error_msg -+#define mkfs_debug_msg(a...) { } -+#define min(x,y) ({ typeof((x)) _x = (x); typeof((y)) _y = (y); (_x>_y)?_y:_x; }) -+ -+#define PAD(x) (((x)+3)&~3) -+ -+struct filesystem_entry { -+ char *name; /* Name of this directory (think basename) */ -+ char *path; /* Path of this directory (think dirname) */ -+ char *fullname; /* Full name of this directory (i.e. path+name) */ -+ char *hostname; /* Full path to this file on the host filesystem */ -+ uint32_t ino; /* Inode number of this file in JFFS2 */ -+ struct stat sb; /* Stores directory permissions and whatnot */ -+ char *link; /* Target a symlink points to. */ -+ struct filesystem_entry *parent; /* Parent directory */ -+ struct filesystem_entry *prev; /* Only relevant to non-directories */ -+ struct filesystem_entry *next; /* Only relevant to non-directories */ -+ struct filesystem_entry *files; /* Only relevant to directories */ -+ struct rb_node hardlink_rb; -+}; -+ -+struct rb_root hardlinks; -+static int out_fd = -1; -+static int in_fd = -1; -+static char default_rootdir[] = "."; -+static char *rootdir = default_rootdir; -+static int verbose = 0; -+static int squash_uids = 0; -+static int squash_perms = 0; -+static int fake_times = 0; -+int target_endian = __BYTE_ORDER; -+static const char *const app_name = "mkfs.jffs2"; -+static const char *const memory_exhausted = "memory exhausted"; -+ -+uint32_t find_hardlink(struct filesystem_entry *e) -+{ -+ struct filesystem_entry *f; -+ struct rb_node **n = &hardlinks.rb_node; -+ struct rb_node *parent = NULL; -+ -+ while (*n) { -+ parent = *n; -+ f = rb_entry(parent, struct filesystem_entry, hardlink_rb); -+ -+ if ((f->sb.st_dev < e->sb.st_dev) || -+ (f->sb.st_dev == e->sb.st_dev && -+ f->sb.st_ino < e->sb.st_ino)) -+ n = &parent->rb_left; -+ else if ((f->sb.st_dev > e->sb.st_dev) || -+ (f->sb.st_dev == e->sb.st_dev && -+ f->sb.st_ino > e->sb.st_ino)) { -+ n = &parent->rb_right; -+ } else -+ return f->ino; -+ } -+ -+ rb_link_node(&e->hardlink_rb, parent, n); -+ rb_insert_color(&e->hardlink_rb, &hardlinks); -+ return 0; -+} -+ -+static void verror_msg(const char *s, va_list p) -+{ -+ fflush(stdout); -+ fprintf(stderr, "%s: ", app_name); -+ vfprintf(stderr, s, p); -+} -+static void error_msg(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+} -+ -+static void error_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+ exit(EXIT_FAILURE); -+} -+ -+static void vperror_msg(const char *s, va_list p) -+{ -+ int err = errno; -+ -+ if (s == 0) -+ s = ""; -+ verror_msg(s, p); -+ if (*s) -+ s = ": "; -+ fprintf(stderr, "%s%s\n", s, strerror(err)); -+} -+ -+static void perror_msg(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+} -+ -+static void perror_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+ exit(EXIT_FAILURE); -+} -+ -+#ifndef DMALLOC -+extern void *xmalloc(size_t size) -+{ -+ void *ptr = malloc(size); -+ -+ if (ptr == NULL && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern void *xcalloc(size_t nmemb, size_t size) -+{ -+ void *ptr = calloc(nmemb, size); -+ -+ if (ptr == NULL && nmemb != 0 && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern void *xrealloc(void *ptr, size_t size) -+{ -+ ptr = realloc(ptr, size); -+ if (ptr == NULL && size != 0) -+ error_msg_and_die(memory_exhausted); -+ return ptr; -+} -+ -+extern char *xstrdup(const char *s) -+{ -+ char *t; -+ -+ if (s == NULL) -+ return NULL; -+ t = strdup(s); -+ if (t == NULL) -+ error_msg_and_die(memory_exhausted); -+ return t; -+} -+#endif -+ -+extern char *xreadlink(const char *path) -+{ -+ static const int GROWBY = 80; /* how large we will grow strings by */ -+ -+ char *buf = NULL; -+ int bufsize = 0, readsize = 0; -+ -+ do { -+ buf = xrealloc(buf, bufsize += GROWBY); -+ readsize = readlink(path, buf, bufsize); /* 1st try */ -+ if (readsize == -1) { -+ perror_msg("%s:%s", app_name, path); -+ return NULL; -+ } -+ } -+ while (bufsize < readsize + 1); -+ -+ buf[readsize] = '\0'; -+ -+ return buf; -+} -+static FILE *xfopen(const char *path, const char *mode) -+{ -+ FILE *fp; -+ if ((fp = fopen(path, mode)) == NULL) -+ perror_msg_and_die("%s", path); -+ return fp; -+} -+ -+static struct filesystem_entry *find_filesystem_entry( -+ struct filesystem_entry *dir, char *fullname, uint32_t type) -+{ -+ struct filesystem_entry *e = dir; -+ -+ if (S_ISDIR(dir->sb.st_mode)) { -+ e = dir->files; -+ } -+ while (e) { -+ /* Only bother to do the expensive strcmp on matching file types */ -+ if (type == (e->sb.st_mode & S_IFMT)) { -+ if (S_ISDIR(e->sb.st_mode)) { -+ int len = strlen(e->fullname); -+ -+ /* Check if we are a parent of the correct path */ -+ if (strncmp(e->fullname, fullname, len) == 0) { -+ /* Is this an _exact_ match? */ -+ if (strcmp(fullname, e->fullname) == 0) { -+ return (e); -+ } -+ /* Looks like we found a parent of the correct path */ -+ if (fullname[len] == '/') { -+ if (e->files) { -+ return (find_filesystem_entry (e, fullname, type)); -+ } else { -+ return NULL; -+ } -+ } -+ } -+ } else { -+ if (strcmp(fullname, e->fullname) == 0) { -+ return (e); -+ } -+ } -+ } -+ e = e->next; -+ } -+ return (NULL); -+} -+ -+static struct filesystem_entry *add_host_filesystem_entry( -+ char *name, char *path, unsigned long uid, unsigned long gid, -+ unsigned long mode, dev_t rdev, struct filesystem_entry *parent) -+{ -+ int status; -+ char *tmp; -+ struct stat sb; -+ time_t timestamp = time(NULL); -+ struct filesystem_entry *entry; -+ -+ memset(&sb, 0, sizeof(struct stat)); -+ status = lstat(path, &sb); -+ -+ if (status >= 0) { -+ /* It is ok for some types of files to not exit on disk (such as -+ * device nodes), but if they _do_ exist the specified mode had -+ * better match the actual file or strange things will happen.... */ -+ if ((mode & S_IFMT) != (sb.st_mode & S_IFMT)) { -+ error_msg_and_die ("%s: file type does not match specified type!", path); -+ } -+ timestamp = sb.st_mtime; -+ } else { -+ /* If this is a regular file, it _must_ exist on disk */ -+ if ((mode & S_IFMT) == S_IFREG) { -+ error_msg_and_die("%s: does not exist!", path); -+ } -+ } -+ -+ /* Squash all permissions so files are owned by root, all -+ * timestamps are _right now_, and file permissions -+ * have group and other write removed */ -+ if (squash_uids) { -+ uid = gid = 0; -+ } -+ if (squash_perms) { -+ if (!S_ISLNK(mode)) { -+ mode &= ~(S_IWGRP | S_IWOTH); -+ mode &= ~(S_ISUID | S_ISGID); -+ } -+ } -+ if (fake_times) { -+ timestamp = 0; -+ } -+ -+ entry = xcalloc(1, sizeof(struct filesystem_entry)); -+ -+ entry->hostname = xstrdup(path); -+ entry->fullname = xstrdup(name); -+ tmp = xstrdup(name); -+ entry->name = xstrdup(basename(tmp)); -+ free(tmp); -+ tmp = xstrdup(name); -+ entry->path = xstrdup(dirname(tmp)); -+ free(tmp); -+ -+ entry->sb.st_ino = sb.st_ino; -+ entry->sb.st_dev = sb.st_dev; -+ entry->sb.st_nlink = sb.st_nlink; -+ -+ entry->sb.st_uid = uid; -+ entry->sb.st_gid = gid; -+ entry->sb.st_mode = mode; -+ entry->sb.st_rdev = rdev; -+ entry->sb.st_atime = entry->sb.st_ctime = -+ entry->sb.st_mtime = timestamp; -+ if (S_ISREG(mode)) { -+ entry->sb.st_size = sb.st_size; -+ } -+ if (S_ISLNK(mode)) { -+ entry->link = xreadlink(path); -+ entry->sb.st_size = strlen(entry->link); -+ } -+ -+ /* This happens only for root */ -+ if (!parent) -+ return (entry); -+ -+ /* Hook the file into the parent directory */ -+ entry->parent = parent; -+ if (!parent->files) { -+ parent->files = entry; -+ } else { -+ struct filesystem_entry *prev; -+ for (prev = parent->files; prev->next; prev = prev->next); -+ prev->next = entry; -+ entry->prev = prev; -+ } -+ -+ return (entry); -+} -+ -+static struct filesystem_entry *recursive_add_host_directory( -+ struct filesystem_entry *parent, char *targetpath, char *hostpath) -+{ -+ int i, n; -+ struct stat sb; -+ char *hpath, *tpath; -+ struct dirent *dp, **namelist; -+ struct filesystem_entry *entry; -+ -+ -+ if (lstat(hostpath, &sb)) { -+ perror_msg_and_die("%s", hostpath); -+ } -+ -+ entry = add_host_filesystem_entry(targetpath, hostpath, -+ sb.st_uid, sb.st_gid, sb.st_mode, 0, parent); -+ -+ n = scandir(hostpath, &namelist, 0, alphasort); -+ if (n < 0) { -+ perror_msg_and_die("opening directory %s", hostpath); -+ } -+ -+ for (i=0; id_name[0] == '.' && (dp->d_name[1] == 0 || -+ (dp->d_name[1] == '.' && dp->d_name[2] == 0))) -+ { -+ free(dp); -+ continue; -+ } -+ -+ asprintf(&hpath, "%s/%s", hostpath, dp->d_name); -+ if (lstat(hpath, &sb)) { -+ perror_msg_and_die("%s", hpath); -+ } -+ if (strcmp(targetpath, "/") == 0) { -+ asprintf(&tpath, "%s%s", targetpath, dp->d_name); -+ } else { -+ asprintf(&tpath, "%s/%s", targetpath, dp->d_name); -+ } -+ -+ switch (sb.st_mode & S_IFMT) { -+ case S_IFDIR: -+ recursive_add_host_directory(entry, tpath, hpath); -+ break; -+ -+ case S_IFREG: -+ case S_IFSOCK: -+ case S_IFIFO: -+ case S_IFLNK: -+ case S_IFCHR: -+ case S_IFBLK: -+ add_host_filesystem_entry(tpath, hpath, sb.st_uid, -+ sb.st_gid, sb.st_mode, sb.st_rdev, entry); -+ break; -+ -+ default: -+ error_msg("Unknown file type %o for %s", sb.st_mode, hpath); -+ break; -+ } -+ free(dp); -+ free(hpath); -+ free(tpath); -+ } -+ free(namelist); -+ return (entry); -+} -+ -+/* the GNU C library has a wonderful scanf("%as", string) which will -+ allocate the string with the right size, good to avoid buffer overruns. -+ the following macros use it if available or use a hacky workaround... -+ */ -+ -+#ifdef __GNUC__ -+#define SCANF_PREFIX "a" -+#define SCANF_STRING(s) (&s) -+#define GETCWD_SIZE 0 -+#else -+#define SCANF_PREFIX "511" -+#define SCANF_STRING(s) (s = malloc(512)) -+#define GETCWD_SIZE -1 -+inline int snprintf(char *str, size_t n, const char *fmt, ...) -+{ -+ int ret; -+ va_list ap; -+ -+ va_start(ap, fmt); -+ ret = vsprintf(str, fmt, ap); -+ va_end(ap); -+ return ret; -+} -+#endif -+ -+/* device table entries take the form of: -+ -+ /dev/mem c 640 0 0 1 1 0 0 - -+ -+ type can be one of: -+ f A regular file -+ d Directory -+ c Character special device file -+ b Block special device file -+ p Fifo (named pipe) -+ -+ I don't bother with symlinks (permissions are irrelevant), hard -+ links (special cases of regular files), or sockets (why bother). -+ -+ Regular files must exist in the target root directory. If a char, -+ block, fifo, or directory does not exist, it will be created. -+ */ -+static int interpret_table_entry(struct filesystem_entry *root, char *line) -+{ -+ char *hostpath; -+ char type, *name = NULL, *tmp, *dir; -+ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; -+ unsigned long start = 0, increment = 1, count = 0; -+ struct filesystem_entry *parent, *entry; -+ -+ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", -+ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, -+ &start, &increment, &count) < 0) -+ { -+ return 1; -+ } -+ -+ if (!strcmp(name, "/")) { -+ error_msg_and_die("Device table entries require absolute paths"); -+ } -+ -+ asprintf(&hostpath, "%s%s", rootdir, name); -+ -+ /* Check if this file already exists... */ -+ switch (type) { -+ case 'd': -+ mode |= S_IFDIR; -+ break; -+ case 'f': -+ mode |= S_IFREG; -+ break; -+ case 'p': -+ mode |= S_IFIFO; -+ break; -+ case 'c': -+ mode |= S_IFCHR; -+ break; -+ case 'b': -+ mode |= S_IFBLK; -+ break; -+ default: -+ error_msg_and_die("Unsupported file type"); -+ } -+ entry = find_filesystem_entry(root, name, mode); -+ if (entry) { -+ /* Ok, we just need to fixup the existing entry -+ * and we will be all done... */ -+ entry->sb.st_uid = uid; -+ entry->sb.st_gid = gid; -+ entry->sb.st_mode = mode; -+ if (major && minor) { -+ entry->sb.st_rdev = makedev(major, minor); -+ } -+ } else { -+ /* If parent is NULL (happens with device table entries), -+ * try and find our parent now) */ -+ tmp = strdup(name); -+ dir = dirname(tmp); -+ parent = find_filesystem_entry(root, dir, S_IFDIR); -+ free(tmp); -+ if (parent == NULL) { -+ error_msg ("skipping device_table entry '%s': no parent directory!", name); -+ free(name); -+ free(hostpath); -+ return 1; -+ } -+ -+ switch (type) { -+ case 'd': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'f': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'p': -+ add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0, parent); -+ break; -+ case 'c': -+ case 'b': -+ if (count > 0) { -+ dev_t rdev; -+ unsigned long i; -+ char *dname, *hpath; -+ -+ for (i = start; i < count; i++) { -+ asprintf(&dname, "%s%lu", name, i); -+ asprintf(&hpath, "%s/%s%lu", rootdir, name, i); -+ rdev = makedev(major, minor + (i * increment - start)); -+ add_host_filesystem_entry(dname, hpath, uid, gid, -+ mode, rdev, parent); -+ free(dname); -+ free(hpath); -+ } -+ } else { -+ dev_t rdev = makedev(major, minor); -+ add_host_filesystem_entry(name, hostpath, uid, gid, -+ mode, rdev, parent); -+ } -+ break; -+ default: -+ error_msg_and_die("Unsupported file type"); -+ } -+ } -+ free(name); -+ free(hostpath); -+ return 0; -+} -+ -+static int parse_device_table(struct filesystem_entry *root, FILE * file) -+{ -+ char *line; -+ int status = 0; -+ size_t length = 0; -+ -+ /* Turn off squash, since we must ensure that values -+ * entered via the device table are not squashed */ -+ squash_uids = 0; -+ squash_perms = 0; -+ -+ /* Looks ok so far. The general plan now is to read in one -+ * line at a time, check for leading comment delimiters ('#'), -+ * then try and parse the line as a device table. If we fail -+ * to parse things, try and help the poor fool to fix their -+ * device table with a useful error msg... */ -+ line = NULL; -+ while (getline(&line, &length, file) != -1) { -+ /* First trim off any whitespace */ -+ int len = strlen(line); -+ -+ /* trim trailing whitespace */ -+ while (len > 0 && isspace(line[len - 1])) -+ line[--len] = '\0'; -+ /* trim leading whitespace */ -+ memmove(line, &line[strspn(line, " \n\r\t\v")], len); -+ -+ /* How long are we after trimming? */ -+ len = strlen(line); -+ -+ /* If this is NOT a comment line, try to interpret it */ -+ if (len && *line != '#') { -+ if (interpret_table_entry(root, line)) -+ status = 1; -+ } -+ -+ free(line); -+ line = NULL; -+ } -+ fclose(file); -+ -+ return status; -+} -+ -+static void cleanup(struct filesystem_entry *dir) -+{ -+ struct filesystem_entry *e, *prev; -+ -+ e = dir->files; -+ while (e) { -+ if (e->name) -+ free(e->name); -+ if (e->path) -+ free(e->path); -+ if (e->fullname) -+ free(e->fullname); -+ e->next = NULL; -+ e->name = NULL; -+ e->path = NULL; -+ e->fullname = NULL; -+ e->prev = NULL; -+ prev = e; -+ if (S_ISDIR(e->sb.st_mode)) { -+ cleanup(e); -+ } -+ e = e->next; -+ free(prev); -+ } -+} -+ -+/* Here is where we do the actual creation of the file system */ -+#include "mtd/jffs2-user.h" -+ -+#define JFFS2_MAX_FILE_SIZE 0xFFFFFFFF -+#ifndef JFFS2_MAX_SYMLINK_LEN -+#define JFFS2_MAX_SYMLINK_LEN 254 -+#endif -+ -+static uint32_t ino = 0; -+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/ -+static int out_ofs = 0; -+static int erase_block_size = 65536; -+static int pad_fs_size = 0; -+static int add_cleanmarkers = 1; -+static struct jffs2_unknown_node cleanmarker; -+static int cleanmarker_size = sizeof(cleanmarker); -+static unsigned char ffbuf[16] = -+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+ -+/* We set this at start of main() using sysconf(), -1 means we don't know */ -+/* When building an fs for non-native systems, use --pagesize=SIZE option */ -+int page_size = -1; -+ -+#include "compr.h" -+ -+static void full_write(int fd, const void *buf, int len) -+{ -+ int ret; -+ -+ while (len > 0) { -+ ret = write(fd, buf, len); -+ -+ if (ret < 0) -+ perror_msg_and_die("write"); -+ -+ if (ret == 0) -+ perror_msg_and_die("write returned zero"); -+ -+ len -= ret; -+ buf += ret; -+ out_ofs += ret; -+ } -+} -+ -+static void padblock(void) -+{ -+ while (out_ofs % erase_block_size) { -+ full_write(out_fd, ffbuf, min(sizeof(ffbuf), -+ erase_block_size - (out_ofs % erase_block_size))); -+ } -+} -+ -+static void pad(int req) -+{ -+ while (req) { -+ if (req > sizeof(ffbuf)) { -+ full_write(out_fd, ffbuf, sizeof(ffbuf)); -+ req -= sizeof(ffbuf); -+ } else { -+ full_write(out_fd, ffbuf, req); -+ req = 0; -+ } -+ } -+} -+ -+static inline void padword(void) -+{ -+ if (out_ofs % 4) { -+ full_write(out_fd, ffbuf, 4 - (out_ofs % 4)); -+ } -+} -+ -+static inline void pad_block_if_less_than(int req) -+{ -+ if (add_cleanmarkers) { -+ if ((out_ofs % erase_block_size) == 0) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+ if ((out_ofs % erase_block_size) + req > erase_block_size) { -+ padblock(); -+ } -+ if (add_cleanmarkers) { -+ if ((out_ofs % erase_block_size) == 0) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+} -+ -+static void write_dirent(struct filesystem_entry *e) -+{ -+ char *name = e->name; -+ struct jffs2_raw_dirent rd; -+ struct stat *statbuf = &(e->sb); -+ static uint32_t version = 0; -+ -+ memset(&rd, 0, sizeof(rd)); -+ -+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd.totlen = cpu_to_je32(sizeof(rd) + strlen(name)); -+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd, -+ sizeof(struct jffs2_unknown_node) - 4)); -+ rd.pino = cpu_to_je32((e->parent) ? e->parent->ino : 1); -+ rd.version = cpu_to_je32(version++); -+ rd.ino = cpu_to_je32(e->ino); -+ rd.mctime = cpu_to_je32(statbuf->st_mtime); -+ rd.nsize = strlen(name); -+ rd.type = IFTODT(statbuf->st_mode); -+ //rd.unused[0] = 0; -+ //rd.unused[1] = 0; -+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd) - 8)); -+ rd.name_crc = cpu_to_je32(crc32(0, name, strlen(name))); -+ -+ pad_block_if_less_than(sizeof(rd) + rd.nsize); -+ full_write(out_fd, &rd, sizeof(rd)); -+ full_write(out_fd, name, rd.nsize); -+ padword(); -+} -+ -+static unsigned int write_regular_file(struct filesystem_entry *e) -+{ -+ int fd, len; -+ uint32_t ver; -+ unsigned int offset; -+ unsigned char *buf, *cbuf, *wbuf; -+ struct jffs2_raw_inode ri; -+ struct stat *statbuf; -+ unsigned int totcomp = 0; -+ -+ statbuf = &(e->sb); -+ if (statbuf->st_size >= JFFS2_MAX_FILE_SIZE) { -+ error_msg("Skipping file \"%s\" too large.", e->path); -+ return -1; -+ } -+ fd = open(e->hostname, O_RDONLY); -+ if (fd == -1) { -+ perror_msg_and_die("%s: open file", e->hostname); -+ } -+ -+ e->ino = ++ino; -+ mkfs_debug_msg("writing file '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) e->parent->ino); -+ write_dirent(e); -+ -+ buf = xmalloc(page_size); -+ cbuf = NULL; -+ -+ ver = 0; -+ offset = 0; -+ -+ memset(&ri, 0, sizeof(ri)); -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ -+ while ((len = read(fd, buf, page_size))) { -+ unsigned char *tbuf = buf; -+ -+ if (len < 0) { -+ perror_msg_and_die("read"); -+ } -+ -+ while (len) { -+ uint32_t dsize, space; -+ uint16_t compression; -+ -+ pad_block_if_less_than(sizeof(ri) + JFFS2_MIN_DATA_LEN); -+ -+ dsize = len; -+ space = -+ erase_block_size - (out_ofs % erase_block_size) - -+ sizeof(ri); -+ if (space > dsize) -+ space = dsize; -+ -+ compression = jffs2_compress(tbuf, &cbuf, &dsize, &space); -+ -+ ri.compr = compression & 0xff; -+ ri.usercompr = (compression >> 8) & 0xff; -+ -+ if (ri.compr) { -+ wbuf = cbuf; -+ } else { -+ wbuf = tbuf; -+ dsize = space; -+ } -+ -+ ri.totlen = cpu_to_je32(sizeof(ri) + space); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.version = cpu_to_je32(++ver); -+ ri.offset = cpu_to_je32(offset); -+ ri.csize = cpu_to_je32(space); -+ ri.dsize = cpu_to_je32(dsize); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, wbuf, space)); -+ -+ full_write(out_fd, &ri, sizeof(ri)); -+ totcomp += sizeof(ri); -+ full_write(out_fd, wbuf, space); -+ totcomp += space; -+ padword(); -+ -+ if (tbuf != cbuf) { -+ free(cbuf); -+ cbuf = NULL; -+ } -+ -+ tbuf += dsize; -+ len -= dsize; -+ offset += dsize; -+ -+ } -+ } -+ if (!je32_to_cpu(ri.version)) { -+ /* Was empty file */ -+ pad_block_if_less_than(sizeof(ri)); -+ -+ ri.version = cpu_to_je32(++ver); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ ri.csize = cpu_to_je32(0); -+ ri.dsize = cpu_to_je32(0); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ -+ full_write(out_fd, &ri, sizeof(ri)); -+ padword(); -+ } -+ free(buf); -+ close(fd); -+ return totcomp; -+} -+ -+static void write_symlink(struct filesystem_entry *e) -+{ -+ int len; -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ mkfs_debug_msg("writing symlink '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) e->parent->ino); -+ write_dirent(e); -+ -+ len = strlen(e->link); -+ if (len > JFFS2_MAX_SYMLINK_LEN) { -+ error_msg("symlink too large. Truncated to %d chars.", -+ JFFS2_MAX_SYMLINK_LEN); -+ len = JFFS2_MAX_SYMLINK_LEN; -+ } -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + len); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(len); -+ ri.dsize = cpu_to_je32(len); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, e->link, len)); -+ -+ pad_block_if_less_than(sizeof(ri) + len); -+ full_write(out_fd, &ri, sizeof(ri)); -+ full_write(out_fd, e->link, len); -+ padword(); -+} -+ -+static void write_pipe(struct filesystem_entry *e) -+{ -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ if (S_ISDIR(statbuf->st_mode)) { -+ mkfs_debug_msg("writing dir '%s' ino=%lu parent_ino=%lu", -+ e->name, (unsigned long) e->ino, -+ (unsigned long) (e->parent) ? e->parent->ino : 1); -+ } -+ write_dirent(e); -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(0); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(0); -+ ri.dsize = cpu_to_je32(0); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(0); -+ -+ pad_block_if_less_than(sizeof(ri)); -+ full_write(out_fd, &ri, sizeof(ri)); -+ padword(); -+} -+ -+static void write_special_file(struct filesystem_entry *e) -+{ -+ jint16_t kdev; -+ struct stat *statbuf; -+ struct jffs2_raw_inode ri; -+ -+ statbuf = &(e->sb); -+ e->ino = ++ino; -+ write_dirent(e); -+ -+ kdev = cpu_to_je16((major(statbuf->st_rdev) << 8) + -+ minor(statbuf->st_rdev)); -+ -+ memset(&ri, 0, sizeof(ri)); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + sizeof(kdev)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, -+ &ri, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ ri.ino = cpu_to_je32(e->ino); -+ ri.mode = cpu_to_jemode(statbuf->st_mode); -+ ri.uid = cpu_to_je16(statbuf->st_uid); -+ ri.gid = cpu_to_je16(statbuf->st_gid); -+ ri.atime = cpu_to_je32(statbuf->st_atime); -+ ri.ctime = cpu_to_je32(statbuf->st_ctime); -+ ri.mtime = cpu_to_je32(statbuf->st_mtime); -+ ri.isize = cpu_to_je32(statbuf->st_size); -+ ri.version = cpu_to_je32(1); -+ ri.csize = cpu_to_je32(sizeof(kdev)); -+ ri.dsize = cpu_to_je32(sizeof(kdev)); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri) - 8)); -+ ri.data_crc = cpu_to_je32(crc32(0, &kdev, sizeof(kdev))); -+ -+ pad_block_if_less_than(sizeof(ri) + sizeof(kdev)); -+ full_write(out_fd, &ri, sizeof(ri)); -+ full_write(out_fd, &kdev, sizeof(kdev)); -+ padword(); -+} -+ -+#ifndef WITHOUT_XATTR -+typedef struct xattr_entry { -+ struct xattr_entry *next; -+ uint32_t xid; -+ int xprefix; -+ char *xname; -+ char *xvalue; -+ int name_len; -+ int value_len; -+} xattr_entry_t; -+ -+#define XATTR_BUFFER_SIZE (64 * 1024) /* 64KB */ -+static uint32_t enable_xattr = 0; -+static uint32_t highest_xid = 0; -+static uint32_t highest_xseqno = 0; -+ -+static struct { -+ int xprefix; -+ char *string; -+ int length; -+} xprefix_tbl[] = { -+ { JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN }, -+ { JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN }, -+ { JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN }, -+ { JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN }, -+ { JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }, -+ { 0, NULL, 0 } -+}; -+ -+static void formalize_posix_acl(void *xvalue, int *value_len) -+{ -+ struct posix_acl_xattr_header *pacl_header; -+ struct posix_acl_xattr_entry *pent, *plim; -+ struct jffs2_acl_header *jacl_header; -+ struct jffs2_acl_entry *jent; -+ struct jffs2_acl_entry_short *jent_s; -+ char buffer[XATTR_BUFFER_SIZE]; -+ int offset = 0; -+ -+ pacl_header = xvalue;; -+ pent = pacl_header->a_entries; -+ plim = xvalue + *value_len; -+ -+ jacl_header = (struct jffs2_acl_header *)buffer; -+ offset += sizeof(struct jffs2_acl_header); -+ jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION); -+ -+ while (pent < plim) { -+ switch(le16_to_cpu(pent->e_tag)) { -+ case ACL_USER_OBJ: -+ case ACL_GROUP_OBJ: -+ case ACL_MASK: -+ case ACL_OTHER: -+ jent_s = (struct jffs2_acl_entry_short *)(buffer + offset); -+ offset += sizeof(struct jffs2_acl_entry_short); -+ jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag)); -+ jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm)); -+ break; -+ case ACL_USER: -+ case ACL_GROUP: -+ jent = (struct jffs2_acl_entry *)(buffer + offset); -+ offset += sizeof(struct jffs2_acl_entry); -+ jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag)); -+ jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm)); -+ jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id)); -+ break; -+ default: -+ printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag)); -+ exit(1); -+ } -+ pent++; -+ } -+ if (offset > *value_len) { -+ printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n", -+ offset, *value_len); -+ exit(1); -+ } -+ memcpy(xvalue, buffer, offset); -+ *value_len = offset; -+} -+ -+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len) -+{ -+ xattr_entry_t *xe; -+ struct jffs2_raw_xattr rx; -+ int name_len; -+ -+ /* create xattr entry */ -+ name_len = strlen(xname); -+ xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len); -+ xe->next = NULL; -+ xe->xid = ++highest_xid; -+ xe->xprefix = xprefix; -+ xe->xname = ((char *)xe) + sizeof(xattr_entry_t); -+ xe->xvalue = xe->xname + name_len + 1; -+ xe->name_len = name_len; -+ xe->value_len = value_len; -+ strcpy(xe->xname, xname); -+ memcpy(xe->xvalue, xvalue, value_len); -+ -+ /* write xattr node */ -+ memset(&rx, 0, sizeof(rx)); -+ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); -+ rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len)); -+ rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); -+ -+ rx.xid = cpu_to_je32(xe->xid); -+ rx.version = cpu_to_je32(1); /* initial version */ -+ rx.xprefix = xprefix; -+ rx.name_len = xe->name_len; -+ rx.value_len = cpu_to_je16(xe->value_len); -+ rx.data_crc = cpu_to_je32(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len)); -+ rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 4)); -+ -+ pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len); -+ full_write(out_fd, &rx, sizeof(rx)); -+ full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len); -+ padword(); -+ -+ return xe; -+} -+ -+#define XATTRENTRY_HASHSIZE 57 -+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len) -+{ -+ static xattr_entry_t **xentry_hash = NULL; -+ xattr_entry_t *xe; -+ int index, name_len; -+ -+ /* create hash table */ -+ if (!xentry_hash) -+ xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE); -+ -+ if (xprefix == JFFS2_XPREFIX_ACL_ACCESS -+ || xprefix == JFFS2_XPREFIX_ACL_DEFAULT) -+ formalize_posix_acl(xvalue, &value_len); -+ -+ name_len = strlen(xname); -+ index = (crc32(0, xname, name_len) ^ crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE; -+ for (xe = xentry_hash[index]; xe; xe = xe->next) { -+ if (xe->xprefix == xprefix -+ && xe->value_len == value_len -+ && !strcmp(xe->xname, xname) -+ && !memcmp(xe->xvalue, xvalue, value_len)) -+ break; -+ } -+ if (!xe) { -+ xe = create_xattr_entry(xprefix, xname, xvalue, value_len); -+ xe->next = xentry_hash[index]; -+ xentry_hash[index] = xe; -+ } -+ return xe; -+} -+ -+static void write_xattr_entry(struct filesystem_entry *e) -+{ -+ struct jffs2_raw_xref ref; -+ struct xattr_entry *xe; -+ char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE]; -+ char *xname, *prefix_str; -+ int i, xprefix, prefix_len; -+ int list_sz, offset, name_len, value_len; -+ -+ if (!enable_xattr) -+ return; -+ -+ list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE); -+ if (list_sz < 0) { -+ if (verbose) -+ printf("llistxattr('%s') = %d : %s\n", -+ e->hostname, errno, strerror(errno)); -+ return; -+ } -+ -+ for (offset = 0; offset < list_sz; offset += name_len) { -+ xname = xlist + offset; -+ name_len = strlen(xname) + 1; -+ -+ for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) { -+ prefix_str = xprefix_tbl[i].string; -+ prefix_len = xprefix_tbl[i].length; -+ if (prefix_str[prefix_len - 1] == '.') { -+ if (!strncmp(xname, prefix_str, prefix_len - 1)) -+ break; -+ } else { -+ if (!strcmp(xname, prefix_str)) -+ break; -+ } -+ } -+ if (!xprefix) { -+ if (verbose) -+ printf("%s: xattr '%s' is not supported.\n", -+ e->hostname, xname); -+ continue; -+ } -+ if ((enable_xattr & (1 << xprefix)) == 0) -+ continue; -+ -+ value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE); -+ if (value_len < 0) { -+ if (verbose) -+ printf("lgetxattr('%s', '%s') = %d : %s\n", -+ e->hostname, xname, errno, strerror(errno)); -+ continue; -+ } -+ xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len); -+ if (!xe) { -+ if (verbose) -+ printf("%s : xattr '%s' was ignored.\n", -+ e->hostname, xname); -+ continue; -+ } -+ -+ memset(&ref, 0, sizeof(ref)); -+ ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); -+ ref.totlen = cpu_to_je32(sizeof(ref)); -+ ref.hdr_crc = cpu_to_je32(crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4)); -+ ref.ino = cpu_to_je32(e->ino); -+ ref.xid = cpu_to_je32(xe->xid); -+ ref.xseqno = cpu_to_je32(highest_xseqno += 2); -+ ref.node_crc = cpu_to_je32(crc32(0, &ref, sizeof(ref) - 4)); -+ -+ pad_block_if_less_than(sizeof(ref)); -+ full_write(out_fd, &ref, sizeof(ref)); -+ padword(); -+ } -+} -+ -+#else /* WITHOUT_XATTR */ -+#define write_xattr_entry(x) -+#endif -+ -+static void recursive_populate_directory(struct filesystem_entry *dir) -+{ -+ struct filesystem_entry *e; -+ unsigned int wrote; -+ -+ if (verbose) { -+ printf("%s\n", dir->fullname); -+ } -+ write_xattr_entry(dir); /* for '/' */ -+ -+ e = dir->files; -+ while (e) { -+ if (e->sb.st_nlink >= 1 && -+ (e->ino = find_hardlink(e))) { -+ -+ write_dirent(e); -+ if (verbose) { -+ printf("\tL %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, (unsigned long) e->ino, -+ (int) (e->sb.st_uid), (int) (e->sb.st_gid), -+ e->name); -+ } -+ } else switch (e->sb.st_mode & S_IFMT) { -+ case S_IFDIR: -+ if (verbose) { -+ printf("\td %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) (e->sb.st_uid), (int) (e->sb.st_gid), -+ e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFSOCK: -+ if (verbose) { -+ printf("\ts %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFIFO: -+ if (verbose) { -+ printf("\tp %04o %9lu %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ write_pipe(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFCHR: -+ if (verbose) { -+ printf("\tc %04o %4d,%4d %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev), -+ minor(e->sb.st_rdev), (int) e->sb.st_uid, -+ (int) e->sb.st_gid, e->name); -+ } -+ write_special_file(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFBLK: -+ if (verbose) { -+ printf("\tb %04o %4d,%4d %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, major(e->sb.st_rdev), -+ minor(e->sb.st_rdev), (int) e->sb.st_uid, -+ (int) e->sb.st_gid, e->name); -+ } -+ write_special_file(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFLNK: -+ if (verbose) { -+ printf("\tl %04o %9lu %5d:%-3d %s -> %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name, -+ e->link); -+ } -+ write_symlink(e); -+ write_xattr_entry(e); -+ break; -+ case S_IFREG: -+ wrote = write_regular_file(e); -+ write_xattr_entry(e); -+ if (verbose) { -+ printf("\tf %04o %9lu (%9u) %5d:%-3d %s\n", -+ e->sb.st_mode & ~S_IFMT, e->sb.st_size, wrote, -+ (int) e->sb.st_uid, (int) e->sb.st_gid, e->name); -+ } -+ break; -+ default: -+ error_msg("Unknown mode %o for %s", e->sb.st_mode, -+ e->fullname); -+ break; -+ } -+ e = e->next; -+ } -+ -+ e = dir->files; -+ while (e) { -+ if (S_ISDIR(e->sb.st_mode)) { -+ if (e->files) { -+ recursive_populate_directory(e); -+ } else if (verbose) { -+ printf("%s\n", e->fullname); -+ } -+ } -+ e = e->next; -+ } -+} -+ -+static void create_target_filesystem(struct filesystem_entry *root) -+{ -+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); -+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size); -+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); -+ -+ if (ino == 0) -+ ino = 1; -+ -+ root->ino = 1; -+ recursive_populate_directory(root); -+ -+ if (pad_fs_size == -1) { -+ padblock(); -+ } else { -+ if (pad_fs_size && add_cleanmarkers){ -+ padblock(); -+ while (out_ofs < pad_fs_size) { -+ full_write(out_fd, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padblock(); -+ } -+ } else { -+ while (out_ofs < pad_fs_size) { -+ full_write(out_fd, ffbuf, min(sizeof(ffbuf), pad_fs_size - out_ofs)); -+ } -+ -+ } -+ } -+} -+ -+static struct option long_options[] = { -+ {"pad", 2, NULL, 'p'}, -+ {"root", 1, NULL, 'r'}, -+ {"pagesize", 1, NULL, 's'}, -+ {"eraseblock", 1, NULL, 'e'}, -+ {"output", 1, NULL, 'o'}, -+ {"help", 0, NULL, 'h'}, -+ {"verbose", 0, NULL, 'v'}, -+ {"version", 0, NULL, 'V'}, -+ {"big-endian", 0, NULL, 'b'}, -+ {"little-endian", 0, NULL, 'l'}, -+ {"no-cleanmarkers", 0, NULL, 'n'}, -+ {"cleanmarker", 1, NULL, 'c'}, -+ {"squash", 0, NULL, 'q'}, -+ {"squash-uids", 0, NULL, 'U'}, -+ {"squash-perms", 0, NULL, 'P'}, -+ {"faketime", 0, NULL, 'f'}, -+ {"devtable", 1, NULL, 'D'}, -+ {"compression-mode", 1, NULL, 'm'}, -+ {"disable-compressor", 1, NULL, 'x'}, -+ {"test-compression", 0, NULL, 't'}, -+ {"compressor-priority", 1, NULL, 'y'}, -+ {"incremental", 1, NULL, 'i'}, -+#ifndef WITHOUT_XATTR -+ {"with-xattr", 0, NULL, 1000 }, -+ {"with-selinux", 0, NULL, 1001 }, -+ {"with-posix-acl", 0, NULL, 1002 }, -+#endif -+ {NULL, 0, NULL, 0} -+}; -+ -+static char *helptext = -+"Usage: mkfs.jffs2 [OPTIONS]\n" -+"Make a JFFS2 file system image from an existing directory tree\n\n" -+"Options:\n" -+" -p, --pad[=SIZE] Pad output to SIZE bytes with 0xFF. If SIZE is\n" -+" not specified, the output is padded to the end of\n" -+" the final erase block\n" -+" -r, -d, --root=DIR Build file system from directory DIR (default: cwd)\n" -+" -s, --pagesize=SIZE Use page size (max data node size) SIZE (default: 4KiB)\n" -+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n" -+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12)\n" -+" -m, --compr-mode=MODE Select compression mode (default: priortiry)\n" -+" -x, --disable-compressor=COMPRESSOR_NAME\n" -+" Disable a compressor\n" -+" -X, --enable-compressor=COMPRESSOR_NAME\n" -+" Enable a compressor\n" -+" -y, --compressor-priority=PRIORITY:COMPRESSOR_NAME\n" -+" Set the priority of a compressor\n" -+" -L, --list-compressors Show the list of the avaiable compressors\n" -+" -t, --test-compression Call decompress and compare with the original (for test)\n" -+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n" -+" -o, --output=FILE Output to FILE (default: stdout)\n" -+" -l, --little-endian Create a little-endian filesystem\n" -+" -b, --big-endian Create a big-endian filesystem\n" -+" -D, --devtable=FILE Use the named FILE as a device table file\n" -+" -f, --faketime Change all file times to '0' for regression testing\n" -+" -q, --squash Squash permissions and owners making all files be owned by root\n" -+" -U, --squash-uids Squash owners making all files be owned by root\n" -+" -P, --squash-perms Squash permissions on all files\n" -+#ifndef WITHOUT_XATTR -+" --with-xattr stuff all xattr entries into image\n" -+" --with-selinux stuff only SELinux Labels into jffs2 image\n" -+" --with-posix-acl stuff only POSIX ACL entries into jffs2 image\n" -+#endif -+" -h, --help Display this help text\n" -+" -v, --verbose Verbose operation\n" -+" -V, --version Display version information\n" -+" -i, --incremental=FILE Parse FILE and generate appendage output for it\n\n"; -+ -+static char *revtext = "1.60"; -+ -+int load_next_block() { -+ -+ int ret; -+ ret = read(in_fd, file_buffer, erase_block_size); -+ -+ if(verbose) -+ printf("Load next block : %d bytes read\n",ret); -+ -+ return ret; -+} -+ -+void process_buffer(int inp_size) { -+ uint8_t *p = file_buffer; -+ union jffs2_node_union *node; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ -+ char name[256]; -+ -+ while ( p < (file_buffer + inp_size)) { -+ -+ node = (union jffs2_node_union *) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic)); -+ p += 4; -+ continue; -+ } -+ -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else -+ obsolete = 0; -+ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE: -+ if(verbose) -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ if ( je32_to_cpu (node->i.ino) > ino ) -+ ino = je32_to_cpu (node->i.ino); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ -+ if(verbose) -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ } -+ } -+} -+ -+void parse_image(){ -+ int ret; -+ -+ file_buffer = malloc(erase_block_size); -+ -+ if (!file_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+ -+ while ((ret = load_next_block())) { -+ process_buffer(ret); -+ } -+ -+ if (file_buffer) -+ free(file_buffer); -+ -+ close(in_fd); -+} -+ -+int main(int argc, char **argv) -+{ -+ int c, opt; -+ char *cwd; -+ struct stat sb; -+ FILE *devtable = NULL; -+ struct filesystem_entry *root; -+ char *compr_name = NULL; -+ int compr_prior = -1; -+ int warn_page_size = 0; -+ -+ page_size = sysconf(_SC_PAGESIZE); -+ if (page_size < 0) /* System doesn't know so ... */ -+ page_size = 4096; /* ... we make an educated guess */ -+ if (page_size != 4096) -+ warn_page_size = 1; /* warn user if page size not 4096 */ -+ -+ jffs2_compressors_init(); -+ -+ while ((opt = getopt_long(argc, argv, -+ "D:d:r:s:o:qUPfh?vVe:lbp::nc:m:x:X:Lty:i:", long_options, &c)) >= 0) -+ { -+ switch (opt) { -+ case 'D': -+ devtable = xfopen(optarg, "r"); -+ if (fstat(fileno(devtable), &sb) < 0) -+ perror_msg_and_die(optarg); -+ if (sb.st_size < 10) -+ error_msg_and_die("%s: not a proper device table file", optarg); -+ break; -+ -+ case 'r': -+ case 'd': /* for compatibility with mkfs.jffs, genext2fs, etc... */ -+ if (rootdir != default_rootdir) { -+ error_msg_and_die("root directory specified more than once"); -+ } -+ rootdir = xstrdup(optarg); -+ break; -+ -+ case 's': -+ page_size = strtol(optarg, NULL, 0); -+ warn_page_size = 0; /* set by user, so don't need to warn */ -+ break; -+ -+ case 'o': -+ if (out_fd != -1) { -+ error_msg_and_die("output filename specified more than once"); -+ } -+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644); -+ if (out_fd == -1) { -+ perror_msg_and_die("open output file"); -+ } -+ break; -+ -+ case 'q': -+ squash_uids = 1; -+ squash_perms = 1; -+ break; -+ -+ case 'U': -+ squash_uids = 1; -+ break; -+ -+ case 'P': -+ squash_perms = 1; -+ break; -+ -+ case 'f': -+ fake_times = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ error_msg_and_die(helptext); -+ -+ case 'v': -+ verbose = 1; -+ break; -+ -+ case 'V': -+ error_msg_and_die("revision %s\n", revtext); -+ -+ case 'e': { -+ char *next; -+ unsigned units = 0; -+ erase_block_size = strtol(optarg, &next, 0); -+ if (!erase_block_size) -+ error_msg_and_die("Unrecognisable erase size\n"); -+ -+ if (*next) { -+ if (!strcmp(next, "KiB")) { -+ units = 1024; -+ } else if (!strcmp(next, "MiB")) { -+ units = 1024 * 1024; -+ } else { -+ error_msg_and_die("Unknown units in erasesize\n"); -+ } -+ } else { -+ if (erase_block_size < 0x1000) -+ units = 1024; -+ else -+ units = 1; -+ } -+ erase_block_size *= units; -+ -+ /* If it's less than 8KiB, they're not allowed */ -+ if (erase_block_size < 0x2000) { -+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n", -+ erase_block_size); -+ erase_block_size = 0x2000; -+ } -+ break; -+ } -+ -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ -+ case 'p': -+ if (optarg) -+ pad_fs_size = strtol(optarg, NULL, 0); -+ else -+ pad_fs_size = -1; -+ break; -+ case 'n': -+ add_cleanmarkers = 0; -+ break; -+ case 'c': -+ cleanmarker_size = strtol(optarg, NULL, 0); -+ if (cleanmarker_size < sizeof(cleanmarker)) { -+ error_msg_and_die("cleanmarker size must be >= 12"); -+ } -+ if (cleanmarker_size >= erase_block_size) { -+ error_msg_and_die("cleanmarker size must be < eraseblock size"); -+ } -+ break; -+ case 'm': -+ if (jffs2_set_compression_mode_name(optarg)) { -+ error_msg_and_die("Unknown compression mode %s", optarg); -+ } -+ break; -+ case 'x': -+ if (jffs2_disable_compressor_name(optarg)) { -+ error_msg_and_die("Unknown compressor name %s",optarg); -+ } -+ break; -+ case 'X': -+ if (jffs2_enable_compressor_name(optarg)) { -+ error_msg_and_die("Unknown compressor name %s",optarg); -+ } -+ break; -+ case 'L': -+ error_msg_and_die("\n%s",jffs2_list_compressors()); -+ break; -+ case 't': -+ jffs2_compression_check_set(1); -+ break; -+ case 'y': -+ compr_name = malloc(strlen(optarg)); -+ sscanf(optarg,"%d:%s",&compr_prior,compr_name); -+ if ((compr_prior>=0)&&(compr_name)) { -+ if (jffs2_set_compressor_priority(compr_name, compr_prior)) -+ exit(EXIT_FAILURE); -+ } -+ else { -+ error_msg_and_die("Cannot parse %s",optarg); -+ } -+ free(compr_name); -+ break; -+ case 'i': -+ if (in_fd != -1) { -+ error_msg_and_die("(incremental) filename specified more than once"); -+ } -+ in_fd = open(optarg, O_RDONLY); -+ if (in_fd == -1) { -+ perror_msg_and_die("cannot open (incremental) file"); -+ } -+ break; -+#ifndef WITHOUT_XATTR -+ case 1000: /* --with-xattr */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_USER) -+ | (1 << JFFS2_XPREFIX_SECURITY) -+ | (1 << JFFS2_XPREFIX_ACL_ACCESS) -+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT) -+ | (1 << JFFS2_XPREFIX_TRUSTED); -+ break; -+ case 1001: /* --with-selinux */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY); -+ break; -+ case 1002: /* --with-posix-acl */ -+ enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS) -+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT); -+ break; -+#endif -+ } -+ } -+ if (warn_page_size) { -+ error_msg("Page size for this system is by default %d", page_size); -+ error_msg("Use the --pagesize=SIZE option if this is not what you want"); -+ } -+ if (out_fd == -1) { -+ if (isatty(1)) { -+ error_msg_and_die(helptext); -+ } -+ out_fd = 1; -+ } -+ if (lstat(rootdir, &sb)) { -+ perror_msg_and_die("%s", rootdir); -+ } -+ if (chdir(rootdir)) -+ perror_msg_and_die("%s", rootdir); -+ -+ if (!(cwd = getcwd(0, GETCWD_SIZE))) -+ perror_msg_and_die("getcwd failed"); -+ -+ if(in_fd != -1) -+ parse_image(); -+ -+ root = recursive_add_host_directory(NULL, "/", cwd); -+ -+ if (devtable) -+ parse_device_table(root, devtable); -+ -+ create_target_filesystem(root); -+ -+ cleanup(root); -+ -+ if (rootdir != default_rootdir) -+ free(rootdir); -+ -+ close(out_fd); -+ -+ if (verbose) { -+ char *s = jffs2_stats(); -+ fprintf(stderr,"\n\n%s",s); -+ free(s); -+ } -+ if ((verbose)||(jffs2_compression_check_get()&&(jffs2_compression_check_errorcnt_get()))) { -+ fprintf(stderr,"Compression errors: %d\n",jffs2_compression_check_errorcnt_get()); -+ } -+ -+ jffs2_compressors_exit(); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd-utils.spec linux-2.6.24.7/drivers/mtd/mtd-utils/mtd-utils.spec ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd-utils.spec 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mtd-utils.spec 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+Summary: Tools for maintaining Memory Technology Devices -+Name: mtd-utils -+Version: 1.0 -+Release: 1 -+License: GPL -+Group: Applications/System -+URL: http://www.linux-mtd.infradead.org/ -+Source0: %{name}-%{version}.tar.gz -+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -+ -+%description -+This package contains tools for erasing and formatting flash devices, -+including JFFS2, M-Systems DiskOnChip devices, etc. -+ -+%prep -+%setup -q -+ -+%build -+make -C util -+ -+%install -+rm -rf $RPM_BUILD_ROOT -+make DESTDIR=$RPM_BUILD_ROOT -C util install -+ -+%clean -+rm -rf $RPM_BUILD_ROOT -+ -+ -+%files -+%defattr(-,root,root,-) -+/usr/sbin -+/usr/man/man1/mkfs.jffs2.1.gz -+/usr/include/mtd -+%doc -+ -+ -+%changelog -+* Wed May 5 2004 - 1.0 -+- Initial build. -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd_debug.c linux-2.6.24.7/drivers/mtd/mtd-utils/mtd_debug.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/mtd_debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/mtd_debug.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,418 @@ -+/* -+ * Copyright (c) 2d3D, Inc. -+ * Written by Abraham vd Merwe -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the author nor the names of other contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * MEMGETINFO -+ */ -+static int getmeminfo (int fd,struct mtd_info_user *mtd) -+{ -+ return (ioctl (fd,MEMGETINFO,mtd)); -+} -+ -+/* -+ * MEMERASE -+ */ -+static int memerase (int fd,struct erase_info_user *erase) -+{ -+ return (ioctl (fd,MEMERASE,erase)); -+} -+ -+/* -+ * MEMGETREGIONCOUNT -+ * MEMGETREGIONINFO -+ */ -+static int getregions (int fd,struct region_info_user *regions,int *n) -+{ -+ int i,err; -+ err = ioctl (fd,MEMGETREGIONCOUNT,n); -+ if (err) return (err); -+ for (i = 0; i < *n; i++) -+ { -+ regions[i].regionindex = i; -+ err = ioctl (fd,MEMGETREGIONINFO,®ions[i]); -+ if (err) return (err); -+ } -+ return (0); -+} -+ -+int erase_flash (int fd,u_int32_t offset,u_int32_t bytes) -+{ -+ int err; -+ struct erase_info_user erase; -+ erase.start = offset; -+ erase.length = bytes; -+ err = memerase (fd,&erase); -+ if (err < 0) -+ { -+ perror ("MEMERASE"); -+ return (1); -+ } -+ fprintf (stderr,"Erased %d bytes from address 0x%.8x in flash\n",bytes,offset); -+ return (0); -+} -+ -+void printsize (u_int32_t x) -+{ -+ int i; -+ static const char *flags = "KMGT"; -+ printf ("%u ",x); -+ for (i = 0; x >= 1024 && flags[i] != '\0'; i++) x /= 1024; -+ i--; -+ if (i >= 0) printf ("(%u%c)",x,flags[i]); -+} -+ -+int flash_to_file (int fd,u_int32_t offset,size_t len,const char *filename) -+{ -+ u_int8_t *buf = NULL; -+ int outfd,err; -+ int size = len * sizeof (u_int8_t); -+ int n = len; -+ -+ if (offset != lseek (fd,offset,SEEK_SET)) -+ { -+ perror ("lseek()"); -+ goto err0; -+ } -+ outfd = creat (filename,O_WRONLY); -+ if (outfd < 0) -+ { -+ perror ("creat()"); -+ goto err1; -+ } -+ -+retry: -+ if ((buf = (u_int8_t *) malloc (size)) == NULL) -+ { -+#define BUF_SIZE (64 * 1024 * sizeof (u_int8_t)) -+ fprintf (stderr, "%s: malloc(%#x)\n", __FUNCTION__, size); -+ if (size != BUF_SIZE) { -+ size = BUF_SIZE; -+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size); -+ goto retry; -+ } -+ perror ("malloc()"); -+ goto err0; -+ } -+ do { -+ if (n <= size) -+ size = n; -+ err = read (fd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: read, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("read()"); -+ goto err2; -+ } -+ err = write (outfd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("write()"); -+ goto err2; -+ } -+ if (err != size) -+ { -+ fprintf (stderr,"Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n",filename,err,size); -+ goto err2; -+ } -+ n -= size; -+ } while (n > 0); -+ -+ if (buf != NULL) -+ free (buf); -+ close (outfd); -+ printf ("Copied %d bytes from address 0x%.8x in flash to %s\n",len,offset,filename); -+ return (0); -+ -+err2: -+ close (outfd); -+err1: -+ if (buf != NULL) -+ free (buf); -+err0: -+ return (1); -+} -+ -+int file_to_flash (int fd,u_int32_t offset,u_int32_t len,const char *filename) -+{ -+ u_int8_t *buf = NULL; -+ FILE *fp; -+ int err; -+ int size = len * sizeof (u_int8_t); -+ int n = len; -+ -+ if (offset != lseek (fd,offset,SEEK_SET)) -+ { -+ perror ("lseek()"); -+ return (1); -+ } -+ if ((fp = fopen (filename,"r")) == NULL) -+ { -+ perror ("fopen()"); -+ return (1); -+ } -+retry: -+ if ((buf = (u_int8_t *) malloc (size)) == NULL) -+ { -+ fprintf (stderr, "%s: malloc(%#x) failed\n", __FUNCTION__, size); -+ if (size != BUF_SIZE) { -+ size = BUF_SIZE; -+ fprintf (stderr, "%s: trying buffer size %#x\n", __FUNCTION__, size); -+ goto retry; -+ } -+ perror ("malloc()"); -+ fclose (fp); -+ return (1); -+ } -+ do { -+ if (n <= size) -+ size = n; -+ if (fread (buf,size,1,fp) != 1 || ferror (fp)) -+ { -+ fprintf (stderr, "%s: fread, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("fread()"); -+ free (buf); -+ fclose (fp); -+ return (1); -+ } -+ err = write (fd,buf,size); -+ if (err < 0) -+ { -+ fprintf (stderr, "%s: write, size %#x, n %#x\n", __FUNCTION__, size, n); -+ perror ("write()"); -+ free (buf); -+ fclose (fp); -+ return (1); -+ } -+ n -= size; -+ } while (n > 0); -+ -+ if (buf != NULL) -+ free (buf); -+ fclose (fp); -+ printf ("Copied %d bytes from %s to address 0x%.8x in flash\n",len,filename,offset); -+ return (0); -+} -+ -+int showinfo (int fd) -+{ -+ int i,err,n; -+ struct mtd_info_user mtd; -+ static struct region_info_user region[1024]; -+ -+ err = getmeminfo (fd,&mtd); -+ if (err < 0) -+ { -+ perror ("MEMGETINFO"); -+ return (1); -+ } -+ -+ err = getregions (fd,region,&n); -+ if (err < 0) -+ { -+ perror ("MEMGETREGIONCOUNT"); -+ return (1); -+ } -+ -+ printf ("mtd.type = "); -+ switch (mtd.type) -+ { -+ case MTD_ABSENT: -+ printf ("MTD_ABSENT"); -+ break; -+ case MTD_RAM: -+ printf ("MTD_RAM"); -+ break; -+ case MTD_ROM: -+ printf ("MTD_ROM"); -+ break; -+ case MTD_NORFLASH: -+ printf ("MTD_NORFLASH"); -+ break; -+ case MTD_NANDFLASH: -+ printf ("MTD_NANDFLASH"); -+ break; -+ case MTD_DATAFLASH: -+ printf ("MTD_DATAFLASH"); -+ break; -+ case MTD_UBIVOLUME: -+ printf ("MTD_UBIVOLUME"); -+ default: -+ printf ("(unknown type - new MTD API maybe?)"); -+ } -+ -+ printf ("\nmtd.flags = "); -+ if (mtd.flags == MTD_CAP_ROM) -+ printf ("MTD_CAP_ROM"); -+ else if (mtd.flags == MTD_CAP_RAM) -+ printf ("MTD_CAP_RAM"); -+ else if (mtd.flags == MTD_CAP_NORFLASH) -+ printf ("MTD_CAP_NORFLASH"); -+ else if (mtd.flags == MTD_CAP_NANDFLASH) -+ printf ("MTD_CAP_NANDFLASH"); -+ else if (mtd.flags == MTD_WRITEABLE) -+ printf ("MTD_WRITEABLE"); -+ else -+ { -+ int first = 1; -+ static struct -+ { -+ const char *name; -+ int value; -+ } flags[] = -+ { -+ { "MTD_WRITEABLE", MTD_WRITEABLE }, -+ { "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE }, -+ { "MTD_NO_ERASE", MTD_NO_ERASE }, -+ { "MTD_STUPID_LOCK", MTD_STUPID_LOCK }, -+ { NULL, -1 } -+ }; -+ for (i = 0; flags[i].name != NULL; i++) -+ if (mtd.flags & flags[i].value) -+ { -+ if (first) -+ { -+ printf (flags[i].name); -+ first = 0; -+ } -+ else printf (" | %s",flags[i].name); -+ } -+ } -+ -+ printf ("\nmtd.size = "); -+ printsize (mtd.size); -+ -+ printf ("\nmtd.erasesize = "); -+ printsize (mtd.erasesize); -+ -+ printf ("\nmtd.writesize = "); -+ printsize (mtd.writesize); -+ -+ printf ("\nmtd.oobsize = "); -+ printsize (mtd.oobsize); -+ -+ printf ("\n" -+ "regions = %d\n" -+ "\n", -+ n); -+ -+ for (i = 0; i < n; i++) -+ { -+ printf ("region[%d].offset = 0x%.8x\n" -+ "region[%d].erasesize = ", -+ i,region[i].offset,i); -+ printsize (region[i].erasesize); -+ printf ("\nregion[%d].numblocks = %d\n" -+ "region[%d].regionindex = %d\n", -+ i,region[i].numblocks, -+ i,region[i].regionindex); -+ } -+ return (0); -+} -+ -+void showusage (const char *progname) -+{ -+ fprintf (stderr, -+ "usage: %s info \n" -+ " %s read \n" -+ " %s write \n" -+ " %s erase \n", -+ progname, -+ progname, -+ progname, -+ progname); -+ exit (1); -+} -+ -+#define OPT_INFO 1 -+#define OPT_READ 2 -+#define OPT_WRITE 3 -+#define OPT_ERASE 4 -+ -+int main (int argc,char *argv[]) -+{ -+ const char *progname; -+ int err = 0,fd,option = OPT_INFO; -+ int open_flag; -+ (progname = strrchr (argv[0],'/')) ? progname++ : (progname = argv[0]); -+ -+ /* parse command-line options */ -+ if (argc == 3 && !strcmp (argv[1],"info")) -+ option = OPT_INFO; -+ else if (argc == 6 && !strcmp (argv[1],"read")) -+ option = OPT_READ; -+ else if (argc == 6 && !strcmp (argv[1],"write")) -+ option = OPT_WRITE; -+ else if (argc == 5 && !strcmp (argv[1],"erase")) -+ option = OPT_ERASE; -+ else -+ showusage (progname); -+ -+ /* open device */ -+ open_flag = (option==OPT_INFO || option==OPT_READ) ? O_RDONLY : O_RDWR; -+ if ((fd = open (argv[2],O_SYNC | open_flag)) < 0) -+ { -+ perror ("open()"); -+ exit (1); -+ } -+ -+ switch (option) -+ { -+ case OPT_INFO: -+ showinfo (fd); -+ break; -+ case OPT_READ: -+ err = flash_to_file (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]); -+ break; -+ case OPT_WRITE: -+ err = file_to_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0),argv[5]); -+ break; -+ case OPT_ERASE: -+ err = erase_flash (fd,strtol (argv[3],NULL,0),strtol (argv[4],NULL,0)); -+ break; -+ } -+ -+ /* close device */ -+ if (close (fd) < 0) -+ perror ("close()"); -+ -+ exit (err); -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump.c linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,403 @@ -+/* -+ * nanddump.c -+ * -+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org) -+ * Steven J. Hill (sjhill@realitydiluted.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of raw NAND chips or NAND -+ * chips contained in DoC devices. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "nanddump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nanddump [OPTIONS] MTD-device\n" -+ "Dumps the contents of a nand mtd partition.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-f file --file=file dump to file\n" -+ "-i --ignoreerrors ignore errors\n" -+ "-l length --length=length length\n" -+ "-n --noecc read without error correction\n" -+ "-o --omitoob omit oob data\n" -+ "-b --omitbad omit bad blocks from the dump\n" -+ "-p --prettyprint print nice (hexdump)\n" -+ "-s addr --startaddress=addr start address\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int ignoreerrors; // ignore errors -+int pretty_print; // print nice in ascii -+int noecc; // don't error correct -+int omitoob; // omit oob data -+unsigned long start_addr; // start address -+unsigned long length; // dump length -+char *mtddev; // mtd device name -+char *dumpfile; // dump file name -+int omitbad; -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "bs:f:il:opn"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"file", required_argument, 0, 'f'}, -+ {"ignoreerrors", no_argument, 0, 'i'}, -+ {"prettyprint", no_argument, 0, 'p'}, -+ {"omitoob", no_argument, 0, 'o'}, -+ {"omitbad", no_argument, 0, 'b'}, -+ {"startaddress", required_argument, 0, 's'}, -+ {"length", required_argument, 0, 'l'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'b': -+ omitbad = 1; -+ break; -+ case 's': -+ start_addr = strtol(optarg, NULL, 0); -+ break; -+ case 'f': -+ if (!(dumpfile = strdup(optarg))) { -+ perror("stddup"); -+ exit(1); -+ } -+ break; -+ case 'i': -+ ignoreerrors = 1; -+ break; -+ case 'l': -+ length = strtol(optarg, NULL, 0); -+ break; -+ case 'o': -+ omitoob = 1; -+ break; -+ case 'p': -+ pretty_print = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ mtddev = argv[optind]; -+} -+ -+/* -+ * Buffers for reading data from flash -+ */ -+unsigned char readbuf[8192]; -+unsigned char oobbuf[256]; -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ unsigned long ofs, end_addr = 0; -+ unsigned long long blockstart = 1; -+ int ret, i, fd, ofd, bs, badblock = 0; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ mtd_info_t meminfo; -+ char pretty_buf[80]; -+ int oobinfochanged = 0 ; -+ struct nand_oobinfo old_oobinfo; -+ struct mtd_ecc_stats stat1, stat2; -+ int eccstats = 0; -+ -+ process_options(argc, argv); -+ -+ /* Open MTD device */ -+ if ((fd = open(mtddev, O_RDONLY)) == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit (1); -+ } -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) && -+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ /* Read the real oob length */ -+ oob.length = meminfo.oobsize; -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } else { -+ -+ /* check if we can read ecc stats */ -+ if (!ioctl(fd, ECCGETSTATS, &stat1)) { -+ eccstats = 1; -+ fprintf(stderr, "ECC failed: %d\n", stat1.failed); -+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected); -+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks); -+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks); -+ } else -+ perror("No ECC status information available"); -+ } -+ -+ /* Open output file for writing. If file name is "-", write to standard -+ * output. */ -+ if (!dumpfile) { -+ ofd = STDOUT_FILENO; -+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) { -+ perror ("open outfile"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Initialize start/end addresses and block size */ -+ if (length) -+ end_addr = start_addr + length; -+ if (!length || end_addr > meminfo.size) -+ end_addr = meminfo.size; -+ -+ bs = meminfo.writesize; -+ -+ /* Print informative message */ -+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n", -+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize); -+ fprintf(stderr, -+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n", -+ (unsigned int) start_addr, (unsigned int) end_addr); -+ -+ /* Dump the flash contents */ -+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) { -+ -+ // new eraseblock , check for bad block -+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) { -+ blockstart = ofs & (~meminfo.erasesize + 1); -+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ } -+ -+ if (badblock) { -+ if (omitbad) -+ continue; -+ memset (readbuf, 0xff, bs); -+ } else { -+ /* Read page data and exit on failure */ -+ if (pread(fd, readbuf, bs, ofs) != bs) { -+ perror("pread"); -+ goto closeall; -+ } -+ } -+ -+ /* ECC stats available ? */ -+ if (eccstats) { -+ if (ioctl(fd, ECCGETSTATS, &stat2)) { -+ perror("ioctl(ECCGETSTATS)"); -+ goto closeall; -+ } -+ if (stat1.failed != stat2.failed) -+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)" -+ " at offset 0x%08lx\n", -+ stat2.failed - stat1.failed, ofs); -+ if (stat1.corrected != stat2.corrected) -+ fprintf(stderr, "ECC: %d corrected bitflip(s) at" -+ " offset 0x%08lx\n", -+ stat2.corrected - stat1.corrected, ofs); -+ stat1 = stat2; -+ } -+ -+ /* Write out page data */ -+ if (pretty_print) { -+ for (i = 0; i < bs; i += 16) { -+ sprintf(pretty_buf, -+ "0x%08x: %02x %02x %02x %02x %02x %02x %02x " -+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -+ (unsigned int) (ofs + i), readbuf[i], -+ readbuf[i+1], readbuf[i+2], -+ readbuf[i+3], readbuf[i+4], -+ readbuf[i+5], readbuf[i+6], -+ readbuf[i+7], readbuf[i+8], -+ readbuf[i+9], readbuf[i+10], -+ readbuf[i+11], readbuf[i+12], -+ readbuf[i+13], readbuf[i+14], -+ readbuf[i+15]); -+ write(ofd, pretty_buf, 60); -+ } -+ } else -+ write(ofd, readbuf, bs); -+ -+ -+ -+ if (omitoob) -+ continue; -+ -+ if (badblock) { -+ memset (readbuf, 0xff, meminfo.oobsize); -+ } else { -+ /* Read OOB data and exit on failure */ -+ oob.start = ofs; -+ if (ioctl(fd, MEMREADOOB, &oob) != 0) { -+ perror("ioctl(MEMREADOOB)"); -+ goto closeall; -+ } -+ } -+ -+ /* Write out OOB data */ -+ if (pretty_print) { -+ if (meminfo.oobsize < 16) { -+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x " -+ "%02x %02x\n", -+ oobbuf[0], oobbuf[1], oobbuf[2], -+ oobbuf[3], oobbuf[4], oobbuf[5], -+ oobbuf[6], oobbuf[7]); -+ write(ofd, pretty_buf, 48); -+ continue; -+ } -+ -+ for (i = 0; i < meminfo.oobsize; i += 16) { -+ sprintf(pretty_buf, " OOB Data: %02x %02x %02x %02x %02x %02x " -+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -+ oobbuf[i], oobbuf[i+1], oobbuf[i+2], -+ oobbuf[i+3], oobbuf[i+4], oobbuf[i+5], -+ oobbuf[i+6], oobbuf[i+7], oobbuf[i+8], -+ oobbuf[i+9], oobbuf[i+10], oobbuf[i+11], -+ oobbuf[i+12], oobbuf[i+13], oobbuf[i+14], -+ oobbuf[i+15]); -+ write(ofd, pretty_buf, 60); -+ } -+ } else -+ write(ofd, oobbuf, meminfo.oobsize); -+ } -+ -+ /* reset oobinfo */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close(fd); -+ close(ofd); -+ return 1; -+ } -+ } -+ /* Close the output file and MTD device */ -+ close(fd); -+ close(ofd); -+ -+ /* Exit happy */ -+ return 0; -+ -+closeall: -+ /* The new mode change is per file descriptor ! */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ } -+ } -+ close(fd); -+ close(ofd); -+ exit(1); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump_vfat.c linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump_vfat.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nanddump_vfat.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nanddump_vfat.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,365 @@ -+/* -+ * nanddump.c -+ * -+ * Copyright (C) 2000 David Woodhouse (dwmw2@infradead.org) -+ * Steven J. Hill (sjhill@realitydiluted.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility dumps the contents of raw NAND chips or NAND -+ * chips contained in DoC devices. -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "nanddump" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nanddump [OPTIONS] MTD-device\n" -+ "Dumps the contents of a nand mtd partition.\n" -+ "\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n" -+ "-f file --file=file dump to file\n" -+ "-i --ignoreerrors ignore errors\n" -+ "-l length --length=length length\n" -+ "-n --noecc read without error correction\n" -+ "-o --omitoob omit oob data\n" -+ "-b --omitbad omit bad blocks from the dump\n" -+ "-p --prettyprint print nice (hexdump)\n" -+ "-s addr --startaddress=addr start address\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+// Option variables -+ -+int ignoreerrors; // ignore errors -+int pretty_print; // print nice in ascii -+int noecc; // don't error correct -+int omitoob; // omit oob data -+unsigned long start_addr; // start address -+unsigned long length; // dump length -+char *mtddev; // mtd device name -+char *dumpfile; // dump file name -+int omitbad; -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "bs:f:il:opn"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"file", required_argument, 0, 'f'}, -+ {"ignoreerrors", no_argument, 0, 'i'}, -+ {"prettyprint", no_argument, 0, 'p'}, -+ {"omitoob", no_argument, 0, 'o'}, -+ {"omitbad", no_argument, 0, 'b'}, -+ {"startaddress", required_argument, 0, 's'}, -+ {"length", required_argument, 0, 'l'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'b': -+ omitbad = 1; -+ break; -+ case 's': -+ start_addr = strtol(optarg, NULL, 0); -+ break; -+ case 'f': -+ if (!(dumpfile = strdup(optarg))) { -+ perror("stddup"); -+ exit(1); -+ } -+ break; -+ case 'i': -+ ignoreerrors = 1; -+ break; -+ case 'l': -+ length = strtol(optarg, NULL, 0); -+ break; -+ case 'o': -+ omitoob = 1; -+ break; -+ case 'p': -+ pretty_print = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help (); -+ -+ mtddev = argv[optind]; -+} -+ -+/* -+ * Buffers for reading data from flash -+ */ -+unsigned char readbuf[8192]; -+unsigned char oobbuf[256]; -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ unsigned long ofs, end_addr = 0; -+ unsigned long long blockstart = 1; -+ int ret, fd, ofd, bs, badblock = 0; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ mtd_info_t meminfo; -+ int oobinfochanged = 0 ; -+ struct nand_oobinfo old_oobinfo; -+ struct mtd_ecc_stats stat1, stat2; -+ int eccstats = 0; -+ -+ process_options(argc, argv); -+ -+ /* Open MTD device */ -+ if ((fd = open(mtddev, O_RDONLY)) == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit (1); -+ } -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 256 && meminfo.writesize == 8192) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 32 && meminfo.writesize == 1024) && -+ !(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ /* Read the real oob length */ -+ oob.length = meminfo.oobsize; -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } else { -+ -+ /* check if we can read ecc stats */ -+ if (!ioctl(fd, ECCGETSTATS, &stat1)) { -+ eccstats = 1; -+ fprintf(stderr, "ECC failed: %d\n", stat1.failed); -+ fprintf(stderr, "ECC corrected: %d\n", stat1.corrected); -+ fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks); -+ fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks); -+ } else -+ perror("No ECC status information available"); -+ } -+ -+ /* Open output file for writing. If file name is "-", write to standard -+ * output. */ -+ if (!dumpfile) { -+ ofd = STDOUT_FILENO; -+ } else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) { -+ perror ("open outfile"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Initialize start/end addresses and block size */ -+ if (length) -+ end_addr = start_addr + length; -+ if (!length || end_addr > meminfo.size) -+ end_addr = meminfo.size; -+ -+ bs = meminfo.writesize; -+ -+ /* Print informative message */ -+ fprintf(stderr, "Block size %u, page size %u, OOB size %u\n", -+ meminfo.erasesize, meminfo.writesize, meminfo.oobsize); -+ fprintf(stderr, -+ "Dumping data starting at 0x%08x and ending at 0x%08x...\n", -+ (unsigned int) start_addr, (unsigned int) end_addr); -+ -+ /* Dump the flash contents */ -+ for (ofs = start_addr; ofs < end_addr ; ofs+=bs) { -+ -+ // new eraseblock , check for bad block -+ if (blockstart != (ofs & (~meminfo.erasesize + 1))) { -+ blockstart = ofs & (~meminfo.erasesize + 1); -+ if ((badblock = ioctl(fd, MEMGETBADBLOCK, &blockstart)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ } -+ -+ if (badblock) { -+ //skip bad block; -+ ofs += meminfo.erasesize - bs; -+ continue; -+ } else { -+ /* Read page data and exit on failure */ -+ if (pread(fd, readbuf, bs, ofs) != bs) { -+ perror("pread"); -+ goto closeall; -+ } -+ } -+ -+ /* ECC stats available ? */ -+ if (eccstats) { -+ if (ioctl(fd, ECCGETSTATS, &stat2)) { -+ perror("ioctl(ECCGETSTATS)"); -+ goto closeall; -+ } -+ if (stat1.failed != stat2.failed) -+ fprintf(stderr, "ECC: %d uncorrectable bitflip(s)" -+ " at offset 0x%08lx\n", -+ stat2.failed - stat1.failed, ofs); -+ if (stat1.corrected != stat2.corrected) -+ fprintf(stderr, "ECC: %d corrected bitflip(s) at" -+ " offset 0x%08lx\n", -+ stat2.corrected - stat1.corrected, ofs); -+ stat1 = stat2; -+ } -+ -+ if (badblock) { -+ memset (readbuf, 0xff, meminfo.oobsize); -+ } else { -+ /* Read OOB data and exit on failure */ -+ oob.start = ofs; -+ if (ioctl(fd, MEMREADOOB, &oob) != 0) { -+ perror("ioctl(MEMREADOOB)"); -+ goto closeall; -+ } -+ if(oobbuf[2]==0xff && oobbuf[3]==0xff && oobbuf[4]==0xff && oobbuf[5]==0xff){ -+ //skip free block; -+ ofs += meminfo.erasesize - bs; -+ continue; -+ } -+ } -+ -+ /* Write out page data */ -+ write(ofd, readbuf, bs); -+ -+ if (omitoob) -+ continue; -+ -+ /* Write out OOB data */ -+ write(ofd, oobbuf, meminfo.oobsize); -+ } -+ -+ /* reset oobinfo */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close(fd); -+ close(ofd); -+ return 1; -+ } -+ } -+ /* Close the output file and MTD device */ -+ close(fd); -+ close(ofd); -+ -+ /* Exit happy */ -+ return 0; -+ -+closeall: -+ /* The new mode change is per file descriptor ! */ -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ } -+ } -+ close(fd); -+ close(ofd); -+ exit(1); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandtest.c linux-2.6.24.7/drivers/mtd/mtd-utils/nandtest.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandtest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nandtest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,284 @@ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+void usage(void) -+{ -+ fprintf(stderr, "usage: nandtest [OPTIONS] \n\n" -+ " -h, --help Display this help output\n" -+ " -m, --markbad Mark blocks bad if they appear so\n" -+ " -s, --seed Supply random seed\n" -+ " -p, --passes Number of passes\n" -+ " -o, --offset Start offset on flash\n" -+ " -l, --length Length of flash to test\n" -+ " -k, --keep Restore existing contents after test\n" -+ "Warning: it is just used for SLC NAND!\n"); -+ -+ exit(1); -+} -+ -+struct mtd_info_user meminfo; -+struct mtd_ecc_stats oldstats, newstats; -+int fd; -+int markbad=0; -+int seed; -+ -+int erase_and_write(loff_mtd_t ofs, unsigned char *data, unsigned char *rbuf) -+{ -+ struct erase_info_user er; -+ ssize_t len; -+ int i; -+ -+ printf("\r%09llx: erasing... ", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ er.start = ofs; -+ er.length = meminfo.erasesize; -+ -+ if (ioctl(fd, MEMERASE, &er)) { -+ perror("MEMERASE"); -+ if (markbad) { -+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs); -+ ioctl(fd, MEMSETBADBLOCK, &ofs); -+ } -+ return 1; -+ } -+ -+ printf("\r%09llx: writing...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ len = pwrite(fd, data, meminfo.erasesize, ofs); -+ if (len < 0) { -+ printf("\n"); -+ perror("write"); -+ if (markbad) { -+ printf("Mark block bad at %09llx\n", (loff_mtd_t)ofs); -+ ioctl(fd, MEMSETBADBLOCK, &ofs); -+ } -+ return 1; -+ } -+ if (len < meminfo.erasesize) { -+ printf("\n"); -+ fprintf(stderr, "Short write (%d bytes)\n", len); -+ exit(1); -+ } -+ -+ printf("\r%09llx: reading...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ len = pread(fd, rbuf, meminfo.erasesize, ofs); -+ if (len < meminfo.erasesize) { -+ printf("\n"); -+ if (len) -+ fprintf(stderr, "Short read (%d bytes)\n", len); -+ else -+ perror("read"); -+ exit(1); -+ } -+ -+ if (ioctl(fd, ECCGETSTATS, &newstats)) { -+ printf("\n"); -+ perror("ECCGETSTATS"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (newstats.corrected > oldstats.corrected) { -+ printf("\nECC corrected at %09llx\n", (loff_mtd_t) ofs); -+ oldstats.corrected = newstats.corrected; -+ } -+ if (newstats.failed > oldstats.failed) { -+ printf("\nECC failed at %09llx\n", (loff_mtd_t) ofs); -+ oldstats.corrected = newstats.corrected; -+ } -+ if (len < meminfo.erasesize) -+ exit(1); -+ -+ printf("\r%09llx: checking...", (loff_mtd_t)ofs); -+ fflush(stdout); -+ -+ if (memcmp(data, rbuf, meminfo.erasesize)) { -+ printf("\n"); -+ fprintf(stderr, "compare failed. seed %d\n", seed); -+ for (i=0; i meminfo.size) { -+ fprintf(stderr, "Length %09llx + offset %09llx exceeds device size %09llx\n", -+ length, offset, meminfo.size); -+ exit(1); -+ } -+ -+ wbuf = malloc(meminfo.erasesize * 3); -+ if (!wbuf) { -+ fprintf(stderr, "Could not allocate %d bytes for buffer\n", -+ meminfo.erasesize * 2); -+ exit(1); -+ } -+ rbuf = wbuf + meminfo.erasesize; -+ kbuf = rbuf + meminfo.erasesize; -+ -+ if (ioctl(fd, ECCGETSTATS, &oldstats)) { -+ perror("ECCGETSTATS"); -+ close(fd); -+ exit(1); -+ } -+ -+ printf("ECC corrections: %d\n", oldstats.corrected); -+ printf("ECC failures : %d\n", oldstats.failed); -+ printf("Bad blocks : %d\n", oldstats.badblocks); -+ printf("BBT blocks : %d\n", oldstats.bbtblocks); -+ -+ for (pass = 0; pass < nr_passes; pass++) { -+ loff_mtd_t test_ofs; -+ -+ for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) { -+ ssize_t len; -+ -+ seed = rand(); -+ srand(seed); -+ -+ if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) { -+ printf("\rBad block at 0x%09llx\n", test_ofs); -+ continue; -+ } -+ -+ for (i=0; i -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+#define PROGRAM "nandwrite" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define MAX_PAGE_SIZE 4096 -+#define MAX_OOB_SIZE 128 -+ -+/* -+ * Buffer array used for writing data -+ */ -+unsigned char writebuf[MAX_PAGE_SIZE]; -+unsigned char oobbuf[MAX_OOB_SIZE]; -+unsigned char oobreadbuf[MAX_OOB_SIZE]; -+ -+// oob layouts to pass into the kernel as default -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+struct nand_oobinfo jffs2_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 0, 1, 2, 3, 6, 7 } -+}; -+ -+struct nand_oobinfo yaffs_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 8, 9, 10, 13, 14, 15} -+}; -+ -+struct nand_oobinfo autoplace_oobinfo = { -+ .useecc = MTD_NANDECC_AUTOPLACE -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n" -+ "Writes to the specified MTD device.\n" -+ "\n" -+ " -a, --autoplace Use auto oob layout\n" -+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n" -+ " -y, --yaffs force yaffs oob layout (legacy support)\n" -+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n" -+ " -m, --markbad mark blocks bad if write fails\n" -+ " -n, --noecc write without ecc\n" -+ " -o, --oob image contains oob data\n" -+ " -s addr, --start=addr set start address (default is 0)\n" -+ " -p, --pad pad to page size\n" -+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n" -+ " -q, --quiet don't display progress messages\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+char *mtd_device, *img; -+int mtdoffset = 0; -+int quiet = 0; -+int writeoob = 0; -+int markbad = 0; -+int autoplace = 0; -+int forcejffs2 = 0; -+int forceyaffs = 0; -+int forcelegacy = 0; -+int noecc = 0; -+int pad = 0; -+int blockalign = 1; /*default to using 16K block size */ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "ab:fjmnopqs:y"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"autoplace", no_argument, 0, 'a'}, -+ {"blockalign", required_argument, 0, 'b'}, -+ {"forcelegacy", no_argument, 0, 'f'}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"markbad", no_argument, 0, 'm'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {"oob", no_argument, 0, 'o'}, -+ {"pad", no_argument, 0, 'p'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"start", required_argument, 0, 's'}, -+ {"yaffs", no_argument, 0, 'y'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'a': -+ autoplace = 1; -+ break; -+ case 'j': -+ forcejffs2 = 1; -+ break; -+ case 'y': -+ forceyaffs = 1; -+ break; -+ case 'f': -+ forcelegacy = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case 'm': -+ markbad = 1; -+ break; -+ case 'o': -+ writeoob = 1; -+ break; -+ case 'p': -+ pad = 1; -+ break; -+ case 's': -+ mtdoffset = strtol (optarg, NULL, 0); -+ break; -+ case 'b': -+ blockalign = atoi (optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help (); -+ -+ mtd_device = argv[optind++]; -+ img = argv[optind]; -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1; -+ struct mtd_info_user meminfo; -+ struct mtd_oob_buf oob; -+ loff_mtd_t offs; -+ int ret, readlen; -+ int oobinfochanged = 0; -+ struct nand_oobinfo old_oobinfo; -+ -+ printf("Warning: nandwrite_mlc instead of nandwrite is used for MLC NAND!\n"); -+ -+ process_options(argc, argv); -+ -+ memset(oobbuf, 0xff, sizeof(oobbuf)); -+ -+ if (pad && writeoob) { -+ fprintf(stderr, "Can't pad when oob data is present.\n"); -+ exit(1); -+ } -+ -+ /* Open the device */ -+ if ((fd = open(mtd_device, O_RDWR)) == -1) { -+ perror("open flash"); -+ exit(1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Set erasesize to specified number of blocks - to match jffs2 -+ * (virtual) block size */ -+ meminfo.erasesize *= blockalign; -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (autoplace) { -+ /* Read the current oob info */ -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ -+ // autoplace ECC ? -+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { -+ -+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ } -+ } -+ -+ if (noecc) { -+ ret = ioctl(fd, MTDFILEMODE, (void *) MTD_MODE_RAW); -+ if (ret == 0) { -+ oobinfochanged = 2; -+ } else { -+ switch (errno) { -+ case ENOTTY: -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ if (ioctl (fd, MEMSETOOBSEL, &none_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ break; -+ default: -+ perror ("MTDFILEMODE"); -+ close (fd); -+ exit (1); -+ } -+ } -+ } -+ -+ /* -+ * force oob layout for jffs2 or yaffs ? -+ * Legacy support -+ */ -+ if (forcejffs2 || forceyaffs) { -+ struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; -+ -+ if (autoplace) { -+ fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n"); -+ goto restoreoob; -+ } -+ if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) { -+ fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n"); -+ goto restoreoob; -+ } -+ if (meminfo.oobsize == 8) { -+ if (forceyaffs) { -+ fprintf (stderr, "YAFSS cannot operate on 256 Byte page size"); -+ goto restoreoob; -+ } -+ /* Adjust number of ecc bytes */ -+ jffs2_oobinfo.eccbytes = 3; -+ } -+ -+ if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) { -+ perror ("MEMSETOOBSEL"); -+ goto restoreoob; -+ } -+ } -+ -+ oob.length = meminfo.oobsize; -+ oob.ptr = noecc ? oobreadbuf : oobbuf; -+ -+ /* Open the input file */ -+ if ((ifd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ goto restoreoob; -+ } -+ -+ // get image length -+ imglen = lseek(ifd, 0, SEEK_END); -+ lseek (ifd, 0, SEEK_SET); -+ -+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0); -+ -+ // Check, if file is pagealigned -+ if ((!pad) && ((imglen % pagelen) != 0)) { -+ fprintf (stderr, "Input file is not page aligned\n"); -+ goto closeall; -+ } -+ -+ // Check, if length fits into device -+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) { -+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %llu bytes\n", -+ imglen, pagelen, meminfo.writesize, meminfo.size); -+ perror ("Input file does not fit into device"); -+ goto closeall; -+ } -+ -+ /* Get data from input and write to the device */ -+ while (imglen && (mtdoffset < meminfo.size)) { -+ // new eraseblock , check for bad block(s) -+ // Stay in the loop to be sure if the mtdoffset changes because -+ // of a bad block, that the next block that will be written to -+ // is also checked. Thus avoiding errors if the block(s) after the -+ // skipped block(s) is also bad (number of blocks depending on -+ // the blockalign -+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) { -+ blockstart = mtdoffset & (~meminfo.erasesize + 1); -+ offs = blockstart; -+ baderaseblock = 0; -+ if (!quiet) -+ fprintf (stdout, "Writing data to block %x\n", blockstart); -+ -+ /* Check all the blocks in an erase block for bad blocks */ -+ do { -+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ -+ if (ret == 1) { -+ baderaseblock = 1; -+ if (!quiet) -+ fprintf (stderr, "Bad block at %x, %u block(s) " -+ "from %x will be skipped\n", -+ (int) offs, blockalign, blockstart); -+ } -+ -+ if (baderaseblock) { -+ mtdoffset = blockstart + meminfo.erasesize; -+ } -+ offs += meminfo.erasesize / blockalign ; -+ } while ( offs < blockstart + meminfo.erasesize ); -+ -+ } -+ -+ readlen = meminfo.writesize; -+ if (pad && (imglen < readlen)) -+ { -+ readlen = imglen; -+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen); -+ } -+ -+ /* Read Page Data from input file */ -+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) { -+ if (cnt == 0) // EOF -+ break; -+ perror ("File I/O error on input file"); -+ goto closeall; -+ } -+ -+ if (writeoob) { -+ /* Read OOB data from input file, exit on failure */ -+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) { -+ perror ("File I/O error on input file"); -+ goto closeall; -+ } -+ if (!noecc) { -+ int i, start, len; -+ /* -+ * We use autoplacement and have the oobinfo with the autoplacement -+ * information from the kernel available -+ * -+ * Modified to support out of order oobfree segments, -+ * such as the layout used by diskonchip.c -+ */ -+ if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) { -+ for (i = 0;old_oobinfo.oobfree[i][1]; i++) { -+ /* Set the reserved bytes to 0xff */ -+ start = old_oobinfo.oobfree[i][0]; -+ len = old_oobinfo.oobfree[i][1]; -+ memcpy(oobbuf + start, -+ oobreadbuf + start, -+ len); -+ } -+ } else { -+ /* Set at least the ecc byte positions to 0xff */ -+ start = old_oobinfo.eccbytes; -+ len = meminfo.oobsize - start; -+ memcpy(oobbuf + start, -+ oobreadbuf + start, -+ len); -+ } -+ } -+ /* Write OOB data first, as ecc will be placed in there*/ -+ oob.start = mtdoffset; -+ if (ioctl(fd, MEMWRITEOOB, &oob) != 0) { -+ perror ("ioctl(MEMWRITEOOB)"); -+ goto closeall; -+ } -+ imglen -= meminfo.oobsize; -+ } -+ -+ /* Write out the Page data */ -+ if (pwrite(fd, writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) { -+ int rewind_blocks; -+ off_t rewind_bytes; -+ erase_info_t erase; -+ -+ perror ("pwrite"); -+ /* Must rewind to blockstart if we can */ -+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */ -+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen; -+ if (writeoob) -+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize; -+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) { -+ perror("lseek"); -+ fprintf(stderr, "Failed to seek backwards to recover from write error\n"); -+ goto closeall; -+ } -+ erase.start = blockstart; -+ erase.length = meminfo.erasesize; -+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n", -+ erase.start, erase.start+erase.length-1); -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ perror("MEMERASE"); -+ goto closeall; -+ } -+ -+ if (markbad) { -+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1); -+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr); -+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) { -+ perror("MEMSETBADBLOCK"); -+ /* But continue anyway */ -+ } -+ } -+ mtdoffset = blockstart + meminfo.erasesize; -+ imglen += rewind_blocks * meminfo.writesize; -+ -+ continue; -+ } -+ imglen -= readlen; -+ mtdoffset += meminfo.writesize; -+ } -+ -+closeall: -+ close(ifd); -+ -+restoreoob: -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ } -+ -+ close(fd); -+ -+ if (imglen > 0) { -+ perror ("Data was only partially written due to error\n"); -+ exit (1); -+ } -+ -+ /* Return happy */ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandwrite_mlc.c linux-2.6.24.7/drivers/mtd/mtd-utils/nandwrite_mlc.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nandwrite_mlc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nandwrite_mlc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,446 @@ -+/* -+ * nandwrite.c -+ * -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) -+ * 2003 Thomas Gleixner (tglx@linutronix.de) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This utility writes a binary image directly to a NAND flash -+ * chip or NAND chips contained in DoC devices. This is the -+ * "inverse operation" of nanddump. -+ * -+ * tglx: Major rewrite to handle bad blocks, write data with or without ECC -+ * write oob data only on request -+ * -+ * Bug/ToDo: -+ */ -+ -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "mtd/mtd-user.h" -+ -+#define PROGRAM "nandwrite" -+#define VERSION "$Revision: 1.1.1.1 $" -+ -+#define MAX_PAGE_SIZE 8192 -+#define MAX_OOB_SIZE 256 -+/* -+ * Buffer array used for writing data -+ */ -+unsigned char writebuf[MAX_PAGE_SIZE]; -+unsigned char oobreadbuf[MAX_OOB_SIZE]; -+ -+// oob layouts to pass into the kernel as default -+struct nand_oobinfo none_oobinfo = { -+ .useecc = MTD_NANDECC_OFF, -+}; -+ -+struct nand_oobinfo jffs2_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 0, 1, 2, 3, 6, 7 } -+}; -+ -+struct nand_oobinfo yaffs_oobinfo = { -+ .useecc = MTD_NANDECC_PLACE, -+ .eccbytes = 6, -+ .eccpos = { 8, 9, 10, 13, 14, 15} -+}; -+ -+struct nand_oobinfo autoplace_oobinfo = { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 36 -+}; -+ -+void display_help (void) -+{ -+ printf("Usage: nandwrite [OPTION] MTD_DEVICE INPUTFILE\n" -+ "Writes to the specified MTD device.\n" -+ "\n" -+ " -a, --autoplace Use auto oob layout\n" -+ " -j, --jffs2 force jffs2 oob layout (legacy support)\n" -+ " -y, --yaffs force yaffs oob layout (legacy support)\n" -+ " -f, --forcelegacy force legacy support on autoplacement enabled mtd device\n" -+ " -m, --markbad mark blocks bad if write fails\n" -+ " -n, --noecc write without ecc\n" -+ " -o, --oob image contains oob data\n" -+ " -s addr, --start=addr set start address (default is 0)\n" -+ " -p, --pad pad to page size\n" -+ " -b, --blockalign=1|2|4 set multiple of eraseblocks to align to\n" -+ " -q, --quiet don't display progress messages\n" -+ " --help display this help and exit\n" -+ " --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version (void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "Copyright (C) 2003 Thomas Gleixner \n" -+ "\n" -+ PROGRAM " comes with NO WARRANTY\n" -+ "to the extent permitted by law.\n" -+ "\n" -+ "You may redistribute copies of " PROGRAM "\n" -+ "under the terms of the GNU General Public Licence.\n" -+ "See the file `COPYING' for more information.\n"); -+ exit(0); -+} -+ -+char *mtd_device, *img; -+unsigned long long mtdoffset = 0; -+int quiet = 0; -+int writeoob = 0; -+int markbad = 1; -+int autoplace = 0; -+int forcejffs2 = 0; -+int forceyaffs = 0; -+int forcelegacy = 0; -+int noecc = 0; -+int pad = 0; -+int blockalign = 1; /*default to using 16K block size */ -+ -+void process_options (int argc, char *argv[]) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "ab:fjmnopqs:y"; -+ static const struct option long_options[] = { -+ {"help", no_argument, 0, 0}, -+ {"version", no_argument, 0, 0}, -+ {"autoplace", no_argument, 0, 'a'}, -+ {"blockalign", required_argument, 0, 'b'}, -+ {"forcelegacy", no_argument, 0, 'f'}, -+ {"jffs2", no_argument, 0, 'j'}, -+ {"markbad", no_argument, 0, 'm'}, -+ {"noecc", no_argument, 0, 'n'}, -+ {"oob", no_argument, 0, 'o'}, -+ {"pad", no_argument, 0, 'p'}, -+ {"quiet", no_argument, 0, 'q'}, -+ {"start", required_argument, 0, 's'}, -+ {"yaffs", no_argument, 0, 'y'}, -+ {0, 0, 0, 0}, -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) { -+ break; -+ } -+ -+ switch (c) { -+ case 0: -+ switch (option_index) { -+ case 0: -+ display_help(); -+ break; -+ case 1: -+ display_version(); -+ break; -+ } -+ break; -+ case 'q': -+ quiet = 1; -+ break; -+ case 'a': -+ autoplace = 1; -+ break; -+ case 'j': -+ forcejffs2 = 1; -+ break; -+ case 'y': -+ forceyaffs = 1; -+ break; -+ case 'f': -+ forcelegacy = 1; -+ break; -+ case 'n': -+ noecc = 1; -+ break; -+ case 'm': -+ markbad = 1; -+ break; -+ case 'o': -+ writeoob = 1; -+ break; -+ case 'p': -+ pad = 1; -+ break; -+ case 's': -+ mtdoffset = strtol (optarg, NULL, 0); -+ break; -+ case 'b': -+ blockalign = atoi (optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help (); -+ -+ mtd_device = argv[optind++]; -+ img = argv[optind]; -+} -+ -+/* -+ * Main program -+ */ -+int main(int argc, char **argv) -+{ -+ int cnt, fd, ifd, imglen = 0, pagelen, baderaseblock, blockstart = -1; -+ struct mtd_info_user meminfo; -+ struct mtd_page_buf oob; -+ loff_mtd_t offs; -+ int ret, readlen; -+ int oobinfochanged = 0; -+ struct nand_oobinfo old_oobinfo; -+ int i; -+ -+ process_options(argc, argv); -+ -+ if (pad && writeoob) { -+ fprintf(stderr, "Can't pad when oob data is present.\n"); -+ exit(1); -+ } -+ -+ /* Open the device */ -+ if ((fd = open(mtd_device, O_RDWR)) == -1) { -+ perror("open flash"); -+ exit(1); -+ } -+ -+ /* Fill in MTD device capability structure */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(fd); -+ exit(1); -+ } -+ -+ /* Set erasesize to specified number of blocks - to match jffs2 -+ * (virtual) block size */ -+ meminfo.erasesize *= blockalign; -+ -+ /* Make sure device page sizes are valid */ -+ if (!(meminfo.oobsize == 16 && meminfo.writesize == 512) && -+ !(meminfo.oobsize == 8 && meminfo.writesize == 256) && -+ !(meminfo.oobsize == 64 && meminfo.writesize == 2048) && -+ !(meminfo.oobsize == 128 && meminfo.writesize == 4096) && -+ !(meminfo.oobsize == 256 && meminfo.writesize == 8192)) { -+ fprintf(stderr, "Unknown flash (not normal NAND)\n"); -+ close(fd); -+ exit(1); -+ } -+ -+ if (autoplace) { -+ /* Read the current oob info */ -+ if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMGETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ -+ // autoplace ECC ? -+ if (autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) { -+ -+ if (ioctl (fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ oobinfochanged = 1; -+ } -+ } -+ -+ memset(oobreadbuf, 0xff, MAX_OOB_SIZE); -+ -+ if (autoplace) { -+ oob.ooblength = meminfo.oobsize-old_oobinfo.eccbytes; /* Get ooblength from kernel */ -+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, old_oobinfo.eccbytes); -+ } else { -+ oob.ooblength = meminfo.oobsize-autoplace_oobinfo.eccbytes; -+ printf("oobsize=%d eccbytes=%d\n", meminfo.oobsize, autoplace_oobinfo.eccbytes); -+ } -+ -+ oob.oobptr = oobreadbuf; -+ oob.datptr = writebuf; -+ -+ /* Open the input file */ -+ if ((ifd = open(img, O_RDONLY)) == -1) { -+ perror("open input file"); -+ goto restoreoob; -+ } -+ -+ // get image length -+ imglen = lseek(ifd, 0, SEEK_END); -+ lseek (ifd, 0, SEEK_SET); -+ -+ pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0); -+ -+ // Check, if file is pagealigned -+ if ((!pad) && ((imglen % pagelen) != 0)) { -+ fprintf (stderr, "Input file is not page aligned\n"); -+ goto closeall; -+ } -+ -+ // Check, if length fits into device -+ if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) { -+ fprintf (stderr, "Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %lld bytes\n", -+ imglen, pagelen, meminfo.writesize, meminfo.size); -+ perror ("Input file does not fit into device"); -+ goto closeall; -+ } -+ -+ /* Get data from input and write to the device */ -+ while (imglen && (mtdoffset < meminfo.size)) { -+ // new eraseblock , check for bad block(s) -+ // Stay in the loop to be sure if the mtdoffset changes because -+ // of a bad block, that the next block that will be written to -+ // is also checked. Thus avoiding errors if the block(s) after the -+ // skipped block(s) is also bad (number of blocks depending on -+ // the blockalign -+ while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) { -+ blockstart = mtdoffset & (~meminfo.erasesize + 1); -+ offs = blockstart; -+ baderaseblock = 0; -+ i=0; -+ if (!quiet) -+ fprintf (stdout, "Writing data to block 0x%x\n", blockstart); -+ -+ /* Check all the blocks in an erase block for bad blocks */ -+ do { -+ if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) { -+ perror("ioctl(MEMGETBADBLOCK)"); -+ goto closeall; -+ } -+ if (ret == 1) { -+ baderaseblock = 1; -+ if (!quiet) -+ fprintf (stderr, "Bad block at 0x%llx, %u block(s) " -+ "from 0x%x will be skipped\n", -+ offs, blockalign, blockstart); -+ } -+ -+ if (baderaseblock) { -+ mtdoffset = blockstart + meminfo.erasesize; -+ } -+ offs += meminfo.erasesize / blockalign ; -+ } while ( offs < blockstart + meminfo.erasesize ); -+ -+ } -+ -+ readlen = meminfo.writesize; -+ if (pad && (imglen < readlen)) -+ { -+ readlen = imglen; -+ memset(writebuf + readlen, 0xff, meminfo.writesize - readlen); -+ } -+ -+ /* Read Page Data from input file */ -+ if ((cnt = read(ifd, writebuf, readlen)) != readlen) { -+ if (cnt == 0) // EOF -+ break; -+ perror ("File I/O error 1 on input file"); -+ goto closeall; -+ } -+ -+ /* Read OOB data from input file, exit on failure */ -+ if(writeoob) { -+ if ((cnt = read(ifd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) { -+ perror ("File I/O error 2 on input file"); -+ goto closeall; -+ } -+ } -+ oob.start = mtdoffset; -+ -+ // write a page include its oob to nand -+ ioctl(fd, MEMWRITEPAGE, &oob); -+ if(oob.datlength != meminfo.writesize){ -+ perror ("ioctl(MEMWRITEPAGE)"); -+ -+ int rewind_blocks; -+ off_t rewind_bytes; -+ erase_info_t erase; -+ -+ /* Must rewind to blockstart if we can */ -+ rewind_blocks = (mtdoffset - blockstart) / meminfo.writesize; /* Not including the one we just attempted */ -+ rewind_bytes = (rewind_blocks * meminfo.writesize) + readlen; -+ if (writeoob) -+ rewind_bytes += (rewind_blocks + 1) * meminfo.oobsize; -+ if (lseek(ifd, -rewind_bytes, SEEK_CUR) == -1) { -+ perror("lseek"); -+ fprintf(stderr, "Failed to seek backwards to recover from write error\n"); -+ goto closeall; -+ } -+ erase.start = blockstart; -+ erase.length = meminfo.erasesize; -+ fprintf(stderr, "Erasing failed write from 0x%09llx-0x%09llx\n", -+ erase.start, erase.start+erase.length-1); -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ perror("MEMERASE"); -+ goto closeall; -+ } -+ -+ if (markbad) { -+ loff_mtd_t bad_addr = mtdoffset & (~(meminfo.erasesize / blockalign) + 1); -+ fprintf(stderr, "Marking block at %09llx bad\n", (long long)bad_addr); -+ if (ioctl(fd, MEMSETBADBLOCK, &bad_addr)) { -+ perror("MEMSETBADBLOCK"); -+ /* But continue anyway */ -+ } -+ } -+ mtdoffset = blockstart + meminfo.erasesize; -+ imglen += rewind_blocks * meminfo.writesize; -+ -+ continue; -+ } -+ if(writeoob) -+ imglen -= meminfo.oobsize; -+ imglen -= readlen; -+ mtdoffset += meminfo.writesize; -+ } -+ -+closeall: -+ close(ifd); -+ -+restoreoob: -+ if (oobinfochanged == 1) { -+ if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) { -+ perror ("MEMSETOOBSEL"); -+ close (fd); -+ exit (1); -+ } -+ } -+ -+ close(fd); -+ -+ if (imglen > 0) { -+ perror ("Data was only partially written due to error\n"); -+ exit (1); -+ } -+ -+ /* Return happy */ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftl_format.c linux-2.6.24.7/drivers/mtd/mtd-utils/nftl_format.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftl_format.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nftl_format.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,419 @@ -+/* -+ * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ToDo: -+ * 1. UnitSizeFactor != 0xFF cases -+ * 2. test, test, and test !!! -+ */ -+ -+#define _XOPEN_SOURCE 500 /* for pread/pwrite */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+unsigned char BadUnitTable[MAX_ERASE_ZONES]; -+unsigned char *readbuf; -+unsigned char *writebuf[4]; -+ -+mtd_info_t meminfo; -+erase_info_t erase; -+int fd; -+struct NFTLMediaHeader *NFTLhdr; -+struct INFTLMediaHeader *INFTLhdr; -+ -+static int do_oobcheck = 1; -+static int do_rwecheck = 1; -+ -+static unsigned char check_block_1(unsigned long block) -+{ -+ unsigned char oobbuf[16]; -+ struct mtd_oob_buf oob = { 0, 16, oobbuf }; -+ -+ oob.start = block * meminfo.erasesize; -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ return ZONE_BAD_ORIGINAL; -+ -+ if(oobbuf[5] == 0) -+ return ZONE_BAD_ORIGINAL; -+ -+ oob.start = block * meminfo.erasesize + 512 /* FIXME */; -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ return ZONE_BAD_ORIGINAL; -+ -+ if(oobbuf[5] == 0) -+ return ZONE_BAD_ORIGINAL; -+ -+ return ZONE_GOOD; -+} -+ -+static unsigned char check_block_2(unsigned long block) -+{ -+ unsigned long ofs = block * meminfo.erasesize; -+ unsigned long blockofs; -+ -+ /* Erase test */ -+ erase.start = ofs; -+ -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pread(fd, readbuf, 512, ofs + blockofs); -+ if (memcmp(readbuf, writebuf[0], 512)) { -+ /* Block wasn't 0xff after erase */ -+ printf(": Block not 0xff after erase\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ -+ pwrite(fd, writebuf[1], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[1], 512)) { -+ printf(": Block not zero after clearing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ /* Write test */ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Second erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pwrite(fd, writebuf[2], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[2], 512)) { -+ printf(": Block not 0x5a after writing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Third erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { -+ pwrite(fd, writebuf[3], 512, blockofs + ofs); -+ pread(fd, readbuf, 512, blockofs + ofs); -+ if (memcmp(readbuf, writebuf[3], 512)) { -+ printf(": Block not 0xa5 after writing\n"); -+ return ZONE_BAD_ORIGINAL; -+ } -+ } -+ if (ioctl(fd, MEMERASE, &erase) != 0) { -+ printf(": Fourth erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ return ZONE_GOOD; -+} -+ -+static unsigned char erase_block(unsigned long block) -+{ -+ unsigned char status; -+ int ret; -+ -+ status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD; -+ erase.start = block * meminfo.erasesize; -+ -+ if (status != ZONE_GOOD) { -+ printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start); -+ fflush(stdout); -+ return status; -+ } -+ -+ printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start); -+ fflush(stdout); -+ -+ if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) { -+ printf(": Erase failed (%s)\n", strerror(errno)); -+ return ZONE_BAD_ORIGINAL; -+ } -+ -+ if (do_rwecheck) { -+ printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start); -+ fflush(stdout); -+ status = check_block_2(block); -+ if (status != ZONE_GOOD) { -+ printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start); -+ fflush(stdout); -+ } -+ } -+ return status; -+} -+ -+static int checkbbt(void) -+{ -+ unsigned char bbt[512]; -+ unsigned char bits; -+ int i, addr; -+ -+ if (pread(fd, bbt, 512, 0x800) < 0) { -+ printf("nftl_format: failed to read BBT, errno=%d\n", errno); -+ return (-1); -+ } -+ -+ -+ for (i = 0; (i < 512); i++) { -+ addr = i / 4; -+ bits = 0x3 << ((i % 4) * 2); -+ if ((bbt[addr] & bits) == 0) { -+ BadUnitTable[i] = ZONE_BAD_ORIGINAL; -+ } -+ } -+ -+ return (0); -+} -+ -+void usage(int rc) -+{ -+ fprintf(stderr, "Usage: nftl_format [-ib] [ []]\n"); -+ exit(rc); -+} -+ -+int main(int argc, char **argv) -+{ -+ unsigned long startofs = 0, part_size = 0; -+ unsigned long ezones = 0, ezone = 0, bad_zones = 0; -+ unsigned char unit_factor = 0xFF; -+ long MediaUnit1 = -1, MediaUnit2 = -1; -+ long MediaUnitOff1 = 0, MediaUnitOff2 = 0; -+ unsigned char oobbuf[16]; -+ struct mtd_oob_buf oob = {0, 16, oobbuf}; -+ char *mtddevice, *nftl; -+ int c, do_inftl = 0, do_bbt = 0; -+ -+ -+ printf("version 1.24 2005/11/07 11:15:13 gleixner\n"); -+ -+ if (argc < 2) -+ usage(1); -+ -+ nftl = "NFTL"; -+ -+ while ((c = getopt(argc, argv, "?hib")) > 0) { -+ switch (c) { -+ case 'i': -+ nftl = "INFTL"; -+ do_inftl = 1; -+ break; -+ case 'b': -+ do_bbt = 1; -+ break; -+ case 'h': -+ case '?': -+ usage(0); -+ break; -+ default: -+ usage(1); -+ break; -+ } -+ } -+ -+ mtddevice = argv[optind++]; -+ if (argc > optind) { -+ startofs = strtoul(argv[optind++], NULL, 0); -+ } -+ if (argc > optind) { -+ part_size = strtoul(argv[optind++], NULL, 0); -+ } -+ -+ // Open and size the device -+ if ((fd = open(mtddevice, O_RDWR)) < 0) { -+ perror("Open flash device"); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ close(fd); -+ return 1; -+ } -+ -+ switch (meminfo.erasesize) { -+ case 0x1000: -+ case 0x2000: -+ case 0x4000: -+ case 0x8000: -+ break; -+ default: -+ printf("Unrecognized Erase size, 0x%x - I'm confused\n", -+ meminfo.erasesize); -+ close(fd); -+ return 1; -+ } -+ writebuf[0] = malloc(meminfo.erasesize * 5); -+ if (!writebuf[0]) { -+ printf("Malloc failed\n"); -+ close(fd); -+ return 1; -+ } -+ writebuf[1] = writebuf[0] + meminfo.erasesize; -+ writebuf[2] = writebuf[1] + meminfo.erasesize; -+ writebuf[3] = writebuf[2] + meminfo.erasesize; -+ readbuf = writebuf[3] + meminfo.erasesize; -+ memset(writebuf[0], 0xff, meminfo.erasesize); -+ memset(writebuf[1], 0x00, meminfo.erasesize); -+ memset(writebuf[2], 0x5a, meminfo.erasesize); -+ memset(writebuf[3], 0xa5, meminfo.erasesize); -+ memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES); -+ -+ if (part_size == 0 || (part_size > meminfo.size - startofs)) -+ /* the user doest not or incorrectly specify NFTL partition size */ -+ part_size = meminfo.size - startofs; -+ -+ erase.length = meminfo.erasesize; -+ ezones = part_size / meminfo.erasesize; -+ -+ if (ezones > MAX_ERASE_ZONES) { -+ /* Ought to change the UnitSizeFactor. But later. */ -+ part_size = meminfo.erasesize * MAX_ERASE_ZONES; -+ ezones = MAX_ERASE_ZONES; -+ unit_factor = 0xFF; -+ } -+ -+ /* If using device BBT then parse that now */ -+ if (do_bbt) { -+ checkbbt(); -+ do_oobcheck = 0; -+ do_rwecheck = 0; -+ } -+ -+ /* Phase 1. Erasing and checking each erase zones in the NFTL partition. -+ N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */ -+ printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n", -+ startofs, startofs + part_size); -+ for (ezone = startofs / meminfo.erasesize; -+ ezone < (ezones + startofs / meminfo.erasesize); ezone++) { -+ if (BadUnitTable[ezone] != ZONE_GOOD) -+ continue; -+ if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) { -+ if (MediaUnit1 == -1) { -+ MediaUnit1 = ezone; -+ } else if (MediaUnit2 == -1) { -+ MediaUnit2 = ezone; -+ } -+ } else { -+ bad_zones++; -+ } -+ } -+ printf("\n"); -+ -+ /* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used -+ by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */ -+ if (do_inftl) { -+ unsigned long maxzones, pezstart, pezend, numvunits; -+ -+ INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]); -+ strcpy(INFTLhdr->bootRecordID, "BNAND"); -+ INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0); -+ INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0); -+ INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1); -+ INFTLhdr->BlockMultiplierBits = cpu_to_le32(0); -+ INFTLhdr->FormatFlags = cpu_to_le32(0); -+ INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION); -+ INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED); -+ /* -+ * Calculate number of virtual units we will have to work -+ * with. I am calculating out the known bad units here, not -+ * sure if that is what M-Systems do... -+ */ -+ MediaUnit2 = MediaUnit1; -+ MediaUnitOff2 = 4096; -+ maxzones = meminfo.size / meminfo.erasesize; -+ pezstart = startofs / meminfo.erasesize + 1; -+ pezend = startofs / meminfo.erasesize + ezones - 1; -+ numvunits = (ezones - 2) * PERCENTUSED / 100; -+ for (ezone = pezstart; ezone < maxzones; ezone++) { -+ if (BadUnitTable[ezone] != ZONE_GOOD) { -+ if (numvunits > 1) -+ numvunits--; -+ } -+ } -+ -+ INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits); -+ INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart); -+ INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend); -+ INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL); -+ INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0); -+ INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit; -+ INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0); -+ -+ } else { -+ -+ NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]); -+ strcpy(NFTLhdr->DataOrgID, "ANAND"); -+ NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize); -+ NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1); -+ /* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */ -+ NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize)); -+ NFTLhdr->UnitSizeFactor = unit_factor; -+ } -+ -+ /* Phase 2. Writing NFTL Media Headers and Bad Unit Table */ -+ printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl); -+ pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1); -+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { -+ pwrite(fd, BadUnitTable + ezone, 512, -+ (MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512)); -+ } -+ -+#if 0 -+ printf(" MediaHeader contents:\n"); -+ printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits)); -+ printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN)); -+ printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize), -+ le32_to_cpu(NFTLhdr->FormattedSize)/512); -+#endif -+ printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl); -+ pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2); -+ for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { -+ pwrite(fd, BadUnitTable + ezone, 512, -+ (MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512)); -+ } -+ -+ /* UCI #1 for newly erased Erase Unit */ -+ memset(oobbuf, 0xff, 16); -+ oobbuf[11] = oobbuf[10] = oobbuf[9] = 0; -+ oobbuf[8] = (do_inftl) ? 0x00 : 0x03; -+ oobbuf[12] = oobbuf[14] = 0x69; -+ oobbuf[13] = oobbuf[15] = 0x3c; -+ -+ /* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit -+ by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0, -+ but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */ -+ /* Phase 3. Writing Unit Control Information for each Erase Unit */ -+ printf("Phase 3. Writing Unit Control Information to each Erase Unit\n"); -+ for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) { -+ /* write UCI #1 to each Erase Unit */ -+ if (BadUnitTable[ezone] != ZONE_GOOD) -+ continue; -+ oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512); -+ if (ioctl(fd, MEMWRITEOOB, &oob)) -+ printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno)); -+ } -+ -+ exit(0); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftldump.c linux-2.6.24.7/drivers/mtd/mtd-utils/nftldump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/nftldump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/nftldump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk" -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * ToDo: -+ * 1. UnitSizeFactor != 0xFF cases -+ * 2. test, test, and test !!! -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static struct NFTLMediaHeader MedHead[2]; -+static mtd_info_t meminfo; -+ -+static struct nftl_oob oobbuf; -+static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf}; -+ -+static int fd, ofd = -1;; -+static int NumMedHeads; -+ -+static unsigned char BadUnitTable[MAX_ERASE_ZONES]; -+ -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+#define SWAP16(x) do { ; } while(0) -+#define SWAP32(x) do { ; } while(0) -+#else -+#define SWAP16(x) do { x = swab16(x); } while(0) -+#define SWAP32(x) do { x = swab32(x); } while(0) -+#endif -+ -+/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */ -+static unsigned short *VUCtable; -+ -+/* FixMe: make this dynamic allocated */ -+#define ERASESIZE 0x2000 -+#define NUMVUNITS ((40*1024*1024) / ERASESIZE) -+static union nftl_uci UCItable[NUMVUNITS][3]; -+ -+static unsigned short nextEUN(unsigned short curEUN) -+{ -+ return UCItable[curEUN][0].a.ReplUnitNum; -+} -+ -+static unsigned int find_media_headers(void) -+{ -+ int i; -+ static unsigned long ofs = 0; -+ -+ NumMedHeads = 0; -+ while (ofs < meminfo.size) { -+ pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs); -+ if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) { -+ SWAP16(MedHead[NumMedHeads].NumEraseUnits); -+ SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN); -+ SWAP32(MedHead[NumMedHeads].FormattedSize); -+ -+ if (NumMedHeads == 0) { -+ printf("NFTL Media Header found at offset 0x%08lx:\n", ofs); -+ printf("NumEraseUnits: %d\n", -+ MedHead[NumMedHeads].NumEraseUnits); -+ printf("FirstPhysicalEUN: %d\n", -+ MedHead[NumMedHeads].FirstPhysicalEUN); -+ printf("Formatted Size: %d\n", -+ MedHead[NumMedHeads].FormattedSize); -+ printf("UnitSizeFactor: 0x%x\n", -+ MedHead[NumMedHeads].UnitSizeFactor); -+ -+ /* read BadUnitTable, I don't know why pread() does not work for -+ larger (7680 bytes) chunks */ -+ for (i = 0; i < MAX_ERASE_ZONES; i += 512) -+ pread(fd, &BadUnitTable[i], 512, ofs + 512 + i); -+ } else -+ printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs); -+ NumMedHeads++; -+ } -+ -+ ofs += meminfo.erasesize; -+ if (NumMedHeads == 2) { -+ if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) { -+ printf("warning: NFTL Media Header is not consistent with " -+ "Spare NFTL Media Header\n"); -+ } -+ break; -+ } -+ } -+ -+ /* allocate Virtual Unit Chain table for this NFTL partition */ -+ VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short)); -+ return NumMedHeads; -+} -+ -+static void dump_erase_units(void) -+{ -+ int i, j; -+ unsigned long ofs; -+ -+ for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN + -+ MedHead[0].NumEraseUnits; i++) { -+ /* For each Erase Unit */ -+ ofs = i * meminfo.erasesize; -+ -+ /* read the Unit Control Information */ -+ for (j = 0; j < 3; j++) { -+ oob.start = ofs + (j * 512); -+ if (ioctl(fd, MEMREADOOB, &oob)) -+ printf("MEMREADOOB at %lx: %s\n", -+ (unsigned long) oob.start, strerror(errno)); -+ memcpy(&UCItable[i][j], &oobbuf.u, 8); -+ } -+ if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) { -+ printf("EraseMark not present in unit %d: %x\n", -+ i, UCItable[i][1].b.EraseMark); -+ } else { -+ /* a properly formatted unit */ -+ SWAP16(UCItable[i][0].a.VirtUnitNum); -+ SWAP16(UCItable[i][0].a.ReplUnitNum); -+ SWAP16(UCItable[i][0].a.SpareVirtUnitNum); -+ SWAP16(UCItable[i][0].a.SpareReplUnitNum); -+ SWAP32(UCItable[i][1].b.WearInfo); -+ SWAP16(UCItable[i][1].b.EraseMark); -+ SWAP16(UCItable[i][1].b.EraseMark1); -+ SWAP16(UCItable[i][2].c.FoldMark); -+ SWAP16(UCItable[i][2].c.FoldMark1); -+ -+ if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) { -+ /* If this is the first in a chain, store the EUN in the VUC table */ -+ if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) { -+ printf("Duplicate start of chain for VUC %d: " -+ "Unit %d replaces Unit %d\n", -+ UCItable[i][0].a.VirtUnitNum & 0x7fff, -+ i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]); -+ } -+ VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i; -+ } -+ } -+ -+ switch (BadUnitTable[i]) { -+ case ZONE_BAD_ORIGINAL: -+ printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i); -+ continue; -+ case ZONE_BAD_MARKED: -+ printf("Unit %d is marked as ZONE_BAD_MARKED\n", i); -+ continue; -+ } -+ -+ /* ZONE_GOOD */ -+ if (UCItable[i][0].a.VirtUnitNum == 0xffff) -+ printf("Unit %d is free\n", i); -+ else -+ printf("Unit %d is in chain %d and %s a replacement\n", i, -+ UCItable[i][0].a.VirtUnitNum & 0x7fff, -+ UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not"); -+ } -+} -+ -+static void dump_virtual_units(void) -+{ -+ int i, j; -+ char readbuf[512]; -+ -+ for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) { -+ unsigned short curEUN = VUCtable[i]; -+ -+ printf("Virtual Unit #%d: ", i); -+ if (!curEUN) { -+ printf("Not present\n"); -+ continue; -+ } -+ printf("%d", curEUN); -+ -+ /* walk through the Virtual Unit Chain */ -+ while ((curEUN = nextEUN(curEUN)) != 0xffff) { -+ printf(", %d", curEUN & 0x7fff); -+ } -+ printf("\n"); -+ -+ if (ofd != -1) { -+ /* Actually write out the data */ -+ for (j = 0; j < meminfo.erasesize / 512; j++) { -+ /* For each sector in the block */ -+ unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i]; -+ unsigned int status; -+ -+ if (thisEUN == 0xffff) thisEUN = 0; -+ -+ while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) { -+ oob.start = (thisEUN * ERASESIZE) + (j * 512); -+ ioctl(fd, MEMREADOOB, &oob); -+ status = oobbuf.b.Status | oobbuf.b.Status1; -+ -+ switch (status) { -+ case SECTOR_FREE: -+ /* This is still free. Don't look any more */ -+ thisEUN = 0; -+ break; -+ -+ case SECTOR_USED: -+ /* SECTOR_USED. This is a good one. */ -+ lastgoodEUN = thisEUN; -+ break; -+ } -+ -+ /* Find the next erase unit in this chain, if any */ -+ if (thisEUN) -+ thisEUN = nextEUN(thisEUN) & 0x7fff; -+ } -+ -+ if (lastgoodEUN == 0xffff) -+ memset(readbuf, 0, 512); -+ else -+ pread(fd, readbuf, 512, -+ (lastgoodEUN * ERASESIZE) + (j * 512)); -+ -+ write(ofd, readbuf, 512); -+ } -+ -+ } -+ } -+} -+ -+int main(int argc, char **argv) -+{ -+ if (argc < 2) { -+ printf("Usage: %s []\n", argv[0]); -+ exit(1); -+ } -+ fd = open(argv[1], O_RDONLY); -+ if (fd == -1) { -+ perror("open flash"); -+ exit (1); -+ } -+ -+ if (argc > 2) { -+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ofd == -1) -+ perror ("open outfile"); -+ } -+ -+ /* get size information of the MTD device */ -+ if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { -+ perror("ioctl(MEMGETINFO)"); -+ close(fd); -+ return 1; -+ } -+ -+ while (find_media_headers() != 0) { -+ dump_erase_units(); -+ dump_virtual_units(); -+ free(VUCtable); -+ } -+ -+ exit(0); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.c linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,390 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli -+ (C) 2002 David Woodhouse -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ linux/lib/rbtree.c -+*/ -+ -+#include -+#include "rbtree.h" -+ -+static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *right = node->rb_right; -+ struct rb_node *parent = rb_parent(node); -+ -+ if ((node->rb_right = right->rb_left)) -+ rb_set_parent(right->rb_left, node); -+ right->rb_left = node; -+ -+ rb_set_parent(right, parent); -+ -+ if (parent) -+ { -+ if (node == parent->rb_left) -+ parent->rb_left = right; -+ else -+ parent->rb_right = right; -+ } -+ else -+ root->rb_node = right; -+ rb_set_parent(node, right); -+} -+ -+static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *left = node->rb_left; -+ struct rb_node *parent = rb_parent(node); -+ -+ if ((node->rb_left = left->rb_right)) -+ rb_set_parent(left->rb_right, node); -+ left->rb_right = node; -+ -+ rb_set_parent(left, parent); -+ -+ if (parent) -+ { -+ if (node == parent->rb_right) -+ parent->rb_right = left; -+ else -+ parent->rb_left = left; -+ } -+ else -+ root->rb_node = left; -+ rb_set_parent(node, left); -+} -+ -+void rb_insert_color(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *parent, *gparent; -+ -+ while ((parent = rb_parent(node)) && rb_is_red(parent)) -+ { -+ gparent = rb_parent(parent); -+ -+ if (parent == gparent->rb_left) -+ { -+ { -+ register struct rb_node *uncle = gparent->rb_right; -+ if (uncle && rb_is_red(uncle)) -+ { -+ rb_set_black(uncle); -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_right == node) -+ { -+ register struct rb_node *tmp; -+ __rb_rotate_left(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ __rb_rotate_right(gparent, root); -+ } else { -+ { -+ register struct rb_node *uncle = gparent->rb_left; -+ if (uncle && rb_is_red(uncle)) -+ { -+ rb_set_black(uncle); -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_left == node) -+ { -+ register struct rb_node *tmp; -+ __rb_rotate_right(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ rb_set_black(parent); -+ rb_set_red(gparent); -+ __rb_rotate_left(gparent, root); -+ } -+ } -+ -+ rb_set_black(root->rb_node); -+} -+ -+static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, -+ struct rb_root *root) -+{ -+ struct rb_node *other; -+ -+ while ((!node || rb_is_black(node)) && node != root->rb_node) -+ { -+ if (parent->rb_left == node) -+ { -+ other = parent->rb_right; -+ if (rb_is_red(other)) -+ { -+ rb_set_black(other); -+ rb_set_red(parent); -+ __rb_rotate_left(parent, root); -+ other = parent->rb_right; -+ } -+ if ((!other->rb_left || rb_is_black(other->rb_left)) && -+ (!other->rb_right || rb_is_black(other->rb_right))) -+ { -+ rb_set_red(other); -+ node = parent; -+ parent = rb_parent(node); -+ } -+ else -+ { -+ if (!other->rb_right || rb_is_black(other->rb_right)) -+ { -+ struct rb_node *o_left; -+ if ((o_left = other->rb_left)) -+ rb_set_black(o_left); -+ rb_set_red(other); -+ __rb_rotate_right(other, root); -+ other = parent->rb_right; -+ } -+ rb_set_color(other, rb_color(parent)); -+ rb_set_black(parent); -+ if (other->rb_right) -+ rb_set_black(other->rb_right); -+ __rb_rotate_left(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ else -+ { -+ other = parent->rb_left; -+ if (rb_is_red(other)) -+ { -+ rb_set_black(other); -+ rb_set_red(parent); -+ __rb_rotate_right(parent, root); -+ other = parent->rb_left; -+ } -+ if ((!other->rb_left || rb_is_black(other->rb_left)) && -+ (!other->rb_right || rb_is_black(other->rb_right))) -+ { -+ rb_set_red(other); -+ node = parent; -+ parent = rb_parent(node); -+ } -+ else -+ { -+ if (!other->rb_left || rb_is_black(other->rb_left)) -+ { -+ register struct rb_node *o_right; -+ if ((o_right = other->rb_right)) -+ rb_set_black(o_right); -+ rb_set_red(other); -+ __rb_rotate_left(other, root); -+ other = parent->rb_left; -+ } -+ rb_set_color(other, rb_color(parent)); -+ rb_set_black(parent); -+ if (other->rb_left) -+ rb_set_black(other->rb_left); -+ __rb_rotate_right(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ } -+ if (node) -+ rb_set_black(node); -+} -+ -+void rb_erase(struct rb_node *node, struct rb_root *root) -+{ -+ struct rb_node *child, *parent; -+ int color; -+ -+ if (!node->rb_left) -+ child = node->rb_right; -+ else if (!node->rb_right) -+ child = node->rb_left; -+ else -+ { -+ struct rb_node *old = node, *left; -+ -+ node = node->rb_right; -+ while ((left = node->rb_left) != NULL) -+ node = left; -+ child = node->rb_right; -+ parent = rb_parent(node); -+ color = rb_color(node); -+ -+ if (child) -+ rb_set_parent(child, parent); -+ if (parent == old) { -+ parent->rb_right = child; -+ parent = node; -+ } else -+ parent->rb_left = child; -+ -+ node->rb_parent_color = old->rb_parent_color; -+ node->rb_right = old->rb_right; -+ node->rb_left = old->rb_left; -+ -+ if (rb_parent(old)) -+ { -+ if (rb_parent(old)->rb_left == old) -+ rb_parent(old)->rb_left = node; -+ else -+ rb_parent(old)->rb_right = node; -+ } else -+ root->rb_node = node; -+ -+ rb_set_parent(old->rb_left, node); -+ if (old->rb_right) -+ rb_set_parent(old->rb_right, node); -+ goto color; -+ } -+ -+ parent = rb_parent(node); -+ color = rb_color(node); -+ -+ if (child) -+ rb_set_parent(child, parent); -+ if (parent) -+ { -+ if (parent->rb_left == node) -+ parent->rb_left = child; -+ else -+ parent->rb_right = child; -+ } -+ else -+ root->rb_node = child; -+ -+ color: -+ if (color == RB_BLACK) -+ __rb_erase_color(child, parent, root); -+} -+ -+/* -+ * This function returns the first node (in sort order) of the tree. -+ */ -+struct rb_node *rb_first(struct rb_root *root) -+{ -+ struct rb_node *n; -+ -+ n = root->rb_node; -+ if (!n) -+ return NULL; -+ while (n->rb_left) -+ n = n->rb_left; -+ return n; -+} -+ -+struct rb_node *rb_last(struct rb_root *root) -+{ -+ struct rb_node *n; -+ -+ n = root->rb_node; -+ if (!n) -+ return NULL; -+ while (n->rb_right) -+ n = n->rb_right; -+ return n; -+} -+ -+struct rb_node *rb_next(struct rb_node *node) -+{ -+ struct rb_node *parent; -+ -+ if (rb_parent(node) == node) -+ return NULL; -+ -+ /* If we have a right-hand child, go down and then left as far -+ as we can. */ -+ if (node->rb_right) { -+ node = node->rb_right; -+ while (node->rb_left) -+ node=node->rb_left; -+ return node; -+ } -+ -+ /* No right-hand children. Everything down and left is -+ smaller than us, so any 'next' node must be in the general -+ direction of our parent. Go up the tree; any time the -+ ancestor is a right-hand child of its parent, keep going -+ up. First time it's a left-hand child of its parent, said -+ parent is our 'next' node. */ -+ while ((parent = rb_parent(node)) && node == parent->rb_right) -+ node = parent; -+ -+ return parent; -+} -+ -+struct rb_node *rb_prev(struct rb_node *node) -+{ -+ struct rb_node *parent; -+ -+ if (rb_parent(node) == node) -+ return NULL; -+ -+ /* If we have a left-hand child, go down and then right as far -+ as we can. */ -+ if (node->rb_left) { -+ node = node->rb_left; -+ while (node->rb_right) -+ node=node->rb_right; -+ return node; -+ } -+ -+ /* No left-hand children. Go up till we find an ancestor which -+ is a right-hand child of its parent */ -+ while ((parent = rb_parent(node)) && node == parent->rb_left) -+ node = parent; -+ -+ return parent; -+} -+ -+void rb_replace_node(struct rb_node *victim, struct rb_node *new, -+ struct rb_root *root) -+{ -+ struct rb_node *parent = rb_parent(victim); -+ -+ /* Set the surrounding nodes to point to the replacement */ -+ if (parent) { -+ if (victim == parent->rb_left) -+ parent->rb_left = new; -+ else -+ parent->rb_right = new; -+ } else { -+ root->rb_node = new; -+ } -+ if (victim->rb_left) -+ rb_set_parent(victim->rb_left, new); -+ if (victim->rb_right) -+ rb_set_parent(victim->rb_right, new); -+ -+ /* Copy the pointers/colour from the victim to the replacement */ -+ *new = *victim; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.h linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rbtree.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rbtree.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ linux/include/linux/rbtree.h -+ -+ To use rbtrees you'll have to implement your own insert and search cores. -+ This will avoid us to use callbacks and to drop drammatically performances. -+ I know it's not the cleaner way, but in C (not in C++) to get -+ performances and genericity... -+ -+ Some example of insert and search follows here. The search is a plain -+ normal search over an ordered tree. The insert instead must be implemented -+ int two steps: as first thing the code must insert the element in -+ order as a red leaf in the tree, then the support library function -+ rb_insert_color() must be called. Such function will do the -+ not trivial work to rebalance the rbtree if necessary. -+ -+----------------------------------------------------------------------- -+static inline struct page * rb_search_page_cache(struct inode * inode, -+ unsigned long offset) -+{ -+ struct rb_node * n = inode->i_rb_page_cache.rb_node; -+ struct page * page; -+ -+ while (n) -+ { -+ page = rb_entry(n, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ n = n->rb_left; -+ else if (offset > page->offset) -+ n = n->rb_right; -+ else -+ return page; -+ } -+ return NULL; -+} -+ -+static inline struct page * __rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ struct rb_node * node) -+{ -+ struct rb_node ** p = &inode->i_rb_page_cache.rb_node; -+ struct rb_node * parent = NULL; -+ struct page * page; -+ -+ while (*p) -+ { -+ parent = *p; -+ page = rb_entry(parent, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ p = &(*p)->rb_left; -+ else if (offset > page->offset) -+ p = &(*p)->rb_right; -+ else -+ return page; -+ } -+ -+ rb_link_node(node, parent, p); -+ -+ return NULL; -+} -+ -+static inline struct page * rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ struct rb_node * node) -+{ -+ struct page * ret; -+ if ((ret = __rb_insert_page_cache(inode, offset, node))) -+ goto out; -+ rb_insert_color(node, &inode->i_rb_page_cache); -+ out: -+ return ret; -+} -+----------------------------------------------------------------------- -+*/ -+ -+#ifndef _LINUX_RBTREE_H -+#define _LINUX_RBTREE_H -+ -+#include -+#include -+ -+struct rb_node -+{ -+ unsigned long rb_parent_color; -+#define RB_RED 0 -+#define RB_BLACK 1 -+ struct rb_node *rb_right; -+ struct rb_node *rb_left; -+} __attribute__((aligned(sizeof(long)))); -+ /* The alignment might seem pointless, but allegedly CRIS needs it */ -+ -+struct rb_root -+{ -+ struct rb_node *rb_node; -+}; -+ -+ -+#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) -+#define rb_color(r) ((r)->rb_parent_color & 1) -+#define rb_is_red(r) (!rb_color(r)) -+#define rb_is_black(r) rb_color(r) -+#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) -+#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) -+ -+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) -+{ -+ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; -+} -+static inline void rb_set_color(struct rb_node *rb, int color) -+{ -+ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; -+} -+ -+#define RB_ROOT (struct rb_root) { NULL, } -+ -+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -+ -+#define container_of(ptr, type, member) ({ \ -+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ -+ (type *)( (char *)__mptr - offsetof(type,member) );}) -+ -+#define rb_entry(ptr, type, member) container_of(ptr, type, member) -+ -+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) -+#define RB_EMPTY_NODE(node) (rb_parent(node) == node) -+#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) -+ -+extern void rb_insert_color(struct rb_node *, struct rb_root *); -+extern void rb_erase(struct rb_node *, struct rb_root *); -+ -+/* Find logical next and previous nodes in a tree */ -+extern struct rb_node *rb_next(struct rb_node *); -+extern struct rb_node *rb_prev(struct rb_node *); -+extern struct rb_node *rb_first(struct rb_root *); -+extern struct rb_node *rb_last(struct rb_root *); -+ -+/* Fast replacement of a single node without remove/rebalance/add/rebalance */ -+extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, -+ struct rb_root *root); -+ -+static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, -+ struct rb_node ** rb_link) -+{ -+ node->rb_parent_color = (unsigned long )parent; -+ node->rb_left = node->rb_right = NULL; -+ -+ *rb_link = node; -+} -+ -+#endif /* _LINUX_RBTREE_H */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/recv_image.c linux-2.6.24.7/drivers/mtd/mtd-utils/recv_image.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/recv_image.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/recv_image.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,484 @@ -+ -+#define _XOPEN_SOURCE 500 -+#define _USE_MISC -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "mtd/mtd-user.h" -+#include "mcast_image.h" -+ -+#define min(x,y) ( (x)>(y)?(y):(x) ) -+ -+#define WBUF_SIZE 4096 -+struct eraseblock { -+ uint32_t flash_offset; -+ unsigned char wbuf[WBUF_SIZE]; -+ int wbuf_ofs; -+ int nr_pkts; -+ int *pkt_indices; -+ uint32_t crc; -+}; -+ -+int main(int argc, char **argv) -+{ -+ struct addrinfo *ai; -+ struct addrinfo hints; -+ struct addrinfo *runp; -+ int ret; -+ int sock; -+ size_t len; -+ int flfd; -+ struct mtd_info_user meminfo; -+ unsigned char *eb_buf, *decode_buf, **src_pkts; -+ int nr_blocks = 0; -+ int pkts_per_block; -+ int block_nr = -1; -+ uint32_t image_crc; -+ int total_pkts = 0; -+ int ignored_pkts = 0; -+ loff_t mtdoffset = 0; -+ int badcrcs = 0; -+ int duplicates = 0; -+ int file_mode = 0; -+ struct fec_parms *fec; -+ int i; -+ struct eraseblock *eraseblocks = NULL; -+ uint32_t start_seq; -+ struct timeval start, now; -+ unsigned long fec_time = 0, flash_time = 0, crc_time = 0, -+ rflash_time = 0, erase_time = 0, net_time = 0; -+ -+ if (argc != 4) { -+ fprintf(stderr, "usage: %s \n", -+ (strrchr(argv[0], '/')?:argv[0]-1)+1); -+ exit(1); -+ } -+ /* Open the device */ -+ flfd = open(argv[3], O_RDWR); -+ -+ if (flfd >= 0) { -+ /* Fill in MTD device capability structure */ -+ if (ioctl(flfd, MEMGETINFO, &meminfo) != 0) { -+ perror("MEMGETINFO"); -+ close(flfd); -+ flfd = -1; -+ } else { -+ printf("Receive to MTD device %s with erasesize %d\n", -+ argv[3], meminfo.erasesize); -+ } -+ } -+ if (flfd == -1) { -+ /* Try again, as if it's a file */ -+ flfd = open(argv[3], O_CREAT|O_TRUNC|O_RDWR, 0644); -+ if (flfd < 0) { -+ perror("open"); -+ exit(1); -+ } -+ meminfo.erasesize = 131072; -+ file_mode = 1; -+ printf("Receive to file %s with (assumed) erasesize %d\n", -+ argv[3], meminfo.erasesize); -+ } -+ -+ pkts_per_block = (meminfo.erasesize + PKT_SIZE - 1) / PKT_SIZE; -+ -+ eb_buf = malloc(pkts_per_block * PKT_SIZE); -+ decode_buf = malloc(pkts_per_block * PKT_SIZE); -+ if (!eb_buf && !decode_buf) { -+ fprintf(stderr, "No memory for eraseblock buffer\n"); -+ exit(1); -+ } -+ src_pkts = malloc(sizeof(unsigned char *) * pkts_per_block); -+ if (!src_pkts) { -+ fprintf(stderr, "No memory for decode packet pointers\n"); -+ exit(1); -+ } -+ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_flags = AI_ADDRCONFIG; -+ hints.ai_socktype = SOCK_DGRAM; -+ -+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai); -+ if (ret) { -+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); -+ exit(1); -+ } -+ runp = ai; -+ for (runp = ai; runp; runp = runp->ai_next) { -+ sock = socket(runp->ai_family, runp->ai_socktype, -+ runp->ai_protocol); -+ if (sock == -1) { -+ perror("socket"); -+ continue; -+ } -+ if (runp->ai_family == AF_INET && -+ IN_MULTICAST( ntohl(((struct sockaddr_in *)runp->ai_addr)->sin_addr.s_addr))) { -+ struct ip_mreq rq; -+ rq.imr_multiaddr = ((struct sockaddr_in *)runp->ai_addr)->sin_addr; -+ rq.imr_interface.s_addr = INADDR_ANY; -+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &rq, sizeof(rq))) { -+ perror("IP_ADD_MEMBERSHIP"); -+ close(sock); -+ continue; -+ } -+ -+ } else if (runp->ai_family == AF_INET6 && -+ ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr.s6_addr[0] == 0xff) { -+ struct ipv6_mreq rq; -+ rq.ipv6mr_multiaddr = ((struct sockaddr_in6 *)runp->ai_addr)->sin6_addr; -+ rq.ipv6mr_interface = 0; -+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &rq, sizeof(rq))) { -+ perror("IPV6_ADD_MEMBERSHIP"); -+ close(sock); -+ continue; -+ } -+ } -+ if (bind(sock, runp->ai_addr, runp->ai_addrlen)) { -+ perror("bind"); -+ close(sock); -+ continue; -+ } -+ break; -+ } -+ if (!runp) -+ exit(1); -+ -+ while (1) { -+ struct image_pkt thispkt; -+ -+ len = read(sock, &thispkt, sizeof(thispkt)); -+ -+ if (len < 0) { -+ perror("read socket"); -+ break; -+ } -+ if (len < sizeof(thispkt)) { -+ fprintf(stderr, "Wrong length %d bytes (expected %d)\n", -+ len, sizeof(thispkt)); -+ continue; -+ } -+ if (!eraseblocks) { -+ image_crc = thispkt.hdr.totcrc; -+ start_seq = ntohl(thispkt.hdr.pkt_sequence); -+ -+ if (meminfo.erasesize != ntohl(thispkt.hdr.blocksize)) { -+ fprintf(stderr, "Erasesize mismatch (0x%x not 0x%x)\n", -+ ntohl(thispkt.hdr.blocksize), meminfo.erasesize); -+ exit(1); -+ } -+ nr_blocks = ntohl(thispkt.hdr.nr_blocks); -+ -+ fec = fec_new(pkts_per_block, ntohs(thispkt.hdr.nr_pkts)); -+ -+ eraseblocks = malloc(nr_blocks * sizeof(*eraseblocks)); -+ if (!eraseblocks) { -+ fprintf(stderr, "No memory for block map\n"); -+ exit(1); -+ } -+ for (i = 0; i < nr_blocks; i++) { -+ eraseblocks[i].pkt_indices = malloc(sizeof(int) * pkts_per_block); -+ if (!eraseblocks[i].pkt_indices) { -+ fprintf(stderr, "Failed to allocate packet indices\n"); -+ exit(1); -+ } -+ eraseblocks[i].nr_pkts = 0; -+ if (!file_mode) { -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+#if 1 /* Deliberately use bad blocks... test write failures */ -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ } -+#endif -+ } -+ eraseblocks[i].flash_offset = mtdoffset; -+ mtdoffset += meminfo.erasesize; -+ eraseblocks[i].wbuf_ofs = 0; -+ } -+ gettimeofday(&start, NULL); -+ } -+ if (image_crc != thispkt.hdr.totcrc) { -+ fprintf(stderr, "\nImage CRC changed from 0x%x to 0x%x. Aborting\n", -+ ntohl(image_crc), ntohl(thispkt.hdr.totcrc)); -+ exit(1); -+ } -+ -+ block_nr = ntohl(thispkt.hdr.block_nr); -+ if (block_nr >= nr_blocks) { -+ fprintf(stderr, "\nErroneous block_nr %d (> %d)\n", -+ block_nr, nr_blocks); -+ exit(1); -+ } -+ for (i=0; i= pkts_per_block) { -+ /* We have a block which we didn't really need */ -+ eraseblocks[block_nr].nr_pkts++; -+ ignored_pkts++; -+ continue; -+ } -+ -+ if (crc32(-1, thispkt.data, PKT_SIZE) != ntohl(thispkt.hdr.thiscrc)) { -+ printf("\nDiscard %08x pkt %d with bad CRC (%08x not %08x)\n", -+ block_nr * meminfo.erasesize, ntohs(thispkt.hdr.pkt_nr), -+ crc32(-1, thispkt.data, PKT_SIZE), -+ ntohl(thispkt.hdr.thiscrc)); -+ badcrcs++; -+ continue; -+ } -+ pkt_again: -+ eraseblocks[block_nr].pkt_indices[eraseblocks[block_nr].nr_pkts++] = -+ ntohs(thispkt.hdr.pkt_nr); -+ total_pkts++; -+ if (!(total_pkts % 50) || total_pkts == pkts_per_block * nr_blocks) { -+ uint32_t pkts_sent = ntohl(thispkt.hdr.pkt_sequence) - start_seq + 1; -+ long time_msec; -+ gettimeofday(&now, NULL); -+ -+ time_msec = ((now.tv_usec - start.tv_usec) / 1000) + -+ (now.tv_sec - start.tv_sec) * 1000; -+ -+ printf("\rReceived %d/%d (%d%%) in %lds @%ldKiB/s, %d lost (%d%%), %d dup/xs ", -+ total_pkts, nr_blocks * pkts_per_block, -+ total_pkts * 100 / nr_blocks / pkts_per_block, -+ time_msec / 1000, -+ total_pkts * PKT_SIZE / 1024 * 1000 / time_msec, -+ pkts_sent - total_pkts - duplicates - ignored_pkts, -+ (pkts_sent - total_pkts - duplicates - ignored_pkts) * 100 / pkts_sent, -+ duplicates + ignored_pkts); -+ fflush(stdout); -+ } -+ -+ if (eraseblocks[block_nr].wbuf_ofs + PKT_SIZE < WBUF_SIZE) { -+ /* New packet doesn't full the wbuf */ -+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs, -+ thispkt.data, PKT_SIZE); -+ eraseblocks[block_nr].wbuf_ofs += PKT_SIZE; -+ } else { -+ int fits = WBUF_SIZE - eraseblocks[block_nr].wbuf_ofs; -+ ssize_t wrotelen; -+ static int faked = 1; -+ -+ memcpy(eraseblocks[block_nr].wbuf + eraseblocks[block_nr].wbuf_ofs, -+ thispkt.data, fits); -+ wrotelen = pwrite(flfd, eraseblocks[block_nr].wbuf, WBUF_SIZE, -+ eraseblocks[block_nr].flash_offset); -+ -+ if (wrotelen < WBUF_SIZE || (block_nr == 5 && eraseblocks[block_nr].nr_pkts == 5 && !faked)) { -+ faked = 1; -+ if (wrotelen < 0) -+ perror("\npacket write"); -+ else -+ fprintf(stderr, "\nshort write of packet wbuf\n"); -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ /* FIXME: Perhaps we should store pkt crcs and try -+ to recover data from the offending eraseblock */ -+ -+ /* We have increased nr_pkts but not yet flash_offset */ -+ erase.start = eraseblocks[block_nr].flash_offset & -+ ~(meminfo.erasesize - 1); -+ erase.length = meminfo.erasesize; -+ -+ printf("Will erase at %08lx len %08lx (bad write was at %08lx)\n", -+ erase.start, erase.length, eraseblocks[block_nr].flash_offset); -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ exit(1); -+ } -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ } -+ eraseblocks[block_nr].flash_offset = mtdoffset; -+ printf("Block #%d will now be at %08lx\n", block_nr, (long)mtdoffset); -+ total_pkts -= eraseblocks[block_nr].nr_pkts; -+ eraseblocks[block_nr].nr_pkts = 0; -+ eraseblocks[block_nr].wbuf_ofs = 0; -+ mtdoffset += meminfo.erasesize; -+ goto pkt_again; -+ } -+ else /* Usually nothing we can do in file mode */ -+ exit(1); -+ } -+ eraseblocks[block_nr].flash_offset += WBUF_SIZE; -+ /* Copy the remainder into the wbuf */ -+ memcpy(eraseblocks[block_nr].wbuf, &thispkt.data[fits], PKT_SIZE - fits); -+ eraseblocks[block_nr].wbuf_ofs = PKT_SIZE - fits; -+ } -+ -+ if (eraseblocks[block_nr].nr_pkts == pkts_per_block) { -+ eraseblocks[block_nr].crc = ntohl(thispkt.hdr.block_crc); -+ -+ if (total_pkts == nr_blocks * pkts_per_block) -+ break; -+ } -+ } -+ printf("\n"); -+ gettimeofday(&now, NULL); -+ net_time = (now.tv_usec - start.tv_usec) / 1000; -+ net_time += (now.tv_sec - start.tv_sec) * 1000; -+ close(sock); -+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) { -+ ssize_t rwlen; -+ gettimeofday(&start, NULL); -+ eraseblocks[block_nr].flash_offset -= meminfo.erasesize; -+ rwlen = pread(flfd, eb_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset); -+ -+ gettimeofday(&now, NULL); -+ rflash_time += (now.tv_usec - start.tv_usec) / 1000; -+ rflash_time += (now.tv_sec - start.tv_sec) * 1000; -+ if (rwlen < 0) { -+ perror("read"); -+ /* Argh. Perhaps we could go back and try again, but if the flash is -+ going to fail to read back what we write to it, and the whole point -+ in this program is to write to it, what's the point? */ -+ fprintf(stderr, "Packets we wrote to flash seem to be unreadable. Aborting\n"); -+ exit(1); -+ } -+ -+ memcpy(eb_buf + meminfo.erasesize, eraseblocks[block_nr].wbuf, -+ eraseblocks[block_nr].wbuf_ofs); -+ -+ for (i=0; i < pkts_per_block; i++) -+ src_pkts[i] = &eb_buf[i * PKT_SIZE]; -+ -+ gettimeofday(&start, NULL); -+ if (fec_decode(fec, src_pkts, eraseblocks[block_nr].pkt_indices, PKT_SIZE)) { -+ /* Eep. This cannot happen */ -+ printf("The world is broken. fec_decode() returned error\n"); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ fec_time += (now.tv_usec - start.tv_usec) / 1000; -+ fec_time += (now.tv_sec - start.tv_sec) * 1000; -+ -+ for (i=0; i < pkts_per_block; i++) -+ memcpy(&decode_buf[i*PKT_SIZE], src_pkts[i], PKT_SIZE); -+ -+ /* Paranoia */ -+ gettimeofday(&start, NULL); -+ if (crc32(-1, decode_buf, meminfo.erasesize) != eraseblocks[block_nr].crc) { -+ printf("\nCRC mismatch for block #%d: want %08x got %08x\n", -+ block_nr, eraseblocks[block_nr].crc, -+ crc32(-1, decode_buf, meminfo.erasesize)); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ crc_time += (now.tv_usec - start.tv_usec) / 1000; -+ crc_time += (now.tv_sec - start.tv_sec) * 1000; -+ start = now; -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ -+ erase.start = eraseblocks[block_nr].flash_offset; -+ erase.length = meminfo.erasesize; -+ -+ printf("\rErasing block at %08x...", erase.start); -+ -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ /* This block has dirty data on it. If the erase failed, we're screwed */ -+ fprintf(stderr, "Erase to clean FEC data from flash failed. Aborting\n"); -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ erase_time += (now.tv_usec - start.tv_usec) / 1000; -+ erase_time += (now.tv_sec - start.tv_sec) * 1000; -+ start = now; -+ } -+ else printf("\r"); -+ write_again: -+ rwlen = pwrite(flfd, decode_buf, meminfo.erasesize, eraseblocks[block_nr].flash_offset); -+ if (rwlen < meminfo.erasesize) { -+ if (rwlen < 0) { -+ perror("\ndecoded data write"); -+ } else -+ fprintf(stderr, "\nshort write of decoded data\n"); -+ -+ if (!file_mode) { -+ struct erase_info_user erase; -+ erase.start = eraseblocks[block_nr].flash_offset; -+ erase.length = meminfo.erasesize; -+ -+ printf("Erasing failed block at %08x\n", -+ eraseblocks[block_nr].flash_offset); -+ -+ if (ioctl(flfd, MEMERASE, &erase)) { -+ perror("MEMERASE"); -+ exit(1); -+ } -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ while (ioctl(flfd, MEMGETBADBLOCK, &mtdoffset) > 0) { -+ printf("Skipping flash bad block at %08x\n", (uint32_t)mtdoffset); -+ mtdoffset += meminfo.erasesize; -+ if (mtdoffset >= meminfo.size) { -+ fprintf(stderr, "Run out of space on flash\n"); -+ exit(1); -+ } -+ } -+ printf("Will try again at %08lx...", (long)mtdoffset); -+ eraseblocks[block_nr].flash_offset = mtdoffset; -+ -+ goto write_again; -+ } -+ else /* Usually nothing we can do in file mode */ -+ exit(1); -+ } -+ gettimeofday(&now, NULL); -+ flash_time += (now.tv_usec - start.tv_usec) / 1000; -+ flash_time += (now.tv_sec - start.tv_sec) * 1000; -+ -+ printf("wrote image block %08x (%d pkts) ", -+ block_nr * meminfo.erasesize, eraseblocks[block_nr].nr_pkts); -+ fflush(stdout); -+ } -+ close(flfd); -+ printf("Net rx %ld.%03lds\n", net_time / 1000, net_time % 1000); -+ printf("flash rd %ld.%03lds\n", rflash_time / 1000, rflash_time % 1000); -+ printf("FEC time %ld.%03lds\n", fec_time / 1000, fec_time % 1000); -+ printf("CRC time %ld.%03lds\n", crc_time / 1000, crc_time % 1000); -+ printf("flash wr %ld.%03lds\n", flash_time / 1000, flash_time % 1000); -+ printf("flash er %ld.%03lds\n", erase_time / 1000, erase_time % 1000); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/rfddump.c linux-2.6.24.7/drivers/mtd/mtd-utils/rfddump.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/rfddump.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/rfddump.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,336 @@ -+/* -+ * rfddump.c -+ * -+ * Copyright (C) 2005 Sean Young -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* next is an array of mapping for each corresponding sector */ -+#define RFD_MAGIC 0x9193 -+#define HEADER_MAP_OFFSET 3 -+#define SECTOR_DELETED 0x0000 -+#define SECTOR_ZERO 0xfffe -+#define SECTOR_FREE 0xffff -+ -+#define SECTOR_SIZE 512 -+ -+#define SECTORS_PER_TRACK 63 -+ -+ -+struct rfd { -+ int block_size; -+ int block_count; -+ int header_sectors; -+ int data_sectors; -+ int header_size; -+ uint16_t *header; -+ int sector_count; -+ int *sector_map; -+ const char *mtd_filename; -+ const char *out_filename; -+ int verbose; -+}; -+ -+#define PROGRAM "rfddump" -+#define VERSION "$Revision 1.0 $" -+ -+void display_help(void) -+{ -+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device filename\n" -+ "Dumps the contents of a resident flash disk\n" -+ "\n" -+ "-h --help display this help and exit\n" -+ "-V --version output version information and exit\n" -+ "-v --verbose Be verbose\n" -+ "-b size --blocksize Block size (defaults to erase unit)\n"); -+ exit(0); -+} -+ -+void display_version(void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "This is free software; see the source for copying conditions. There is NO\n" -+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); -+ -+ exit(0); -+} -+ -+void process_options(int argc, char *argv[], struct rfd *rfd) -+{ -+ int error = 0; -+ -+ rfd->block_size = 0; -+ rfd->verbose = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hvVb:"; -+ static const struct option long_options[] = { -+ { "help", no_argument, 0, 'h' }, -+ { "version", no_argument, 0, 'V', }, -+ { "blocksize", required_argument, 0, 'b' }, -+ { "verbose", no_argument, 0, 'v' }, -+ { NULL, 0, 0, 0 } -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) -+ break; -+ -+ switch (c) { -+ case 'h': -+ display_help(); -+ break; -+ case 'V': -+ display_version(); -+ break; -+ case 'v': -+ rfd->verbose = 1; -+ break; -+ case 'b': -+ rfd->block_size = atoi(optarg); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 2 || error) -+ display_help(); -+ -+ rfd->mtd_filename = argv[optind]; -+ rfd->out_filename = argv[optind + 1]; -+} -+ -+int build_block_map(struct rfd *rfd, int fd, int block) -+{ -+ int i; -+ int sectors; -+ -+ if (pread(fd, rfd->header, rfd->header_size, block * rfd->block_size) -+ != rfd->header_size) { -+ return -1; -+ } -+ -+ if (le16_to_cpu(rfd->header[0]) != RFD_MAGIC) { -+ if (rfd->verbose) -+ printf("Block #%02d: Magic missing\n", block); -+ -+ return 0; -+ } -+ -+ sectors = 0; -+ for (i=0; idata_sectors; i++) { -+ uint16_t entry = le16_to_cpu(rfd->header[i + HEADER_MAP_OFFSET]); -+ -+ if (entry == SECTOR_FREE || entry == SECTOR_DELETED) -+ continue; -+ -+ if (entry == SECTOR_ZERO) -+ entry = 0; -+ -+ if (entry >= rfd->sector_count) { -+ fprintf(stderr, "%s: warning: sector %d out of range\n", -+ rfd->mtd_filename, entry); -+ continue; -+ } -+ -+ if (rfd->sector_map[entry] != -1) { -+ fprintf(stderr, "%s: warning: more than one entry " -+ "for sector %d\n", rfd->mtd_filename, entry); -+ continue; -+ } -+ -+ rfd->sector_map[entry] = rfd->block_size * block + -+ (i + rfd->header_sectors) * SECTOR_SIZE; -+ sectors++; -+ } -+ -+ if (rfd->verbose) -+ printf("Block #%02d: %d sectors\n", block, sectors); -+ -+ return 1; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int fd, sectors_per_block; -+ mtd_info_t mtd_info; -+ struct rfd rfd; -+ int i, blocks_found; -+ int out_fd = 0; -+ uint8_t sector[512]; -+ int blank, rc, cylinders; -+ -+ process_options(argc, argv, &rfd); -+ -+ fd = open(rfd.mtd_filename, O_RDONLY); -+ if (fd == -1) { -+ perror(rfd.mtd_filename); -+ return 1; -+ } -+ -+ if (rfd.block_size == 0) { -+ if (ioctl(fd, MEMGETINFO, &mtd_info)) { -+ perror(rfd.mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (mtd_info.type != MTD_NORFLASH) { -+ fprintf(stderr, "%s: wrong type\n", rfd.mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ sectors_per_block = mtd_info.erasesize / SECTOR_SIZE; -+ -+ rfd.block_size = mtd_info.erasesize; -+ rfd.block_count = mtd_info.size / mtd_info.erasesize; -+ } else { -+ struct stat st; -+ -+ if (fstat(fd, &st) == -1) { -+ perror(rfd.mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (st.st_size % SECTOR_SIZE) -+ fprintf(stderr, "%s: warning: not a multiple of sectors (512 bytes)\n", rfd.mtd_filename); -+ -+ sectors_per_block = rfd.block_size / SECTOR_SIZE; -+ -+ if (st.st_size % rfd.block_size) -+ fprintf(stderr, "%s: warning: not a multiple of block size\n", rfd.mtd_filename); -+ -+ rfd.block_count = st.st_size / rfd.block_size; -+ -+ if (!rfd.block_count) { -+ fprintf(stderr, "%s: not large enough for one block\n", rfd.mtd_filename); -+ close(fd); -+ return 2; -+ } -+ } -+ -+ rfd.header_sectors = -+ ((HEADER_MAP_OFFSET + sectors_per_block) * -+ sizeof(uint16_t) + SECTOR_SIZE - 1) / SECTOR_SIZE; -+ rfd.data_sectors = sectors_per_block - rfd.header_sectors; -+ cylinders = ((rfd.block_count - 1) * rfd.data_sectors - 1) -+ / SECTORS_PER_TRACK; -+ rfd.sector_count = cylinders * SECTORS_PER_TRACK; -+ rfd.header_size = -+ (HEADER_MAP_OFFSET + rfd.data_sectors) * sizeof(uint16_t); -+ -+ rfd.header = malloc(rfd.header_size); -+ if (!rfd.header) { -+ perror(PROGRAM); -+ close(fd); -+ return 2; -+ } -+ rfd.sector_map = malloc(rfd.sector_count * sizeof(int)); -+ if (!rfd.sector_map) { -+ perror(PROGRAM); -+ close(fd); -+ free(rfd.sector_map); -+ return 2; -+ } -+ -+ rfd.mtd_filename = rfd.mtd_filename; -+ -+ for (i=0; i 0) -+ blocks_found++; -+ if (rc < 0) -+ goto err; -+ } -+ -+ if (!blocks_found) { -+ fprintf(stderr, "%s: no RFD blocks found\n", rfd.mtd_filename); -+ goto err; -+ } -+ -+ for (i=0; i -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This is very easy: just erase all the blocks and put the magic at -+ * the beginning of each block. -+ */ -+ -+#define _XOPEN_SOURCE 500 /* For pread/pwrite */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define PROGRAM "rfdformat" -+#define VERSION "$Revision 1.0 $" -+ -+void display_help(void) -+{ -+ printf("Usage: " PROGRAM " [OPTIONS] MTD-device\n" -+ "Formats NOR flash for resident flash disk\n" -+ "\n" -+ "-h --help display this help and exit\n" -+ "-V --version output version information and exit\n"); -+ exit(0); -+} -+ -+void display_version(void) -+{ -+ printf(PROGRAM " " VERSION "\n" -+ "\n" -+ "This is free software; see the source for copying conditions. There is NO\n" -+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); -+ -+ exit(0); -+} -+ -+void process_options(int argc, char *argv[], const char **mtd_filename) -+{ -+ int error = 0; -+ -+ for (;;) { -+ int option_index = 0; -+ static const char *short_options = "hV"; -+ static const struct option long_options[] = { -+ { "help", no_argument, 0, 'h' }, -+ { "version", no_argument, 0, 'V', }, -+ { NULL, 0, 0, 0 } -+ }; -+ -+ int c = getopt_long(argc, argv, short_options, -+ long_options, &option_index); -+ if (c == EOF) -+ break; -+ -+ switch (c) { -+ case 'h': -+ display_help(); -+ break; -+ case 'V': -+ display_version(); -+ break; -+ case '?': -+ error = 1; -+ break; -+ } -+ } -+ -+ if ((argc - optind) != 1 || error) -+ display_help(); -+ -+ *mtd_filename = argv[optind]; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ static const uint8_t magic[] = { 0x93, 0x91 }; -+ int fd, block_count, i; -+ struct mtd_info_user mtd_info; -+ char buf[512]; -+ const char *mtd_filename; -+ -+ process_options(argc, argv, &mtd_filename); -+ -+ fd = open(mtd_filename, O_RDWR); -+ if (fd == -1) { -+ perror(mtd_filename); -+ return 1; -+ } -+ -+ if (ioctl(fd, MEMGETINFO, &mtd_info)) { -+ perror(mtd_filename); -+ close(fd); -+ return 1; -+ } -+ -+ if (mtd_info.type != MTD_NORFLASH) { -+ fprintf(stderr, "%s: not NOR flash\n", mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ if (mtd_info.size > 32*1024*1024) { -+ fprintf(stderr, "%s: flash larger than 32MiB not supported\n", -+ mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ block_count = mtd_info.size / mtd_info.erasesize; -+ -+ if (block_count < 2) { -+ fprintf(stderr, "%s: at least two erase units required\n", -+ mtd_filename); -+ close(fd); -+ return 2; -+ } -+ -+ for (i=0; i -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "mcast_image.h" -+ -+int tx_rate = 80000; -+int pkt_delay; -+ -+#undef RANDOMDROP -+ -+int main(int argc, char **argv) -+{ -+ struct addrinfo *ai; -+ struct addrinfo hints; -+ struct addrinfo *runp; -+ int ret; -+ int sock; -+ struct image_pkt pktbuf; -+ int rfd; -+ struct stat st; -+ int writeerrors = 0; -+ uint32_t erasesize; -+ unsigned char *image, *blockptr = NULL; -+ uint32_t block_nr, pkt_nr; -+ int nr_blocks; -+ struct timeval then, now, nextpkt; -+ long time_msecs; -+ int pkts_per_block; -+ int total_pkts_per_block; -+ struct fec_parms *fec; -+ unsigned char *last_block; -+ uint32_t *block_crcs; -+ long tosleep; -+ uint32_t sequence = 0; -+ -+ if (argc == 6) { -+ tx_rate = atol(argv[5]) * 1024; -+ if (tx_rate < PKT_SIZE || tx_rate > 20000000) { -+ fprintf(stderr, "Bogus TX rate %d KiB/s\n", tx_rate); -+ exit(1); -+ } -+ argc = 5; -+ } -+ if (argc != 5) { -+ fprintf(stderr, "usage: %s []\n", -+ (strrchr(argv[0], '/')?:argv[0]-1)+1); -+ exit(1); -+ } -+ pkt_delay = (sizeof(pktbuf) * 1000000) / tx_rate; -+ printf("Inter-packet delay (avg): %dµs\n", pkt_delay); -+ printf("Transmit rate: %d KiB/s\n", tx_rate / 1024); -+ -+ erasesize = atol(argv[4]); -+ if (!erasesize) { -+ fprintf(stderr, "erasesize cannot be zero\n"); -+ exit(1); -+ } -+ -+ pkts_per_block = (erasesize + PKT_SIZE - 1) / PKT_SIZE; -+ total_pkts_per_block = pkts_per_block * 3 / 2; -+ -+ /* We have to pad it with zeroes, so can't use it in-place */ -+ last_block = malloc(pkts_per_block * PKT_SIZE); -+ if (!last_block) { -+ fprintf(stderr, "Failed to allocate last-block buffer\n"); -+ exit(1); -+ } -+ -+ fec = fec_new(pkts_per_block, total_pkts_per_block); -+ if (!fec) { -+ fprintf(stderr, "Error initialising FEC\n"); -+ exit(1); -+ } -+ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_flags = AI_ADDRCONFIG; -+ hints.ai_socktype = SOCK_DGRAM; -+ -+ ret = getaddrinfo(argv[1], argv[2], &hints, &ai); -+ if (ret) { -+ fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); -+ exit(1); -+ } -+ runp = ai; -+ for (runp = ai; runp; runp = runp->ai_next) { -+ sock = socket(runp->ai_family, runp->ai_socktype, -+ runp->ai_protocol); -+ if (sock == -1) { -+ perror("socket"); -+ continue; -+ } -+ if (connect(sock, runp->ai_addr, runp->ai_addrlen) == 0) -+ break; -+ perror("connect"); -+ close(sock); -+ } -+ if (!runp) -+ exit(1); -+ -+ rfd = open(argv[3], O_RDONLY); -+ if (rfd < 0) { -+ perror("open"); -+ exit(1); -+ } -+ -+ if (fstat(rfd, &st)) { -+ perror("fstat"); -+ exit(1); -+ } -+ -+ if (st.st_size % erasesize) { -+ fprintf(stderr, "Image size %ld bytes is not a multiple of erasesize %d bytes\n", -+ st.st_size, erasesize); -+ exit(1); -+ } -+ image = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, rfd, 0); -+ if (image == MAP_FAILED) { -+ perror("mmap"); -+ exit(1); -+ } -+ -+ nr_blocks = st.st_size / erasesize; -+ -+ block_crcs = malloc(nr_blocks * sizeof(uint32_t)); -+ if (!block_crcs) { -+ fprintf(stderr, "Failed to allocate memory for CRCs\n"); -+ exit(1); -+ } -+ -+ memcpy(last_block, image + (nr_blocks - 1) * erasesize, erasesize); -+ memset(last_block + erasesize, 0, (PKT_SIZE * pkts_per_block) - erasesize); -+ -+ printf("Checking CRC...."); -+ fflush(stdout); -+ -+ pktbuf.hdr.resend = 0; -+ pktbuf.hdr.totcrc = htonl(crc32(-1, image, st.st_size)); -+ pktbuf.hdr.nr_blocks = htonl(nr_blocks); -+ pktbuf.hdr.blocksize = htonl(erasesize); -+ pktbuf.hdr.thislen = htonl(PKT_SIZE); -+ pktbuf.hdr.nr_pkts = htons(total_pkts_per_block); -+ -+ printf("%08x\n", ntohl(pktbuf.hdr.totcrc)); -+ printf("Checking block CRCs...."); -+ fflush(stdout); -+ for (block_nr=0; block_nr < nr_blocks; block_nr++) { -+ printf("\rChecking block CRCS.... %d/%d", -+ block_nr + 1, nr_blocks); -+ fflush(stdout); -+ block_crcs[block_nr] = crc32(-1, image + (block_nr * erasesize), erasesize); -+ } -+ -+ printf("\nImage size %ld KiB (0x%08lx). %d blocks at %d pkts/block\n" -+ "Estimated transmit time per cycle: %ds\n", -+ (long)st.st_size / 1024, (long) st.st_size, -+ nr_blocks, pkts_per_block, -+ nr_blocks * pkts_per_block * pkt_delay / 1000000); -+ gettimeofday(&then, NULL); -+ nextpkt = then; -+ -+#ifdef RANDOMDROP -+ srand((unsigned)then.tv_usec); -+ printf("Random seed %u\n", (unsigned)then.tv_usec); -+#endif -+ while (1) for (pkt_nr=0; pkt_nr < total_pkts_per_block; pkt_nr++) { -+ -+ if (blockptr && pkt_nr == 0) { -+ unsigned long amt_sent = total_pkts_per_block * nr_blocks * sizeof(pktbuf); -+ gettimeofday(&now, NULL); -+ -+ time_msecs = (now.tv_sec - then.tv_sec) * 1000; -+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000; -+ printf("\n%ld KiB sent in %ldms (%ld KiB/s)\n", -+ amt_sent / 1024, time_msecs, -+ amt_sent / 1024 * 1000 / time_msecs); -+ then = now; -+ } -+ -+ for (block_nr = 0; block_nr < nr_blocks; block_nr++) { -+ -+ int actualpkt; -+ -+ /* Calculating the redundant FEC blocks is expensive; -+ the first $pkts_per_block are cheap enough though -+ because they're just copies. So alternate between -+ simple and complex stuff, so that we don't start -+ to choke and fail to keep up with the expected -+ bitrate in the second half of the sequence */ -+ if (block_nr & 1) -+ actualpkt = pkt_nr; -+ else -+ actualpkt = total_pkts_per_block - 1 - pkt_nr; -+ -+ blockptr = image + (erasesize * block_nr); -+ if (block_nr == nr_blocks - 1) -+ blockptr = last_block; -+ -+ fec_encode_linear(fec, blockptr, pktbuf.data, actualpkt, PKT_SIZE); -+ -+ pktbuf.hdr.thiscrc = htonl(crc32(-1, pktbuf.data, PKT_SIZE)); -+ pktbuf.hdr.block_crc = htonl(block_crcs[block_nr]); -+ pktbuf.hdr.block_nr = htonl(block_nr); -+ pktbuf.hdr.pkt_nr = htons(actualpkt); -+ pktbuf.hdr.pkt_sequence = htonl(sequence++); -+ -+ printf("\rSending data block %08x packet %3d/%d", -+ block_nr * erasesize, -+ pkt_nr, total_pkts_per_block); -+ -+ if (pkt_nr && !block_nr) { -+ unsigned long amt_sent = pkt_nr * nr_blocks * sizeof(pktbuf); -+ -+ gettimeofday(&now, NULL); -+ -+ time_msecs = (now.tv_sec - then.tv_sec) * 1000; -+ time_msecs += ((int)(now.tv_usec - then.tv_usec)) / 1000; -+ printf(" (%ld KiB/s) ", -+ amt_sent / 1024 * 1000 / time_msecs); -+ } -+ -+ fflush(stdout); -+ -+#ifdef RANDOMDROP -+ if ((rand() % 1000) < 20) { -+ printf("\nDropping packet %d of block %08x\n", pkt_nr+1, block_nr * erasesize); -+ continue; -+ } -+#endif -+ gettimeofday(&now, NULL); -+#if 1 -+ tosleep = nextpkt.tv_usec - now.tv_usec + -+ (1000000 * (nextpkt.tv_sec - now.tv_sec)); -+ -+ /* We need hrtimers for this to actually work */ -+ if (tosleep > 0) { -+ struct timespec req; -+ -+ req.tv_nsec = (tosleep % 1000000) * 1000; -+ req.tv_sec = tosleep / 1000000; -+ -+ nanosleep(&req, NULL); -+ } -+#else -+ while (now.tv_sec < nextpkt.tv_sec || -+ (now.tv_sec == nextpkt.tv_sec && -+ now.tv_usec < nextpkt.tv_usec)) { -+ gettimeofday(&now, NULL); -+ } -+#endif -+ nextpkt.tv_usec += pkt_delay; -+ if (nextpkt.tv_usec >= 1000000) { -+ nextpkt.tv_sec += nextpkt.tv_usec / 1000000; -+ nextpkt.tv_usec %= 1000000; -+ } -+ -+ /* If the time for the next packet has already -+ passed (by some margin), then we've lost time -+ Adjust our expected timings accordingly. If -+ we're only a little way behind, don't slip yet */ -+ if (now.tv_usec > (now.tv_usec + (5 * pkt_delay) + -+ 1000000 * (nextpkt.tv_sec - now.tv_sec))) { -+ nextpkt = now; -+ } -+ -+ if (write(sock, &pktbuf, sizeof(pktbuf)) < 0) { -+ perror("write"); -+ writeerrors++; -+ if (writeerrors > 10) { -+ fprintf(stderr, "Too many consecutive write errors\n"); -+ exit(1); -+ } -+ } else -+ writeerrors = 0; -+ -+ -+ -+ } -+ } -+ munmap(image, st.st_size); -+ close(rfd); -+ close(sock); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/summary.h linux-2.6.24.7/drivers/mtd/mtd-utils/summary.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/summary.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/summary.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,178 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2004 Ferenc Havasi , -+ * Zoltan Sogor , -+ * Patrik Kluba , -+ * University of Szeged, Hungary -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ */ -+ -+#ifndef JFFS2_SUMMARY_H -+#define JFFS2_SUMMARY_H -+ -+#include -+#include -+ -+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->dirty_size += _x; \ -+ jeb->free_size -= _x ; jeb->dirty_size += _x; \ -+}while(0) -+#define USED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->used_size += _x; \ -+ jeb->free_size -= _x ; jeb->used_size += _x; \ -+}while(0) -+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->wasted_size += _x; \ -+ jeb->free_size -= _x ; jeb->wasted_size += _x; \ -+}while(0) -+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->unchecked_size += _x; \ -+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \ -+}while(0) -+ -+#define BLK_STATE_ALLFF 0 -+#define BLK_STATE_CLEAN 1 -+#define BLK_STATE_PARTDIRTY 2 -+#define BLK_STATE_CLEANMARKER 3 -+#define BLK_STATE_ALLDIRTY 4 -+#define BLK_STATE_BADBLOCK 5 -+ -+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff -+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) -+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) -+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) -+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) -+ -+/* Summary structures used on flash */ -+ -+struct jffs2_sum_unknown_flash -+{ -+ jint16_t nodetype; /* node type */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_inode_flash -+{ -+ jint16_t nodetype; /* node type */ -+ jint32_t inode; /* inode number */ -+ jint32_t version; /* inode version */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* record length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_dirent_flash -+{ -+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ -+ jint32_t totlen; /* record length */ -+ jint32_t offset; /* ofset on jeb */ -+ jint32_t pino; /* parent inode */ -+ jint32_t version; /* dirent version */ -+ jint32_t ino; /* == zero for unlink */ -+ uint8_t nsize; /* dirent name size */ -+ uint8_t type; /* dirent type */ -+ uint8_t name[0]; /* dirent name */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xattr_flash -+{ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */ -+ jint32_t xid; /* xattr identifier */ -+ jint32_t version; /* version number */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* node length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xref_flash -+{ -+ jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */ -+ jint32_t offset; /* offset on jeb */ -+} __attribute__((packed)); -+ -+union jffs2_sum_flash -+{ -+ struct jffs2_sum_unknown_flash u; -+ struct jffs2_sum_inode_flash i; -+ struct jffs2_sum_dirent_flash d; -+ struct jffs2_sum_xattr_flash x; -+ struct jffs2_sum_xref_flash r; -+}; -+ -+/* Summary structures used in the memory */ -+ -+struct jffs2_sum_unknown_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* node type */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_inode_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* node type */ -+ jint32_t inode; /* inode number */ -+ jint32_t version; /* inode version */ -+ jint32_t offset; /* offset on jeb */ -+ jint32_t totlen; /* record length */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_dirent_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ -+ jint32_t totlen; /* record length */ -+ jint32_t offset; /* ofset on jeb */ -+ jint32_t pino; /* parent inode */ -+ jint32_t version; /* dirent version */ -+ jint32_t ino; /* == zero for unlink */ -+ uint8_t nsize; /* dirent name size */ -+ uint8_t type; /* dirent type */ -+ uint8_t name[0]; /* dirent name */ -+} __attribute__((packed)); -+ -+struct jffs2_sum_xattr_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; -+ jint32_t xid; -+ jint32_t version; -+ jint32_t offset; -+ jint32_t totlen; -+} __attribute__((packed)); -+ -+struct jffs2_sum_xref_mem -+{ -+ union jffs2_sum_mem *next; -+ jint16_t nodetype; -+ jint32_t offset; -+} __attribute__((packed)); -+ -+union jffs2_sum_mem -+{ -+ struct jffs2_sum_unknown_mem u; -+ struct jffs2_sum_inode_mem i; -+ struct jffs2_sum_dirent_mem d; -+ struct jffs2_sum_xattr_mem x; -+ struct jffs2_sum_xref_mem r; -+}; -+ -+struct jffs2_summary -+{ -+ uint32_t sum_size; -+ uint32_t sum_num; -+ uint32_t sum_padded; -+ union jffs2_sum_mem *sum_list_head; -+ union jffs2_sum_mem *sum_list_tail; -+}; -+ -+/* Summary marker is stored at the end of every sumarized erase block */ -+ -+struct jffs2_sum_marker -+{ -+ jint32_t offset; /* offset of the summary node in the jeb */ -+ jint32_t magic; /* == JFFS2_SUM_MAGIC */ -+}; -+ -+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/sumtool.c linux-2.6.24.7/drivers/mtd/mtd-utils/sumtool.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/sumtool.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/sumtool.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,951 @@ -+/* -+ * sumtool.c -+ * -+ * Copyright (C) 2004 Zoltan Sogor , -+ * Ferenc Havasi -+ * University of Szeged, Hungary -+ * 2006 KaiGai Kohei -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Overview: -+ * This is a utility insert summary information into JFFS2 image for -+ * faster mount time -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "summary.h" -+ -+#define PAD(x) (((x)+3)&~3) -+ -+static const char *const app_name = "sumtool"; -+ -+static struct jffs2_summary *sum_collected = NULL; -+ -+static int verbose = 0; -+static int padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */ -+static int add_cleanmarkers = 1; /* add cleanmarker to output */ -+static int use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */ -+static int found_cleanmarkers = 0; /* cleanmarker found in input file */ -+static struct jffs2_unknown_node cleanmarker; -+static int cleanmarker_size = sizeof(cleanmarker); -+static const char *short_options = "o:i:e:hvVblnc:p"; -+static int erase_block_size = 65536; -+static int out_fd = -1; -+static int in_fd = -1; -+ -+static uint8_t *data_buffer = NULL; /* buffer for inodes */ -+static unsigned int data_ofs = 0; /* inode buffer offset */ -+ -+static uint8_t *file_buffer = NULL; /* file buffer contains the actual erase block*/ -+static unsigned int file_ofs = 0; /* position in the buffer */ -+ -+int target_endian = __BYTE_ORDER; -+ -+static struct option long_options[] = { -+ {"output", 1, NULL, 'o'}, -+ {"input", 1, NULL, 'i'}, -+ {"eraseblock", 1, NULL, 'e'}, -+ {"help", 0, NULL, 'h'}, -+ {"verbose", 0, NULL, 'v'}, -+ {"version", 0, NULL, 'V'}, -+ {"bigendian", 0, NULL, 'b'}, -+ {"littleendian", 0, NULL, 'l'}, -+ {"no-cleanmarkers", 0, NULL, 'n'}, -+ {"cleanmarker", 1, NULL, 'c'}, -+ {"pad", 0, NULL, 'p'}, -+ {NULL, 0, NULL, 0} -+}; -+ -+static char *helptext = -+"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n" -+"Convert the input JFFS2 image to a summarized JFFS2 image\n" -+"Summary makes mounting faster - if summary support enabled in your kernel\n\n" -+"Options:\n" -+" -e, --eraseblock=SIZE Use erase block size SIZE (default: 64KiB)\n" -+" (usually 16KiB on NAND)\n" -+" -c, --cleanmarker=SIZE Size of cleanmarker (default 12).\n" -+" (usually 16 bytes on NAND, and will be set to\n" -+" this value if left at the default 12). Will be\n" -+" stored in OOB after each physical page composing\n" -+" a physical eraseblock.\n" -+" -n, --no-cleanmarkers Don't add a cleanmarker to every eraseblock\n" -+" -o, --output=FILE Output to FILE \n" -+" -i, --input=FILE Input from FILE \n" -+" -b, --bigendian Image is big endian\n" -+" -l --littleendian Image is little endian\n" -+" -h, --help Display this help text\n" -+" -v, --verbose Verbose operation\n" -+" -V, --version Display version information\n" -+" -p, --pad Pad the OUTPUT with 0xFF to the end of the final\n" -+" eraseblock\n\n"; -+ -+ -+static char *revtext = "$Revision: 1.1.1.1 $"; -+ -+static unsigned char ffbuf[16] = { -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+ -+static void verror_msg(const char *s, va_list p) -+{ -+ fflush(stdout); -+ fprintf(stderr, "%s: ", app_name); -+ vfprintf(stderr, s, p); -+} -+ -+static void error_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ verror_msg(s, p); -+ va_end(p); -+ putc('\n', stderr); -+ exit(EXIT_FAILURE); -+} -+ -+static void vperror_msg(const char *s, va_list p) -+{ -+ int err = errno; -+ -+ if (s == 0) -+ s = ""; -+ verror_msg(s, p); -+ if (*s) -+ s = ": "; -+ fprintf(stderr, "%s%s\n", s, strerror(err)); -+} -+ -+static void perror_msg_and_die(const char *s, ...) -+{ -+ va_list p; -+ -+ va_start(p, s); -+ vperror_msg(s, p); -+ va_end(p); -+ exit(EXIT_FAILURE); -+} -+ -+ -+ -+static void full_write(void *target_buff, const void *buf, int len); -+ -+void setup_cleanmarker() -+{ -+ cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); -+ cleanmarker.totlen = cpu_to_je32(cleanmarker_size); -+ cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4)); -+} -+ -+void process_options (int argc, char **argv) -+{ -+ int opt,c; -+ -+ while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) { -+ switch (opt) { -+ case 'o': -+ if (out_fd != -1) -+ error_msg_and_die("output filename specified more than once"); -+ out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644); -+ if (out_fd == -1) -+ perror_msg_and_die("open output file"); -+ break; -+ -+ case 'i': -+ if (in_fd != -1) -+ error_msg_and_die("input filename specified more than once"); -+ in_fd = open(optarg, O_RDONLY); -+ if (in_fd == -1) -+ perror_msg_and_die("open input file"); -+ break; -+ case 'b': -+ target_endian = __BIG_ENDIAN; -+ break; -+ case 'l': -+ target_endian = __LITTLE_ENDIAN; -+ break; -+ case 'h': -+ case '?': -+ error_msg_and_die(helptext); -+ case 'v': -+ verbose = 1; -+ break; -+ -+ case 'V': -+ error_msg_and_die("revision %.*s\n", -+ (int) strlen(revtext) - 13, revtext + 11); -+ -+ case 'e': { -+ char *next; -+ unsigned units = 0; -+ erase_block_size = strtol(optarg, &next, 0); -+ if (!erase_block_size) -+ error_msg_and_die("Unrecognisable erase size\n"); -+ -+ if (*next) { -+ if (!strcmp(next, "KiB")) { -+ units = 1024; -+ } else if (!strcmp(next, "MiB")) { -+ units = 1024 * 1024; -+ } else { -+ error_msg_and_die("Unknown units in erasesize\n"); -+ } -+ } else { -+ if (erase_block_size < 0x1000) -+ units = 1024; -+ else -+ units = 1; -+ } -+ erase_block_size *= units; -+ -+ /* If it's less than 8KiB, they're not allowed */ -+ if (erase_block_size < 0x2000) { -+ fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n", -+ erase_block_size); -+ erase_block_size = 0x2000; -+ } -+ break; -+ } -+ -+ case 'n': -+ add_cleanmarkers = 0; -+ break; -+ case 'c': -+ cleanmarker_size = strtol(optarg, NULL, 0); -+ -+ if (cleanmarker_size < sizeof(cleanmarker)) { -+ error_msg_and_die("cleanmarker size must be >= 12"); -+ } -+ if (cleanmarker_size >= erase_block_size) { -+ error_msg_and_die("cleanmarker size must be < eraseblock size"); -+ } -+ -+ use_input_cleanmarker_size = 0; -+ found_cleanmarkers = 1; -+ setup_cleanmarker(); -+ -+ break; -+ case 'p': -+ padto = 1; -+ break; -+ } -+ } -+} -+ -+ -+void init_buffers() -+{ -+ data_buffer = malloc(erase_block_size); -+ -+ if (!data_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+ -+ file_buffer = malloc(erase_block_size); -+ -+ if (!file_buffer) { -+ perror("out of memory"); -+ close (in_fd); -+ close (out_fd); -+ exit(1); -+ } -+} -+ -+void init_sumlist() -+{ -+ sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary)); -+ -+ if (!sum_collected) -+ error_msg_and_die("Can't allocate memory for jffs2_summary!\n"); -+ -+ memset(sum_collected, 0, sizeof(struct jffs2_summary)); -+} -+ -+void clean_buffers() -+{ -+ if (data_buffer) -+ free(data_buffer); -+ if (file_buffer) -+ free(file_buffer); -+} -+ -+void clean_sumlist() -+{ -+ union jffs2_sum_mem *temp; -+ -+ if (sum_collected) { -+ -+ while (sum_collected->sum_list_head) { -+ temp = sum_collected->sum_list_head; -+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; -+ free(temp); -+ sum_collected->sum_num--; -+ } -+ -+ if (sum_collected->sum_num != 0) -+ printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???"); -+ -+ free(sum_collected); -+ } -+} -+ -+int load_next_block() -+{ -+ int ret; -+ ret = read(in_fd, file_buffer, erase_block_size); -+ file_ofs = 0; -+ -+ if (verbose) -+ printf("Load next block : %d bytes read\n",ret); -+ -+ return ret; -+} -+ -+void write_buff_to_file() -+{ -+ int ret; -+ int len = data_ofs; -+ -+ uint8_t *buf = NULL; -+ -+ buf = data_buffer; -+ while (len > 0) { -+ ret = write(out_fd, buf, len); -+ -+ if (ret < 0) -+ perror_msg_and_die("write"); -+ -+ if (ret == 0) -+ perror_msg_and_die("write returned zero"); -+ -+ len -= ret; -+ buf += ret; -+ } -+ -+ data_ofs = 0; -+} -+ -+void dump_sum_records() -+{ -+ -+ struct jffs2_raw_summary isum; -+ struct jffs2_sum_marker *sm; -+ union jffs2_sum_mem *temp; -+ jint32_t offset; -+ jint32_t *tpage; -+ void *wpage; -+ int datasize, infosize, padsize; -+ jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC); -+ -+ if (!sum_collected->sum_num || !sum_collected->sum_list_head) -+ return; -+ -+ datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker); -+ infosize = sizeof(struct jffs2_raw_summary) + datasize; -+ padsize = erase_block_size - data_ofs - infosize; -+ infosize += padsize; datasize += padsize; -+ offset = cpu_to_je32(data_ofs); -+ -+ tpage = (jint32_t *) malloc(datasize); -+ -+ if(!tpage) -+ error_msg_and_die("Can't allocate memory to dump summary information!\n"); -+ -+ memset(tpage, 0xff, datasize); -+ memset(&isum, 0, sizeof(isum)); -+ -+ isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); -+ isum.totlen = cpu_to_je32(infosize); -+ isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); -+ isum.padded = cpu_to_je32(0); -+ -+ if (add_cleanmarkers && found_cleanmarkers) { -+ isum.cln_mkr = cpu_to_je32(cleanmarker_size); -+ } else { -+ isum.cln_mkr = cpu_to_je32(0); -+ } -+ -+ isum.sum_num = cpu_to_je32(sum_collected->sum_num); -+ wpage = tpage; -+ -+ while (sum_collected->sum_num) { -+ switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) { -+ -+ case JFFS2_NODETYPE_INODE : { -+ struct jffs2_sum_inode_flash *sino_ptr = wpage; -+ -+ sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype; -+ sino_ptr->inode = sum_collected->sum_list_head->i.inode; -+ sino_ptr->version = sum_collected->sum_list_head->i.version; -+ sino_ptr->offset = sum_collected->sum_list_head->i.offset; -+ sino_ptr->totlen = sum_collected->sum_list_head->i.totlen; -+ -+ wpage += JFFS2_SUMMARY_INODE_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_DIRENT : { -+ struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; -+ -+ sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype; -+ sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen; -+ sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset; -+ sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino; -+ sdrnt_ptr->version = sum_collected->sum_list_head->d.version; -+ sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino; -+ sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize; -+ sdrnt_ptr->type = sum_collected->sum_list_head->d.type; -+ -+ memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name, -+ sum_collected->sum_list_head->d.nsize); -+ -+ wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize); -+ break; -+ } -+ -+ case JFFS2_NODETYPE_XATTR: { -+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; -+ -+ sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype; -+ sxattr_ptr->xid = sum_collected->sum_list_head->x.xid; -+ sxattr_ptr->version = sum_collected->sum_list_head->x.version; -+ sxattr_ptr->offset = sum_collected->sum_list_head->x.offset; -+ sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen; -+ -+ wpage += JFFS2_SUMMARY_XATTR_SIZE; -+ break; -+ } -+ -+ case JFFS2_NODETYPE_XREF: { -+ struct jffs2_sum_xref_flash *sxref_ptr = wpage; -+ -+ sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype; -+ sxref_ptr->offset = sum_collected->sum_list_head->r.offset; -+ -+ wpage += JFFS2_SUMMARY_XREF_SIZE; -+ break; -+ } -+ -+ default : { -+ printf("Unknown node type!\n"); -+ } -+ } -+ -+ temp = sum_collected->sum_list_head; -+ sum_collected->sum_list_head = sum_collected->sum_list_head->u.next; -+ free(temp); -+ -+ sum_collected->sum_num--; -+ } -+ -+ sum_collected->sum_size = 0; -+ sum_collected->sum_num = 0; -+ sum_collected->sum_list_tail = NULL; -+ -+ wpage += padsize; -+ -+ sm = wpage; -+ sm->offset = offset; -+ sm->magic = magic; -+ -+ isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize)); -+ isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); -+ -+ full_write(data_buffer + data_ofs, &isum, sizeof(isum)); -+ full_write(data_buffer + data_ofs, tpage, datasize); -+ -+ free(tpage); -+} -+ -+static void full_write(void *target_buff, const void *buf, int len) -+{ -+ memcpy(target_buff, buf, len); -+ data_ofs += len; -+} -+ -+static void pad(int req) -+{ -+ while (req) { -+ if (req > sizeof(ffbuf)) { -+ full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf)); -+ req -= sizeof(ffbuf); -+ } else { -+ full_write(data_buffer + data_ofs, ffbuf, req); -+ req = 0; -+ } -+ } -+} -+ -+static inline void padword() -+{ -+ if (data_ofs % 4) -+ full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4)); -+} -+ -+ -+static inline void pad_block_if_less_than(int req,int plus) -+{ -+ -+ int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ if (data_ofs + req > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } -+ -+ if (add_cleanmarkers && found_cleanmarkers) { -+ if (!data_ofs) { -+ full_write(data_buffer, &cleanmarker, sizeof(cleanmarker)); -+ pad(cleanmarker_size - sizeof(cleanmarker)); -+ padword(); -+ } -+ } -+} -+ -+void flush_buffers() -+{ -+ -+ if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */ -+ if (data_ofs != cleanmarker_size) { /* INODE BUFFER */ -+ -+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ /* If we have a full inode buffer, then write out inode and summary data */ -+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } else { /* else just write out inode data */ -+ if (padto) -+ pad(erase_block_size - data_ofs); -+ write_buff_to_file(); -+ } -+ } -+ } else { /* NO CLEANMARKER */ -+ if (data_ofs != 0) { /* INODE BUFFER */ -+ -+ int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8; -+ datasize += (4 - (datasize % 4)) % 4; -+ -+ /* If we have a full inode buffer, then write out inode and summary data */ -+ if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) { -+ dump_sum_records(); -+ write_buff_to_file(); -+ } else { /* Else just write out inode data */ -+ if(padto) -+ pad(erase_block_size - data_ofs); -+ write_buff_to_file(); -+ } -+ } -+ } -+} -+ -+int add_sum_mem(union jffs2_sum_mem *item) -+{ -+ -+ if (!sum_collected->sum_list_head) -+ sum_collected->sum_list_head = (union jffs2_sum_mem *) item; -+ if (sum_collected->sum_list_tail) -+ sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item; -+ sum_collected->sum_list_tail = (union jffs2_sum_mem *) item; -+ -+ switch (je16_to_cpu(item->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_XATTR: -+ sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ case JFFS2_NODETYPE_XREF: -+ sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE; -+ sum_collected->sum_num++; -+ break; -+ -+ default: -+ error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype)); -+ } -+ return 0; -+} -+ -+void add_sum_inode_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem)); -+ -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->i.nodetype; -+ temp->inode = node->i.ino; -+ temp->version = node->i.version; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->totlen = node->i.totlen; -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_dirent_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) -+ malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize); -+ -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->d.nodetype; -+ temp->totlen = node->d.totlen; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->pino = node->d.pino; -+ temp->version = node->d.version; -+ temp->ino = node->d.ino; -+ temp->nsize = node->d.nsize; -+ temp->type = node->d.type; -+ temp->next = NULL; -+ -+ memcpy(temp->name,node->d.name,node->d.nsize); -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_xattr_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_xattr_mem *temp = (struct jffs2_sum_xattr_mem *) -+ malloc(sizeof(struct jffs2_sum_xattr_mem)); -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->x.nodetype; -+ temp->xid = node->x.xid; -+ temp->version = node->x.version; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->totlen = node->x.totlen; -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void add_sum_xref_mem(union jffs2_node_union *node) -+{ -+ struct jffs2_sum_xref_mem *temp = (struct jffs2_sum_xref_mem *) -+ malloc(sizeof(struct jffs2_sum_xref_mem)); -+ if (!temp) -+ error_msg_and_die("Can't allocate memory for summary information!\n"); -+ -+ temp->nodetype = node->r.nodetype; -+ temp->offset = cpu_to_je32(data_ofs); -+ temp->next = NULL; -+ -+ add_sum_mem((union jffs2_sum_mem *) temp); -+} -+ -+void write_dirent_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize)); -+ add_sum_dirent_mem(node); -+ full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen)); -+ padword(); -+} -+ -+ -+void write_inode_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE); -+ add_sum_inode_mem(node); /* Add inode summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */ -+ padword(); -+} -+ -+void write_xattr_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE); -+ add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen)); -+ padword(); -+} -+ -+void write_xref_to_buff(union jffs2_node_union *node) -+{ -+ pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE); -+ add_sum_xref_mem(node); /* Add xref summary mem to summary list */ -+ full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen)); -+ padword(); -+} -+ -+void create_summed_image(int inp_size) -+{ -+ uint8_t *p = file_buffer; -+ union jffs2_node_union *node; -+ uint32_t crc, length; -+ uint16_t type; -+ int bitchbitmask = 0; -+ int obsolete; -+ char name[256]; -+ -+ while ( p < (file_buffer + inp_size)) { -+ -+ node = (union jffs2_node_union *) p; -+ -+ /* Skip empty space */ -+ if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) { -+ p += 4; -+ continue; -+ } -+ -+ if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) { -+ if (!bitchbitmask++) -+ printf ("Wrong bitmask at 0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic)); -+ p += 4; -+ continue; -+ } -+ -+ bitchbitmask = 0; -+ -+ type = je16_to_cpu(node->u.nodetype); -+ if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) { -+ obsolete = 1; -+ type |= JFFS2_NODE_ACCURATE; -+ } else { -+ obsolete = 0; -+ } -+ -+ node->u.nodetype = cpu_to_je16(type); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4); -+ if (crc != je32_to_cpu (node->u.hdr_crc)) { -+ printf ("Wrong hdr_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc); -+ p += 4; -+ continue; -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ if (verbose) -+ printf ("%8s Inode node at 0x%08x, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino), -+ je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), -+ je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset)); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8); -+ if (crc != je32_to_cpu (node->i.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize)); -+ if (crc != je32_to_cpu(node->i.data_crc)) { -+ printf ("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc); -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ continue; -+ } -+ -+ write_inode_to_buff(node); -+ -+ p += PAD(je32_to_cpu (node->i.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ memcpy (name, node->d.name, node->d.nsize); -+ name [node->d.nsize] = 0x0; -+ -+ if (verbose) -+ printf ("%8s Dirent node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino), -+ je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino), -+ node->d.nsize, name); -+ -+ crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8); -+ if (crc != je32_to_cpu (node->d.node_crc)) { -+ printf ("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ continue; -+ } -+ -+ crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize); -+ if (crc != je32_to_cpu(node->d.name_crc)) { -+ printf ("Wrong name_crc at 0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc); -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ continue; -+ } -+ -+ write_dirent_to_buff(node); -+ -+ p += PAD(je32_to_cpu (node->d.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_XATTR: -+ if (je32_to_cpu(node->x.node_crc) == 0xffffffff) -+ obsolete = 1; -+ if (verbose) -+ printf("%8s Xdatum node at 0x%08x, totlen 0x%08x, " -+ "#xid %5u, version %5u\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->x.totlen), -+ je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version)); -+ crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4); -+ if (crc != je32_to_cpu(node->x.node_crc)) { -+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->x.node_crc), crc); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ continue; -+ } -+ length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len); -+ crc = crc32(0, node->x.data, length); -+ if (crc != je32_to_cpu(node->x.data_crc)) { -+ printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->x.data_crc), crc); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ continue; -+ } -+ -+ write_xattr_to_buff(node); -+ p += PAD(je32_to_cpu (node->x.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_XREF: -+ if (je32_to_cpu(node->r.node_crc) == 0xffffffff) -+ obsolete = 1; -+ if (verbose) -+ printf("%8s Xref node at 0x%08x, totlen 0x%08x, " -+ "#ino %5u, xid %5u\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu(node->r.totlen), -+ je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid)); -+ crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4); -+ if (crc != je32_to_cpu(node->r.node_crc)) { -+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n", -+ p - file_buffer, je32_to_cpu(node->r.node_crc), crc); -+ p += PAD(je32_to_cpu (node->r.totlen)); -+ continue; -+ } -+ -+ write_xref_to_buff(node); -+ p += PAD(je32_to_cpu (node->r.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_CLEANMARKER: -+ if (verbose) { -+ printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ if (!found_cleanmarkers) { -+ found_cleanmarkers = 1; -+ -+ if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){ -+ cleanmarker_size = je32_to_cpu (node->u.totlen); -+ setup_cleanmarker(); -+ } -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ if (verbose) { -+ printf ("%8s Padding node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ break; -+ -+ case 0xffff: -+ p += 4; -+ break; -+ -+ default: -+ if (verbose) { -+ printf ("%8s Unknown node at 0x%08x, totlen 0x%08x\n", -+ obsolete ? "Obsolete" : "", -+ p - file_buffer, je32_to_cpu (node->u.totlen)); -+ } -+ -+ p += PAD(je32_to_cpu (node->u.totlen)); -+ } -+ } -+} -+ -+int main(int argc, char **argv) -+{ -+ int ret; -+ -+ process_options(argc,argv); -+ -+ if ((in_fd == -1) || (out_fd == -1)) { -+ if(in_fd != -1) -+ close(in_fd); -+ if(out_fd != -1) -+ close(out_fd); -+ fprintf(stderr,helptext); -+ error_msg_and_die("You must specify input and output files!\n"); -+ } -+ -+ init_buffers(); -+ init_sumlist(); -+ -+ while ((ret = load_next_block())) { -+ create_summed_image(ret); -+ } -+ -+ flush_buffers(); -+ clean_buffers(); -+ clean_sumlist(); -+ -+ if (in_fd != -1) -+ close(in_fd); -+ if (out_fd != -1) -+ close(out_fd); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,14 @@ -+ -+all: checkfs makefiles -+ -+checkfs: checkfs.c Makefile common.h comm.o -+ gcc -g -Wall checkfs.c comm.o -o checkfs -+ -+comm.o: comm.c Makefile -+ gcc -g -Wall -c comm.c -o comm.o -+ -+makefiles: makefiles.c Makefile common.h -+ gcc -g -Wall makefiles.c -o makefiles -+ -+clean: -+ rm -f makefiles checkfs *~ *.o -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/README linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/README ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,173 @@ -+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+$Log: not supported by cvs2svn $ -+Revision 1.2 2001/06/21 23:07:06 dwmw2 -+Initial import to MTD CVS -+ -+Revision 1.1 2001/06/11 19:34:40 vipin -+Added README file to dir. -+ -+ -+This is the README file for the "checkfs" power fail test program. -+By: Vipin Malik -+ -+NOTE: This program requires an external "power cycling box" -+connected to one of the com ports of the system under test. -+This power cycling box should wait for a random amount of time -+after it receives a "ok to power me down" message over the -+serial port, and then yank power to the system under test. -+(The box that I rigged up tested with waits anywhere from -+0 to ~40 seconds). -+ -+ -+It should then restore power after a few seconds and wait for the -+message again. -+ -+ -+ABOUT: -+ -+This program's primary purpose it to test the reliiability -+of various file systems under Linux. -+ -+SETUP: -+ -+You need to setup the file system you want to test and run the -+"makefiles" program ONCE. This creates a set of files that are -+required by the "checkfs" program. -+ -+Also copy the "checkfs" executable program to the same dir. -+ -+Then you need to make sure that the program "checkfs" is called -+automatically on startup. You can customise the operation of -+the "checkfs" program by passing it various cmd line arguments. -+run "checkfs -?" for more details. -+ -+****NOTE******* -+Make sure that you call the checkfs program only after you have -+mounted the file system you want to test (this is obvious), but -+also after you have run any "scan" utilities to check for and -+fix any file systems errors. The e2fsck is one utility for the -+ext2 file system. For an automated setup you of course need to -+provide these scan programs to run in standalone mode (-f -y -+flags for e2fsck for example). -+ -+File systems like JFFS and JFFS2 do not have any such external -+utilities and you may call "checkfs" right after you have mounted -+the respective file system under test. -+ -+There are two ways you can mount the file system under test: -+ -+1. Mount your root fs on a "standard" fs like ext2 and then -+mount the file system under test (which may be ext2 on another -+partition or device) and then run "checkfs" on this mounted -+partition OR -+ -+2. Make your fs AND device that you have put this fs as your -+root fs and run "checkfs" on the root device (i.e. "/"). -+You can of course still run checkfs under a separate dir -+under your "/" root dir. -+ -+I have found the second method to be a particularly stringent -+arrangement (and thus preferred when you are trying to break -+something). -+ -+Using this arrangement I was able to find that JFFS clobbered -+some "sister" files on the root fs even though "checkfs" would -+run fine through all its own check files. -+ -+(I found this out when one of the clobbered sister file happened -+to be /bin/bash. The system refused to run rc.local thus -+preventing my "checkfs" program from being launched :) -+ -+"checkfs": -+ -+The "formatting" reliability of the fs as well as the file data integrity -+of files on the fs can be checked using this program. -+ -+"formatiing" reliability can only be checked via an indirect method. -+If there is severe formatting reliability issues with the file system, -+it will most likely cause other system failures that will prevent this -+program from running successfully on a power up. This will prevent -+a "ok to power me down" message from going out to the power cycling -+black box and prevent power being turned off again. -+ -+File data reliability is checked more directly. A fixed number of -+files are created in the current dir (using the program "makefiles"). -+ -+Each file has a random number of bytes in it (set by using the -+-s cmd line flag). The number of "ints" in the file is stored as the -+first "int" in it (note: 0 length files are not allowed). Each file -+is then filled with random data and a 16 bit CRC appended at the end. -+ -+When "checkfs" is run, it runs through all files (with predetermined -+file names)- one at a time- and checks for the number of "int's" -+in it as well as the ending CRC. -+ -+The program exits if the numbers of files that are corrupt are greater -+that a user specified parameter (set by using the -e cmd line flag). -+ -+If the number of corrupt files is less than this parameter, the corrupt -+files are repaired and operation resumes as explained below. -+ -+The idea behind allowing a user specified amount of corrupt files is as -+follows: -+ -+If you are testing for "formatting" reliability of a fs, and for -+the data reliability of "other" files present of the fs, use -e 1. -+"other" files are defined as sister files on the fs, not being written to -+by the "checkfs" test program. -+ -+As mentioned, in this case you would set -e 1, or allow at most 1 file -+to be corrupt each time after a power fail. This would be the file -+that was probably being written to when power failed (and CRC was not -+updated to reflect the new data being written). You would check file -+systems like ext2 etc. with such a configuration. -+(As you have no hope that these file systems provide for either your -+new data or old data to be present in the file if power failed during -+the write. This is called "roll back and recover".) -+ -+With JFFS2 I tested for such "roll back and recover" file data reliability -+by setting -e 0 and making sure that all writes to the file being -+updated are done in a *single* write(). -+ -+This is how I found that JFFS2 (yet) does NOT support this functionality. -+(There was a great debate if this was a bug or a feature that was lacking -+or even an issue at all. See the mtd archives for more details). -+ -+In other words, JFFS2 will partially update a file on FLASH even before -+the write() command has completed, thus leaving part old data part new -+data in your file if power failed in the middle of a write(). -+ -+This is bad functionality if you are updating a binary structure or a -+CRC protected file (as in our case). -+ -+ -+If All Files Check Out OK: -+ -+On the startup scan, if there are less errors than specified by the "-e flag" -+a "ok to power me down message" is sent via the specified com port. -+ -+The actual format of this message will depend on the format expected -+by the power cycling box that will receive this message. One may customise -+the actual message that goes out in the "do_pwr_dn)" routine in "comm.c". -+ -+This file is called with an open file descriptor to the comm port that -+this message needs to go out over and the count of the current power -+cycle (in case your power cycling box can display/log this count). -+ -+After this message has been sent out, the checkfs program goes into -+a while(1) loop of writing new data (with CRC), one at a time, into -+all the "check files" in the dir. -+ -+Its life comes to a sudden end when power is asynchronously pulled from -+under its feet (by your external power cycling box). -+ -+It comes back to life when power is restored and the system boots and -+checkfs is called from the rc.local script file. -+ -+The cycle then repeats till a problem is detected, at which point -+the "ok to power me down" message is not sent and the cycle stops -+waiting for the user to examine the system. -+ -+ -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/checkfs.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,695 @@ -+/* -+ -+ * Copyright Daniel Industries. -+ * -+ * Created by: Vipin Malik (vipin.malik@daniel.com) -+ * -+ * This code is released under the GPL version 2. See the file COPYING -+ * for more details. -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ -+ This program opens files in progression (file00001, file00002 etc), -+ upto MAX_NUM_FILES and checks their CRC. If a file is not found or the -+ CRC does not match it stops it's operation. -+ -+ Everything is logged in a logfile called './logfile'. -+ -+ If everything is ok this program sends a signal, via com1, to the remote -+ power control box to power cycle this computer. -+ -+ This program then proceeds to create new files file0....file -+ in a endless loop and checksum each before closing them. -+ -+ STRUCTURE OF THE FILES: -+ The fist int is the size of the file in bytes. -+ The last 2 bytes are the CRC for the entire file. -+ There is random data in between. -+ -+ The files are opened in the current dir. -+ -+ $Id: checkfs.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Log: not supported by cvs2svn $ -+ Revision 1.8 2005/11/07 11:15:17 gleixner -+ [MTD / JFFS2] Clean up trailing white spaces -+ -+ Revision 1.7 2001/06/21 23:04:17 dwmw2 -+ Initial import to MTD CVS -+ -+ Revision 1.6 2001/06/08 22:26:05 vipin -+ Split the modbus comm part of the program (that sends the ok to pwr me down -+ message) into another file "comm.c" -+ -+ Revision 1.5 2001/06/08 21:29:56 vipin -+ fixed small issue with write() checking for < 0 instead of < (bytes to be written). -+ Now it does the latter (as it should). -+ -+ Revision 1.4 2001/05/11 22:29:40 vipin -+ Added a test to check and err out if the first int in file (which tells us -+ how many bytes there are in the file) is zero. This will prevent a corrupt -+ file with zero's in it from passing the crc test. -+ -+ Revision 1.3 2001/05/11 21:33:54 vipin -+ Changed to use write() rather than fwrite() when creating new file. Additionally, -+ and more important, it now does a single write() for the entire data. This will -+ enable us to use this program to test for power fail *data* reliability when -+ writing over an existing file, specially on powr fail "safe" file systems as -+ jffs/jffs2. Also added a new cmdline parameter "-e" that specifies the max # of -+ errors that can be tolerated. This should be set to ZERO to test for the above, -+ as old data should be reliabily maintained if the newer write never "took" before -+ power failed. If the write did succeed, then the newer data will have its own -+ CRC in place when it gets checked => hence no error. In theory at least! -+ -+ -+ Revision 1.2 2001/05/11 19:27:33 vipin -+ Added cmd line args to change serial port, and specify max size of -+ random files created. Some cleanup. Added -Wall to Makefile. -+ -+ Revision 1.1 2001/05/11 16:06:28 vipin -+ Importing checkfs (the power fail test program) into CVS. This was -+ originally done for NEWS. NEWS had a lot of version, this is -+ based off the last one done for NEWS. The "makefiles" program -+ is run once initially to create the files in the current dir. -+ "checkfs" is then run on every powerup to check consistancy -+ of the files. See checkfs.c for more details. -+ -+ -+*/ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+ -+ -+ -+extern int do_pwr_dn(int fd, int cycleCnt); -+ -+#define CMDLINE_PORT "-p" -+#define CMDLINE_MAXFILEBYTES "-s" -+#define CMDLINE_MAXERROR "-e" -+#define CMDLINE_HELPSHORT "-?" -+#define CMDLINE_HELPLONG "--help" -+ -+ -+int CycleCount; -+ -+char SerialDevice[255] = "/dev/ttyS0"; /* default, can be changed -+ through cmd line. */ -+ -+#define MAX_INTS_ALLOW 100000 /* max # of int's in the file written. -+ Statis limit to size struct. */ -+float FileSizeMax = 1024.0; /*= (file size in bytes), MUST be float*/ -+ -+int MaxErrAllowed = 1; /* default, can ge changed thru cmd line*/ -+ -+ -+/* Needed for CRC generation/checking */ -+static const unsigned short crc_ccitt_table[] = { -+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, -+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, -+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, -+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, -+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, -+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, -+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, -+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, -+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, -+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, -+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, -+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, -+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, -+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, -+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, -+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, -+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, -+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, -+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, -+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, -+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, -+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, -+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, -+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, -+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, -+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, -+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, -+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, -+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, -+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, -+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, -+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -+}; -+ -+ -+/* -+ Set's up the Linux serial port. Must be passed string to device to -+ open. Parameters are fixed to 9600,e,1 -+ -+ [A possible enhancement to this program would be to pass these -+ parameters via the command line.] -+ -+ Returns file descriptor to open port. Use this fd to write to port -+ and close it later, when done. -+*/ -+int setupSerial (const char *dev) { -+ int i, fd; -+ struct termios tios; -+ -+ fd = open(dev,O_RDWR | O_NDELAY ); -+ if (fd < 0) { -+ fprintf(stderr, "%s: %s\n", dev, sys_errlist[errno]); -+ exit(1); -+ } -+ if (tcgetattr(fd, &tios) < 0) { -+ fprintf(stderr,"Could not get terminal attributes: %s",sys_errlist[errno]); -+ exit(1); -+ } -+ -+ tios.c_cflag = -+ CS7 | -+ CREAD | // Enable Receiver -+ HUPCL | // Hangup after close -+ CLOCAL | // Ignore modem control lines -+ PARENB; // Enable parity (even by default) -+ -+ -+ -+ tios.c_iflag = IGNBRK; // Ignore break -+ tios.c_oflag = 0; -+ tios.c_lflag = 0; -+ for(i = 0; i < NCCS; i++) { -+ tios.c_cc[i] = '\0'; // no special characters -+ } -+ tios.c_cc[VMIN] = 1; -+ tios.c_cc[VTIME] = 0; -+ -+ cfsetospeed (&tios, B9600); -+ cfsetispeed (&tios, B9600); -+ -+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { -+ fprintf(stderr,"Could not set attributes: ,%s",sys_errlist[errno]); -+ exit(1); -+ } -+ return fd; -+} -+ -+ -+ -+ -+ -+//A portion of this code was taken from the AX.25 HDLC packet driver -+//in LINUX. Once I test and have a better understanding of what -+//it is doing, it will be better commented. -+ -+//For now one can speculate that the CRC routine always expects the -+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end) -+//and returns TRUE if it is and FALSE if it doesn't. -+//Why don't people document better!!!! -+int check_crc_ccitt(char *filename) -+{ -+ FILE *fp; -+ FILE *logfp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ char done; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ -+ /*the first int contains an int that is the length of the file in long.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "verify checksum:Error reading from file: %s\n", filename); -+ fclose(fp); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ /* printf("Checking %i bytes for CRC in \"%s\".\n", len, filename); */ -+ -+ /* Make sure that we did not read 0 as the number of bytes in file. This -+ check prevents a corrupt file with zero's in it from passing the -+ CRC test. A good file will always have some data in it. */ -+ if(len == 0) -+ { -+ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "verify checksum: first int claims there are 0 data in file. Error!: %s\n", filename); -+ fclose(fp); -+ fclose(logfp); -+ return FALSE; -+ } -+ -+ -+ rewind(fp); -+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those -+ two MUST also be included in the checksum calculation. -+ */ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ done = FALSE; -+ while(!done){ -+ if(fread(&dataByte, sizeof(char), 1, fp) != 1){ -+ retry--; -+ }else{ -+ done = TRUE; -+ } -+ if(retry == 0){ -+ done = TRUE; -+ } -+ } -+ if(!retry){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ fprintf(logfp, "Unexpected end of file: %s\n", filename); -+ fprintf(logfp, "...bytes left to be read %i.\n",len); -+ fclose(logfp); -+ fclose(fp); -+ return FALSE; -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ fclose(fp); -+ if( (crc & 0xffff) != 0xf0b8){ -+ /*printf("The CRC of read file:%x\n", crc); */ -+ return FALSE; -+ } -+ return TRUE; -+}/*end check_crc_ccitt() */ -+ -+ -+ -+/* -+ Sends "OK to power me down" message to the remote -+ power cycling box, via the serial port. -+ Also updates the num power cycle count in a local -+ file. -+ This file "./cycleCnt" must be present. This is -+ initially (and once) created by the separate "makefiles.c" -+ program. -+*/ -+void send_pwrdn_ok(void){ -+ -+ int fd; -+ FILE *cyclefp; -+ int cycle_fd; -+ -+ cyclefp = fopen("cycleCnt","rb"); -+ if(!cyclefp){ -+ printf("expecting file \"cycleCnt\". Cannot continue.\n"); -+ exit(1); -+ } -+ if(fread(&CycleCount, sizeof(CycleCount),1,cyclefp) != 1){ -+ fprintf(stderr, "Error! Unexpected end of file cycleCnt.\n"); -+ exit(1); -+ } -+ fclose(cyclefp); -+ -+ CycleCount++; -+ -+ /*now write this puppy back*/ -+ cyclefp = fopen("cycleCnt","wb"); -+ cycle_fd = fileno(cyclefp); -+ if(!cyclefp){ -+ fprintf(stderr, "Error! cannot open file for write:\"cycleCnt\". Cannot continue.\n"); -+ exit(1); -+ } -+ if(fwrite(&CycleCount, sizeof(CycleCount), 1,cyclefp) !=1){ -+ fprintf(stderr, "Error writing to file cycleCnt. Cannot continue.\n"); -+ exit(1); -+ } -+ if(fdatasync(cycle_fd)){ -+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(cyclefp); -+ (void)sync(); -+ -+ printf("\n\n Sending Power down command to the remote box.\n"); -+ fd = setupSerial(SerialDevice); -+ -+ if(do_pwr_dn(fd, CycleCount) < 0) -+ { -+ fprintf(stderr, "Error sending power down command.\n"); -+ exit(1); -+ } -+ -+ close(fd); -+}//end send_pwrnd_ok() -+ -+ -+ -+ -+/* -+ Appends 16bit CRC at the end of numBytes long buffer. -+ Make sure buf, extends at least 2 bytes beyond. -+ */ -+void appendChecksum(char *buf, int numBytes){ -+ -+ unsigned short crc = 0xffff; -+ int index = 0; -+ -+ /* printf("Added CRC (2 bytes) to %i bytes.\n", numBytes); */ -+ -+ for (; numBytes > 0; numBytes--){ -+ -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ buf[index++]) & 0xff]; -+ } -+ crc ^= 0xffff; -+ /*printf("The CRC: %x\n\n", crc);*/ -+ -+ buf[index++] = crc; -+ buf[index++] = crc >> 8; -+ -+ -+ -+}/*end checksum()*/ -+ -+ -+ -+ -+ -+/* -+ This guy make a new "random data file" with the filename -+ passed to it. This file is checksummed with the checksum -+ stored at the end. The first "int" in the file is the -+ number of int's in it (this is needed to know how much -+ data to read and checksum later). -+*/ -+void make_new_file(char *filename){ -+ -+ -+ int dfd; /* data file descriptor */ -+ int rand_data; -+ int data_size; -+ int temp_size; -+ int dataIndex = 0; -+ int err; -+ -+ -+ struct { -+ int sizeInBytes; /* must be int */ -+ int dataInt[MAX_INTS_ALLOW+1]; /* how many int's can we write? */ -+ }__attribute((packed)) dataBuf; -+ -+ -+ fprintf(stderr, "Creating File:%s. ", filename); -+ -+ if((dfd = open(filename, O_RDWR | O_CREAT | O_SYNC)) <= 0) -+ { -+ printf("Error! Cannot open file: %s\n",filename); -+ perror("Error"); -+ exit(1); -+ } -+ -+ /*now write a bunch of random binary data to the file*/ -+ /*first figure out how much data to write. That is random also.*/ -+ -+ /*file should not be less than 5 ints long. (so that we have decent length files, -+ that's all)*/ -+ while( -+ ((data_size = (int)(1+(int)((FileSizeMax/sizeof(int))*rand()/(RAND_MAX+1.0)))) < 5) -+ ); -+ -+ /* printf("Writing %i ints to the file.\n", data_size); */ -+ -+ temp_size = data_size * sizeof(int); -+ -+ /* Make sure that all data is written in one go! This is important to -+ check for reliability of file systems like JFFS/JFFS that purport to -+ have "reliable" writes during powre fail. -+ */ -+ -+ dataBuf.sizeInBytes = temp_size; -+ -+ data_size--; /*one alrady written*/ -+ dataIndex = 0; -+ -+ while(data_size--){ -+ rand_data = (int)(1 + (int)(10000.0*rand()/(RAND_MAX+1.0))); -+ -+ dataBuf.dataInt[dataIndex++] = rand_data; -+ -+ } -+ -+ /*now calculate the file checksum and append it to the end*/ -+ appendChecksum((char *)&dataBuf, dataBuf.sizeInBytes); -+ -+ /* Don't forget to increase the size of data written by the 2 chars of CRC at end. -+ These 2 bytes are NOT included in the sizeInBytes field. */ -+ if((err = write(dfd, (void *)&dataBuf, dataBuf.sizeInBytes + sizeof(short))) < -+ (dataBuf.sizeInBytes + sizeof(short)) -+ ) -+ { -+ printf("Error writing data buffer to file. Written %i bytes rather than %i bytes.", -+ err, dataBuf.sizeInBytes); -+ perror("Error"); -+ exit(1); -+ } -+ -+ /* Now that the data is (hopefully) safely written. I can truncate the file to the new -+ length so that I can reclaim any unused space, if the older file was larger. -+ */ -+ if(ftruncate(dfd, dataBuf.sizeInBytes + sizeof(short)) < 0) -+ { -+ perror("Error: Unable to truncate file."); -+ exit(1); -+ } -+ -+ -+ close(dfd); -+ -+ -+}//end make_new_file() -+ -+ -+ -+/* -+ Show's help on stdout -+ */ -+void printHelp(char **argv) -+{ -+ printf("Usage:%s \n", argv[0]); -+ printf("%s : Set com port to send ok to pwr dn msg on\n", -+ CMDLINE_PORT); -+ printf("%s : Set Max size in bytes of each file to be created.\n", -+ CMDLINE_MAXFILEBYTES); -+ printf("%s : Set Max errors allowed when checking all files for CRC on start.\n", -+ CMDLINE_MAXERROR); -+ printf("%s or %s: This Help screen.\n", CMDLINE_HELPSHORT, -+ CMDLINE_HELPLONG); -+ -+}/* end printHelp()*/ -+ -+ -+ -+void processCmdLine(int argc, char **argv) -+{ -+ -+ int cnt; -+ -+ /* skip past name of this program, process rest */ -+ for(cnt = 1; cnt < argc; cnt++) -+ { -+ if(strcmp(argv[cnt], CMDLINE_PORT) == 0) -+ { -+ strncpy(SerialDevice, argv[++cnt], sizeof(SerialDevice)); -+ continue; -+ }else -+ if(strcmp(argv[cnt], CMDLINE_MAXFILEBYTES) == 0) -+ { -+ FileSizeMax = (float)atoi(argv[++cnt]); -+ if(FileSizeMax > (MAX_INTS_ALLOW*sizeof(int))) -+ { -+ printf("Max file size allowd is %i.\n", -+ MAX_INTS_ALLOW*sizeof(int)); -+ exit(0); -+ } -+ -+ continue; -+ }else -+ if(strcmp(argv[cnt], CMDLINE_HELPSHORT) == 0) -+ { -+ printHelp(argv); -+ exit(0); -+ -+ }else -+ if(strcmp(argv[cnt], CMDLINE_HELPLONG) == 0) -+ { -+ printHelp(argv); -+ exit(0); -+ }else -+ -+ if(strcmp(argv[cnt], CMDLINE_MAXERROR) == 0) -+ { -+ MaxErrAllowed = atoi(argv[++cnt]); -+ } -+ else -+ { -+ printf("Unknown cmd line option:%s\n", argv[cnt]); -+ printHelp(argv); -+ exit(0); -+ -+ } -+ } -+ -+ -+}/* end processCmdLine() */ -+ -+ -+ -+ -+ -+int main(int argc, char **argv){ -+ -+ FILE *logfp; -+ int log_fd; -+ char filename[30]; -+ short filenameCounter = 0; -+ unsigned short counter; -+ unsigned short numberFiles; -+ char error = FALSE; -+ short errorCnt = 0; -+ time_t timep; -+ char * time_string; -+ unsigned int seed; -+ -+ -+ numberFiles = MAX_NUM_FILES; -+ -+ if(argc >= 1) -+ { -+ processCmdLine(argc, argv); -+ } -+ -+ -+ /* -+ First open MAX_NUM_FILES and make sure that the checksum is ok. -+ Also make an intry into the logfile. -+ */ -+ /* timestamp! */ -+ time(&timep); -+ time_string = (char *)ctime((time_t *)&timep); -+ -+ /*start a new check, make a log entry and continue*/ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"%s", time_string); -+ fprintf(logfp,"Starting new check.\n"); -+ if(fdatasync(log_fd) == -1){ -+ fprintf(stderr,"Error! Cannot sync file data with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(logfp); -+ (void)sync(); -+ -+ /* -+ Now check all random data files in this dir. -+ */ -+ for(counter=0;counter MaxErrAllowed){ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"\nMax Error count exceed. Stopping!\n"); -+ if(fdatasync(log_fd) == -1){ -+ fprintf(stderr,"Error! Cannot sync file data with disk.\n"); -+ exit(1); -+ } -+ fclose(logfp); -+ (void)sync(); -+ -+ fprintf(stderr, "Too many errors. See \"logfile\".\n"); -+ exit(1); -+ }/* if too many errors */ -+ -+ /*we have decided to continue, however first repair this file -+ so that we do not cumulate errors across power cycles.*/ -+ make_new_file(filename); -+ } -+ }//for -+ -+ /*all files checked, make a log entry and continue*/ -+ logfp = fopen("logfile","a"); /*open for appending only.*/ -+ log_fd = fileno(logfp); -+ fprintf(logfp,"All files checked. Total errors found: %i\n\n", errorCnt); -+ if(fdatasync(log_fd)){ -+ fprintf(stderr, "Error! cannot sync file buffer with disk.\n"); -+ exit(1); -+ } -+ -+ fclose(logfp); -+ (void)sync(); -+ -+ /*now send a message to the remote power box and have it start a random -+ pwer down timer after which power will be killed to this unit. -+ */ -+ send_pwrdn_ok(); -+ -+ /*now go into a forever loop of writing to files and CRC'ing them on -+ a continious basis.*/ -+ -+ /*start from a random file #*/ -+ /*seed rand based on the current time*/ -+ seed = (unsigned int)time(NULL); -+ srand(seed); -+ -+ filenameCounter=(int)(1+(int)((float)(MAX_NUM_FILES-1)*rand()/(RAND_MAX+1.0))); -+ -+ while(1){ -+ -+ for(;filenameCounter -+#include -+#include -+ -+ -+ -+/* -+ This is the routine that forms and -+ sends the "ok to pwr me down" message -+ to the remote power cycling "black box". -+ -+ */ -+int do_pwr_dn(int fd, int cycleCnt) -+{ -+ -+ char buf[200]; -+ -+ sprintf(buf, "ok to power me down!\nCount = %i\n", cycleCnt); -+ -+ if(write(fd, buf, strlen(buf)) < strlen(buf)) -+ { -+ perror("write error"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/common.h linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/common.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,7 @@ -+/* $Id: common.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ */ -+//this .h file is common to both the file creation utility and -+//the file checking utility. -+#define TRUE 1 -+#define FALSE 0 -+ -+#define MAX_NUM_FILES 100 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/checkfs/makefiles.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ -+ * Copyright Daniel Industries. -+ -+ * Created by: Vipin Malik (vipin.malik@daniel.com) -+ * -+ * This is GPL code. See the file COPYING for more details -+ * -+ * Software distributed under the Licence is distributed on an "AS IS" -+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -+ * See the Licence for the specific language governing rights and -+ * limitations under the Licence. -+ -+ * $Id: makefiles.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ -+This program creates MAX_NUM_FILES files (file00001, file00002 etc) and -+fills them with random numbers till they are a random length. Then it checksums -+the files (with the checksum as the last two bytes) and closes the file. -+ -+The fist int is the size of the file in bytes. -+ -+It then opens another file and the process continues. -+ -+The files are opened in the current dir. -+ -+*/ -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+ -+#define FILESIZE_MAX 20000.0 /* for each file in sizeof(int). Must be a float # -+ Hence, 20000.0 = 20000*4 = 80KB max file size -+ */ -+ -+static const unsigned short crc_ccitt_table[] = { -+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, -+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, -+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, -+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, -+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, -+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, -+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, -+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, -+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, -+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, -+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, -+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, -+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, -+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, -+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, -+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, -+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, -+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, -+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, -+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, -+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, -+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, -+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, -+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, -+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, -+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, -+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, -+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, -+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, -+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, -+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, -+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -+}; -+ -+//This code was taken from the AX.25 HDLC packet driver -+//in LINUX. Once I test and have a better understanding of what -+//it is doing, it will be better commented. -+ -+//For now one can speculate that the CRC routine always expects the -+//CRC to calculate out to 0xf0b8 (the hardcoded value at the end) -+//and returns TRUE if it is and FALSE if it doesn't. -+//Why don't people document better!!!! -+void check_crc_ccitt(char *filename) -+{ -+ FILE *fp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ printf("Verify checksum:Error! Cannot open filename passed for verify checksum: %s\n",filename); -+ exit(1); -+ } -+ /*the first int contains an int that is the length of the file in long.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ printf("verify checksum:Error reading from file: %s", filename); -+ fclose(fp); -+ exit(1); -+ } -+ rewind(fp); -+ len+=2; /*the file has two extra bytes at the end, it's checksum. Those -+ two MUST also be included in the checksum calculation. -+ */ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--); -+ if(!retry){ -+ printf("Unexpected error reading from file: %s\n", filename); -+ printf("...bytes left to be read %i.\n\n",len); -+ fclose(fp); -+ exit(1); -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ fclose(fp); -+ if( (crc & 0xffff) != 0xf0b8){ -+ printf("Verify checksum: Error in file %s.\n\n",filename); -+ exit(1); -+ } -+}//end check_crc_ccitt() -+ -+ -+ -+/*this routine opens a file 'filename' and checksumn's the entire -+ contents, and then appends the checksum at the end of the file, -+ closes the file and returns. -+*/ -+void checksum(char *filename){ -+ -+ FILE *fp; -+ unsigned short crc = 0xffff; -+ int len; -+ char dataByte; -+ int retry; -+ -+ fp = fopen(filename,"rb"); -+ if(!fp){ -+ printf("Error! Cannot open filename passed for checksum: %s\n",filename); -+ exit(1); -+ } -+ /*the first int contains an int that is the length of the file in longs.*/ -+ if(fread(&len, sizeof(int), 1, fp) != 1){ -+ printf("Error reading from file: %s", filename); -+ fclose(fp); -+ exit(1); -+ } -+ printf("Calculating checksum on %i bytes.\n",len); -+ rewind(fp); /*the # of bytes int is also included in the checksum.*/ -+ -+ for (;len>0;len--){ -+ retry=5; /*retry 5 times*/ -+ while(!fread(&dataByte, sizeof(char), 1, fp) && retry--); -+ if(!retry){ -+ printf("Unexpected error reading from file: %s\n", filename); -+ printf("...bytes left to be read %i.\n\n",len); -+ fclose(fp); -+ exit(1); -+ } -+ crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ dataByte) & 0xff]; -+ } -+ crc ^= 0xffff; -+ printf("The CRC: %x\n\n", crc); -+ -+ /*the CRC has been calculated. now close the file and open it in append mode*/ -+ fclose(fp); -+ -+ fp = fopen(filename,"ab"); /*open in append mode. CRC goes at the end.*/ -+ if(!fp){ -+ printf("Error! Cannot open filename to update checksum: %s\n",filename); -+ exit(1); -+ } -+ if(fwrite(&crc, sizeof(crc), 1, fp) != 1){ -+ printf("error! unable to update the file for checksum.\n"); -+ fclose(fp); -+ exit(1); -+ } -+ fflush(fp); -+ fclose(fp); -+ -+ -+}/*end checksum()*/ -+ -+ -+ -+int main(void){ -+ -+ FILE *fp, *cyclefp; -+ int cycleCount; -+ int rand_data; -+ int data_size; -+ int temp_size; -+ char filename[30]; -+ short filenameCounter = 0; -+ unsigned short counter; -+ unsigned short numberFiles; -+ -+ numberFiles = MAX_NUM_FILES; -+ -+ for(counter=0;counter -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+/* Structures to store data written to the test file system, -+ so that we can check whether the file system is correct. */ -+ -+struct write_info /* Record of random data written into a file */ -+{ -+ struct write_info *next; -+ off_t offset; /* Where in the file the data was written */ -+ size_t size; /* Number of bytes written */ -+ unsigned random_seed; /* Seed for rand() to create random data */ -+ off_t random_offset; /* Call rand() this number of times first */ -+}; -+ -+struct file_info /* Each file has one of these */ -+{ -+ char *name; -+ struct dir_info *parent; /* Parent directory */ -+ struct write_info *writes; /* Record accumulated writes to the file */ -+ struct write_info *raw_writes; -+ /* Record in order all writes to the file */ -+ struct fd_info *fds; /* All open file descriptors for this file */ -+ off_t length; -+ int deleted; /* File has been deleted but is still open */ -+ int no_space_error; /* File has incurred a ENOSPC error */ -+}; -+ -+struct dir_info /* Each directory has one of these */ -+{ -+ char *name; -+ struct dir_info *parent; /* Parent directory or null -+ for our top directory */ -+ unsigned number_of_entries; -+ struct dir_entry_info *first; -+}; -+ -+struct dir_entry_info /* Each entry in a directory has one of these */ -+{ -+ struct dir_entry_info *next; -+ char type; /* f => file, d=> dir */ -+ int checked; /* Temporary flag used when checking */ -+ union entry_ -+ { -+ struct file_info *file; -+ struct dir_info *dir; -+ } entry; -+}; -+ -+struct fd_info /* We keep a number of files open */ -+{ -+ struct fd_info *next; -+ struct file_info *file; -+ int fd; -+}; -+ -+struct open_file_info /* We keep a list of open files */ -+{ -+ struct open_file_info *next; -+ struct fd_info *fdi; -+}; -+ -+static struct dir_info *top_dir = NULL; /* Our top directory */ -+ -+static struct open_file_info *open_files = NULL; /* We keep a list of -+ open files */ -+static size_t open_files_count = 0; -+ -+static int grow = 1; /* Should we try to grow files and directories */ -+static int shrink = 0; /* Should we try to shrink files and directories */ -+static int full = 0; /* Flag that the file system is full */ -+static uint64_t operation_count = 0; /* Number of operations used to fill -+ up the file system */ -+static uint64_t initial_free_space = 0; /* Free space on file system when -+ test starts */ -+static unsigned log10_initial_free_space = 0; /* log10 of initial_free_space */ -+ -+static char *copy_string(const char *s) -+{ -+ char *str; -+ -+ if (!s) -+ return NULL; -+ str = (char *) malloc(strlen(s) + 1); -+ CHECK(str != NULL); -+ strcpy(str, s); -+ return str; -+} -+ -+static char *cat_strings(const char *a, const char *b) -+{ -+ char *str; -+ size_t sz; -+ -+ if (a && !b) -+ return copy_string(a); -+ if (b && !a) -+ return copy_string(b); -+ if (!a && !b) -+ return NULL; -+ sz = strlen(a) + strlen(b) + 1; -+ str = (char *) malloc(sz); -+ CHECK(str != NULL); -+ strcpy(str, a); -+ strcat(str, b); -+ return str; -+} -+ -+static char *cat_paths(const char *a, const char *b) -+{ -+ char *str; -+ size_t sz; -+ int as, bs; -+ size_t na, nb; -+ -+ if (a && !b) -+ return copy_string(a); -+ if (b && !a) -+ return copy_string(b); -+ if (!a && !b) -+ return NULL; -+ -+ as = 0; -+ bs = 0; -+ na = strlen(a); -+ nb = strlen(b); -+ if (na && a[na - 1] == '/') -+ as = 1; -+ if (nb && b[0] == '/') -+ bs = 1; -+ if ((as && !bs) || (!as && bs)) -+ return cat_strings(a, b); -+ if (as && bs) -+ return cat_strings(a, b + 1); -+ -+ sz = na + nb + 2; -+ str = (char *) malloc(sz); -+ CHECK(str != NULL); -+ strcpy(str, a); -+ strcat(str, "/"); -+ strcat(str, b); -+ return str; -+} -+ -+static char *dir_path(struct dir_info *parent, const char *name) -+{ -+ char *parent_path; -+ char *path; -+ -+ if (!parent) -+ return cat_paths(tests_file_system_mount_dir, name); -+ parent_path = dir_path(parent->parent, parent->name); -+ path = cat_paths(parent_path, name); -+ free(parent_path); -+ return path; -+} -+ -+static struct dir_entry_info *dir_entry_new(void) -+{ -+ struct dir_entry_info *entry; -+ size_t sz; -+ -+ sz = sizeof(struct dir_entry_info); -+ entry = (struct dir_entry_info *) malloc(sz); -+ CHECK(entry != NULL); -+ memset(entry, 0, sz); -+ return entry; -+} -+ -+static void open_file_add(struct fd_info *fdi) -+{ -+ struct open_file_info *ofi; -+ size_t sz; -+ -+ sz = sizeof(struct open_file_info); -+ ofi = (struct open_file_info *) malloc(sz); -+ CHECK(ofi != NULL); -+ memset(ofi, 0, sz); -+ ofi->next = open_files; -+ ofi->fdi = fdi; -+ open_files = ofi; -+ open_files_count += 1; -+} -+ -+static void open_file_remove(struct fd_info *fdi) -+{ -+ struct open_file_info *ofi; -+ struct open_file_info **prev; -+ -+ prev = &open_files; -+ for (ofi = open_files; ofi; ofi = ofi->next) { -+ if (ofi->fdi == fdi) { -+ *prev = ofi->next; -+ free(ofi); -+ open_files_count -= 1; -+ return; -+ } -+ prev = &ofi->next; -+ } -+ CHECK(0); /* We are trying to remove something that is not there */ -+} -+ -+static struct fd_info *fd_new(struct file_info *file, int fd) -+{ -+ struct fd_info *fdi; -+ size_t sz; -+ -+ sz = sizeof(struct fd_info); -+ fdi = (struct fd_info *) malloc(sz); -+ CHECK(fdi != NULL); -+ memset(fdi, 0, sz); -+ fdi->next = file->fds; -+ fdi->file = file; -+ fdi->fd = fd; -+ file->fds = fdi; -+ open_file_add(fdi); -+ return fdi; -+} -+ -+static struct dir_info *dir_new(struct dir_info *parent, const char *name) -+{ -+ struct dir_info *dir; -+ size_t sz; -+ char *path; -+ -+ path = dir_path(parent, name); -+ if (mkdir(path, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ full = 1; -+ free(path); -+ return NULL; -+ } -+ free(path); -+ -+ sz = sizeof(struct dir_info); -+ dir = (struct dir_info *) malloc(sz); -+ CHECK(dir != NULL); -+ memset(dir, 0, sz); -+ dir->name = copy_string(name); -+ dir->parent = parent; -+ if (parent) { -+ struct dir_entry_info *entry; -+ -+ entry = dir_entry_new(); -+ entry->type = 'd'; -+ entry->entry.dir = dir; -+ entry->next = parent->first; -+ parent->first = entry; -+ parent->number_of_entries += 1; -+ } -+ return dir; -+} -+ -+static void file_delete(struct file_info *file); -+ -+static void dir_remove(struct dir_info *dir) -+{ -+ char *path; -+ struct dir_entry_info *entry; -+ struct dir_entry_info **prev; -+ int found; -+ -+ /* Remove directory contents */ -+ while (dir->first) { -+ struct dir_entry_info *entry; -+ -+ entry = dir->first; -+ if (entry->type == 'd') -+ dir_remove(entry->entry.dir); -+ else if (entry->type == 'f') -+ file_delete(entry->entry.file); -+ else -+ CHECK(0); /* Invalid struct dir_entry_info */ -+ } -+ /* Remove entry from parent directory */ -+ found = 0; -+ prev = &dir->parent->first; -+ for (entry = dir->parent->first; entry; entry = entry->next) { -+ if (entry->type == 'd' && entry->entry.dir == dir) { -+ dir->parent->number_of_entries -= 1; -+ *prev = entry->next; -+ free(entry); -+ found = 1; -+ break; -+ } -+ prev = &entry->next; -+ } -+ CHECK(found); /* Check the file is in the parent directory */ -+ /* Remove directory itself */ -+ path = dir_path(dir->parent, dir->name); -+ CHECK(rmdir(path) != -1); -+} -+ -+static struct file_info *file_new(struct dir_info *parent, const char *name) -+{ -+ struct file_info *file = NULL; -+ char *path; -+ mode_t mode; -+ int fd; -+ size_t sz; -+ struct dir_entry_info *entry; -+ -+ CHECK(parent != NULL); -+ -+ path = dir_path(parent, name); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(path, O_CREAT | O_EXCL | O_RDWR, mode); -+ if (fd == -1) { -+ CHECK(errno == ENOSPC); -+ free(path); -+ full = 1; -+ return NULL; -+ } -+ free(path); -+ -+ sz = sizeof(struct file_info); -+ file = (struct file_info *) malloc(sz); -+ CHECK(file != NULL); -+ memset(file, 0, sz); -+ file->name = copy_string(name); -+ file->parent = parent; -+ -+ fd_new(file, fd); -+ -+ entry = dir_entry_new(); -+ entry->type = 'f'; -+ entry->entry.file = file; -+ entry->next = parent->first; -+ parent->first = entry; -+ parent->number_of_entries += 1; -+ -+ return file; -+} -+ -+static void file_delete(struct file_info *file) -+{ -+ char *path; -+ struct dir_entry_info *entry; -+ struct dir_entry_info **prev; -+ int found; -+ -+ /* Remove file entry from parent directory */ -+ found = 0; -+ prev = &file->parent->first; -+ for (entry = file->parent->first; entry; entry = entry->next) { -+ if (entry->type == 'f' && entry->entry.file == file) { -+ file->parent->number_of_entries -= 1; -+ *prev = entry->next; -+ free(entry); -+ found = 1; -+ break; -+ } -+ prev = &entry->next; -+ } -+ CHECK(found); /* Check the file is in the parent directory */ -+ -+ /* Delete the file */ -+ path = dir_path(file->parent, file->name); -+ CHECK(unlink(path) != -1); -+ free(path); -+ -+ /* Free struct file_info if file is not open */ -+ if (!file->fds) { -+ struct write_info *w, *next; -+ -+ free(file->name); -+ w = file->writes; -+ while (w) { -+ next = w->next; -+ free(w); -+ w = next; -+ } -+ free(file); -+ } else -+ file->deleted = 1; -+} -+ -+static void file_info_display(struct file_info *file) -+{ -+ struct write_info *w; -+ unsigned wcnt; -+ -+ fprintf(stderr, "File Info:\n"); -+ fprintf(stderr, " Name: %s\n", file->name); -+ fprintf(stderr, " Directory: %s\n", file->parent->name); -+ fprintf(stderr, " Length: %u\n", (unsigned) file->length); -+ fprintf(stderr, " File was open: %s\n", -+ (file->fds == NULL) ? "false" : "true"); -+ fprintf(stderr, " File was deleted: %s\n", -+ (file->deleted == 0) ? "false" : "true"); -+ fprintf(stderr, " File was out of space: %s\n", -+ (file->no_space_error == 0) ? "false" : "true"); -+ fprintf(stderr, " Write Info:\n"); -+ wcnt = 0; -+ w = file->writes; -+ while (w) { -+ fprintf(stderr, " Offset: %u Size: %u Seed: %u" -+ " R.Off: %u\n", -+ (unsigned) w->offset, -+ (unsigned) w->size, -+ (unsigned) w->random_seed, -+ (unsigned) w->random_offset); -+ wcnt += 1; -+ w = w->next; -+ } -+ fprintf(stderr, " %u writes\n", wcnt); -+ fprintf(stderr, " ============================================\n"); -+ fprintf(stderr, " Raw Write Info:\n"); -+ wcnt = 0; -+ w = file->raw_writes; -+ while (w) { -+ fprintf(stderr, " Offset: %u Size: %u Seed: %u" -+ " R.Off: %u\n", -+ (unsigned) w->offset, -+ (unsigned) w->size, -+ (unsigned) w->random_seed, -+ (unsigned) w->random_offset); -+ wcnt += 1; -+ w = w->next; -+ } -+ fprintf(stderr, " %u writes\n", wcnt); -+ fprintf(stderr, " ============================================\n"); -+} -+ -+static struct fd_info *file_open(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_RDWR); -+ CHECK(fd != -1); -+ free(path); -+ return fd_new(file, fd); -+} -+ -+#define BUFFER_SIZE 32768 -+ -+static size_t file_write_data( struct file_info *file, -+ int fd, -+ off_t offset, -+ size_t size, -+ unsigned seed) -+{ -+ size_t remains, actual, block; -+ ssize_t written; -+ char buf[BUFFER_SIZE]; -+ -+ srand(seed); -+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1); -+ remains = size; -+ actual = 0; -+ written = BUFFER_SIZE; -+ while (remains) { -+ /* Fill up buffer with random data */ -+ if (written < BUFFER_SIZE) -+ memmove(buf, buf + written, BUFFER_SIZE - written); -+ else -+ written = 0; -+ for (; written < BUFFER_SIZE; ++written) -+ buf[written] = rand(); -+ /* Write a block of data */ -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written < 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ full = 1; -+ file->no_space_error = 1; -+ break; -+ } -+ remains -= written; -+ actual += written; -+ } -+ return actual; -+} -+ -+static void file_write_info(struct file_info *file, -+ off_t offset, -+ size_t size, -+ unsigned seed) -+{ -+ struct write_info *new_write, *w, **prev, *tmp; -+ int inserted; -+ size_t sz; -+ off_t end, chg; -+ -+ /* Create struct write_info */ -+ sz = sizeof(struct write_info); -+ new_write = (struct write_info *) malloc(sz); -+ CHECK(new_write != NULL); -+ memset(new_write, 0, sz); -+ new_write->offset = offset; -+ new_write->size = size; -+ new_write->random_seed = seed; -+ -+ w = (struct write_info *) malloc(sz); -+ CHECK(w != NULL); -+ memset(w, 0, sz); -+ w->next = file->raw_writes; -+ w->offset = offset; -+ w->size = size; -+ w->random_seed = seed; -+ file->raw_writes = w; -+ -+ /* Insert it into file->writes */ -+ inserted = 0; -+ end = offset + size; -+ w = file->writes; -+ prev = &file->writes; -+ while (w) { -+ if (w->offset >= end) { -+ /* w comes after new_write, so insert before it */ -+ new_write->next = w; -+ *prev = new_write; -+ inserted = 1; -+ break; -+ } -+ /* w does not come after new_write */ -+ if (w->offset + w->size > offset) { -+ /* w overlaps new_write */ -+ if (w->offset < offset) { -+ /* w begins before new_write begins */ -+ if (w->offset + w->size <= end) -+ /* w ends before new_write ends */ -+ w->size = offset - w->offset; -+ else { -+ /* w ends after new_write ends */ -+ /* Split w */ -+ tmp = (struct write_info *) malloc(sz); -+ CHECK(tmp != NULL); -+ *tmp = *w; -+ chg = end - tmp->offset; -+ tmp->offset += chg; -+ tmp->random_offset += chg; -+ tmp->size -= chg; -+ w->size = offset - w->offset; -+ /* Insert new struct write_info */ -+ w->next = new_write; -+ new_write->next = tmp; -+ inserted = 1; -+ break; -+ } -+ } else { -+ /* w begins after new_write begins */ -+ if (w->offset + w->size <= end) { -+ /* w is completely overlapped, -+ so remove it */ -+ *prev = w->next; -+ tmp = w; -+ w = w->next; -+ free(tmp); -+ continue; -+ } -+ /* w ends after new_write ends */ -+ chg = end - w->offset; -+ w->offset += chg; -+ w->random_offset += chg; -+ w->size -= chg; -+ continue; -+ } -+ } -+ prev = &w->next; -+ w = w->next; -+ } -+ if (!inserted) -+ *prev = new_write; -+ /* Update file length */ -+ if (end > file->length) -+ file->length = end; -+} -+ -+/* Randomly select offset and and size to write in a file */ -+static void get_offset_and_size(struct file_info *file, -+ off_t *offset, -+ size_t *size) -+{ -+ size_t r, n; -+ -+ r = tests_random_no(100); -+ if (r == 0 && grow) -+ /* 1 time in 100, when growing, write off the end of the file */ -+ *offset = file->length + tests_random_no(10000000); -+ else if (r < 4) -+ /* 3 (or 4) times in 100, write at the beginning of file */ -+ *offset = 0; -+ else if (r < 52 || !grow) -+ /* 48 times in 100, write into the file */ -+ *offset = tests_random_no(file->length); -+ else -+ /* 48 times in 100, write at the end of the file */ -+ *offset = file->length; -+ /* Distribute the size logarithmically */ -+ if (tests_random_no(1000) == 0) -+ r = tests_random_no(log10_initial_free_space + 2); -+ else -+ r = tests_random_no(log10_initial_free_space); -+ n = 1; -+ while (r--) -+ n *= 10; -+ *size = tests_random_no(n); -+ if (!grow && *offset + *size > file->length) -+ *size = file->length - *offset; -+ if (*size == 0) -+ *size = 1; -+} -+ -+static void file_truncate_info(struct file_info *file, size_t new_length); -+static void file_close(struct fd_info *fdi); -+ -+static int file_ftruncate(struct file_info *file, int fd, off_t new_length) -+{ -+ if (ftruncate(fd, new_length) == -1) { -+ CHECK(errno = ENOSPC); -+ file->no_space_error = 1; -+ /* Delete errored files */ -+ if (!file->deleted) { -+ struct fd_info *fdi; -+ -+ fdi = file->fds; -+ while (fdi) { -+ file_close(fdi); -+ fdi = file->fds; -+ } -+ file_delete(file); -+ } -+ return 0; -+ } -+ return 1; -+} -+ -+static void file_write(struct file_info *file, int fd) -+{ -+ off_t offset; -+ size_t size, actual; -+ unsigned seed; -+ int truncate = 0; -+ -+ get_offset_and_size(file, &offset, &size); -+ seed = tests_random_no(10000000); -+ actual = file_write_data(file, fd, offset, size, seed); -+ -+ if (offset + actual <= file->length && shrink) -+ /* 1 time in 100, when shrinking -+ truncate after the write */ -+ if (tests_random_no(100) == 0) -+ truncate = 1; -+ -+ if (actual != 0) -+ file_write_info(file, offset, actual, seed); -+ -+ /* Delete errored files */ -+ if (file->no_space_error) { -+ if (!file->deleted) { -+ struct fd_info *fdi; -+ -+ fdi = file->fds; -+ while (fdi) { -+ file_close(fdi); -+ fdi = file->fds; -+ } -+ file_delete(file); -+ } -+ return; -+ } -+ -+ if (truncate) { -+ size_t new_length = offset + actual; -+ if (file_ftruncate(file, fd, new_length)) -+ file_truncate_info(file, new_length); -+ } -+} -+ -+static void file_write_file(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_WRONLY); -+ CHECK(fd != -1); -+ file_write(file, fd); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+static void file_truncate_info(struct file_info *file, size_t new_length) -+{ -+ struct write_info *w, **prev, *tmp; -+ -+ /* Remove / truncate file->writes */ -+ w = file->writes; -+ prev = &file->writes; -+ while (w) { -+ if (w->offset >= new_length) { -+ /* w comes after eof, so remove it */ -+ *prev = w->next; -+ tmp = w; -+ w = w->next; -+ free(tmp); -+ continue; -+ } -+ if (w->offset + w->size > new_length) -+ w->size = new_length - w->offset; -+ prev = &w->next; -+ w = w->next; -+ } -+ /* Update file length */ -+ file->length = new_length; -+} -+ -+static void file_truncate(struct file_info *file, int fd) -+{ -+ size_t new_length; -+ -+ new_length = tests_random_no(file->length); -+ -+ if (file_ftruncate(file, fd, new_length)) -+ file_truncate_info(file, new_length); -+} -+ -+static void file_truncate_file(struct file_info *file) -+{ -+ int fd; -+ char *path; -+ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_WRONLY); -+ CHECK(fd != -1); -+ file_truncate(file, fd); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+static void file_close(struct fd_info *fdi) -+{ -+ struct file_info *file; -+ struct fd_info *fdp; -+ struct fd_info **prev; -+ -+ /* Close file */ -+ CHECK(close(fdi->fd) != -1); -+ /* Remove struct fd_info */ -+ open_file_remove(fdi); -+ file = fdi->file; -+ prev = &file->fds; -+ for (fdp = file->fds; fdp; fdp = fdp->next) { -+ if (fdp == fdi) { -+ *prev = fdi->next; -+ free(fdi); -+ if (file->deleted && !file->fds) { -+ /* Closing deleted file */ -+ struct write_info *w, *next; -+ -+ w = file->writes; -+ while (w) { -+ next = w->next; -+ free(w); -+ w = next; -+ } -+ free(file->name); -+ free(file); -+ } -+ return; -+ } -+ prev = &fdp->next; -+ } -+ CHECK(0); /* Didn't find struct fd_info */ -+} -+ -+static void file_rewrite_data(int fd, struct write_info *w, char *buf) -+{ -+ size_t remains, block; -+ ssize_t written; -+ off_t r; -+ -+ srand(w->random_seed); -+ for (r = 0; r < w->random_offset; ++r) -+ rand(); -+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1); -+ remains = w->size; -+ written = BUFFER_SIZE; -+ while (remains) { -+ /* Fill up buffer with random data */ -+ if (written < BUFFER_SIZE) -+ memmove(buf, buf + written, BUFFER_SIZE - written); -+ else -+ written = 0; -+ for (; written < BUFFER_SIZE; ++written) -+ buf[written] = rand(); -+ /* Write a block of data */ -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ CHECK(written == block); -+ remains -= written; -+ } -+} -+ -+static void save_file(int fd, struct file_info *file) -+{ -+ int w_fd; -+ struct write_info *w; -+ char buf[BUFFER_SIZE]; -+ char name[256]; -+ -+ /* Open file to save contents to */ -+ strcpy(name, "/tmp/"); -+ strcat(name, file->name); -+ strcat(name, ".integ.sav.read"); -+ fprintf(stderr, "Saving %s\n", name); -+ w_fd = open(name, O_CREAT | O_WRONLY, 0777); -+ CHECK(w_fd != -1); -+ -+ /* Start at the beginning */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ -+ for (;;) { -+ ssize_t r = read(fd, buf, BUFFER_SIZE); -+ CHECK(r != -1); -+ if (!r) -+ break; -+ CHECK(write(w_fd, buf, r) == r); -+ } -+ CHECK(close(w_fd) != -1); -+ -+ /* Open file to save contents to */ -+ strcpy(name, "/tmp/"); -+ strcat(name, file->name); -+ strcat(name, ".integ.sav.written"); -+ fprintf(stderr, "Saving %s\n", name); -+ w_fd = open(name, O_CREAT | O_WRONLY, 0777); -+ CHECK(w_fd != -1); -+ -+ for (w = file->writes; w; w = w->next) -+ file_rewrite_data(w_fd, w, buf); -+ -+ CHECK(close(w_fd) != -1); -+} -+ -+static void file_check_hole( struct file_info *file, -+ int fd, off_t offset, -+ size_t size) -+{ -+ size_t remains, block, i; -+ char buf[BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, offset, SEEK_SET) != (off_t) -1); -+ remains = size; -+ while (remains) { -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ CHECK(read(fd, buf, block) == block); -+ for (i = 0; i < block; ++i) { -+ if (buf[i] != 0) { -+ fprintf(stderr, "file_check_hole failed at %u " -+ "checking hole at %u size %u\n", -+ (unsigned) (size - remains + i), -+ (unsigned) offset, -+ (unsigned) size); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(buf[i] == 0); -+ } -+ remains -= block; -+ } -+} -+ -+static void file_check_data( struct file_info *file, -+ int fd, -+ struct write_info *w) -+{ -+ size_t remains, block, i; -+ off_t r; -+ char buf[BUFFER_SIZE]; -+ -+ srand(w->random_seed); -+ for (r = 0; r < w->random_offset; ++r) -+ rand(); -+ CHECK(lseek(fd, w->offset, SEEK_SET) != (off_t) -1); -+ remains = w->size; -+ while (remains) { -+ if (remains > BUFFER_SIZE) -+ block = BUFFER_SIZE; -+ else -+ block = remains; -+ CHECK(read(fd, buf, block) == block); -+ for (i = 0; i < block; ++i) { -+ char c = (char) rand(); -+ if (buf[i] != c) { -+ fprintf(stderr, "file_check_data failed at %u " -+ "checking data at %u size %u\n", -+ (unsigned) (w->size - remains + i), -+ (unsigned) w->offset, -+ (unsigned) w->size); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(buf[i] == c); -+ } -+ remains -= block; -+ } -+} -+ -+static void file_check(struct file_info *file, int fd) -+{ -+ int open_and_close = 0; -+ char *path = NULL; -+ off_t pos; -+ struct write_info *w; -+ -+ /* Do not check files that have errored */ -+ if (file->no_space_error) -+ return; -+ if (fd == -1) -+ open_and_close = 1; -+ if (open_and_close) { -+ /* Open file */ -+ path = dir_path(file->parent, file->name); -+ fd = open(path, O_RDONLY); -+ CHECK(fd != -1); -+ } -+ /* Check length */ -+ pos = lseek(fd, 0, SEEK_END); -+ if (pos != file->length) { -+ fprintf(stderr, "file_check failed checking length " -+ "expected %u actual %u\n", -+ (unsigned) file->length, -+ (unsigned) pos); -+ file_info_display(file); -+ save_file(fd, file); -+ } -+ CHECK(pos == file->length); -+ /* Check each write */ -+ pos = 0; -+ for (w = file->writes; w; w = w->next) { -+ if (w->offset > pos) -+ file_check_hole(file, fd, pos, w->offset - pos); -+ file_check_data(file, fd, w); -+ pos = w->offset + w->size; -+ } -+ if (file->length > pos) -+ file_check_hole(file, fd, pos, file->length - pos); -+ if (open_and_close) { -+ CHECK(close(fd) != -1); -+ free(path); -+ } -+} -+ -+static const char *dir_entry_name(const struct dir_entry_info *entry) -+{ -+ CHECK(entry != NULL); -+ if (entry->type == 'd') -+ return entry->entry.dir->name; -+ else if (entry->type == 'f') -+ return entry->entry.file->name; -+ else { -+ CHECK(0); -+ return NULL; -+ } -+} -+ -+static int search_comp(const void *pa, const void *pb) -+{ -+ const struct dirent *a = (const struct dirent *) pa; -+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb; -+ return strcmp(a->d_name, dir_entry_name(b)); -+} -+ -+static void dir_entry_check(struct dir_entry_info **entry_array, -+ size_t number_of_entries, -+ struct dirent *ent) -+{ -+ struct dir_entry_info **found; -+ struct dir_entry_info *entry; -+ size_t sz; -+ -+ sz = sizeof(struct dir_entry_info *); -+ found = bsearch(ent, entry_array, number_of_entries, sz, search_comp); -+ CHECK(found != NULL); -+ entry = *found; -+ CHECK(!entry->checked); -+ entry->checked = 1; -+} -+ -+static int sort_comp(const void *pa, const void *pb) -+{ -+ const struct dir_entry_info *a = * (const struct dir_entry_info **) pa; -+ const struct dir_entry_info *b = * (const struct dir_entry_info **) pb; -+ return strcmp(dir_entry_name(a), dir_entry_name(b)); -+} -+ -+static void dir_check(struct dir_info *dir) -+{ -+ struct dir_entry_info **entry_array, **p; -+ size_t sz, n; -+ struct dir_entry_info *entry; -+ DIR *d; -+ struct dirent *ent; -+ unsigned checked = 0; -+ char *path; -+ -+ /* Create an array of entries */ -+ sz = sizeof(struct dir_entry_info *); -+ n = dir->number_of_entries; -+ entry_array = (struct dir_entry_info **) malloc(sz * n); -+ CHECK(entry_array != NULL); -+ -+ entry = dir->first; -+ p = entry_array; -+ while (entry) { -+ *p++ = entry; -+ entry->checked = 0; -+ entry = entry->next; -+ } -+ -+ /* Sort it by name */ -+ qsort(entry_array, n, sz, sort_comp); -+ -+ /* Go through directory on file system checking entries match */ -+ path = dir_path(dir->parent, dir->name); -+ d = opendir(path); -+ CHECK(d != NULL); -+ for (;;) { -+ errno = 0; -+ ent = readdir(d); -+ if (ent) { -+ if (strcmp(".",ent->d_name) != 0 && -+ strcmp("..",ent->d_name) != 0) { -+ dir_entry_check(entry_array, n, ent); -+ checked += 1; -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(closedir(d) != -1); -+ CHECK(checked == dir->number_of_entries); -+ free(path); -+ -+ /* Now check each entry */ -+ entry = dir->first; -+ while (entry) { -+ if (entry->type == 'd') -+ dir_check(entry->entry.dir); -+ else if (entry->type == 'f') -+ file_check(entry->entry.file, -1); -+ else -+ CHECK(0); -+ entry = entry->next; -+ } -+ -+ free(entry_array); -+} -+ -+static void check_deleted_files(void) -+{ -+ struct open_file_info *ofi; -+ -+ for (ofi = open_files; ofi; ofi = ofi->next) -+ if (ofi->fdi->file->deleted) -+ file_check(ofi->fdi->file, ofi->fdi->fd); -+} -+ -+static void close_open_files(void) -+{ -+ struct open_file_info *ofi; -+ -+ for (ofi = open_files; ofi; ofi = open_files) -+ file_close(ofi->fdi); -+} -+ -+static char *make_name(struct dir_info *dir) -+{ -+ static char name[256]; -+ struct dir_entry_info *entry; -+ int found; -+ -+ do { -+ found = 0; -+ sprintf(name, "%u", (unsigned) tests_random_no(1000000)); -+ for (entry = dir->first; entry; entry = entry->next) { -+ if (strcmp(dir_entry_name(entry), name) == 0) { -+ found = 1; -+ break; -+ } -+ } -+ } while (found); -+ return name; -+} -+ -+static void operate_on_dir(struct dir_info *dir); -+static void operate_on_file(struct file_info *file); -+ -+/* Randomly select something to do with a directory entry */ -+static void operate_on_entry(struct dir_entry_info *entry) -+{ -+ /* If shrinking, 1 time in 50, remove a directory */ -+ if (entry->type == 'd') { -+ if (shrink && tests_random_no(50) == 0) { -+ dir_remove(entry->entry.dir); -+ return; -+ } -+ operate_on_dir(entry->entry.dir); -+ } -+ /* If shrinking, 1 time in 10, remove a file */ -+ if (entry->type == 'f') { -+ if (shrink && tests_random_no(10) == 0) { -+ file_delete(entry->entry.file); -+ return; -+ } -+ operate_on_file(entry->entry.file); -+ } -+} -+ -+/* Randomly select something to do with a directory */ -+static void operate_on_dir(struct dir_info *dir) -+{ -+ size_t r; -+ struct dir_entry_info *entry; -+ -+ r = tests_random_no(12); -+ if (r == 0 && grow) -+ /* When growing, 1 time in 12 create a file */ -+ file_new(dir, make_name(dir)); -+ else if (r == 1 && grow) -+ /* When growing, 1 time in 12 create a directory */ -+ dir_new(dir, make_name(dir)); -+ else { -+ /* Otherwise randomly select an entry to operate on */ -+ r = tests_random_no(dir->number_of_entries); -+ entry = dir->first; -+ while (entry && r) { -+ entry = entry->next; -+ --r; -+ } -+ if (entry) -+ operate_on_entry(entry); -+ } -+} -+ -+/* Randomly select something to do with a file */ -+static void operate_on_file(struct file_info *file) -+{ -+ /* Try to keep at least 10 files open */ -+ if (open_files_count < 10) { -+ file_open(file); -+ return; -+ } -+ /* Try to keep about 20 files open */ -+ if (open_files_count < 20 && tests_random_no(2) == 0) { -+ file_open(file); -+ return; -+ } -+ /* Try to keep up to 40 files open */ -+ if (open_files_count < 40 && tests_random_no(20) == 0) { -+ file_open(file); -+ return; -+ } -+ /* Occasionly truncate */ -+ if (shrink && tests_random_no(100) == 0) { -+ file_truncate_file(file); -+ return; -+ } -+ /* Mostly just write */ -+ file_write_file(file); -+} -+ -+/* Randomly select something to do with an open file */ -+static void operate_on_open_file(struct fd_info *fdi) -+{ -+ size_t r; -+ -+ r = tests_random_no(1000); -+ if (shrink && r == 0) -+ file_truncate(fdi->file, fdi->fd); -+ else if (r < 21) -+ file_close(fdi); -+ else if (shrink && r < 121 && !fdi->file->deleted) -+ file_delete(fdi->file); -+ else -+ file_write(fdi->file, fdi->fd); -+} -+ -+/* Select an open file at random */ -+static void operate_on_an_open_file(void) -+{ -+ size_t r; -+ struct open_file_info *ofi; -+ -+ /* Close any open files that have errored */ -+ ofi = open_files; -+ while (ofi) { -+ if (ofi->fdi->file->no_space_error) { -+ struct fd_info *fdi; -+ -+ fdi = ofi->fdi; -+ ofi = ofi->next; -+ file_close(fdi); -+ } else -+ ofi = ofi->next; -+ } -+ r = tests_random_no(open_files_count); -+ for (ofi = open_files; ofi; ofi = ofi->next, --r) -+ if (!r) { -+ operate_on_open_file(ofi->fdi); -+ return; -+ } -+} -+ -+static void do_an_operation(void) -+{ -+ /* Half the time operate on already open files */ -+ if (tests_random_no(100) < 50) -+ operate_on_dir(top_dir); -+ else -+ operate_on_an_open_file(); -+} -+ -+static void create_test_data(void) -+{ -+ uint64_t i; -+ -+ grow = 1; -+ shrink = 0; -+ full = 0; -+ operation_count = 0; -+ while (!full) { -+ do_an_operation(); -+ ++operation_count; -+ } -+ grow = 0; -+ shrink = 1; -+ /* Drop to less than 90% full */ -+ for (;;) { -+ uint64_t free; -+ uint64_t total; -+ for (i = 0; i < 10; ++i) -+ do_an_operation(); -+ free = tests_get_free_space(); -+ total = tests_get_total_space(); -+ if ((free * 100) / total >= 10) -+ break; -+ } -+ grow = 0; -+ shrink = 0; -+ full = 0; -+ for (i = 0; i < operation_count * 2; ++i) -+ do_an_operation(); -+} -+ -+static void update_test_data(void) -+{ -+ uint64_t i; -+ -+ grow = 1; -+ shrink = 0; -+ full = 0; -+ while (!full) -+ do_an_operation(); -+ grow = 0; -+ shrink = 1; -+ /* Drop to less than 50% full */ -+ for (;;) { -+ uint64_t free; -+ uint64_t total; -+ for (i = 0; i < 10; ++i) -+ do_an_operation(); -+ free = tests_get_free_space(); -+ total = tests_get_total_space(); -+ if ((free * 100) / total >= 50) -+ break; -+ } -+ grow = 0; -+ shrink = 0; -+ full = 0; -+ for (i = 0; i < operation_count * 2; ++i) -+ do_an_operation(); -+} -+ -+void integck(void) -+{ -+ pid_t pid; -+ int64_t rpt; -+ uint64_t z; -+ char dir_name[256]; -+ -+ /* Make our top directory */ -+ pid = getpid(); -+ printf("pid is %u\n", (unsigned) pid); -+ tests_cat_pid(dir_name, "integck_test_dir_", pid); -+ if (chdir(dir_name) != -1) { -+ /* Remove it if it is already there */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+ } -+ initial_free_space = tests_get_free_space(); -+ log10_initial_free_space = 0; -+ for (z = initial_free_space; z >= 10; z /= 10) -+ ++log10_initial_free_space; -+ top_dir = dir_new(NULL, dir_name); -+ -+ if (!top_dir) -+ return; -+ -+ srand(pid); -+ -+ create_test_data(); -+ -+ if (!tests_fs_is_rootfs()) { -+ close_open_files(); -+ tests_remount(); /* Requires root access */ -+ } -+ -+ /* Check everything */ -+ dir_check(top_dir); -+ check_deleted_files(); -+ -+ for (rpt = 0; tests_repeat_parameter == 0 || -+ rpt < tests_repeat_parameter; ++rpt) { -+ update_test_data(); -+ -+ if (!tests_fs_is_rootfs()) { -+ close_open_files(); -+ tests_remount(); /* Requires root access */ -+ } -+ -+ /* Check everything */ -+ dir_check(top_dir); -+ check_deleted_files(); -+ } -+ -+ /* Tidy up by removing everything */ -+ close_open_files(); -+ tests_clear_dir(dir_name); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *integck_get_title(void) -+{ -+ return "Test file system integrity"; -+} -+ -+/* Description of this test */ -+ -+const char *integck_get_description(void) -+{ -+ return -+ "Create a directory named integck_test_dir_pid " \ -+ "where pid is the process id. " \ -+ "Randomly create and delete files and directories. " \ -+ "Randomly write to and truncate files. " \ -+ "Un-mount and re-mount test file " \ -+ "system (if it is not the root file system ). " \ -+ "Check data. Make more random changes. " \ -+ "Un-mount and re-mount again. Check again. " \ -+ "Repeat some number of times. " -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, integck_get_title(), -+ integck_get_description(), "n"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ integck(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,18 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -+ -+LDFLAGS := $(LDFLAGS) -+ -+all: tests.o -+ -+tests.o: tests.h -+ -+clean: -+ rm -f *.o -+ -+tests: -+ echo -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1091 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+char *tests_file_system_mount_dir = TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR; -+ -+char *tests_file_system_type = TESTS_DEFAULT_FILE_SYSTEM_TYPE; -+ -+int tests_ok_to_sync = 0; /* Whether to use fsync */ -+ -+/* General purpose test parameter to specify some aspect of test size. -+ May be used by different tests in different ways or not at all. -+ Set by the -z or --size option. */ -+int64_t tests_size_parameter = 0; -+ -+/* General purpose test parameter to specify some aspect of test repetition. -+ May be used by different tests in different ways or not at all. -+ Set by the -n, --repeat options. */ -+int64_t tests_repeat_parameter = 0; -+ -+/* General purpose test parameter to specify some aspect of test sleeping. -+ May be used by different tests in different ways or not at all. -+ Set by the -p, --sleep options. */ -+int64_t tests_sleep_parameter = 0; -+ -+/* Program name from argv[0] */ -+char *program_name = "unknown"; -+ -+/* General purpose test parameter to specify a file should be unlinked. -+ May be used by different tests in different ways or not at all. */ -+int tests_unlink_flag = 0; -+ -+/* General purpose test parameter to specify a file should be closed. -+ May be used by different tests in different ways or not at all. */ -+int tests_close_flag = 0; -+ -+/* General purpose test parameter to specify a file should be deleted. -+ May be used by different tests in different ways or not at all. */ -+int tests_delete_flag = 0; -+ -+/* General purpose test parameter to specify a file have a hole. -+ May be used by different tests in different ways or not at all. */ -+int tests_hole_flag = 0; -+ -+/* Whether it is ok to test on the root file system */ -+static int rootok = 0; -+ -+/* Function invoked by the CHECK macro */ -+void tests_test(int test,const char *msg,const char *file,unsigned line) -+{ -+ int eno; -+ time_t t; -+ -+ if (test) -+ return; -+ eno = errno; -+ time(&t); -+ fprintf(stderr, "Test failed: %s on %s" -+ "Test failed: %s in %s at line %u\n", -+ program_name, ctime(&t), msg, file, line); -+ if (eno) { -+ fprintf(stderr,"errno = %d\n",eno); -+ fprintf(stderr,"strerror = %s\n",strerror(eno)); -+ } -+ exit(1); -+} -+ -+static int is_zero(const char *p) -+{ -+ for (;*p;++p) -+ if (*p != '0') -+ return 0; -+ return 1; -+} -+ -+static void fold(const char *text, int width) -+{ -+ int pos, bpos = 0; -+ const char *p; -+ char line[1024]; -+ -+ if (width > 1023) { -+ printf("%s\n", text); -+ return; -+ } -+ p = text; -+ pos = 0; -+ while (p[pos]) { -+ while (!isspace(p[pos])) { -+ line[pos] = p[pos]; -+ if (!p[pos]) -+ break; -+ ++pos; -+ if (pos == width) { -+ line[pos] = '\0'; -+ printf("%s\n", line); -+ p += pos; -+ pos = 0; -+ } -+ } -+ while (pos < width) { -+ line[pos] = p[pos]; -+ if (!p[pos]) { -+ bpos = pos; -+ break; -+ } -+ if (isspace(p[pos])) -+ bpos = pos; -+ ++pos; -+ } -+ line[bpos] = '\0'; -+ printf("%s\n", line); -+ p += bpos; -+ pos = 0; -+ while (p[pos] && isspace(p[pos])) -+ ++p; -+ } -+} -+ -+/* Handle common program options */ -+int tests_get_args(int argc, -+ char *argv[], -+ const char *title, -+ const char *desc, -+ const char *opts) -+{ -+ int run_test = 0; -+ int display_help = 0; -+ int display_title = 0; -+ int display_description = 0; -+ int i; -+ char *s; -+ -+ program_name = argv[0]; -+ -+ s = getenv("TEST_FILE_SYSTEM_MOUNT_DIR"); -+ if (s) -+ tests_file_system_mount_dir = strdup(s); -+ s = getenv("TEST_FILE_SYSTEM_TYPE"); -+ if (s) -+ tests_file_system_type = strdup(s); -+ -+ run_test = 1; -+ rootok = 1; -+ for (i = 1; i < argc; ++i) { -+ if (strcmp(argv[i], "--help") == 0 || -+ strcmp(argv[i], "-h") == 0) -+ display_help = 1; -+ else if (strcmp(argv[i], "--title") == 0 || -+ strcmp(argv[i], "-t") == 0) -+ display_title = 1; -+ else if (strcmp(argv[i], "--description") == 0 || -+ strcmp(argv[i], "-d") == 0) -+ display_description = 1; -+ else if (strcmp(argv[i], "--sync") == 0 || -+ strcmp(argv[i], "-s") == 0) -+ tests_ok_to_sync = 1; -+ else if (strncmp(argv[i], "--size", 6) == 0 || -+ strncmp(argv[i], "-z", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n) -+ tests_size_parameter = n; -+ else { -+ int all_zero = 1; -+ for (; all_zero && *p; ++p) -+ if (*p != '0') -+ all_zero = 0; -+ if (all_zero) -+ tests_size_parameter = 0; -+ else -+ display_help = 1; -+ } -+ } else if (strncmp(argv[i], "--repeat", 8) == 0 || -+ strncmp(argv[i], "-n", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n || is_zero(p)) -+ tests_repeat_parameter = n; -+ else -+ display_help = 1; -+ } else if (strncmp(argv[i], "--sleep", 7) == 0 || -+ strncmp(argv[i], "-p", 2) == 0) { -+ int64_t n; -+ char *p; -+ if (i+1 < argc && !isdigit(argv[i][strlen(argv[i])-1])) -+ ++i; -+ p = argv[i]; -+ while (*p && !isdigit(*p)) -+ ++p; -+ n = atoll(p); -+ if (n || is_zero(p)) -+ tests_sleep_parameter = n; -+ else -+ display_help = 1; -+ } else if (strcmp(argv[i], "--unlink") == 0 || -+ strcmp(argv[i], "-u") == 0) -+ tests_unlink_flag = 1; -+ else if (strcmp(argv[i], "--hole") == 0 || -+ strcmp(argv[i], "-o") == 0) -+ tests_hole_flag = 1; -+ else if (strcmp(argv[i], "--close") == 0 || -+ strcmp(argv[i], "-c") == 0) -+ tests_close_flag = 1; -+ else if (strcmp(argv[i], "--delete") == 0 || -+ strcmp(argv[i], "-e") == 0) -+ tests_delete_flag = 1; -+ else -+ display_help = 1; -+ } -+ -+ if (display_help) { -+ run_test = 0; -+ display_title = 0; -+ display_description = 0; -+ if (!opts) -+ opts = ""; -+ printf("File System Test Program\n\n"); -+ printf("Test Title: %s\n\n", title); -+ printf("Usage is: %s [ options ]\n",argv[0]); -+ printf(" Options are:\n"); -+ printf(" -h, --help "); -+ printf("Display this help\n"); -+ printf(" -t, --title "); -+ printf("Display the test title\n"); -+ printf(" -d, --description "); -+ printf("Display the test description\n"); -+ if (strchr(opts, 's')) { -+ printf(" -s, --sync "); -+ printf("Make use of fsync\n"); -+ } -+ if (strchr(opts, 'z')) { -+ printf(" -z, --size "); -+ printf("Set size parameter\n"); -+ } -+ if (strchr(opts, 'n')) { -+ printf(" -n, --repeat "); -+ printf("Set repeat parameter\n"); -+ } -+ if (strchr(opts, 'p')) { -+ printf(" -p, --sleep "); -+ printf("Set sleep parameter\n"); -+ } -+ if (strchr(opts, 'u')) { -+ printf(" -u, --unlink "); -+ printf("Unlink file\n"); -+ } -+ if (strchr(opts, 'o')) { -+ printf(" -o, --hole "); -+ printf("Create a hole in a file\n"); -+ } -+ if (strchr(opts, 'c')) { -+ printf(" -c, --close "); -+ printf("Close file\n"); -+ } -+ if (strchr(opts, 'e')) { -+ printf(" -e, --delete "); -+ printf("Delete file\n"); -+ } -+ printf("\nBy default, testing is done in directory "); -+ printf("/mnt/test_file_system. To change this\nuse "); -+ printf("environmental variable "); -+ printf("TEST_FILE_SYSTEM_MOUNT_DIR. By default, "); -+ printf("the file\nsystem tested is jffs2. To change this "); -+ printf("set TEST_FILE_SYSTEM_TYPE.\n\n"); -+ printf("Test Description:\n"); -+ fold(desc, 80); -+ } else { -+ if (display_title) -+ printf("%s\n", title); -+ if (display_description) -+ printf("%s\n", desc); -+ if (display_title || display_description) -+ if (argc == 2 || (argc == 3 && -+ display_title && -+ display_description)) -+ run_test = 0; -+ } -+ return run_test; -+} -+ -+/* Return the number of files (or directories) in the given directory */ -+unsigned tests_count_files_in_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0; -+ -+ dir = opendir(dir_name); -+ CHECK(dir != NULL); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(closedir(dir) != -1); -+ return count; -+} -+ -+/* Change to the file system mount directory, check that it is empty, -+ matches the file system type, and is not the root file system */ -+void tests_check_test_file_system(void) -+{ -+ struct statfs fs_info; -+ struct stat f_info; -+ struct stat root_f_info; -+ -+ if (chdir(tests_file_system_mount_dir) == -1 || -+ statfs(tests_file_system_mount_dir, &fs_info) == -1) { -+ fprintf(stderr, "Invalid test file system mount directory:" -+ " %s\n", tests_file_system_mount_dir); -+ fprintf(stderr, "Use environment variable " -+ "TEST_FILE_SYSTEM_MOUNT_DIR\n"); -+ CHECK(0); -+ } -+ if (strcmp(tests_file_system_type, "jffs2") == 0 && -+ fs_info.f_type != JFFS2_SUPER_MAGIC) { -+ fprintf(stderr, "File system type is not jffs2\n"); -+ CHECK(0); -+ } -+ /* Check that the test file system is not the root file system */ -+ if (!rootok) { -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat("/", &root_f_info) != -1); -+ CHECK(f_info.st_dev != root_f_info.st_dev); -+ } -+} -+ -+/* Get the free space for the file system of the current directory */ -+uint64_t tests_get_free_space(void) -+{ -+ struct statvfs fs_info; -+ -+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1); -+ return (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize; -+} -+ -+/* Get the total space for the file system of the current directory */ -+uint64_t tests_get_total_space(void) -+{ -+ struct statvfs fs_info; -+ -+ CHECK(statvfs(tests_file_system_mount_dir, &fs_info) != -1); -+ return (uint64_t) fs_info.f_blocks * (uint64_t) fs_info.f_frsize; -+} -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+static char write_buffer[WRITE_BUFFER_SIZE]; -+ -+static void init_write_buffer() -+{ -+ static int init = 0; -+ -+ if (!init) { -+ int i, d; -+ uint64_t u; -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ srand(1); -+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i) -+ write_buffer[i] = rand() / d; -+ init = 1; -+ } -+} -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t tests_fill_file(int fd, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ init_write_buffer(); -+ remains = size; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual_size += written; -+ if (written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ tests_maybe_sync(fd); -+ return actual_size; -+} -+ -+/* Write size random bytes into file descriptor fd at offset, -+ returning the number of bytes actually written */ -+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ CHECK(lseek(fd, offset, SEEK_SET) == offset); -+ -+ init_write_buffer(); -+ remains = size; -+ start = offset % WRITE_BUFFER_SIZE; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual_size += written; -+ if (written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ tests_maybe_sync(fd); -+ return actual_size; -+} -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file_fd(int fd) -+{ -+ ssize_t sz; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ do { -+ sz = read(fd, buf, WRITE_BUFFER_SIZE); -+ CHECK(sz >= 0); -+ CHECK(memcmp(buf, write_buffer, sz) == 0); -+ } while (sz); -+} -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file(const char *file_name) -+{ -+ int fd; -+ -+ fd = open(file_name, O_RDONLY); -+ CHECK(fd != -1); -+ tests_check_filled_file_fd(fd); -+ CHECK(close(fd) != -1); -+} -+ -+void tests_sync_directory(const char *file_name) -+{ -+ char *path; -+ char *dir; -+ int fd; -+ -+ if (!tests_ok_to_sync) -+ return; -+ -+ path = strdup(file_name); -+ dir = dirname(path); -+ fd = open(dir,O_RDONLY | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ CHECK(fsync(fd) != -1); -+ CHECK(close(fd) != -1); -+ free(path); -+} -+ -+/* Delete a file */ -+void tests_delete_file(const char *file_name) -+{ -+ CHECK(unlink(file_name) != -1); -+ tests_sync_directory(file_name); -+} -+ -+/* Create a file of size file_size */ -+uint64_t tests_create_file(const char *file_name, uint64_t file_size) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ uint64_t actual_size; /* Less than size if the file system is full */ -+ -+ flags = O_CREAT | O_TRUNC | O_WRONLY | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_size = tests_fill_file(fd, file_size); -+ CHECK(close(fd) != -1); -+ if (file_size != 0 && actual_size == 0) -+ tests_delete_file(file_name); -+ else -+ tests_sync_directory(file_name); -+ return actual_size; -+} -+ -+/* Calculate: free_space * numerator / denominator */ -+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator) -+{ -+ if (denominator == 0) -+ denominator = 1; -+ if (numerator > denominator) -+ numerator = denominator; -+ return numerator * (tests_get_free_space() / denominator); -+} -+ -+/* Create file "fragment_n" where n is the file_number, and unlink it */ -+int tests_create_orphan(unsigned file_number) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ flags = O_CREAT | O_TRUNC | O_RDWR | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && (errno == ENOSPC || errno == EMFILE)) -+ return fd; /* File system full or too many open files */ -+ CHECK(fd != -1); -+ tests_sync_directory(file_name); -+ CHECK(unlink(file_name) != -1); -+ return fd; -+} -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_write_fragment_file(unsigned file_number, -+ int fd, -+ off_t offset, -+ unsigned size) -+{ -+ int i, d; -+ uint64_t u; -+ ssize_t written; -+ off_t pos; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ if (size > WRITE_BUFFER_SIZE) -+ size = WRITE_BUFFER_SIZE; -+ -+ pos = lseek(fd, 0, SEEK_END); -+ CHECK(pos != (off_t) -1); -+ if (offset > pos) -+ offset = pos; -+ -+ pos = lseek(fd, offset, SEEK_SET); -+ CHECK(pos != (off_t) -1); -+ CHECK(pos == offset); -+ -+ srand(file_number); -+ while (offset--) -+ rand(); -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (i = 0; i < size; ++i) -+ buf[i] = rand() / d; -+ -+ written = write(fd, buf, size); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ written = 0; -+ } -+ tests_maybe_sync(fd); -+ return (unsigned) written; -+} -+ -+/* Write size bytes to the end of file descriptor fd using file_number -+ to determine the random data written i.e. seed for random numbers */ -+unsigned tests_fill_fragment_file(unsigned file_number, int fd, unsigned size) -+{ -+ off_t offset; -+ -+ offset = lseek(fd, 0, SEEK_END); -+ CHECK(offset != (off_t) -1); -+ -+ return tests_write_fragment_file(file_number, fd, offset, size); -+} -+ -+/* Write size bytes to the end of file "fragment_n" where n is the file_number -+ and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_append_to_fragment_file(unsigned file_number, -+ unsigned size, -+ int create) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ unsigned actual_growth; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ if (create) -+ flags = O_CREAT | O_EXCL | O_WRONLY | tests_maybe_sync_flag(); -+ else -+ flags = O_WRONLY | tests_maybe_sync_flag(); -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_growth = tests_fill_fragment_file(file_number, fd, size); -+ CHECK(close(fd) != -1); -+ if (create && !actual_growth) -+ tests_delete_fragment_file(file_number); -+ return actual_growth; -+} -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_overwite_fragment_file( unsigned file_number, -+ off_t offset, -+ unsigned size) -+{ -+ int fd; -+ unsigned actual_size; -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ fd = open(file_name, O_RDWR | tests_maybe_sync_flag()); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ actual_size = tests_write_fragment_file(file_number, -+ fd, offset, size); -+ CHECK(close(fd) != -1); -+ return actual_size; -+} -+ -+/* Delete file "fragment_n" where n is the file_number */ -+void tests_delete_fragment_file(unsigned file_number) -+{ -+ char file_name[256]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ tests_delete_file(file_name); -+} -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file_fd(unsigned file_number, int fd) -+{ -+ ssize_t sz, i; -+ int d; -+ uint64_t u; -+ char buf[8192]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ srand(file_number); -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (;;) { -+ sz = read(fd, buf, 8192); -+ if (sz == 0) -+ break; -+ CHECK(sz >= 0); -+ for (i = 0; i < sz; ++i) -+ CHECK(buf[i] == (char) (rand() / d)); -+ } -+} -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file(unsigned file_number) -+{ -+ int fd; -+ ssize_t sz, i; -+ int d; -+ uint64_t u; -+ char file_name[256]; -+ char buf[8192]; -+ -+ sprintf(file_name, "fragment_%u", file_number); -+ fd = open(file_name, O_RDONLY); -+ CHECK(fd != -1); -+ srand(file_number); -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ for (;;) { -+ sz = read(fd, buf, 8192); -+ if (sz == 0) -+ break; -+ CHECK(sz >= 0); -+ for (i = 0; i < sz; ++i) -+ CHECK(buf[i] == (char) (rand() / d)); -+ } -+ CHECK(close(fd) != -1); -+} -+ -+/* Central point to decide whether to use fsync */ -+void tests_maybe_sync(int fd) -+{ -+ if (tests_ok_to_sync) -+ CHECK(fsync(fd) != -1); -+} -+ -+/* Return O_SYNC if ok to sync otherwise return 0 */ -+int tests_maybe_sync_flag(void) -+{ -+ if (tests_ok_to_sync) -+ return O_SYNC; -+ return 0; -+} -+ -+/* Return random number from 0 to n - 1 */ -+size_t tests_random_no(size_t n) -+{ -+ uint64_t a, b; -+ -+ if (!n) -+ return 0; -+ if (n - 1 <= RAND_MAX) { -+ a = rand(); -+ b = RAND_MAX; -+ b += 1; -+ } else { -+ const uint64_t u = 1 + (uint64_t) RAND_MAX; -+ a = rand(); -+ a *= u; -+ a += rand(); -+ b = u * u; -+ CHECK(n <= b); -+ } -+ if (RAND_MAX <= UINT32_MAX && n <= UINT32_MAX) -+ return a * n / b; -+ else /*if (RAND_MAX <= UINT64_MAX && n <= UINT64_MAX)*/ { -+ uint64_t x, y; -+ if (a < n) { -+ x = a; -+ y = n; -+ } else { -+ x = n; -+ y = a; -+ } -+ return (x * (y / b)) + ((x * (y % b)) / b); -+ } -+} -+ -+/* Make a directory empty */ -+void tests_clear_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ char buf[4096]; -+ -+ dir = opendir(dir_name); -+ CHECK(dir != NULL); -+ CHECK(getcwd(buf, 4096) != NULL); -+ CHECK(chdir(dir_name) != -1); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (entry->d_type == DT_DIR) { -+ tests_clear_dir(entry->d_name); -+ CHECK(rmdir(entry->d_name) != -1); -+ } else -+ CHECK(unlink(entry->d_name) != -1); -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ CHECK(chdir(buf) != -1); -+ CHECK(closedir(dir) != -1); -+} -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t tests_create_entry(char *return_name) -+{ -+ int fd; -+ char name[256]; -+ -+ for (;;) { -+ sprintf(name, "%u", (unsigned) tests_random_no(10000000)); -+ fd = open(name, O_RDONLY); -+ if (fd == -1) -+ break; -+ close(fd); -+ } -+ if (return_name) -+ strcpy(return_name, name); -+ if (tests_random_no(2)) { -+ return tests_create_file(name, tests_random_no(4096)); -+ } else { -+ if (mkdir(name, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ return 0; -+ } -+ return TESTS_EMPTY_DIR_SIZE; -+ } -+} -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t tests_remove_entry(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0, pos; -+ int64_t result = 0; -+ -+ dir = opendir("."); -+ CHECK(dir != NULL); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ pos = tests_random_no(count); -+ count = 0; -+ rewinddir(dir); -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (!entry) { -+ CHECK(errno == 0); -+ break; -+ } -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (count == pos) { -+ if (entry->d_type == DT_DIR) { -+ tests_clear_dir(entry->d_name); -+ CHECK(rmdir(entry->d_name) != -1); -+ result = TESTS_EMPTY_DIR_SIZE; -+ } else { -+ struct stat st; -+ CHECK(stat(entry->d_name, &st) != -1); -+ result = st.st_size; -+ CHECK(unlink(entry->d_name) != -1); -+ } -+ } -+ ++count; -+ } -+ } -+ CHECK(closedir(dir) != -1); -+ return result; -+} -+ -+/* Read mount information from /proc/mounts or /etc/mtab */ -+int tests_get_mount_info(struct mntent *info) -+{ -+ FILE *f; -+ struct mntent *entry; -+ int found = 0; -+ -+ f = fopen("/proc/mounts", "rb"); -+ if (!f) -+ f = fopen("/etc/mtab", "rb"); -+ CHECK(f != NULL); -+ while (!found) { -+ entry = getmntent(f); -+ if (entry) { -+ if (strcmp(entry->mnt_dir, -+ tests_file_system_mount_dir) == 0) { -+ found = 1; -+ *info = *entry; -+ } -+ } else -+ break; -+ } -+ CHECK(fclose(f) == 0); -+ return found; -+} -+ -+/* Un-mount and re-mount test file system */ -+void tests_remount(void) -+{ -+ struct mntent mount_info; -+ char *source; -+ char *target; -+ char *filesystemtype; -+ unsigned long mountflags; -+ void *data; -+ char cwd[4096]; -+ -+ CHECK(tests_get_mount_info(&mount_info)); -+ -+ if (strcmp(mount_info.mnt_dir,"/") == 0) -+ return; -+ -+ CHECK(getcwd(cwd, 4096) != NULL); -+ CHECK(chdir("/") != -1); -+ -+ CHECK(umount(tests_file_system_mount_dir) != -1); -+ -+ source = mount_info.mnt_fsname; -+ target = tests_file_system_mount_dir; -+ filesystemtype = tests_file_system_type; -+ mountflags = 0; -+ data = NULL; -+ -+ CHECK(mount(source, target, filesystemtype, mountflags, data) != -1); -+ -+ CHECK(chdir(cwd) != -1); -+} -+ -+/* Check whether the test file system is also the root file system */ -+int tests_fs_is_rootfs(void) -+{ -+ struct stat f_info; -+ struct stat root_f_info; -+ -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat("/", &root_f_info) != -1); -+ if (f_info.st_dev == root_f_info.st_dev) -+ return 1; -+ else -+ return 0; -+} -+ -+/* Try to make a directory empty */ -+void tests_try_to_clear_dir(const char *dir_name) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ char buf[4096]; -+ -+ dir = opendir(dir_name); -+ if (dir == NULL) -+ return; -+ if (getcwd(buf, 4096) == NULL || chdir(dir_name) == -1) { -+ closedir(dir); -+ return; -+ } -+ for (;;) { -+ errno = 0; -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (entry->d_type == DT_DIR) { -+ tests_try_to_clear_dir(entry->d_name); -+ rmdir(entry->d_name); -+ } else -+ unlink(entry->d_name); -+ } -+ } else { -+ CHECK(errno == 0); -+ break; -+ } -+ } -+ chdir(buf); -+ closedir(dir); -+} -+ -+/* Check whether the test file system is also the current file system */ -+int tests_fs_is_currfs(void) -+{ -+ struct stat f_info; -+ struct stat curr_f_info; -+ -+ CHECK(stat(tests_file_system_mount_dir, &f_info) != -1); -+ CHECK(stat(".", &curr_f_info) != -1); -+ if (f_info.st_dev == curr_f_info.st_dev) -+ return 1; -+ else -+ return 0; -+} -+ -+#define PID_BUF_SIZE 64 -+ -+/* Concatenate a pid to a string in a signal safe way */ -+void tests_cat_pid(char *buf, const char *name, pid_t pid) -+{ -+ char *p; -+ unsigned x; -+ const char digits[] = "0123456789"; -+ char pid_buf[PID_BUF_SIZE]; -+ -+ x = (unsigned) pid; -+ p = pid_buf + PID_BUF_SIZE; -+ *--p = '\0'; -+ if (x) -+ while (x) { -+ *--p = digits[x % 10]; -+ x /= 10; -+ } -+ else -+ *--p = '0'; -+ buf[0] = '\0'; -+ strcat(buf, name); -+ strcat(buf, p); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/lib/tests.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,199 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#ifndef included_tests_tests_h__ -+#define included_tests_tests_h__ -+ -+#include -+ -+/* Main macro for testing */ -+#define CHECK(x) tests_test((x),__func__,__FILE__,__LINE__) -+ -+/* The default directory in which tests are conducted */ -+#define TESTS_DEFAULT_FILE_SYSTEM_MOUNT_DIR "/mnt/test_file_system" -+ -+/* The default file system type to test */ -+#define TESTS_DEFAULT_FILE_SYSTEM_TYPE "jffs2" -+ -+/* Estimated size of an empty directory */ -+#define TESTS_EMPTY_DIR_SIZE 128 -+ -+/* Function invoked by the CHECK macro */ -+void tests_test(int test,const char *msg,const char *file,unsigned line); -+ -+/* Handle common program options */ -+int tests_get_args(int argc, -+ char *argv[], -+ const char *title, -+ const char *desc, -+ const char *opts); -+ -+/* Return the number of files (or directories) in the given directory */ -+unsigned tests_count_files_in_dir(const char *dir_name); -+ -+/* Change to the file system mount directory, check that it is empty, -+ matches the file system type, and is not the root file system */ -+void tests_check_test_file_system(void); -+ -+/* Get the free space for the file system of the current directory */ -+uint64_t tests_get_free_space(void); -+ -+/* Get the total space for the file system of the current directory */ -+uint64_t tests_get_total_space(void); -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t tests_fill_file(int fd, uint64_t size); -+ -+/* Write size random bytes into file descriptor fd at offset, -+ returning the number of bytes actually written */ -+uint64_t tests_write_filled_file(int fd, off_t offset, uint64_t size); -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file_fd(int fd); -+ -+/* Check that a file written using tests_fill_file() and/or -+ tests_write_filled_file() and/or tests_create_file() -+ contains the expected random data */ -+void tests_check_filled_file(const char *file_name); -+ -+/* Delete a file */ -+void tests_delete_file(const char *file_name); -+ -+/* Create a file of size file_size */ -+uint64_t tests_create_file(const char *file_name, uint64_t file_size); -+ -+/* Calculate: free_space * numerator / denominator */ -+uint64_t tests_get_big_file_size(unsigned numerator, unsigned denominator); -+ -+/* Create file "fragment_n" where n is the file_number, and unlink it */ -+int tests_create_orphan(unsigned file_number); -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_write_fragment_file(unsigned file_number, -+ int fd, -+ off_t offset, -+ unsigned size); -+ -+/* Write size bytes to the end of file descriptor fd using file_number -+ to determine the random data written i.e. seed for random numbers */ -+unsigned tests_fill_fragment_file(unsigned file_number, -+ int fd, -+ unsigned size); -+ -+/* Write size bytes to the end of file "fragment_n" where n is the file_number -+ and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_append_to_fragment_file(unsigned file_number, -+ unsigned size, -+ int create); -+ -+/* Write size bytes at offset to the file "fragment_n" where n is the -+ file_number and file_number also determines the random data written -+ i.e. seed for random numbers */ -+unsigned tests_overwite_fragment_file( unsigned file_number, -+ off_t offset, -+ unsigned size); -+ -+/* Delete file "fragment_n" where n is the file_number */ -+void tests_delete_fragment_file(unsigned file_number); -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file_fd(unsigned file_number, int fd); -+ -+/* Check the random data in file "fragment_n" is what is expected */ -+void tests_check_fragment_file(unsigned file_number); -+ -+/* Central point to decide whether to use fsync */ -+void tests_maybe_sync(int fd); -+ -+/* Return O_SYNC if ok to sync otherwise return 0 */ -+int tests_maybe_sync_flag(void); -+ -+/* Return random number from 0 to n - 1 */ -+size_t tests_random_no(size_t n); -+ -+/* Make a directory empty */ -+void tests_clear_dir(const char *dir_name); -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t tests_create_entry(char *return_name); -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t tests_remove_entry(void); -+ -+/* Un-mount and re-mount test file system */ -+void tests_remount(void); -+ -+/* Check whether the test file system is also the root file system */ -+int tests_fs_is_rootfs(void); -+ -+/* Try to make a directory empty */ -+void tests_try_to_clear_dir(const char *dir_name); -+ -+/* Check whether the test file system is also the current file system */ -+int tests_fs_is_currfs(void); -+ -+/* Concatenate a pid to a string in a signal safe way */ -+void tests_cat_pid(char *buf, const char *name, pid_t pid); -+ -+extern char *tests_file_system_mount_dir; -+ -+extern char *tests_file_system_type; -+ -+/* General purpose test parameter to specify some aspect of test size. -+ May be used by different tests in different ways. -+ Set by the -z, --size options. */ -+extern int64_t tests_size_parameter; -+ -+/* General purpose test parameter to specify some aspect of test repetition. -+ May be used by different tests in different ways. -+ Set by the -n, --repeat options. */ -+extern int64_t tests_repeat_parameter; -+ -+/* General purpose test parameter to specify some aspect of test sleeping. -+ May be used by different tests in different ways. -+ Set by the -p, --sleep options. */ -+extern int64_t tests_sleep_parameter; -+ -+/* General purpose test parameter to specify a file should be unlinked. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_unlink_flag; -+ -+/* General purpose test parameter to specify a file should be closed. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_close_flag; -+ -+/* General purpose test parameter to specify a file should be deleted. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_delete_flag; -+ -+/* General purpose test parameter to specify a file have a hole. -+ May be used by different tests in different ways or not at all. */ -+extern int tests_hole_flag; -+ -+/* Program name from argv[0] */ -+extern char *program_name; -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/run_all.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,49 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+rm -rf ${TEST_DIR}/* -+ -+./simple/test_1 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./simple/test_2 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./integrity/integck || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/rndrm00 -z0 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/rmdir00 -z0 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_1 -z10000000 -e || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_2 -z10000000 || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+./stress/atoms/stress_3 -z1000000000 -e || exit 1 -+ -+rm -rf ${TEST_DIR}/* -+ -+cd stress || exit 1 -+ -+./stress00.sh 3600 || exit 1 -+ -+./stress01.sh 3600 || exit 1 -+ -+cd .. || exit 1 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = test_1 \ -+ test_2 \ -+ ftrunc \ -+ orph -+ -+all: $(TARGETS) -+ -+$(TARGETS): ../lib/tests.o -+ -+../lib/tests.o: ../lib/tests.h -+ -+clean: -+ rm -f *.o $(TARGETS) -+ -+tests: all -+ ./test_1 --sync -+ ./test_2 --sync -+ ./ftrunc -+ ./orph --sync -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/ftrunc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void ftrunc(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char *file_name; -+ off_t actual; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ file_name = "ftrunc_test_file"; -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ actual = 0; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ actual += written; -+ } -+ CHECK(ftruncate(fd, (actual ? actual - 1 : actual)) != -1); -+ CHECK(close(fd) != -1); -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *ftrunc_get_title(void) -+{ -+ return "Truncate a large test file"; -+} -+ -+/* Description of this test */ -+ -+const char *ftrunc_get_description(void) -+{ -+ return -+ "Create a file named ftrunc_test_file. " \ -+ "Truncate the file to reduce its length by 1. " \ -+ "Then remove the truncated file. " -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, ftrunc_get_title(), -+ ftrunc_get_description(), "z"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ ftrunc(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/orph.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,184 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define MAX_ORPHANS 1000000 -+ -+void orph(void) -+{ -+ pid_t pid; -+ unsigned i, j, k, n; -+ int fd, done, full; -+ int64_t repeat; -+ ssize_t sz; -+ char dir_name[256]; -+ int fds[MAX_ORPHANS]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "orph_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ full = 0; -+ done = 0; -+ n = 0; -+ while (n + 100 < MAX_ORPHANS && !done) { -+ /* Make 100 more orphans */ -+ for (i = 0; i < 100; i++) { -+ fd = tests_create_orphan(n + i); -+ if (fd < 0) { -+ done = 1; -+ if (errno == ENOSPC) -+ full = 1; -+ else if (errno != EMFILE) -+ CHECK(0); -+ errno = 0; -+ break; -+ } -+ fds[n + i] = fd; -+ } -+ if (!full) { -+ /* Write to orphans just created */ -+ k = i; -+ for (i = 0; i < k; i++) { -+ if (tests_write_fragment_file(n + i, -+ fds[n+i], -+ 0, 1000) -+ != 1000) { -+ /* -+ * Out of space, so close -+ * remaining files -+ */ -+ for (j = i; j < k; j++) -+ CHECK(close(fds[n + j]) -+ != -1); -+ done = 1; -+ break; -+ } -+ } -+ } -+ if (!done) -+ CHECK(tests_count_files_in_dir(".") == 0); -+ n += i; -+ } -+ /* Check the data in the files */ -+ for (i = 0; i < n; i++) -+ tests_check_fragment_file_fd(i, fds[i]); -+ if (!full && n) { -+ /* Ensure the file system is full */ -+ n -= 1; -+ do { -+ sz = write(fds[n], fds, 4096); -+ if (sz == -1 && errno == ENOSPC) { -+ errno = 0; -+ break; -+ } -+ CHECK(sz >= 0); -+ } while (sz == 4096); -+ CHECK(close(fds[n]) != -1); -+ } -+ /* Check the data in the files */ -+ for (i = 0; i < n; i++) -+ tests_check_fragment_file_fd(i, fds[i]); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Close orphans */ -+ for (i = 0; i < n; i++) -+ CHECK(close(fds[i]) != -1); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ } -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *orph_get_title(void) -+{ -+ return "Create many open unlinked files"; -+} -+ -+/* Description of this test */ -+ -+const char *orph_get_description(void) -+{ -+ return -+ "Create a directory named orph_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create files and keep them open and unlink them. " \ -+ "Create as many files as possible until the file system is " \ -+ "full or the maximum allowed open files is reached. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " \ -+ "Sleep is specified in milliseconds. " \ -+ "Then close the files. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "Finally remove the directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, orph_get_title(), -+ orph_get_description(), "nps"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ orph(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_1.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,150 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void test_1(void) -+{ -+ int fd; -+ pid_t pid; -+ uint64_t i; -+ uint64_t block; -+ uint64_t actual_size; -+ char name[256]; -+ char old[16]; -+ char buf[16]; -+ off_t old_len; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "test_1_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Create a file that fills half the free space on the file system */ -+ tests_create_file("big_file", tests_get_big_file_size(1,2)); -+ CHECK(tests_count_files_in_dir(".") == 1); -+ fd = open("big_file", O_RDWR | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ CHECK(read(fd, old, 5) == 5); -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(write(fd,"start", 5) == 5); -+ CHECK(lseek(fd,0,SEEK_END) != (off_t) -1); -+ CHECK(write(fd, "end", 3) == 3); -+ tests_maybe_sync(fd); -+ /* Delete the file while it is still open */ -+ tests_delete_file("big_file"); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ /* Create files to file up the file system */ -+ for (block = 1000000, i = 1; ; block /= 10) { -+ while (i != 0) { -+ sprintf(name, "fill_up_%llu", i); -+ actual_size = tests_create_file(name, block); -+ if (actual_size != 0) -+ ++i; -+ if (actual_size != block) -+ break; -+ } -+ if (block == 1) -+ break; -+ } -+ /* Check the big file */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(read(fd, buf, 5) == 5); -+ CHECK(strncmp(buf, "start", 5) == 0); -+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1); -+ CHECK(read(fd, buf, 3) == 3); -+ CHECK(strncmp(buf, "end", 3) == 0); -+ /* Check the other files and delete them */ -+ i -= 1; -+ CHECK(tests_count_files_in_dir(".") == i); -+ for (; i > 0; --i) { -+ sprintf(name, "fill_up_%llu", i); -+ tests_check_filled_file(name); -+ tests_delete_file(name); -+ } -+ CHECK(tests_count_files_in_dir(".") == 0); -+ /* Check the big file again */ -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(read(fd, buf, 5) == 5); -+ CHECK(strncmp(buf, "start", 5) == 0); -+ CHECK(lseek(fd, -3, SEEK_END) != (off_t) -1); -+ CHECK(read(fd, buf, 3) == 3); -+ CHECK(strncmp(buf, "end", 3) == 0); -+ CHECK(lseek(fd, 0, SEEK_SET) != (off_t) -1); -+ CHECK(write(fd,old, 5) == 5); -+ old_len = lseek(fd, -3, SEEK_END); -+ CHECK(old_len != (off_t) -1); -+ CHECK(ftruncate(fd,old_len) != -1); -+ tests_check_filled_file_fd(fd); -+ /* Close the big file*/ -+ CHECK(close(fd) != -1); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *test_1_get_title(void) -+{ -+ return "Fill file system while holding deleted big file descriptor"; -+} -+ -+/* Description of this test */ -+ -+const char *test_1_get_description(void) -+{ -+ return -+ "Create a directory named test_1_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create a big file (approx. half the file system in size), " \ -+ "open it, and unlink it. " \ -+ "Create many smaller files until the file system is full. " \ -+ "Check the big file is ok. " \ -+ "Delete all the smaller files. " \ -+ "Check the big file again. " \ -+ "Finally delete the big file and directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, test_1_get_title(), -+ test_1_get_description(), "s"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ test_1(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/simple/test_2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,201 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void test_2(void) -+{ -+ pid_t pid; -+ int create, full; -+ unsigned i, number_of_files; -+ unsigned growth; -+ unsigned size; -+ uint64_t big_file_size; -+ int fd; -+ off_t offset; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "test_2_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Create up to 1000 files appending 400 bytes at a time to each file */ -+ /* until the file system is full.*/ -+ create = 1; -+ full = 0; -+ number_of_files = 1000; -+ while (!full) { -+ for (i = 0; i < number_of_files; ++i) { -+ growth = tests_append_to_fragment_file(i, 400, create); -+ if (!growth) { -+ full = 1; -+ if (create) -+ number_of_files = i; -+ break; -+ } -+ } -+ create = 0; -+ } -+ /* Check the files */ -+ CHECK(tests_count_files_in_dir(".") == number_of_files); -+ for (i = 0; i < number_of_files; ++i) -+ tests_check_fragment_file(i); -+ /* Delete half of them */ -+ for (i = 1; i < number_of_files; i += 2) -+ tests_delete_fragment_file(i); -+ /* Check them again */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ /* Create a big file that fills two thirds of the free space */ -+ big_file_size = tests_get_big_file_size(2,3); -+ /* Check the big file */ -+ tests_create_file("big_file", big_file_size); -+ CHECK(tests_count_files_in_dir(".") == 1 + (number_of_files + 1) / 2); -+ tests_check_filled_file("big_file"); -+ /* Open the big file */ -+ fd = open("big_file",O_RDWR | tests_maybe_sync_flag()); -+ CHECK(fd != -1); -+ /* Delete the big file while it is still open */ -+ tests_delete_file("big_file"); -+ /* Check the big file again */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ tests_check_filled_file_fd(fd); -+ -+ /* Write parts of the files and check them */ -+ -+ offset = 100; /* Offset to write at, in the small files */ -+ size = 200; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 300; /* Offset to write at, in the small files */ -+ size = 400; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 110; /* Offset to write at, in the small files */ -+ size = 10; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 10; /* Offset to write at, in the small files */ -+ size = 1000; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ offset = 0; /* Offset to write at, in the small files */ -+ size = 100000; /* Number of bytes to write at the offset */ -+ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_overwite_fragment_file(i, offset, size); -+ /* Rewrite the big file entirely */ -+ tests_write_filled_file(fd, 0, big_file_size); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ tests_check_filled_file_fd(fd); -+ -+ /* Close the big file*/ -+ CHECK(close(fd) != -1); -+ /* Check the small files */ -+ CHECK(tests_count_files_in_dir(".") == (number_of_files + 1) / 2); -+ for (i = 0; i < number_of_files; i += 2) -+ tests_check_fragment_file(i); -+ /* Delete the small files */ -+ for (i = 0; i < number_of_files; i += 2) -+ tests_delete_fragment_file(i); -+ CHECK(tests_count_files_in_dir(".") == 0); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *test_2_get_title(void) -+{ -+ return "Repeated write many small files and one big deleted file"; -+} -+ -+/* Description of this test */ -+ -+const char *test_2_get_description(void) -+{ -+ return -+ "Create a directory named test_2_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "create about 1000 files. Append 400 bytes to each until " \ -+ "the file system is full. Then delete half of them. Then " \ -+ "create a big file that uses about 2/3 of the remaining free " \ -+ "space. Get a file descriptor for the big file, and delete " \ -+ "the big file. Then repeatedly write to the small files " \ -+ "and the big file. " \ -+ "Finally delete the big file and directory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, test_2_get_title(), -+ test_2_get_description(), "s"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ test_2(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+ -+SUBDIRS = atoms -+ -+all tests: $(SUBDIRS) -+ -+clean: $(SUBDIRS) -+ rm -rf run_pdf_test_file_* -+ -+.PHONY: $(SUBDIRS) -+$(SUBDIRS): -+ $(MAKE) -C $@ $(MAKECMDGOALS) -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = stress_1 \ -+ stress_2 \ -+ stress_3 \ -+ pdfrun \ -+ rndwrite00 \ -+ fwrite00 \ -+ rmdir00 \ -+ rndrm00 \ -+ rndrm99 \ -+ gcd_hupper -+ -+all: $(TARGETS) -+ -+$(TARGETS): ../../lib/tests.o -+ -+../lib/tests.o: ../../lib/tests.h -+ -+clean: -+ rm -f *.o $(TARGETS) run_pdf_test_file -+ -+tests: all -+ ./stress_1 -e -+ ./stress_2 -+ ./stress_3 -e -+ ./pdfrun -+ ./rndwrite00 -e -+ ./fwrite00 -+ ./rmdir00 -+ ./rndrm00 -+ ./rndrm99 -+ ./gcd_hupper -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/fwrite00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,209 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+#define HOLE_BLOCK_SIZE 10000000 -+ -+void filestress00(void) -+{ -+ int fd, i, deleted; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ int64_t repeat; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ fd = -1; -+ deleted = 1; -+ pid = getpid(); -+ tests_cat_pid(file_name, "filestress00_test_file_", pid); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ /* Open the file */ -+ if (fd == -1) { -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ deleted = 0; -+ if (tests_unlink_flag) { -+ CHECK(unlink(file_name) != -1); -+ deleted = 1; -+ } -+ } -+ /* Get a different set of random data */ -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ if (tests_hole_flag) { -+ /* Make a hole */ -+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1); -+ written = write(fd, "!", 1); -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ } -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ /* Write at set points into the hole */ -+ remains = tests_size_parameter; -+ while (remains > HOLE_BLOCK_SIZE) { -+ CHECK(lseek(fd, HOLE_BLOCK_SIZE, -+ SEEK_CUR) != -1); -+ written = write(fd, "!", 1); -+ remains -= HOLE_BLOCK_SIZE; -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ break; -+ } -+ } -+ } else { -+ /* Write data into the file */ -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ /* File system full */ -+ CHECK(errno == ENOSPC); -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ } -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Close if tests_close_flag */ -+ if (tests_close_flag) { -+ CHECK(close(fd) != -1); -+ fd = -1; -+ } -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Delete if tests_delete flag */ -+ if (!deleted && tests_delete_flag) { -+ CHECK(unlink(file_name) != -1); -+ deleted = 1; -+ } -+ } -+ CHECK(close(fd) != -1); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ /* Tidy up */ -+ if (!deleted) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *filestress00_get_title(void) -+{ -+ return "File stress test 00"; -+} -+ -+/* Description of this test */ -+ -+const char *filestress00_get_description(void) -+{ -+ return -+ "Create a file named filestress00_test_file_pid, where " \ -+ "pid is the process id. If the unlink option " \ -+ "(-u or --unlink) is specified, " \ -+ "unlink the file while holding the open file descriptor. " \ -+ "If the hole option (-o or --hole) is specified, " \ -+ "write a single character at the end of the file, creating a " \ -+ "hole. " \ -+ "Write a single character in the hole every 10 million " \ -+ "bytes. " \ -+ "If the hole option is not specified, then the file is " \ -+ "filled with random data. " \ -+ "If the close option (-c or --close) is specified the file " \ -+ "is closed. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "If the delete option (-e or --delete) is specified, then " \ -+ "the file is deleted. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The file size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " \ -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, filestress00_get_title(), -+ filestress00_get_description(), "znpuoce"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ filestress00(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/gcd_hupper.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,259 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define MAX_NAME_SIZE 1024 -+ -+struct gcd_pid -+{ -+ struct gcd_pid *next; -+ int pid; -+ char *name; -+ int mtd_index; -+}; -+ -+struct gcd_pid *gcd_pid_list = NULL; -+ -+int add_gcd_pid(const char *number) -+{ -+ int pid; -+ FILE *f; -+ char file_name[MAX_NAME_SIZE]; -+ char program_name[MAX_NAME_SIZE]; -+ -+ pid = atoi(number); -+ if (pid <= 0) -+ return 0; -+ snprintf(file_name, MAX_NAME_SIZE, "/proc/%s/stat", number); -+ f = fopen(file_name, "r"); -+ if (f == NULL) -+ return 0; -+ if (fscanf(f, "%d %s", &pid, program_name) != 2) { -+ fclose(f); -+ return 0; -+ } -+ if (strncmp(program_name, "(jffs2_gcd_mtd", 14) != 0) -+ pid = 0; -+ if (pid) { -+ size_t sz; -+ struct gcd_pid *g; -+ -+ sz = sizeof(struct gcd_pid); -+ g = (struct gcd_pid *) malloc(sz); -+ g->pid = pid; -+ g->name = (char *) malloc(strlen(program_name) + 1); -+ if (g->name) -+ strcpy(g->name, program_name); -+ else -+ exit(1); -+ g->mtd_index = atoi(program_name + 14); -+ g->next = gcd_pid_list; -+ gcd_pid_list = g; -+ } -+ fclose(f); -+ return pid; -+} -+ -+int get_pid_list(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ -+ dir = opendir("/proc"); -+ if (dir == NULL) -+ return 1; -+ for (;;) { -+ entry = readdir(dir); -+ if (entry) { -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ add_gcd_pid(entry->d_name); -+ } else -+ break; -+ } -+ closedir(dir); -+ return 0; -+} -+ -+int parse_index_number(const char *name) -+{ -+ const char *p, *q; -+ int all_zero; -+ int index; -+ -+ p = name; -+ while (*p && !isdigit(*p)) -+ ++p; -+ if (!*p) -+ return -1; -+ all_zero = 1; -+ for (q = p; *q; ++q) { -+ if (!isdigit(*q)) -+ return -1; -+ if (*q != '0') -+ all_zero = 0; -+ } -+ if (all_zero) -+ return 0; -+ index = atoi(p); -+ if (index <= 0) -+ return -1; -+ return index; -+} -+ -+int get_mtd_index(void) -+{ -+ FILE *f; -+ struct mntent *entry; -+ struct stat f_info; -+ struct stat curr_f_info; -+ int found; -+ int mtd_index = -1; -+ -+ if (stat(tests_file_system_mount_dir, &f_info) == -1) -+ return -1; -+ f = fopen("/proc/mounts", "rb"); -+ if (!f) -+ f = fopen("/etc/mtab", "rb"); -+ if (f == NULL) -+ return -1; -+ found = 0; -+ for (;;) { -+ entry = getmntent(f); -+ if (!entry) -+ break; -+ if (stat(entry->mnt_dir, &curr_f_info) == -1) -+ continue; -+ if (f_info.st_dev == curr_f_info.st_dev) { -+ int i; -+ -+ i = parse_index_number(entry->mnt_fsname); -+ if (i != -1) { -+ if (found && i != mtd_index) -+ return -1; -+ found = 1; -+ mtd_index = i; -+ } -+ } -+ } -+ fclose(f); -+ return mtd_index; -+} -+ -+int get_gcd_pid() -+{ -+ struct gcd_pid *g; -+ int mtd_index; -+ -+ if (get_pid_list()) -+ return 0; -+ mtd_index = get_mtd_index(); -+ if (mtd_index == -1) -+ return 0; -+ for (g = gcd_pid_list; g; g = g->next) -+ if (g->mtd_index == mtd_index) -+ return g->pid; -+ return 0; -+} -+ -+void gcd_hupper(void) -+{ -+ int64_t repeat; -+ int pid; -+ -+ pid = get_gcd_pid(); -+ CHECK(pid != 0); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ CHECK(kill(pid, SIGHUP) != -1); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+} -+ -+/* Title of this test */ -+ -+const char *gcd_hupper_get_title(void) -+{ -+ return "Send HUP signals to gcd"; -+} -+ -+/* Description of this test */ -+ -+const char *gcd_hupper_get_description(void) -+{ -+ return -+ "Determine the PID of the gcd process. " \ -+ "Send it SIGHUP (may require root privileges). " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 1. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, gcd_hupper_get_title(), -+ gcd_hupper_get_description(), "np"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ gcd_hupper(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/pdfrun.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,143 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void adjust_size(void) -+{ -+ char dummy[1024]; -+ unsigned long total_memory; -+ FILE *f; -+ -+ total_memory = 0; -+ f = fopen("/proc/meminfo", "r"); -+ fscanf(f, "%s %lu", dummy, &total_memory); -+ fclose(f); -+ if (total_memory > 0 && tests_size_parameter > total_memory / 2) -+ tests_size_parameter = total_memory / 2; -+} -+ -+void run_pdf(void) -+{ -+ int fd, i; -+ pid_t pid; -+ int64_t repeat; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ if (tests_fs_is_currfs()) -+ return; -+ adjust_size(); -+ pid = getpid(); -+ tests_cat_pid(file_name, "run_pdf_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ CHECK(lseek(fd, 0, SEEK_SET) == 0); -+ } -+ CHECK(close(fd) != -1); -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *run_pdf_get_title(void) -+{ -+ return "Create / overwrite a large file in the current directory"; -+} -+ -+/* Description of this test */ -+ -+const char *run_pdf_get_description(void) -+{ -+ return -+ "Create a file named run_pdf_test_file_pid, " \ -+ "where pid is the process id. The file is created " \ -+ "in the current directory, " \ -+ "if the current directory is NOT on the test " \ -+ "file system, otherwise no action is taken. " \ -+ "If a repeat count is specified, then the task repeats " \ -+ "that number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The size is adjusted so that it is not more than " \ -+ "half the size of total memory."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, run_pdf_get_title(), -+ run_pdf_get_description(), "zn"); -+ if (!run_test) -+ return 1; -+ /* Do the actual test */ -+ run_pdf(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rmdir00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void rmdir00(void) -+{ -+ int64_t repeat; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rmdir00_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Remove everything in the directory */ -+ tests_clear_dir("."); -+ /* Fill with sub-dirs and small files */ -+ do { -+ this_size = tests_create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rmdir00_get_title(void) -+{ -+ return "Create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rmdir00_get_description(void) -+{ -+ return -+ "Create a directory named rmdir00_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, create " \ -+ "a number of sub-directories and small files. " \ -+ "The total size of all sub-directories and files " \ -+ "is specified by the size parameter. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration, " \ -+ "and then removing the sub-directories and files created " \ -+ "during the last iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rmdir00_get_title(), -+ rmdir00_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rmdir00(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,157 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+void rndrm00(void) -+{ -+ int64_t repeat; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rndrm00_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Create and remove sub-dirs and small files, */ -+ /* but tending to grow */ -+ do { -+ if (tests_random_no(3)) { -+ this_size = tests_create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } else { -+ this_size = tests_remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ if (!this_size) -+ this_size = 1; -+ } -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Create and remove sub-dirs and small files, but */ -+ /* but tending to shrink */ -+ do { -+ if (!tests_random_no(3)) { -+ this_size = tests_create_entry(NULL); -+ size += this_size; -+ } else { -+ this_size = tests_remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ } -+ } while ((tests_size_parameter != 0 && -+ size > tests_size_parameter / 10) || -+ (tests_size_parameter == 0 && size > 100000)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rndrm00_get_title(void) -+{ -+ return "Randomly create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rndrm00_get_description(void) -+{ -+ return -+ "Create a directory named rndrm00_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "randomly create and remove " \ -+ "a number of sub-directories and small files, " \ -+ "but do more creates than removes. " \ -+ "When the total size of all sub-directories and files " \ -+ "is greater than the size specified by the size parameter, " \ -+ "start to do more removes than creates. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndrm00_get_title(), -+ rndrm00_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndrm00(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndrm99.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,431 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+uint32_t files_created = 0; -+uint32_t files_removed = 0; -+uint32_t dirs_created = 0; -+uint32_t dirs_removed = 0; -+int64_t *size_ptr = 0; -+ -+void display_stats(void) -+{ -+ printf( "\nrndrm99 stats:\n" -+ "\tNumber of files created = %u\n" -+ "\tNumber of files deleted = %u\n" -+ "\tNumber of directories created = %u\n" -+ "\tNumber of directories deleted = %u\n" -+ "\tCurrent net size of creates and deletes = %lld\n", -+ (unsigned) files_created, -+ (unsigned) files_removed, -+ (unsigned) dirs_created, -+ (unsigned) dirs_removed, -+ (long long) (size_ptr ? *size_ptr : 0)); -+ fflush(stdout); -+} -+ -+struct timeval tv_before; -+struct timeval tv_after; -+ -+void before(void) -+{ -+ CHECK(gettimeofday(&tv_before, NULL) != -1); -+} -+ -+void after(const char *msg) -+{ -+ time_t diff; -+ CHECK(gettimeofday(&tv_after, NULL) != -1); -+ diff = tv_after.tv_sec - tv_before.tv_sec; -+ if (diff >= 8) { -+ printf("\nrndrm99: the following fn took more than 8 seconds: %s (took %u secs)\n",msg,(unsigned) diff); -+ fflush(stdout); -+ display_stats(); -+ } -+} -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+static char write_buffer[WRITE_BUFFER_SIZE]; -+ -+static void init_write_buffer() -+{ -+ static int init = 0; -+ -+ if (!init) { -+ int i, d; -+ uint64_t u; -+ -+ u = RAND_MAX; -+ u += 1; -+ u /= 256; -+ d = (int) u; -+ srand(1); -+ for (i = 0; i < WRITE_BUFFER_SIZE; ++i) -+ write_buffer[i] = rand() / d; -+ init = 1; -+ } -+} -+ -+/* Write size random bytes into file descriptor fd at the current position, -+ returning the number of bytes actually written */ -+uint64_t fill_file(int fd, uint64_t size) -+{ -+ ssize_t written; -+ size_t sz; -+ unsigned start = 0, length; -+ uint64_t remains; -+ uint64_t actual_size = 0; -+ -+ init_write_buffer(); -+ remains = size; -+ while (remains > 0) { -+ length = WRITE_BUFFER_SIZE - start; -+ if (remains > length) -+ sz = length; -+ else -+ sz = (size_t) remains; -+ before(); -+ written = write(fd, write_buffer + start, sz); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ after("write"); -+ fprintf(stderr,"\nrndrm99: write failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ break; -+ } -+ after("write"); -+ remains -= written; -+ actual_size += written; -+ if ((size_t) written == sz) -+ start = 0; -+ else -+ start += written; -+ } -+ return actual_size; -+} -+ -+/* Create a file of size file_size */ -+uint64_t create_file(const char *file_name, uint64_t file_size) -+{ -+ int fd; -+ int flags; -+ mode_t mode; -+ uint64_t actual_size; /* Less than size if the file system is full */ -+ -+ flags = O_CREAT | O_TRUNC | O_WRONLY; -+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; -+ before(); -+ fd = open(file_name, flags, mode); -+ if (fd == -1 && errno == ENOSPC) { -+ errno = 0; -+ after("open"); -+ fprintf(stderr,"\nrndrm99: open failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ return 0; /* File system full */ -+ } -+ CHECK(fd != -1); -+ after("open"); -+ actual_size = fill_file(fd, file_size); -+ before(); -+ CHECK(close(fd) != -1); -+ after("close"); -+ if (file_size != 0 && actual_size == 0) { -+ printf("\nrndrm99: unlinking zero size file\n");fflush(stdout); -+ before(); -+ CHECK(unlink(file_name) != -1); -+ after("unlink (create_file)"); -+ } -+ return actual_size; -+} -+ -+/* Create an empty sub-directory or small file in the current directory */ -+int64_t create_entry(char *return_name) -+{ -+ int fd; -+ char name[256]; -+ int64_t res; -+ -+ for (;;) { -+ sprintf(name, "%u", (unsigned) tests_random_no(10000000)); -+ before(); -+ fd = open(name, O_RDONLY); -+ after("open (create_entry)"); -+ if (fd == -1) -+ break; -+ before(); -+ close(fd); -+ after("close (create_entry)"); -+ } -+ if (return_name) -+ strcpy(return_name, name); -+ if (tests_random_no(2)) { -+ res = create_file(name, tests_random_no(4096)); -+ if (res > 0) -+ files_created += 1; -+ return res; -+ } else { -+ before(); -+ if (mkdir(name, 0777) == -1) { -+ CHECK(errno == ENOSPC); -+ after("mkdir"); -+ errno = 0; -+ fprintf(stderr,"\nrndrm99: mkdir failed with ENOSPC\n");fflush(stderr); -+ display_stats(); -+ return 0; -+ } -+ after("mkdir"); -+ dirs_created += 1; -+ return TESTS_EMPTY_DIR_SIZE; -+ } -+} -+ -+/* Remove a random file of empty sub-directory from the current directory */ -+int64_t remove_entry(void) -+{ -+ DIR *dir; -+ struct dirent *entry; -+ unsigned count = 0, pos; -+ int64_t result = 0; -+ -+ before(); -+ dir = opendir("."); -+ CHECK(dir != NULL); -+ after("opendir"); -+ for (;;) { -+ errno = 0; -+ before(); -+ entry = readdir(dir); -+ if (entry) { -+ after("readdir 1"); -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) -+ ++count; -+ } else { -+ CHECK(errno == 0); -+ after("readdir 1"); -+ break; -+ } -+ } -+ pos = tests_random_no(count); -+ count = 0; -+ before(); -+ rewinddir(dir); -+ after("rewinddir"); -+ for (;;) { -+ errno = 0; -+ before(); -+ entry = readdir(dir); -+ if (!entry) { -+ CHECK(errno == 0); -+ after("readdir 2"); -+ break; -+ } -+ after("readdir 2"); -+ if (strcmp(".",entry->d_name) != 0 && -+ strcmp("..",entry->d_name) != 0) { -+ if (count == pos) { -+ if (entry->d_type == DT_DIR) { -+ before(); -+ tests_clear_dir(entry->d_name); -+ after("tests_clear_dir"); -+ before(); -+ CHECK(rmdir(entry->d_name) != -1); -+ after("rmdir"); -+ result = TESTS_EMPTY_DIR_SIZE; -+ dirs_removed += 1; -+ } else { -+ struct stat st; -+ before(); -+ CHECK(stat(entry->d_name, &st) != -1); -+ after("stat"); -+ result = st.st_size; -+ before(); -+ CHECK(unlink(entry->d_name) != -1); -+ after("unlink"); -+ files_removed += 1; -+ } -+ } -+ ++count; -+ } -+ } -+ before(); -+ CHECK(closedir(dir) != -1); -+ after("closedir"); -+ return result; -+} -+ -+void rndrm99(void) -+{ -+ int64_t repeat, loop_cnt; -+ int64_t size, this_size; -+ pid_t pid; -+ char dir_name[256]; -+ -+ size_ptr = &size; -+ /* Create a directory to test in */ -+ pid = getpid(); -+ tests_cat_pid(dir_name, "rndrm99_test_dir_", pid); -+ if (chdir(dir_name) == -1) -+ CHECK(mkdir(dir_name, 0777) != -1); -+ CHECK(chdir(dir_name) != -1); -+ /* Repeat loop */ -+ repeat = tests_repeat_parameter; -+ size = 0; -+ for (;;) { -+ /* Create and remove sub-dirs and small files, */ -+ /* but tending to grow */ -+ printf("\nrndrm99: growing\n");fflush(stdout); -+ loop_cnt = 0; -+ do { -+ if (loop_cnt++ % 2000 == 0) -+ display_stats(); -+ if (tests_random_no(3)) { -+ this_size = create_entry(NULL); -+ if (!this_size) -+ break; -+ size += this_size; -+ } else { -+ this_size = remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ if (!this_size) -+ this_size = 1; -+ } -+ } while (this_size && -+ (tests_size_parameter == 0 || -+ size < tests_size_parameter)); -+ /* Create and remove sub-dirs and small files, but */ -+ /* but tending to shrink */ -+ printf("\nrndrm99: shrinking\n");fflush(stdout); -+ loop_cnt = 0; -+ do { -+ if (loop_cnt++ % 2000 == 0) -+ display_stats(); -+ if (!tests_random_no(3)) { -+ this_size = create_entry(NULL); -+ size += this_size; -+ } else { -+ this_size = remove_entry(); -+ size -= this_size; -+ if (size < 0) -+ size = 0; -+ } -+ } while ((tests_size_parameter != 0 && -+ size > tests_size_parameter / 10) || -+ (tests_size_parameter == 0 && size > 100000)); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ printf("\nrndrm99: sleeping\n");fflush(stdout); -+ usleep(s); -+ } -+ } -+ printf("\nrndrm99: tidying\n");fflush(stdout); -+ display_stats(); -+ /* Tidy up by removing everything */ -+ tests_clear_dir("."); -+ CHECK(chdir("..") != -1); -+ CHECK(rmdir(dir_name) != -1); -+ size_ptr = 0; -+} -+ -+/* Title of this test */ -+ -+const char *rndrm99_get_title(void) -+{ -+ return "Randomly create and remove directories and files"; -+} -+ -+/* Description of this test */ -+ -+const char *rndrm99_get_description(void) -+{ -+ return -+ "Create a directory named rndrm99_test_dir_pid, where " \ -+ "pid is the process id. Within that directory, " \ -+ "randomly create and remove " \ -+ "a number of sub-directories and small files, " \ -+ "but do more creates than removes. " \ -+ "When the total size of all sub-directories and files " \ -+ "is greater than the size specified by the size parameter, " \ -+ "start to do more removes than creates. " \ -+ "The size parameter is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "A size of zero fills the file system until there is no " -+ "space left. " \ -+ "The task repeats, sleeping in between each iteration. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 1. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 1; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndrm99_get_title(), -+ rndrm99_get_description(), "znp"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndrm99(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/rndwrite00.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,201 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define BLOCK_SIZE 32768 -+#define BUFFER_SIZE 32768 -+ -+static void check_file(int fd, char *data, size_t length) -+{ -+ size_t n, i; -+ char buf[BUFFER_SIZE]; -+ -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ n = 0; -+ for (;;) { -+ i = read(fd, buf, BUFFER_SIZE); -+ CHECK(i >= 0); -+ if (i == 0) -+ break; -+ CHECK(memcmp(buf, data + n, i) == 0); -+ n += i; -+ } -+ CHECK(n == length); -+} -+ -+void rndwrite00(void) -+{ -+ int fd; -+ pid_t pid; -+ ssize_t written; -+ size_t remains; -+ size_t block; -+ size_t actual_size; -+ size_t check_every; -+ char *data, *p, *q; -+ off_t offset; -+ size_t size; -+ int64_t repeat; -+ char file_name[256]; -+ char buf[4096]; -+ -+ /* Create file */ -+ pid = getpid(); -+ tests_cat_pid(file_name, "rndwrite00_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ /* Allocate memory to hold file data */ -+ CHECK(tests_size_parameter > 0); -+ CHECK(tests_size_parameter <= SIZE_MAX); -+ data = (char *) malloc(tests_size_parameter); -+ CHECK(data != NULL); -+ /* Fill with random data */ -+ srand(pid); -+ for (p = data, q = data + tests_size_parameter; p != q; ++p) -+ *p = rand(); -+ /* Write to file */ -+ p = data; -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > BLOCK_SIZE) -+ block = BLOCK_SIZE; -+ else -+ block = remains; -+ written = write(fd, p, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ p += written; -+ } -+ actual_size = p - data; -+ /* Repeating bit */ -+ repeat = tests_repeat_parameter; -+ check_every = actual_size / 8192; -+ for (;;) { -+ offset = tests_random_no(actual_size); -+ size = tests_random_no(4096); -+ /* Don't change the file size */ -+ if (offset + size > actual_size) -+ size = actual_size - offset; -+ if (!size) -+ continue; -+ for (p = buf, q = p + size; p != q; ++p) -+ *p = rand(); -+ CHECK(lseek(fd, offset, SEEK_SET) != -1); -+ written = write(fd, buf, size); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ } else -+ memcpy(data + offset, buf, written); -+ /* Break if repeat count exceeded */ -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ if (repeat % check_every == 0) -+ check_file(fd, data, actual_size); -+ /* Sleep */ -+ if (tests_sleep_parameter > 0) { -+ unsigned us = tests_sleep_parameter * 1000; -+ unsigned rand_divisor = RAND_MAX / us; -+ unsigned s = (us / 2) + (rand() / rand_divisor); -+ usleep(s); -+ } -+ } -+ /* Check and close file */ -+ check_file(fd, data, actual_size); -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *rndwrite00_get_title(void) -+{ -+ return "Randomly write a large test file"; -+} -+ -+/* Description of this test */ -+ -+const char *rndwrite00_get_description(void) -+{ -+ return -+ "Create a file named rndwrite00_test_file_pid, where " \ -+ "pid is the process id. " \ -+ "The file is filled with random data. " \ -+ "The size of the file is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "Then a randomly sized block of random data is written at a " \ -+ "random location in the file. "\ -+ "The block size is always in the range 1 to 4095. " \ -+ "If a sleep value is specified, the process sleeps. " \ -+ "The number of writes is given by the repeat count. " \ -+ "The repeat count is set by the -n or --repeat option, " \ -+ "otherwise it defaults to 10000. " \ -+ "A repeat count of zero repeats forever. " \ -+ "The sleep value is given by the -p or --sleep option, " \ -+ "otherwise it defaults to 0. " -+ "Sleep is specified in milliseconds. " \ -+ "Periodically the data in the file is checked with a copy " \ -+ "held in memory. " \ -+ "If the delete option is specified the file is finally " \ -+ "deleted."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 10000; -+ -+ /* Set default test sleep */ -+ tests_sleep_parameter = 0; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, rndwrite00_get_title(), -+ rndwrite00_get_description(), "zne"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ rndwrite00(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_1.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,109 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_1(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ pid = getpid(); -+ tests_cat_pid(file_name, "stress_1_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_1_get_title(void) -+{ -+ return "Create / overwrite a large file"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_1_get_description(void) -+{ -+ return -+ "Create a file named stress_1_test_file_pid, " \ -+ "where pid is the process id. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The file will be deleted if the delete option " \ -+ "is specified. "; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_1_get_title(), -+ stress_1_get_description(), "ze"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_1(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_2.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,120 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_2(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ int64_t repeat; -+ size_t block; -+ char *file_name; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ file_name = "stress_2_test_file"; -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ CHECK(unlink(file_name) != -1); -+ pid = getpid(); -+ srand(pid); -+ repeat = tests_repeat_parameter; -+ for (;;) { -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ if (tests_repeat_parameter > 0 && --repeat <= 0) -+ break; -+ } -+ CHECK(close(fd) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_2_get_title(void) -+{ -+ return "Create / overwrite a large deleted file"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_2_get_description(void) -+{ -+ return -+ "Create a file named stress_2_test_file. " \ -+ "Open it, delete it while holding the open file descriptor, " \ -+ "then fill it with random data. " \ -+ "Repeated re-write the file some number of times. " \ -+ "The repeat count is given by the -n or --repeat option, " \ -+ "otherwise it defaults to 10. " \ -+ "The file size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Set default test repetition */ -+ tests_repeat_parameter = 10; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_2_get_title(), -+ stress_2_get_description(), "zn"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_2(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/atoms/stress_3.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,122 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tests.h" -+ -+#define WRITE_BUFFER_SIZE 32768 -+ -+void stress_3(void) -+{ -+ int fd, i; -+ pid_t pid; -+ ssize_t written; -+ int64_t remains; -+ size_t block; -+ char file_name[256]; -+ char buf[WRITE_BUFFER_SIZE]; -+ -+ pid = getpid(); -+ tests_cat_pid(file_name, "stress_3_test_file_", pid); -+ fd = open(file_name, O_CREAT | O_WRONLY, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ CHECK(fd != -1); -+ pid = getpid(); -+ srand(pid); -+ for (i = 0; i < WRITE_BUFFER_SIZE;++i) -+ buf[i] = rand(); -+ CHECK(lseek(fd, tests_size_parameter, SEEK_SET) != -1); -+ CHECK(write(fd, "!", 1) == 1); -+ CHECK(lseek(fd, 0, SEEK_SET) != -1); -+ remains = tests_size_parameter; -+ while (remains > 0) { -+ if (remains > WRITE_BUFFER_SIZE) -+ block = WRITE_BUFFER_SIZE; -+ else -+ block = remains; -+ written = write(fd, buf, block); -+ if (written <= 0) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ break; -+ } -+ remains -= written; -+ } -+ if (ftruncate(fd, 0) == -1) { -+ CHECK(errno == ENOSPC); /* File system full */ -+ errno = 0; -+ } -+ CHECK(close(fd) != -1); -+ if (tests_delete_flag) -+ CHECK(unlink(file_name) != -1); -+} -+ -+/* Title of this test */ -+ -+const char *stress_3_get_title(void) -+{ -+ return "Create a file with a large hole and fill it"; -+} -+ -+/* Description of this test */ -+ -+const char *stress_3_get_description(void) -+{ -+ return -+ "Create a file named stress_3_test_file_pid, " \ -+ "where pid is the process id. " \ -+ "Write a single character past the end of the file, " \ -+ "based on the specified file size, " \ -+ "which creates a hole in the file. " -+ "Fill the hole with random data. " \ -+ "Then truncate the file length to zero. " \ -+ "The size is given by the -z or --size option, " \ -+ "otherwise it defaults to 1000000. " \ -+ "The file will be deleted if the delete option " \ -+ "is specified."; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int run_test; -+ -+ /* Set default test file size */ -+ tests_size_parameter = 1000000; -+ -+ /* Handle common arguments */ -+ run_test = tests_get_args(argc, argv, stress_3_get_title(), -+ stress_3_get_description(), "ze"); -+ if (!run_test) -+ return 1; -+ /* Change directory to the file system and check it is ok for testing */ -+ tests_check_test_file_system(); -+ /* Do the actual test */ -+ stress_3(); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress00.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,52 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+FREESPACE=`../utils/free_space "$TEST_DIR"` -+ -+if test -z "$FREESPACE"; -+then -+ echo "Failed to determine free space" -+ exit 1 -+fi -+ -+if test -n "$1"; -+then -+ DURATION="-d$1"; -+else -+ DURATION=""; -+fi -+ -+FWRITE00=atoms/fwrite00 -+RNDWR=atoms/rndwrite00 -+GCHUP=atoms/gcd_hupper -+PDFLUSH=atoms/pdfrun -+FSIZE=$(( $FREESPACE/15 )); -+ -+../utils/fstest_monitor $DURATION \ -+"$FWRITE00 -z $FSIZE -n0 -p 20" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -s" \ -+"$FWRITE00 -z $FSIZE -n0 -p 20 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 70 -o" \ -+"$FWRITE00 -z $FSIZE -n0 -p 15 -s -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -u -o -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 10 -o -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -o -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -p 100 -s -o" \ -+"$RNDWR -z $FSIZE -n0 -p 10 -e" \ -+"$RNDWR -z $FSIZE -n0 -p 100 -e" \ -+"$PDFLUSH -z 1073741824 -n0" -+ -+STATUS=$? -+ -+rm -rf ${TEST_DIR}/* -+ -+exit $STATUS -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/stress/stress01.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+#!/bin/sh -+ -+TEST_DIR=$TEST_FILE_SYSTEM_MOUNT_DIR -+if test -z "$TEST_DIR"; -+then -+ TEST_DIR="/mnt/test_file_system" -+fi -+ -+FREESPACE=`../utils/free_space "$TEST_DIR"` -+ -+if test -z "$FREESPACE"; -+then -+ echo "Failed to determine free space" -+ exit 1 -+fi -+ -+if test -n "$1"; -+then -+ DURATION="-d$1"; -+else -+ DURATION=""; -+fi -+ -+FWRITE00=atoms/fwrite00 -+RNDWR=atoms/rndwrite00 -+PDFLUSH=atoms/pdfrun -+FSIZE=$(( $FREESPACE/15 )); -+ -+../utils/fstest_monitor $DURATION \ -+"$FWRITE00 -z $FSIZE -n0 -p 300" \ -+"$FWRITE00 -z $FSIZE -n0 -u" \ -+"$FWRITE00 -z $FSIZE -n0 -u -c" \ -+"$FWRITE00 -z $FSIZE -n0 -s -o" \ -+"$RNDWR -z $FSIZE -n0 -e" -+ -+STATUS=$? -+ -+rm -rf ${TEST_DIR}/* -+ -+exit $STATUS -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+CFLAGS := $(CFLAGS) -Wall -g -O2 -I../lib -+ -+LDFLAGS := $(LDFLAGS) -+ -+TARGETS = fstest_monitor free_space -+ -+all: $(TARGETS) -+ -+clean: -+ rm -f *.o $(TARGETS) -+ -+tests: all -+ ./fstest_monitor -+ ./free_space > /dev/null -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/free_space.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+ -+int main(int argc, char *argv[]) -+{ -+ char *dir_name = "."; -+ uint64_t free_space; -+ struct statvfs fs_info; -+ -+ if (argc > 1) { -+ if (strncmp(argv[1], "--help", 6) == 0 || -+ strncmp(argv[1], "-h", 2) == 0) { -+ printf( "Usage is: " -+ "free_space [directory]\n" -+ "\n" -+ "Display the free space of the file system " -+ "of the directory given\n" -+ "or the current directory if no " -+ "directory is given.\nThe value output is " -+ "in bytes.\n" -+ ); -+ return 1; -+ } -+ dir_name = argv[1]; -+ } -+ if (statvfs(dir_name, &fs_info) == -1) -+ return 1; -+ -+ free_space = (uint64_t) fs_info.f_bavail * (uint64_t) fs_info.f_frsize; -+ -+ printf("%llu\n", (unsigned long long) free_space); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/fs-tests/utils/fstest_monitor.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -+ * 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct child_info { -+ struct child_info *next; -+ pid_t pid; -+ int terminated; -+ int killed; -+ int gone; -+}; -+ -+struct child_info *children = 0; -+ -+void kill_children(void) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (!child->gone) { -+ if (!child->terminated) { -+ child->terminated = 1; -+ kill(child->pid, SIGTERM); -+ } /*else if (!child->killed) { -+ child->killed = 1; -+ kill(child->pid, SIGKILL); -+ }*/ -+ } -+ child = child->next; -+ } -+} -+ -+void add_child(pid_t child_pid) -+{ -+ struct child_info *child; -+ size_t sz; -+ -+ sz = sizeof(struct child_info); -+ child = (struct child_info *) malloc(sz); -+ memset(child, 0, sz); -+ child->pid = child_pid; -+ child->next = children; -+ children = child; -+} -+ -+void mark_child_gone(pid_t child_pid) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (child->pid == child_pid) { -+ child->gone = 1; -+ break; -+ } -+ child = child->next; -+ } -+} -+ -+int have_children(void) -+{ -+ struct child_info *child; -+ -+ child = children; -+ while (child) { -+ if (!child->gone) -+ return 1; -+ child = child->next; -+ } -+ return 0; -+} -+ -+int parse_command_line(char *cmdline, int *pargc, char ***pargv) -+{ -+ char **tmp; -+ char *p, *v, *q; -+ size_t sz; -+ int argc = 0; -+ int state = 0; -+ char *argv[1024]; -+ -+ if (!cmdline) -+ return 1; -+ q = v = (char *) malloc(strlen(cmdline) + 1024); -+ if (!v) -+ return 1; -+ p = cmdline; -+ for (;;) { -+ char c = *p++; -+ if (!c) { -+ *v++ = 0; -+ break; -+ } -+ switch (state) { -+ case 0: /* Between args */ -+ if (isspace(c)) -+ break; -+ argv[argc++] = v; -+ if (c == '"') { -+ state = 2; -+ break; -+ } else if (c == '\'') { -+ state = 3; -+ break; -+ } -+ state = 1; -+ case 1: /* Not quoted */ -+ if (c == '\\') { -+ if (*p) -+ *v++ = *p; -+ } else if (isspace(c)) { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ case 2: /* Double quoted */ -+ if (c == '\\' && *p == '"') { -+ *v++ = '"'; -+ ++p; -+ } else if (c == '"') { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ case 3: /* Single quoted */ -+ if (c == '\'') { -+ *v++ = 0; -+ state = 0; -+ } else -+ *v++ = c; -+ break; -+ } -+ } -+ argv[argc] = 0; -+ sz = sizeof(char *) * (argc + 1); -+ tmp = (char **) malloc(sz); -+ if (!tmp) { -+ free(q); -+ return 1; -+ } -+ if (argc == 0) -+ free(q); -+ memcpy(tmp, argv, sz); -+ *pargc = argc; -+ *pargv = tmp; -+ return 0; -+} -+ -+void signal_handler(int signum) -+{ -+ kill_children(); -+} -+ -+int result = 0; -+int alarm_gone_off = 0; -+ -+void alarm_handler(int signum) -+{ -+ if (!result) -+ alarm_gone_off = 1; -+ kill_children(); -+} -+ -+int main(int argc, char *argv[], char **env) -+{ -+ int p; -+ pid_t child_pid; -+ int status; -+ int duration = 0; -+ -+ p = 1; -+ if (argc > 1) { -+ if (strncmp(argv[p], "--help", 6) == 0 || -+ strncmp(argv[p], "-h", 2) == 0) { -+ printf( "Usage is: " -+ "fstest_monitor options programs...\n" -+ " Options are:\n" -+ " -h, --help " -+ "This help message\n" -+ " -d, --duration arg " -+ "Stop after arg seconds\n" -+ "\n" -+ "Run programs and wait for them." -+ " If duration is specified,\n" -+ "kill all programs" -+ " after that number of seconds have elapsed.\n" -+ "Example: " -+ "fstest_monitor \"/bin/ls -l\" /bin/date\n" -+ ); -+ return 1; -+ } -+ if (strncmp(argv[p], "--duration", 10) == 0 || -+ strncmp(argv[p], "-d", 2) == 0) { -+ char *s; -+ if (p+1 < argc && !isdigit(argv[p][strlen(argv[p])-1])) -+ ++p; -+ s = argv[p]; -+ while (*s && !isdigit(*s)) -+ ++s; -+ duration = atoi(s); -+ ++p; -+ } -+ } -+ -+ signal(SIGTERM, signal_handler); -+ signal(SIGINT, signal_handler); -+ for (; p < argc; ++p) { -+ child_pid = fork(); -+ if (child_pid) { -+ /* Parent */ -+ if (child_pid == (pid_t) -1) { -+ kill_children(); -+ result = 1; -+ break; -+ } -+ add_child(child_pid); -+ } else { -+ /* Child */ -+ int cargc; -+ char **cargv; -+ -+ if (parse_command_line(argv[p], &cargc, &cargv)) -+ return 1; -+ execve(cargv[0], cargv, env); -+ return 1; -+ } -+ } -+ if (!result && duration > 0) { -+ signal(SIGALRM, alarm_handler); -+ alarm(duration); -+ } -+ while (have_children()) { -+ status = 0; -+ child_pid = wait(&status); -+ if (child_pid == (pid_t) -1) { -+ if (errno == EINTR) -+ continue; -+ kill_children(); -+ return 1; -+ } -+ mark_child_gone(child_pid); -+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { -+ result = 1; -+ kill_children(); -+ } -+ } -+ -+ if (alarm_gone_off) -+ return 0; -+ -+ return result; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/COPYING linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/COPYING ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/COPYING 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/COPYING 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) 19yy -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) 19yy name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/JitterTest.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1044 @@ -+/*********************************************************************** -+ * -+ * Copyright: Daniel Measurement and Control, Inc. -+ * 9753 Pine Lake Drive -+ * Houston, TX 77055 -+ * -+ * Created by: Vipin Malik and Gail Murray -+ * Released under GPL by permission of Daniel Industries. -+ * -+ * This software is licensed under the GPL version 2. Plese see the file -+ * COPYING for details on the license. -+ * -+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose -+ * are made in this software. Please use at your own risk. -+ * -+ * Filename: JitterTest.c -+ * -+ * Description: Program to be used to measure wake jitter. -+ * See README file for more info. -+ * -+ * -+ * Revision History: -+ * $Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ * $Log: not supported by cvs2svn $ -+ * Revision 1.13 2005/11/07 11:15:20 gleixner -+ * [MTD / JFFS2] Clean up trailing white spaces -+ * -+ * Revision 1.12 2001/08/10 19:23:11 vipin -+ * Ready to be released under GPL! Added proper headers etc. -+ * -+ * Revision 1.11 2001/07/09 15:35:50 vipin -+ * Couple of new features:1. The program runs by default as a "regular" -+ * (SCHED_OTHER) task by default, unless the -p n cmd line parameter is -+ * specified. It then runs as SCHED_RR at that priority. -+ * 2. Added ability to send SIGSTOP/SIGCONT to a specified PID. This -+ * would presumably be the PID of the JFFS2 GC task. SIGSTOP is sent -+ * before writing to the fs, and a SIGCONT after the write is done. -+ * 3. The "pad" data now written to the file on the "fs under test" is -+ * random, not sequential as previously. -+ * -+ * Revision 1.10 2001/06/27 19:14:24 vipin -+ * Now console file to log at can be specified from cmd line. This can enable -+ * you to run two instances of the program- one logging to the /dev/console -+ * and another to a regular file (if you want the data) or /dev/null if you don't. -+ * -+ * Revision 1.9 2001/06/25 20:21:31 vipin -+ * This is the latest version, NOT the one last checked in! -+ * -+ * Revision 1.7 2001/06/18 22:36:19 vipin -+ * Fix minor typo that excluded '\n' from msg on console. -+ * -+ * Revision 1.6 2001/06/18 21:17:50 vipin -+ * Added option to specify the amount of data written to outfile each period. -+ * The regular info is written, but is then padded to the requested size. -+ * This will enable testing of different sized writes to JFFS fs. -+ * -+ * Revision 1.5 2001/06/08 19:36:23 vipin -+ * All write() are now checked for return err code. -+ * -+ * Revision 1.4 2001/06/06 23:10:31 vipin -+ * Added README file. -+ * In JitterTest.c: Changed operation of periodic timer to one shot. The timer is now -+ * reset when the task wakes. This way every "jitter" is from the last time and -+ * jitters from previous times are not accumulated and screw aroud with our display. -+ * -+ * All jitter is now +ve. (as it should be). Also added a "read file" functionality -+ * to test for jitter in task if we have to read from JFFS fs. -+ * The program now also prints data to console- where it can be logged, interspersed with -+ * other "interesting" printk's from the kernel and drivers (flash sector erases etc.) -+ * -+ * Revision 1.3 2001/03/01 19:20:39 gmurray -+ * Add priority scheduling. Shortened name of default output file. -+ * Changed default interrupt period. Output delta time and jitter -+ * instead of time of day. -+ * -+ * Revision 1.2 2001/02/28 16:20:19 vipin -+ * Added version control Id and log fields. -+ * -+ ***********************************************************************/ -+/*************************** Included Files ***************************/ -+#include /* fopen, printf, fprintf, fclose */ -+#include /* strcpy, strcmp */ -+#include /* exit, atol, atoi */ -+#include /* setitimer, settimeofday, gettimeofday */ -+#include /* signal */ -+#include /* sched_setscheduler, sched_get_priority_min,*/ -+/* sched_get_priority_max */ -+#include /* gettimeofday, sleep */ -+#include -+#include -+#include -+#include -+ -+ -+ -+/**************************** Enumerations ****************************/ -+enum timerActions -+ { -+ ONESHOT, -+ AUTORESETTING -+ }; -+ -+ -+ -+/****************************** Constants *****************************/ -+/* Exit error codes */ -+#define EXIT_FILE_OPEN_ERR (1) /* error opening output file*/ -+#define EXIT_REG_SIGALRM_ERR (2) /* error registering SIGALRM*/ -+#define EXIT_REG_SIGINT_ERR (3) /* error registering SIGINT */ -+#define EXIT_INV_INT_PERIOD (4) /* error invalid int. period*/ -+#define EXIT_MIN_PRIORITY_ERR (5) /* error, minimum priority */ -+#define EXIT_MAX_PRIORITY_ERR (6) /* error, maximum priority */ -+#define EXIT_INV_SCHED_PRIORITY (7) /* error, invalid priority */ -+#define EXIT_SET_SCHEDULER_ERR (8) /* error, set scheduler */ -+#define EXIT_PREV_TIME_OF_DAY_ERR (9) /* error, init. prev. */ -+/* time of day */ -+ -+#define MAX_FILE_NAME_LEN (32) /* maximum file name length */ -+ -+#define STRINGS_EQUAL ((int) 0) /* strcmp value if equal */ -+ -+#define MIN_INT_PERIOD_MILLISEC ( 5L) /* minimum interrupt period */ -+#define MAX_INT_PERIOD_MILLISEC (5000L) /* maximum interrupt period */ -+#define DEF_INT_PERIOD_MILLISEC ( 10L) /* default interrupt period */ -+ -+#define READ_FILE_MESSAGE "This is a junk file. Must contain at least 1 byte though!\n" -+ -+/* The user can specify that the program pad out the write file to -+ a given number of bytes. But a minimum number needs to be written. This -+ will contain the jitter info. -+*/ -+#define MIN_WRITE_BYTES 30 -+#define DEFAULT_WRITE_BYTES 30 -+#define MAX_WRITE_BYTES 4096 -+ -+/* used for gen a printable ascii random # between spc and '~' */ -+#define MIN_ASCII 32 /* can be char*/ -+#define MAX_ASCII 126.0 /* needs to be float. See man rand() */ -+ -+/*---------------------------------------------------------------------- -+ * It appears that the preprocessor can't handle multi-line #if -+ * statements. Thus, the check on the default is divided into two -+ * #if statements. -+ *---------------------------------------------------------------------*/ -+#if (DEF_INT_PERIOD_MILLISEC < MIN_INT_PERIOD_MILLISEC) -+#error *** Invalid default interrupt period. *** -+#endif -+ -+#if (DEF_INT_PERIOD_MILLISEC > MAX_INT_PERIOD_MILLISEC) -+#error *** Invalid default interrupt period. *** -+#endif -+ -+ -+#define TRUE 1 /* Boolean true value */ -+#define FALSE 0 -+ -+/* Time conversion constants. */ -+#define MILLISEC_PER_SEC (1000L) /* milliseconds per second */ -+#define MICROSEC_PER_MILLISEC (1000L) /* microsecs per millisec */ -+#define MICROSEC_PER_SEC (1000000L) /* microsecs per second */ -+ -+#define PRIORITY_POLICY ((int) SCHED_RR) /* If specified iwth "-p" */ -+ -+ -+ -+/************************** Module Variables **************************/ -+/* version identifier (value supplied by CVS)*/ -+static const char Version[] = "$Id: JitterTest.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $"; -+ -+static char OutFileName[MAX_FILE_NAME_LEN+1]; /* output file name */ -+static char LogFile[MAX_FILE_NAME_LEN+1] = "/dev/console"; /* default */ -+static char ReadFile[MAX_FILE_NAME_LEN+1]; /* This file is read. Should -+ contain at least 1 byte */ -+ -+static int WriteBytes = DEFAULT_WRITE_BYTES; /* pad out file to these many bytes. */ -+static int Fd1; /* fd where the above buffer if o/p */ -+static int Cfd; /* fd to console (or file specified) */ -+static int Fd2; /* fd for the ReadFile */ -+static int DoRead = FALSE; /* should we attempt to ReadFile?*/ -+static long InterruptPeriodMilliSec; /* interrupt period, millisec */ -+static int MinPriority; /* minimum scheduler priority */ -+static int MaxPriority; /* maximum scheduler priority */ -+static int RequestedPriority; /* requested priority */ -+static struct itimerval ITimer; /* interrupt timer structure */ -+static struct timeval PrevTimeVal; /* previous time structure */ -+static struct timeval CurrTimeVal; /* current time structure */ -+static long LastMaxDiff = 0; /* keeps track of worst jitter encountered */ -+ -+static int GrabKProfile = FALSE; /* To help determine system bottle necks -+ this parameter can be set. This causes -+ the /proc/profile file to be read and -+ stored in unique filenames in current -+ dir, and indication to be o/p on the -+ /dev/console also. -+ */ -+static long ProfileTriggerMSecs = 15000l; /* Jitter time in seconds that triggers -+ a snapshot of the profile to be taken -+ -+ */ -+static int SignalGCTask = FALSE; /* should be signal SIGSTOP/SIGCONT to gc task?*/ -+static int GCTaskPID; -+ -+static int RunAsRTTask = FALSE; /* default action unless priority is -+ specified on cmd line */ -+ -+ -+/********************* Local Function Prototypes **********************/ -+void HandleCmdLineArgs(int argc, char *argv[]); -+void SetFileName(char * pFileName); -+void SetInterruptPeriod(char * pASCIIInterruptPeriodMilliSec); -+void SetSchedulerPriority(char * pASCIISchedulerPriority); -+ -+void PrintVersionInfo(void); -+void PrintHelpInfo(void); -+ -+int Write(int fd, void *buf, size_t bytes, int lineNo); -+ -+void InitITimer(struct itimerval * pITimer, int action); -+ -+/* For catching timer interrupts (SIGALRM). */ -+void AlarmHandler(int sigNum); -+ -+/* For catching Ctrl+C SIGINT. */ -+void SignalHandler(int sigNum); -+ -+ -+ -+/*********************************************************************** -+ * main function -+ * return: exit code -+ ***********************************************************************/ -+int main( -+ int argc, -+ char *argv[]) -+{ -+ struct sched_param schedParam; -+ -+ int mypri; -+ char tmpBuf[200]; -+ -+ -+ strcpy(OutFileName,"jitter.dat"); -+ InterruptPeriodMilliSec = MIN_INT_PERIOD_MILLISEC; -+ -+ /* Get the minimum and maximum priorities. */ -+ MinPriority = sched_get_priority_min(PRIORITY_POLICY); -+ MaxPriority = sched_get_priority_max(PRIORITY_POLICY); -+ if (MinPriority == -1) { -+ printf("\n*** Unable to get minimum priority. ***\n"); -+ exit(EXIT_MIN_PRIORITY_ERR); -+ } -+ if (MaxPriority == -1) { -+ printf("\n*** Unable to get maximum priority. ***\n"); -+ exit(EXIT_MAX_PRIORITY_ERR); -+ } -+ -+ /* Set requested priority to minimum value as default. */ -+ RequestedPriority = MinPriority; -+ -+ HandleCmdLineArgs(argc, argv); -+ -+ if(mlockall(MCL_CURRENT|MCL_FUTURE) < 0){ -+ printf("Could not lock task into memory. Bye\n"); -+ perror("Error"); -+ } -+ -+ if(RunAsRTTask){ -+ -+ /* Set the priority. */ -+ schedParam.sched_priority = RequestedPriority; -+ if (sched_setscheduler( -+ 0, -+ PRIORITY_POLICY, -+ &schedParam) != (int) 0) { -+ printf("Exiting: Unsuccessful sched_setscheduler.\n"); -+ close(Fd1); -+ exit(EXIT_SET_SCHEDULER_ERR); -+ } -+ -+ -+ /* Double check as I have some doubts that it's really -+ running at realtime priority! */ -+ if((mypri = sched_getscheduler(0)) != RequestedPriority) -+ { -+ printf("Not running with request priority %i. running with priority %i instead!\n", -+ RequestedPriority, mypri); -+ }else -+ { -+ printf("Running with %i priority. Good!\n", mypri); -+ } -+ -+ } -+ -+ /*------------------------- Initializations --------------------------*/ -+ if((Fd1 = open(OutFileName, O_RDWR|O_CREAT|O_SYNC)) <= 0) -+ { -+ perror("Cannot open outfile for write:"); -+ exit(1); -+ } -+ -+ /* If a request is made to read from a specified file, then create that -+ file and fill with junk data so that there is something there to read. -+ */ -+ if(DoRead) -+ { -+ -+ if((Fd2 = open(ReadFile, O_RDWR|O_CREAT|O_SYNC|O_TRUNC)) <= 0) -+ { -+ perror("cannot open read file:"); -+ exit(1); -+ }else -+ { -+ -+ /* Don't really care how much we write here */ -+ if(write(Fd2, READ_FILE_MESSAGE, strlen(READ_FILE_MESSAGE)) < 0) -+ { -+ perror("Problems writing to readfile:"); -+ exit(1); -+ } -+ lseek(Fd2, 0, SEEK_SET); /* position back to byte #0 */ -+ } -+ } -+ -+ -+ -+ /* Also log output to console. This way we can capture it -+ on a serial console to a log file. -+ */ -+ if((Cfd = open(LogFile, O_WRONLY|O_SYNC)) <= 0) -+ { -+ perror("cannot open o/p logfile:"); -+ exit(1); -+ } -+ -+ -+ /* Set-up handler for periodic interrupt. */ -+ if (signal(SIGALRM, &AlarmHandler) == SIG_ERR) { -+ printf("Couldn't register signal handler for SIGALRM.\n"); -+ sprintf(tmpBuf, -+ "Couldn't register signal handler for SIGALRM.\n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ exit(EXIT_REG_SIGALRM_ERR); -+ } -+ -+ /* Set-up handler for Ctrl+C to exit the program. */ -+ if (signal(SIGINT, &SignalHandler) == SIG_ERR) { -+ printf("Couldn't register signal handler for SIGINT.\n"); -+ sprintf(tmpBuf, -+ "Couldn't register signal handler for SIGINT.\n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ exit(EXIT_REG_SIGINT_ERR); -+ } -+ -+ printf("Press Ctrl+C to exit the program.\n"); -+ printf("Output File: %s\n", OutFileName); -+ printf("Scheduler priority: %d\n", RequestedPriority); -+ sprintf(tmpBuf, "\nScheduler priority: %d\n", -+ RequestedPriority); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ printf("Interrupt period: %ld milliseconds\n", -+ InterruptPeriodMilliSec); -+ sprintf(tmpBuf, "Interrupt period: %ld milliseconds\n", -+ InterruptPeriodMilliSec); -+ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ fflush(0); -+ -+ -+ -+ /* Initialize the periodic timer. */ -+ InitITimer(&ITimer, ONESHOT); -+ -+ /* Initialize "previous" time. */ -+ if (gettimeofday(&PrevTimeVal, NULL) != (int) 0) { -+ printf("Exiting - "); -+ printf("Unable to initialize previous time of day.\n"); -+ sprintf(tmpBuf, "Exiting - "); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ sprintf(tmpBuf, -+ "Unable to initialize previous time of day.\n"); -+ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ } -+ -+ /* Start the periodic timer. */ -+ setitimer(ITIMER_REAL, &ITimer, NULL); -+ -+ -+ while(TRUE) { /* Intentional infinite loop. */ -+ /* Sleep for one second. */ -+ sleep((unsigned int) 1); -+ } -+ -+ /* Just in case. File should be closed in SignalHandler. */ -+ close(Fd1); -+ close(Cfd); -+ -+ return 0; -+} -+ -+ -+ -+ -+/*********************************************************************** -+ * SignalHandler -+ * This is a handler for the SIGINT signal. It is assumed that the -+ * SIGINT is due to the user pressing Ctrl+C to halt the program. -+ * output: N/A -+ ***********************************************************************/ -+void SignalHandler( -+ int sigNum) -+{ -+ -+ char tmpBuf[200]; -+ -+ /* Note sigNum not used. */ -+ printf("Ctrl+C detected. Worst Jitter time was:%fms.\nJitterTest exiting.\n", -+ (float)LastMaxDiff/1000.0); -+ -+ sprintf(tmpBuf, -+ "\nCtrl+C detected. Worst Jitter time was:%fms\nJitterTest exiting.\n", -+ (float)LastMaxDiff/1000.0); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ close(Fd1); -+ close(Cfd); -+ exit(0); -+} -+ -+ -+ -+ -+ -+/* -+ A snapshot of the /proc/profile needs to be taken. -+ This is stored as a new file every time, and the -+ stats reset by doing a (any) write to the /proc/profile -+ file. -+ */ -+void doGrabKProfile(int jitterusec, char *fileName) -+{ -+ int fdSnapshot; -+ int fdProfile; -+ int readBytes; -+ char readBuf[4096]; -+ -+ if((fdSnapshot = open(fileName, O_WRONLY | O_CREAT)) <= 0) -+ { -+ fprintf(stderr, "Could not open file %s.\n", fileName); -+ perror("Error:"); -+ return; -+ } -+ -+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) -+ { -+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); -+ close(fdSnapshot); -+ return; -+ } -+ -+ while((readBytes = read(fdProfile, readBuf, sizeof(readBuf))) > 0) -+ { -+ write(fdSnapshot, readBuf, readBytes); -+ } -+ -+ close(fdSnapshot); -+ -+ if(write(fdProfile, readBuf, 1) != 1) -+ { -+ perror("Could Not clear profile by writing to /proc/profile:"); -+ } -+ -+ close(fdProfile); -+ -+ -+ -+}/* end doGrabKProfile()*/ -+ -+ -+/* -+ Call this routine to clear the kernel profiling buffer /proc/profile -+*/ -+void clearProfileBuf(void){ -+ -+ -+ int fdProfile; -+ char readBuf[10]; -+ -+ -+ if((fdProfile = open("/proc/profile", O_RDWR)) <= 0) -+ { -+ fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n"); -+ return; -+ } -+ -+ -+ if(write(fdProfile, readBuf, 1) != 1) -+ { -+ perror("Could Not clear profile by writing to /proc/profile:"); -+ } -+ -+ close(fdProfile); -+ -+ -+}/* end clearProfileBuf() */ -+ -+ -+ -+ -+ -+/*********************************************************************** -+ * AlarmHandler -+ * This is a handler for the SIGALRM signal (due to the periodic -+ * timer interrupt). It prints the time (seconds) to -+ * the output file. -+ * output: N/A -+ ***********************************************************************/ -+void AlarmHandler( -+ int sigNum) /* signal number (not used) */ -+{ -+ -+ long timeDiffusec; /* diff time in micro seconds */ -+ long intervalusec; -+ -+ -+ char tmpBuf[MAX_WRITE_BYTES]; -+ int cntr; -+ char padChar; -+ -+ static int profileFileNo = 0; -+ char profileFileName[150]; -+ -+ static int seedStarter = 0; /* carries over rand info to next time -+ where time() will be the same as this time -+ if invoked < 1sec apart. -+ */ -+ -+ if (gettimeofday(&CurrTimeVal, NULL) == (int) 0) { -+ -+ /*---------------------------------------------------------------- -+ * Compute the elapsed time between the current and previous -+ * time of day values and store the result. -+ * -+ * Print the elapsed time to the output file. -+ *---------------------------------------------------------------*/ -+ -+ timeDiffusec = (long)(((((long long)CurrTimeVal.tv_sec) * 1000000L) + CurrTimeVal.tv_usec) - -+ (((long long)PrevTimeVal.tv_sec * 1000000L) + PrevTimeVal.tv_usec)); -+ -+ sprintf(tmpBuf," %f ms ", (float)timeDiffusec/1000.0); -+ -+ intervalusec = InterruptPeriodMilliSec * 1000L; -+ -+ timeDiffusec = timeDiffusec - intervalusec; -+ -+ sprintf(&tmpBuf[strlen(tmpBuf)]," %f ms", (float)timeDiffusec/1000.0); -+ -+ -+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */ -+ if(SignalGCTask){ -+ -+ if(kill(GCTaskPID, SIGSTOP) < 0){ -+ -+ perror("error:"); -+ } -+ } -+ -+ -+ /* Store some historical #'s */ -+ if(abs(timeDiffusec) > LastMaxDiff) -+ { -+ LastMaxDiff = abs(timeDiffusec); -+ sprintf(&tmpBuf[strlen(tmpBuf)],"!"); -+ -+ if((GrabKProfile == TRUE) && (ProfileTriggerMSecs < (abs(timeDiffusec)/1000))) -+ { -+ sprintf(profileFileName, "JitterTest.profilesnap-%i", profileFileNo); -+ -+ /* go and grab the kernel performance profile. */ -+ doGrabKProfile(timeDiffusec, profileFileName); -+ profileFileNo++; /* unique name next time */ -+ -+ /* Say so on the console so that a marker gets put in the console log */ -+ sprintf(&tmpBuf[strlen(tmpBuf)],"", -+ profileFileName); -+ -+ } -+ -+ } -+ -+ -+ -+ -+ sprintf(&tmpBuf[strlen(tmpBuf)],"\n"); /* CR for the data going out of the console */ -+ -+ Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ /* The "-1" below takes out the '\n' at the end that we appended for the msg printed on -+ the console.*/ -+ sprintf(&tmpBuf[strlen(tmpBuf)-1]," PadBytes:"); -+ -+ /* Now pad the output file if requested by user. */ -+ if(WriteBytes > MIN_WRITE_BYTES) -+ { -+ -+ /* start from a new place every time */ -+ srand(time(NULL) + seedStarter); -+ -+ /* already written MIN_WRITE_BYTES by now */ -+ for(cntr = strlen(tmpBuf); cntr < WriteBytes - 1 ; cntr++) /* "-1" adj for '\n' at end */ -+ { -+ /* don't accept any # < 'SPACE' */ -+ padChar = (char)(MIN_ASCII+(int)((MAX_ASCII-(float)MIN_ASCII)*rand()/(RAND_MAX+1.0))); -+ -+ -+ /* -+ padChar = (cntr % (126-33)) + 33; -+ */ -+ -+ tmpBuf[cntr] = padChar; -+ } -+ -+ seedStarter = tmpBuf[cntr-1]; /* save for next time */ -+ -+ tmpBuf[cntr] = '\n'; /* CR for the data going into the outfile. */ -+ tmpBuf[cntr+1] = '\0'; /* NULL terminate the string */ -+ } -+ -+ /* write out the entire line to the output file. */ -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ -+ /* Read a byte from the specified file */ -+ if(DoRead) -+ { -+ -+ read(Fd2, tmpBuf, 1); -+ lseek(Fd2, 0, SEEK_SET); /* back to start */ -+ } -+ -+ -+ /* Start the periodic timer again. */ -+ setitimer(ITIMER_REAL, &ITimer, NULL); -+ -+ -+ /* Update previous time with current time. */ -+ PrevTimeVal.tv_sec = CurrTimeVal.tv_sec; -+ PrevTimeVal.tv_usec = CurrTimeVal.tv_usec; -+ } -+ -+ else { -+ sprintf(tmpBuf, "gettimeofday error \n"); -+ Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__); -+ -+ printf("gettimeofday error \n"); -+ } -+ -+ /* now clear the profiling buffer */ -+ if(GrabKProfile == TRUE){ -+ -+ clearProfileBuf(); -+ } -+ -+ /* should we send a SIGSTOP/SIGCONT to the specified PID? */ -+ if(SignalGCTask){ -+ -+ if(kill(GCTaskPID, SIGCONT) < 0){ -+ -+ perror("error:"); -+ } -+ } -+ -+ -+ return; -+} -+ -+ -+ -+/*********************************************************************** -+ * InitITimer -+ * This function initializes the 'struct itimerval' structure whose -+ * address is passed to interrupt every InterruptPeriodMilliSec. -+ * output: N/A -+ ***********************************************************************/ -+void InitITimer( -+ struct itimerval * pITimer, /* pointer to interrupt timer struct*/ -+ int action) /* ONESHOT or autosetting? */ -+{ -+ long seconds; /* seconds portion of int. period */ -+ long microSeconds; /* microsec. portion of int. period */ -+ -+ /*-------------------------------------------------------------------- -+ * Divide the desired interrupt period into its seconds and -+ * microseconds components. -+ *-------------------------------------------------------------------*/ -+ if (InterruptPeriodMilliSec < MILLISEC_PER_SEC) { -+ seconds = 0L; -+ microSeconds = InterruptPeriodMilliSec * MICROSEC_PER_MILLISEC; -+ } -+ else { -+ seconds = InterruptPeriodMilliSec / MILLISEC_PER_SEC; -+ microSeconds = -+ (InterruptPeriodMilliSec - (seconds * MILLISEC_PER_SEC)) * -+ MICROSEC_PER_MILLISEC; -+ } -+ -+ /* Initialize the interrupt period structure. */ -+ pITimer->it_value.tv_sec = seconds; -+ pITimer->it_value.tv_usec = microSeconds; -+ -+ if(action == ONESHOT) -+ { -+ /* This will (should) prevent the timer from restarting itself */ -+ pITimer->it_interval.tv_sec = 0; -+ pITimer->it_interval.tv_usec = 0; -+ }else -+ { -+ pITimer->it_interval.tv_sec = seconds; -+ pITimer->it_interval.tv_usec = microSeconds; -+ -+ } -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * HandleCmdLineArgs -+ * This function handles the command line arguments. -+ * output: stack size -+ ***********************************************************************/ -+void HandleCmdLineArgs( -+ int argc, /* number of command-line arguments */ -+ char *argv[]) /* ptrs to command-line arguments */ -+{ -+ int argNum; /* argument number */ -+ -+ if (argc > (int) 1) { -+ -+ for (argNum = (int) 1; argNum < argc; argNum++) { -+ -+ /* The command line contains an argument. */ -+ -+ if ((strcmp(argv[argNum],"--version") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-v") == STRINGS_EQUAL)) { -+ /* Print version information and exit. */ -+ PrintVersionInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--help") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-h") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-?") == STRINGS_EQUAL)) { -+ /* Print help information and exit. */ -+ PrintHelpInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--file") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-f") == STRINGS_EQUAL)) { -+ /* Set the name of the output file. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetFileName(argv[argNum]); -+ } -+ else { -+ printf("*** Output file name not specified. ***\n"); -+ printf("Default output file name will be used.\n"); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--time") == STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-t") == STRINGS_EQUAL)) { -+ /* Set the interrupt period. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetInterruptPeriod(argv[argNum]); -+ } -+ else { -+ printf("*** Interrupt period not specified. ***\n"); -+ printf("Default interrupt period will be used.\n"); -+ } -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--priority") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-p") == STRINGS_EQUAL)) { -+ /* Set the scheduler priority. */ -+ ++argNum; -+ if (argNum < argc) { -+ SetSchedulerPriority(argv[argNum]); -+ } -+ else { -+ printf("*** Scheduler priority not specified. ***\n"); -+ printf("Default scheduler priority will be used.\n"); -+ } -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--readfile") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-r") == STRINGS_EQUAL)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ strncpy(ReadFile, argv[argNum], sizeof(ReadFile)); -+ DoRead = TRUE; -+ } -+ -+ else if ((strcmp(argv[argNum],"--write_bytes") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-w") == STRINGS_EQUAL)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ WriteBytes = atoi(argv[argNum]); -+ -+ if(WriteBytes < MIN_WRITE_BYTES) -+ { -+ printf("Writing less than %i bytes is not allowed. Bye.\n", -+ MIN_WRITE_BYTES); -+ exit(0); -+ } -+ -+ -+ } -+ -+ else if ((strcmp(argv[argNum],"--consolefile") == -+ STRINGS_EQUAL) || -+ (strcmp(argv[argNum],"-c") == STRINGS_EQUAL)) { -+ /* Set the file to log console log on. */ -+ ++argNum; -+ -+ strncpy(LogFile, argv[argNum], sizeof(LogFile)); -+ } -+ -+ else if ((strcmp(argv[argNum],"--grab_kprofile") == -+ STRINGS_EQUAL)) -+ { -+ /* We will read the /proc/profile file on configurable timeout */ -+ GrabKProfile = TRUE; -+ -+ ++argNum; -+ -+ /* If the jittter is > this #, then the profile is grabbed. */ -+ ProfileTriggerMSecs = (long) atoi(argv[argNum]); -+ -+ if(ProfileTriggerMSecs <= 0){ -+ -+ printf("Illegal value for profile trigger threshold.\n"); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--siggc") == -+ STRINGS_EQUAL)) -+ { -+ /* We will SIGSTOP/SIGCONT the specified pid */ -+ SignalGCTask = TRUE; -+ -+ ++argNum; -+ -+ GCTaskPID = atoi(argv[argNum]); -+ -+ if(ProfileTriggerMSecs <= 0){ -+ -+ printf("Illegal value for JFFS(2) GC task pid.\n"); -+ exit(0); -+ } -+ } -+ -+ -+ else { -+ /* Unknown argument. Print help information and exit. */ -+ printf("Invalid option %s\n", argv[argNum]); -+ printf("Try 'JitterTest --help' for more information.\n"); -+ exit(0); -+ } -+ } -+ } -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetFileName -+ * This function sets the output file name. -+ * output: N/A -+ ***********************************************************************/ -+void SetFileName( -+ char * pFileName) /* ptr to desired output file name */ -+{ -+ size_t fileNameLen; /* file name length (bytes) */ -+ -+ /* Check file name length. */ -+ fileNameLen = strlen(pFileName); -+ if (fileNameLen > (size_t) MAX_FILE_NAME_LEN) { -+ printf("File name %s exceeds maximum length %d.\n", -+ pFileName, MAX_FILE_NAME_LEN); -+ exit(0); -+ } -+ -+ /* File name length is OK so save the file name. */ -+ strcpy(OutFileName, pFileName); -+ -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetInterruptPeriod -+ * This function sets the interrupt period. -+ * output: N/A -+ ***********************************************************************/ -+void SetInterruptPeriod( -+ char * /* ptr to desired interrupt period */ -+ pASCIIInterruptPeriodMilliSec) -+{ -+ long period; /* interrupt period */ -+ -+ period = atol(pASCIIInterruptPeriodMilliSec); -+ if ((period < MIN_INT_PERIOD_MILLISEC) || -+ (period > MAX_INT_PERIOD_MILLISEC)) { -+ printf("Invalid interrupt period: %ld ms.\n", period); -+ exit(EXIT_INV_INT_PERIOD); -+ } -+ else { -+ InterruptPeriodMilliSec = period; -+ } -+ return; -+} -+ -+ -+/*********************************************************************** -+ * SetSchedulerPriority -+ * This function sets the desired scheduler priority. -+ * output: N/A -+ ***********************************************************************/ -+void SetSchedulerPriority( -+ char * pASCIISchedulerPriority) /* ptr to desired scheduler priority*/ -+{ -+ int priority; /* desired scheduler priority value */ -+ -+ priority = atoi(pASCIISchedulerPriority); -+ if ((priority < MinPriority) || -+ (priority > MaxPriority)) { -+ printf("Scheduler priority %d outside of range [%d, %d]\n", -+ priority, MinPriority, MaxPriority); -+ exit(EXIT_INV_SCHED_PRIORITY); -+ } -+ else { -+ RequestedPriority = priority; -+ RunAsRTTask = TRUE; /* We shall run as a POSIX real time task */ -+ } -+ return; -+} -+ -+ -+/*********************************************************************** -+ * PrintVersionInfo -+ * This function prints version information. -+ * output: N/A -+ ***********************************************************************/ -+void PrintVersionInfo(void) -+{ -+ printf("JitterTest version %s\n", Version); -+ printf("Copyright (c) 2001, Daniel Industries, Inc.\n"); -+ return; -+} -+ -+ -+/*********************************************************************** -+ * PrintHelpInfo -+ * This function prints help information. -+ * output: N/A -+ ***********************************************************************/ -+void PrintHelpInfo(void) -+{ -+ printf("Usage: JitterTest [options]\n"); -+ printf(" *** Requires root privileges. ***\n"); -+ printf("Option:\n"); -+ printf(" [-h, --help, -?] Print this message and exit.\n"); -+ printf(" [-v, --version] "); -+ printf( "Print the version number of JitterTest and exit.\n"); -+ printf(" [-f FILE, --file FILE] Set output file name to FILE. Typically you would put this on the fs under test\n"); -+ printf(" [-c FILE, --consolefile] Set device or file to write the console log to.\n\tTypically you would set this to /dev/console and save it on another computer.\n"); -+ printf(" [-w BYTES, --write_bytes BYTES Write BYTES to FILE each period.\n"); -+ printf(" [-r FILE, --readfile FILE] Also read 1 byte every cycle from FILE. FILE will be created and filled with data.\n"); -+ printf(" [-t , --time ] "); -+ printf( "Set interrupt period to milliseconds.\n"); -+ printf(" "); -+ printf( "Range: [%ld, %ld] milliseconds.\n", -+ MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC); -+ printf(" [-p , --priority ] "); -+ printf( "Set scheduler priority to .\n"); -+ printf(" "); -+ printf( "Range: [%d, %d] (higher number = higher priority)\n", -+ MinPriority, MaxPriority); -+ printf(" [--grab_kprofile ] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n"); -+ printf(" [--siggc ] Before writing to fs send SIGSTOP to PID. After write send SIGCONT\n"); -+ return; -+ -+} -+ -+ -+/* A common write that checks for write errors and exits. Pass it __LINE__ for lineNo */ -+int Write(int fd, void *buf, size_t bytes, int lineNo) -+{ -+ -+ int err; -+ -+ err = write(fd, buf, bytes); -+ -+ if(err < bytes) -+ { -+ -+ printf("Write Error at line %i! Wanted to write %i bytes, but wrote only %i bytes.\n", -+ lineNo, bytes, err); -+ perror("Write did not complete. Error. Bye:"); /* show error from errno. */ -+ exit(1); -+ -+ } -+ -+ return err; -+ -+}/* end Write*/ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,46 @@ -+CC=gcc -+# uncomment following for performance -+CCFLAGS=-O3 -Wall -m486 -fomit-frame-pointer -+ -+# uncomment following for debugging. Uncomment either this or the one above. Not both. -+# CCFLAGS=-Wall -g -+ -+ -+all: JitterTest plotJittervsFill -+ -+JitterTest: JitterTest.c Makefile -+ gcc $(CCFLAGS) -lm JitterTest.c -o JitterTest -+ -+plotJittervsFill: plotJittervsFill.c Makefile -+ gcc $(CCFLAGS) plotJittervsFill.c -o plotJittervsFill -+ -+clean: -+ rm -rf *~ -+ rm -rf core -+ rm -rf *.o -+ rm -rf JitterTest -+ -+ -+dep: -+ makedepend -I./ *.c -+# DO NOT DELETE -+ -+JitterTest.o: /usr/include/stdio.h /usr/include/features.h -+JitterTest.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h -+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stddef.h -+JitterTest.o: /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/include/stdarg.h -+JitterTest.o: /usr/include/bits/types.h /usr/include/libio.h -+JitterTest.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h -+JitterTest.o: /usr/include/string.h /usr/include/stdlib.h -+JitterTest.o: /usr/include/sys/types.h /usr/include/time.h -+JitterTest.o: /usr/include/endian.h /usr/include/bits/endian.h -+JitterTest.o: /usr/include/sys/select.h /usr/include/bits/select.h -+JitterTest.o: /usr/include/bits/sigset.h /usr/include/sys/sysmacros.h -+JitterTest.o: /usr/include/alloca.h /usr/include/sys/time.h -+JitterTest.o: /usr/include/bits/time.h /usr/include/signal.h -+JitterTest.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h -+JitterTest.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h -+JitterTest.o: /usr/include/asm/sigcontext.h /usr/include/bits/sigstack.h -+JitterTest.o: /usr/include/sched.h /usr/include/bits/sched.h -+JitterTest.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h -+JitterTest.o: /usr/include/bits/confname.h /usr/include/getopt.h -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/README linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/README ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,197 @@ -+$Id: README,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ -+This is the README file for the JitterTest (and friends) -+program. -+ -+This program is used to measure what the jitter of a -+real time task would be under "standard" Linux. -+ -+More particularly, what is the effect of running -+a real time task under Linux with background -+JFFS file system activity. -+ -+The jitter is measured in milli seconds (ms) from -+the expected time of arrival of a signal from a -+periodic timer (set by the task) to when the -+task actually gets the signal. -+ -+This jitter is then stored in a file specified -+(or the default output file "jitter.dat"). -+ -+The data may also be sent out to the console by -+writing to /dev/console (See help options. This is -+highly desirable specially if you have redirected -+your console to the serial port and are storing it -+as a minicom log on another computer for later analysis -+using some tools provided here). -+ -+This is particularly useful if you have a serial -+console and are outputting "interesting" info -+from inside some kernel task or driver. -+(or something as simple as a "df" program running -+periodically and redirecting o/p to the console). -+ -+One "interesting" thing that I have measured -+is the effect of FLASH chip erases on the jitter -+of a real time task. -+ -+One can do that by putting a printk at the -+beginning of the flash erase routine in the MTD -+flash chip driver. -+ -+Now you will get jitter data interspersed with -+flash sector erase events. Other printk's can also -+be placed at suspected jitter causing locations in -+the system. -+ -+ -+ -+EXECUTING THE PROGRAM "JitterTest" -+ -+You may specify a file to be read by the -+program every time it wakes up (every cycle). -+This file is created and filled with some junk -+data. The purpose of this is to test the jitter -+of the program if it were reading from- say -+a JFFS (Journaling Flash File System) file system. -+ -+By specifying the complete paths of the read and write -+(o/p) files you can test the jitter a POSIX type -+real time task will experience under Linux, under -+various conditions. -+ -+These can be as follows: -+ -+1. O/P file on ram file system, no i/p file. -+ -+ In this case you would presumably generate other -+"typical" background activity for your system and -+examine the worst case jitter experienced by -+a task that is neither reading nor writing to -+a file system. -+ -+Other cases could be: -+ -+2. O/P to ram fs, I/P from JFFS (type) fs: -+ -+ This is specially useful to test the proper -+operation of erase suspend type of operation -+in JFFS file systems (with an MTD layer that -+supports it). -+ -+ In this test you would generate some background -+write/erase type activity that would generate -+chip erases. Since this program is reading from -+the same file system, you contrast the latencies -+with those obtained with writes going to the same -+fs. -+ -+3. Both read and writes to (or just write to) JFFS -+file system: -+ -+ Here you would test for latencies experienced by -+a program if it were writing (and optionally also -+reading) from a JFFS fs. -+ -+ -+ -+ -+Grabing a kernel profile: -+ -+This program can also conditionally grab a kernel profile. -+Specify --grab_kprofile on the cmd line as well as -+a "threshold" parameter (see help options by -?). -+ -+Any jitter greater than this "threshold" will cause the -+program to read the /proc/profile file and dump it in -+a local file with increasing file numbers. It will also -+output the filename at that time to the console file specified. -+This will allow you to corelate later in time the various profiles -+with data in your console file and what was going on at that time. -+ -+These profile files may then be later examined by running them through -+ksymoops. -+ -+Make sure you specify "profile=2" on the kernel command line -+when you boot the kernel if you want to use this functionality. -+ -+ -+ -+Signalling the JFFS[2] GC task: -+ -+You can also force this program to send a SIGSTOP/SIGCONT to the -+JFFS (or JFFS2) gc task by specifing --siggc on the cmd line. -+ -+This will let you investigate the effect of forcing the gc task to -+wake up and do its thing when you are not writing to the fs and to -+force it to sleep when you want to write to the fs. -+ -+These are just various tools to investigate the possibility of -+achieving minimal read/write latency when using JFFS[2]. -+ -+You need to manually do a "ps aux" and look up the PID of the gc -+thread and provide it to the program. -+ -+ -+ -+ -+EXECUTING THE PROGRAM "plotJittervsFill" -+ -+This program is a post processing tool that will extract the jitter -+times as printed by the JitterTest program in its console log file -+as well as the data printed by the "df" command. -+ -+This "df" data happens to be in the console log because you will -+run the shell file fillJffs2.sh on a console when you are doing -+your jitter test. -+ -+This shell script copies a specified file to another specified file -+every programmable seconds. It also does a "df" and redirects output -+to /dev/console where it is mixed with the output from JitterTest. -+ -+All this console data is stored on another computer, as all this data -+is being outputted to the serial port as you have redirected the console -+to the serial port (that is the only guaranteed way to not loose any -+console log or printk data). -+ -+You can then run this saved console log through this program and it -+will output a very nice text file with the %fill in one col and -+corrosponding jitter values in the second. gnuplot then does a -+beautifull plot of this resulting file showing you graphically the -+jitters encountered at different fill % of your JFFS[2] fs. -+ -+ -+ -+OTHER COMMENTS: -+ -+Use the "-w BYTES" cmd line parameter to simulate your test case. -+Not everyone has the same requirements. Someone may want to measure -+the jitter of JFFS2 with 500 bytes being written every 500ms. Others -+may want to measure the system performance writing 2048 bytes every -+5 seconds. -+ -+RUNNING MULTIPLE INSTANCES: -+ -+Things get real interesting when you run multiple instances of this -+program *at the same time*. -+ -+You could have one version running as a real time task (by specifing -+the priority with the -p cmd line parameter), not interacting with -+any fs or at the very least not reading and writing to JFFS[2]. -+ -+At the same time you could have another version running as a regular -+task (by not specifing any priority) but reading and writing to JFFS[2]. -+ -+This way you can easily measure the blocking performance of the real time -+task while another non-real time task interacts with JFFS[2] in the back ground. -+ -+You get the idea. -+ -+ -+WATCH OUT! -+ -+Be particularly careful of running this program as a real time task AND -+writing to JFFS[2]. Any blocks will cause your whole system to block till -+any garbage collect initiated by writes by this task complete. I have measured -+these blocks to be of the order of 40-50 seconds on a reasonably powerful -+32 bit embedded system. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/filljffs2.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#!/bin/bash -+ -+# Pass following cmd line: -+# 1st - file to copy -+# 2nd - file to copy to -+# 3rd - time to sleep between copies -+ -+while [ $(( 1 )) -gt $(( 0 )) ] -+do -+ cp $1 $2 -+ rm $2 -+ df |grep mtd > /dev/console -+ echo "sleeping $3" -+ sleep $3 -+done -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/jittertest/plotJittervsFill.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,312 @@ -+/* -+ *********************************************************************** -+ * -+ * Copyright: Daniel Measurement and Control, Inc. -+ * 9753 Pine Lake Drive -+ * Houston, TX 77055 -+ * -+ * Created by: Vipin Malik -+ * Released under GPL by permission of Daniel Industries. -+ * -+ * This software is licensed under the GPL version 2. Plese see the file -+ * COPYING for details on the license. -+ * -+ * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose -+ * are made in this software. Please use at your own risk. -+ * -+ File: plotJittervsFill.c -+ By: Vipin Malik -+ -+ About: This program reads in a jitter log file as created -+ by the JitterTest.c program and extracts all the jitters -+ in the file that are greater than a threshold specified -+ as a parameter on the cmd line. It also extracts the -+ amount of disk space at (form the "df" out that should also -+ be present in the log file) after the jitter extracted. -+ -+ It writes the data to the stderr (where you may redirect it). -+ It is suitable for plotting, as the data is written as -+ COL1=UsedSpace COL2=Jitter -+ -+ $Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Log: not supported by cvs2svn $ -+ Revision 1.6 2005/11/07 11:15:21 gleixner -+ [MTD / JFFS2] Clean up trailing white spaces -+ -+ Revision 1.5 2001/08/10 19:23:11 vipin -+ Ready to be released under GPL! Added proper headers etc. -+ -+ Revision 1.4 2001/07/02 22:25:40 vipin -+ Fixed couple of minor cosmetic typos. -+ -+ Revision 1.3 2001/07/02 14:46:46 vipin -+ Added a debug option where it o/p's line numbers to debug funky values. -+ -+ Revision 1.2 2001/06/26 19:48:57 vipin -+ Now prints out jitter values found at end of log file, after which -+ no new "df" disk usage values were encountered. The last "df" disk usage -+ encountered is printed for these orphaned values. -+ -+ Revision 1.1 2001/06/25 19:13:55 vipin -+ Added new file- plotJittervsFill.c- that mines the data log file -+ outputed from the fillFlash.sh script file and JitterTest.c file -+ and produces output suitable to be plotted. -+ This output plot may be examined to see visually the relationship -+ of the Jitter vs disk usage of the fs under test. -+ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static char Version_string[] = "$Id: plotJittervsFill.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $"; -+static char LogFile[250] = "InputLogFile.log"; -+ -+static int JitterThreshold_ms = 1000; -+static int Debug = 0; /* Debug level. Each "-d" on the cmd line increases the level */ -+ -+#define TRUE 1 -+#define FALSE 0 -+ -+#define MIN_JITTER_THRESHOLD 1 /* ms minimum jitter threshold */ -+ -+void PrintHelpInfo(void) -+{ -+ printf("Usage: plotJittervsFill [options] -f [--file] -t [--jitter_threshold] \n"); -+ printf("[options]:\n-v [--version] Print version and exit\n"); -+ printf("-d Debug. Prints input file line number for each data point picked up.\n"); -+ printf("-h [--help] [-?] Print this help screen and exit.\n"); -+} -+ -+ -+ -+/*********************************************************************** -+ * HandleCmdLineArgs -+ * This function handles the command line arguments. -+ * output: stack size -+ ***********************************************************************/ -+void HandleCmdLineArgs( -+ int argc, /* number of command-line arguments */ -+ char *argv[]) /* ptrs to command-line arguments */ -+{ -+ int argNum; /* argument number */ -+ -+ if (argc > (int) 1) { -+ -+ for (argNum = (int) 1; argNum < argc; argNum++) { -+ -+ /* The command line contains an argument. */ -+ -+ if ((strcmp(argv[argNum],"--version") == 0) || -+ (strcmp(argv[argNum],"-v") == 0)) { -+ /* Print version information and exit. */ -+ printf("%s\n", Version_string); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--help") == 0) || -+ (strcmp(argv[argNum],"-h") == 0) || -+ (strcmp(argv[argNum],"-?") == 0)) { -+ /* Print help information and exit. */ -+ PrintHelpInfo(); -+ exit(0); -+ } -+ -+ else if ((strcmp(argv[argNum],"--file") == 0) || -+ (strcmp(argv[argNum],"-f") == 0)) { -+ /* Set the name of the output file. */ -+ ++argNum; -+ if (argNum < argc) { -+ strncpy(LogFile, argv[argNum], sizeof(LogFile)); -+ } -+ else { -+ printf("*** Input file name not specified. ***\n"); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"--jitter_threshold") == 0) || -+ (strcmp(argv[argNum],"-t") == 0)) { -+ /* Set the file to read*/ -+ ++argNum; -+ -+ JitterThreshold_ms = atoi(argv[argNum]); -+ -+ if(JitterThreshold_ms < MIN_JITTER_THRESHOLD) -+ { -+ printf("A jitter threshold less than %i ms is not allowed. Bye.\n", -+ MIN_JITTER_THRESHOLD); -+ exit(0); -+ } -+ } -+ -+ else if ((strcmp(argv[argNum],"-d") == 0)) -+ { -+ /* Increment debug level */ -+ -+ Debug++; -+ } -+ -+ else { -+ /* Unknown argument. Print help information and exit. */ -+ printf("Invalid option %s\n", argv[argNum]); -+ printf("Try 'plotJittervsFill --help' for more information.\n"); -+ exit(0); -+ } -+ } -+ } -+ -+ return; -+} -+ -+ -+ -+ -+ -+int main( -+ int argc, -+ char *argv[]) -+{ -+ -+ char lineBuf[1024]; /* how long a single line be? */ -+ int converted; -+ int lineNo = 0; -+ int cnt; -+ -+ FILE *fp; -+ -+ int junkInt1, junkInt2, junkInt3; -+ float junkFloat1; -+ float jitter_ms; -+ -+#define MAX_SAVE_BUFFER 1000 /* How many values will be picked up while searching for -+ a % disk full line (i.e. before they can be printed out) -+ */ -+ int saveJitter[MAX_SAVE_BUFFER]; /* lets us record multiple jitter values that exceed -+ our threshold till we find a "df" field- which is when -+ we can o/p all these values. -+ */ -+ int dataLineNo[MAX_SAVE_BUFFER]; /* The saved line #'s for the above. Printed if debug specified. */ -+ -+ int saveJitterCnt = 0; -+ int lookFor_df = FALSE; -+ int dfPercent = -1; /* will be >= 0 if at least one found. The init value is a flag. */ -+ -+ char junkStr1[500], junkStr2[500]; -+ -+ HandleCmdLineArgs(argc, argv); -+ -+ if((fp = fopen(LogFile, "r")) == NULL) -+ { -+ printf("Unable to open input log file %s for read.\b", LogFile); -+ perror("Error:"); -+ exit(1); -+ } -+ -+ -+ -+ while(fgets(lineBuf, sizeof(lineBuf), fp) != NULL) -+ { -+ lineNo++; -+ -+ -+ /* Are we looking for a "df" o/p line? (to see how full -+ the flash is?)*/ -+ -+ /* is there a "%" in this line? */ -+ if((strstr(lineBuf, "%") != NULL) && (lookFor_df)) -+ { -+ converted = sscanf(lineBuf, "%s %i %i %i %i\n", -+ junkStr1, &junkInt1, &junkInt2, &junkInt3, &dfPercent); -+ if(converted < 5) -+ { -+ printf("Line %i contains \"%%\", but expected fileds not found. Skipping.\n", lineNo); -+ }else -+ { -+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ -+ for(cnt = 0; cnt < saveJitterCnt; cnt++) -+ { -+ if(Debug) -+ { -+ fprintf(stderr, "%i\t%i\t%i\n", (int)dataLineNo[cnt], -+ dfPercent, (int)saveJitter[cnt]); -+ }else -+ { -+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); -+ } -+ -+ -+ } -+ -+ saveJitterCnt = 0; /* all flushed. Reset for next saves. */ -+ lookFor_df = FALSE; -+ } -+ -+ } -+ -+ -+ /* is there a "ms" in this line?*/ -+ if(strstr(lineBuf, "ms") == NULL) -+ { -+ continue; -+ } -+ -+ /* grab the ms jitter value */ -+ converted = sscanf(lineBuf, "%f %s %f %s\n", &junkFloat1, junkStr1, &jitter_ms, junkStr2); -+ if(converted < 4) -+ { -+ printf("Line %i contains \"ms\", but expected fileds not found. Converted %i, Skipping.", -+ lineNo, converted); -+ printf("1=%i, 2=%s.\n", junkInt1, junkStr1); -+ continue; /* not our jitter line*/ -+ } -+ -+ /* Is the jitter value > threshold value? */ -+ if(abs(jitter_ms) > JitterThreshold_ms) -+ { -+ /* Found a jitter line that matches our crietrion. -+ Now set flag to be on the look out for the next -+ "df" output so that we can see how full the flash is. -+ */ -+ -+ if(saveJitterCnt < MAX_SAVE_BUFFER) -+ { -+ saveJitter[saveJitterCnt] = (int)abs(jitter_ms); /* why keep the (ms) jitter in float */ -+ dataLineNo[saveJitterCnt] = lineNo; -+ saveJitterCnt++; -+ lookFor_df = TRUE; -+ } -+ else -+ { -+ printf("Oops! I've run out of buffer space before I found a %% use line. Dropping itter value. Increase MAX_SAVE_BUFFER and recompile.\n"); -+ } -+ -+ -+ } -+ -+ } -+ -+ -+ /* Now print out any saved jitter values that were not printed out because we did not find -+ and "df" after these were picked up. Only print if a "df" disk usage was ever found. -+ */ -+ if(lookFor_df && (dfPercent >= 0)) -+ { -+ /* Now print out the saved jitter values (in col2) with this dfPercent value as the col1. */ -+ for(cnt = 0; cnt < saveJitterCnt; cnt++) -+ { -+ fprintf(stderr, "%i\t%i\n", dfPercent, (int)saveJitter[cnt]); -+ } -+ } -+ -+ return 0; -+ -+ -+}/* end main() */ -+ -+ -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,48 @@ -+LIBUBI_PATH=../../ubi-utils/new-utils/ -+LIBUBI_SRC_PATH=../../ubi-utils/new-utils/src/ -+LIBUBI_HEADER_PATH=../../ubi-utils/new-utils/include -+UBI_HEADERS_PATH=../../include/ -+UBIUTILS_PATH=../../ubi-utils/new-utils/ -+ -+CC := $(CROSS)gcc -+ -+TESTS=io_update volrefcnt integ io_paral io_read io_basic \ -+ mkvol_basic mkvol_bad mkvol_paral rsvol -+ -+HELPER_NAMES=ubiupdatevol -+HELPERS=$(addprefix helpers/, $(HELPER_NAMES)) -+ -+# Because of implicite rules we use make treats .o files as intermediate, thus -+# it removes the. If you want to prevent the removal, uncomment the below -+#.SECONDARY: $(addsuffix .o, $(TESTS)) $(addsuffix .o, $(HELPERS)) -+ -+CFLAGS += -Wall -I$(LIBUBI_HEADER_PATH) -I $(UBI_HEADERS_PATH) -L. -O2 -+ -+all: ubi-utils libubi $(TESTS) $(HELPERS) -+ -+# Compile ubilib with the udevsettle hack -+libubi: $(LIBUBI_SRC_PATH)/libubi.c $(LIBUBI_HEADER_PATH)/libubi.h $(LIBUBI_SRC_PATH)/libubi_int.h -+ $(CC) $(CFLAGS) -I $(LIBUBI_SRC_PATH) -I../../include -DUDEV_SETTLE_HACK -c $(LIBUBI_SRC_PATH)/libubi.c -o libubi.o -+ ar cr libubi.a libubi.o -+ -+# The below cancels existing implicite rule to make programs from .c files, -+# in order to force make using our rule defined below -+%: %.c -+ -+# The below is the rule to get an .o file from a .c file -+%.o: %.c -+ $(CC) $(CFLAGS) $< -c -o $@ -+ -+# And the below is the rule to get final test executable from its .o and common.o -+%: %.o common.o -+ $(CC) $(CFLAGS) $^ -lubi -o $@ -+ -+# *paral tests require libpthread, thus the below rule for them -+%paral: %paral.o common.o -+ $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ -+ -+ubi-utils: -+ make -C $(UBIUTILS_PATH) -+ -+clean: -+ rm -f $(TESTS) $(addsuffix .o, $(TESTS)) libubi.* $(HELPERS) $(addsuffix .o, $(HELPERS)) -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/README.udev 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+There is a problem with udev: when a volume is created, there is a delay -+before corresponding /dev/ubiX_Y device node is created by udev, so some -+tests fail because of this. The symptom is error messages like -+"cannot open /dev/ubi0_0". -+ -+One possible solution of this problem is to pre-create UBI device and volume -+nodes. There is even a script which may be used for this in ubi-utils/scripts/. -+But this is not enough because udev will still remove and re-create the nodes -+and tests will still fail. So you need to stop removing device nodes using -+the following udev rule: -+ -+ KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device" -+ -+In our Ubuntu distribution we put that to new file: -+/etc/udev/rules.d/50-local.rules -+ -+Another possibility is to call udevsettle utility in libubi after the volume -+has been created See src/libubi.c - the call is compiled in only if -+UDEV_SETTLE_HACK is defined. This is anyway an ugly hack, but works, although -+makes the tests slower. Suggestions are welcome. -+ -+So, if you have udevsettel unility in your system, you do not have to do -+anyting, and the tests should work, because we compile libubi with -+UDEV_SETTLE_HACK. Otherwise, you should remove -D UDEV_SETTLE_HACK -+from the makefile and pre-create UBI device nodes. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,336 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * The stuff which is common for many tests. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "common.h" -+ -+/** -+ * __initial_check - check that common prerequisites which are required to run -+ * tests. -+ * -+ * @test test name -+ * @argc count of command-line arguments -+ * @argv command-line arguments -+ * -+ * This function returns %0 if all is fine and test may be run and %-1 if not. -+ */ -+int __initial_check(const char *test, int argc, char * const argv[]) -+{ -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ -+ /* -+ * All tests require UBI character device name as the first parameter, -+ * check this. -+ */ -+ if (argc < 2) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "UBI character device node is not specified"); -+ return -1; -+ } -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ __failed(test, __FUNCTION__, __LINE__, "libubi_open"); -+ return -1; -+ } -+ -+ if (ubi_get_dev_info(libubi, argv[1], &dev_info)) { -+ __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (dev_info.avail_lebs < MIN_AVAIL_EBS) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "insufficient available eraseblocks %d on UBI " -+ "device, required %d", -+ dev_info.avail_lebs, MIN_AVAIL_EBS); -+ goto close; -+ } -+ -+ if (dev_info.vol_count != 0) { -+ __err_msg(test, __FUNCTION__, __LINE__, -+ "device %s is not empty", argv[1]); -+ goto close; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return -1; -+} -+ -+/** -+ * __err_msg - print a message to stderr. -+ * -+ * @test test name -+ * @func function name -+ * @line line number -+ * @fmt format string -+ */ -+void __err_msg(const char *test, const char *func, int line, -+ const char *fmt, ...) -+{ -+ va_list args; -+ -+ fprintf(stderr, "[%s] %s():%d: ", test, func, line); -+ va_start(args, fmt); -+ vfprintf(stderr, fmt, args); -+ fprintf(stderr, "\n"); -+ va_end(args); -+} -+ -+/** -+ * __failed - print function fail message. -+ * -+ * @test test name -+ * @func calling function name -+ * @line line number -+ * @failed failed function name -+ */ -+void __failed(const char *test, const char *func, int line, -+ const char *failed) -+{ -+ fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n", -+ test, func, line, failed, errno, strerror(errno)); -+} -+ -+/** -+ * __check_volume - check volume information. -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @vol_id ID of existing volume to check -+ * @req volume creation request to compare with -+ * -+ * This function checks if a volume created using @req request has exactly the -+ * requested characteristics. Returns 0 in case of success and %-1 in case of -+ * error. -+ */ -+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, int vol_id, -+ const struct ubi_mkvol_request *req) -+{ -+ int ret; -+ struct ubi_vol_info vol_info; -+ int leb_size; -+ long long rsvd_bytes; -+ -+ ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info); -+ if (ret) { -+ __failed(test, func, line, "ubi_get_vol_info"); -+ return -1; -+ } -+ -+ if (req->alignment != vol_info.alignment) { -+ __err_msg(test, func, line, -+ "bad alignment: requested %d, got %d", -+ req->alignment, vol_info.alignment); -+ return -1; -+ } -+ if (req->vol_type != vol_info.type) { -+ __err_msg(test, func, line, "bad type: requested %d, got %d", -+ req->vol_type, vol_info.type); -+ return -1; -+ } -+ if (strlen(req->name) != strlen(vol_info.name) || -+ strcmp(req->name, vol_info.name) != 0) { -+ __err_msg(test, func, line, -+ "bad name: requested \"%s\", got \"%s\"", -+ req->name, vol_info.name); -+ return -1; -+ } -+ if (vol_info.corrupted) { -+ __err_msg(test, func, line, "corrupted new volume"); -+ return -1; -+ } -+ -+ leb_size = dev_info->leb_size - (dev_info->leb_size % req->alignment); -+ if (leb_size != vol_info.leb_size) { -+ __err_msg(test, func, line, -+ "bad usable LEB size %d, should be %d", -+ vol_info.leb_size, leb_size); -+ return -1; -+ } -+ -+ rsvd_bytes = req->bytes; -+ if (rsvd_bytes % leb_size) -+ rsvd_bytes += leb_size - (rsvd_bytes % leb_size); -+ -+ if (rsvd_bytes != vol_info.rsvd_bytes) { -+ __err_msg(test, func, line, -+ "bad reserved bytes %lld, should be %lld", -+ vol_info.rsvd_bytes, rsvd_bytes); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * __check_vol_patt - check that volume contains certain data -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @node volume character device node -+ * @byte data pattern to check -+ * -+ * This function returns %0 if the volume contains only @byte bytes, and %-1 if -+ * not. -+ */ -+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, -+ const char *node, uint8_t byte) -+{ -+ int ret, fd; -+ long long bytes = 0; -+ struct ubi_vol_info vol_info; -+ unsigned char buf[512]; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) { -+ __failed(test, func, line, "open"); -+ __err_msg(test, func, line, "cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ ret = ubi_get_vol_info(libubi, node, &vol_info); -+ if (ret) { -+ __failed(test, func, line, "ubi_get_vol_info"); -+ goto close; -+ } -+ -+ while (bytes < vol_info.data_bytes) { -+ int i; -+ -+ memset(buf, ~byte, 512); -+ ret = read(fd, buf, 512); -+ if (ret == -1) { -+ __failed(test, func, line, "read"); -+ __err_msg(test, func, line, "bytes = %lld, ret = %d", -+ bytes, ret); -+ goto close; -+ } -+ -+ if (ret == 0 && bytes + ret < vol_info.data_bytes) { -+ __err_msg(test, func, line, -+ "EOF, but read only %lld bytes of %lld", -+ bytes + ret, vol_info.data_bytes); -+ goto close; -+ } -+ -+ for (i = 0; i < ret; i++) -+ if (buf[i] != byte) { -+ __err_msg(test, func, line, -+ "byte at %lld is not %#x but %#x", -+ bytes + i, byte, (int)buf[i]); -+ goto close; -+ } -+ -+ bytes += ret; -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * __update_vol_patt - update volume using a certain byte pattern -+ * -+ * @libubi libubi descriptor -+ * @dev_info UBI device description -+ * @test test name -+ * @func function name -+ * @line line number -+ * @node volume character device node -+ * @byte data pattern to check -+ * -+ * This function returns %0 in case of success, and %-1 if in case of failure. -+ */ -+int __update_vol_patt(libubi_t libubi, const char *test, const char *func, -+ int line, const char *node, long long bytes, uint8_t byte) -+{ -+ int ret, fd; -+ long long written = 0; -+ unsigned char buf[512]; -+ -+ fd = open(node, O_RDWR); -+ if (fd == -1) { -+ __failed(test, func, line, "open"); -+ __err_msg(test, func, line, "cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ if (ubi_update_start(libubi, fd, bytes)) { -+ __failed(test, func, line, "ubi_update_start"); -+ __err_msg(test, func, line, "bytes = %lld", bytes); -+ goto close; -+ } -+ -+ memset(buf, byte, 512); -+ -+ while (written != bytes) { -+ ret = write(fd, buf, 512); -+ if (ret == -1) { -+ __failed(test, func, line, "write"); -+ __err_msg(test, func, line, "written = %lld, ret = %d", -+ written, ret); -+ goto close; -+ } -+ written += ret; -+ -+ if (written > bytes) { -+ __err_msg(test, func, line, "update length %lld bytes, " -+ "but %lld bytes are already written", -+ bytes, written); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.h linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,103 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * The stuff which is common for many tests. -+ */ -+ -+#ifndef __COMMON_H__ -+#define __COMMON_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d" -+#define MIN_AVAIL_EBS 5 -+#define PAGE_SIZE 4096 -+ -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+ -+#define err_msg(fmt, ...) \ -+ __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) -+ -+#define failed(name) \ -+ __failed(TESTNAME, __FUNCTION__, __LINE__, name) -+ -+#define initial_check(argc, argv) \ -+ __initial_check(TESTNAME, argc, argv) -+ -+#define check_volume(vol_id, req) \ -+ __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__, \ -+ __LINE__, vol_id, req) -+ -+#define check_vol_patt(node, byte) \ -+ __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__, \ -+ node, byte) -+ -+#define update_vol_patt(node, bytes, byte) \ -+ __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__, \ -+ node, bytes, byte) -+ -+#define check_failed(ret, error, func, fmt, ...) ({ \ -+ int __ret; \ -+ \ -+ if (!ret) { \ -+ err_msg("%s() returned success but should have failed", func); \ -+ err_msg(fmt, ##__VA_ARGS__); \ -+ __ret = -1; \ -+ } \ -+ if (errno != (error)) { \ -+ err_msg("%s failed with error %d (%s), expected %d (%s)", \ -+ func, errno, strerror(errno), error, strerror(error)); \ -+ err_msg(fmt, ##__VA_ARGS__); \ -+ __ret = -1; \ -+ } \ -+ __ret = 0; \ -+}) -+ -+/* Alignments to test, @s is eraseblock size */ -+#define ALIGNMENTS(s) \ -+ {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1, \ -+ (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2, \ -+ (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3, \ -+ (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9, \ -+ (s)-8, (s)-6, (s)-4, (s)-1, (s)}; -+ -+extern void __err_msg(const char *test, const char *func, int line, -+ const char *fmt, ...); -+void __failed(const char *test, const char *func, int line, -+ const char *failed); -+int __initial_check(const char *test, int argc, char * const argv[]); -+int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, int vol_id, -+ const struct ubi_mkvol_request *req); -+int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, -+ const char *test, const char *func, int line, -+ const char *node, uint8_t byte); -+int __update_vol_patt(libubi_t libubi, const char *test, const char *func, -+ int line, const char *node, long long bytes, -+ uint8_t byte); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__COMMON_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/integ.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,783 @@ -+#define _LARGEFILE64_SOURCE -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "libubi.h" -+ -+struct erase_block_info; -+struct volume_info; -+struct ubi_device_info; -+ -+struct write_info -+{ -+ struct write_info *next; -+ struct erase_block_info *erase_block; -+ int offset_within_block; /* Offset within erase block */ -+ off64_t offset; /* Offset within volume */ -+ int size; -+ int random_seed; -+}; -+ -+struct erase_block_info -+{ -+ struct volume_info *volume; -+ int block_number; -+ off64_t offset; /* Offset within volume */ -+ off64_t top_of_data; -+ int touched; /* Have we done anything at all with this erase block */ -+ int erased; /* This erased block is currently erased */ -+ struct write_info *writes; -+}; -+ -+struct volume_fd -+{ -+ struct volume_fd *next; -+ struct volume_info *volume; -+ int fd; -+}; -+ -+struct volume_info -+{ -+ struct volume_info *next; -+ struct ubi_device_info *ubi_device; -+ struct volume_fd *fds; -+ struct erase_block_info *erase_blocks; -+ const char *device_file_name; -+ struct ubi_vol_info info; -+}; -+ -+struct ubi_device_info -+{ -+ struct volume_info *volumes; -+ const char *device_file_name; -+ struct ubi_dev_info info; -+}; -+ -+struct open_volume_fd -+{ -+ struct open_volume_fd *next; -+ struct volume_fd *vol_fd; -+}; -+ -+#define MAX_UBI_DEVICES 64 -+ -+static libubi_t libubi; -+ -+static struct ubi_info info; -+static struct ubi_device_info ubi_array[MAX_UBI_DEVICES]; -+ -+static uint64_t total_written = 0; -+static uint64_t total_space = 0; -+ -+static struct open_volume_fd *open_volumes; -+static size_t open_volume_count = 0; -+ -+static const char *ubi_module_load_string; -+ -+static unsigned char *write_buffer = NULL; -+static unsigned char *read_buffer = NULL; -+ -+static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */ -+ -+static unsigned long next_seed = 1; -+ -+static unsigned get_next_seed() -+{ -+ next_seed = next_seed * 1103515245 + 12345; -+ return ((unsigned) (next_seed / 65536) % 32768); -+} -+ -+static void error_exit(const char *msg) -+{ -+ int eno = errno; -+ fprintf(stderr,"UBI Integrity Test Error: %s\n",msg); -+ if (eno) { -+ fprintf(stderr, "errno = %d\n", eno); -+ fprintf(stderr, "strerror = %s\n", strerror(eno)); -+ } -+ exit(1); -+} -+ -+static void *allocate(size_t n) -+{ -+ void *p = malloc(n); -+ if (!p) -+ error_exit("Memory allocation failure"); -+ memset(p, 0, n); -+ return p; -+} -+ -+static unsigned get_random_number(unsigned n) -+{ -+ uint64_t r, b; -+ -+ if (n < 1) -+ return 0; -+ r = rand(); -+ r *= n; -+ b = RAND_MAX; -+ b += 1; -+ r /= b; -+ return r; -+} -+ -+static struct volume_fd *open_volume(struct volume_info *vol) -+{ -+ struct volume_fd *s; -+ struct open_volume_fd *ofd; -+ int fd; -+ -+ if (vol->fds) { -+ /* If already open dup it */ -+ fd = dup(vol->fds->fd); -+ if (fd == -1) -+ error_exit("Failed to dup volume device file des"); -+ } else { -+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); -+ if (fd == -1) -+ error_exit("Failed to open volume device file"); -+ } -+ s = allocate(sizeof(*s)); -+ s->fd = fd; -+ s->volume = vol; -+ s->next = vol->fds; -+ vol->fds = s; -+ /* Add to open volumes list */ -+ ofd = allocate(sizeof(*ofd)); -+ ofd->vol_fd = s; -+ ofd->next = open_volumes; -+ open_volumes = ofd; -+ open_volume_count += 1; -+ return 0; -+} -+ -+static void close_volume(struct volume_fd *vol_fd) -+{ -+ struct volume_fd *vfd, *vfd_last; -+ struct open_volume_fd *ofd, *ofd_last; -+ int fd = vol_fd->fd; -+ -+ /* Remove from open volumes list */ -+ ofd_last = NULL; -+ ofd = open_volumes; -+ while (ofd) { -+ if (ofd->vol_fd == vol_fd) { -+ if (ofd_last) -+ ofd_last->next = ofd->next; -+ else -+ open_volumes = ofd->next; -+ free(ofd); -+ open_volume_count -= 1; -+ break; -+ } -+ ofd_last = ofd; -+ ofd = ofd->next; -+ } -+ /* Remove from volume fd list */ -+ vfd_last = NULL; -+ vfd = vol_fd->volume->fds; -+ while (vfd) { -+ if (vfd == vol_fd) { -+ if (vfd_last) -+ vfd_last->next = vfd->next; -+ else -+ vol_fd->volume->fds = vfd->next; -+ free(vfd); -+ break; -+ } -+ vfd_last = vfd; -+ vfd = vfd->next; -+ } -+ /* Close volume device file */ -+ if (close(fd) == -1) -+ error_exit("Failed to close volume file descriptor"); -+} -+ -+static void set_random_data(unsigned seed, unsigned char *buf, int size) -+{ -+ int i; -+ unsigned r; -+ -+ r = rand(); -+ srand(seed); -+ for (i = 0; i < size; ++i) -+ buf[i] = rand(); -+ srand(r); -+} -+ -+#if 0 -+static void print_write_info(struct write_info *w) -+{ -+ printf("Offset: %lld Size:%d Seed:%u\n", w->offset, w->size, w->random_seed); -+ fflush(stdout); -+} -+#endif -+ -+static void check_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ struct write_info *w; -+ off64_t gap_end; -+ int leb_size = erase_block->volume->info.leb_size; -+ ssize_t bytes_read; -+ -+ w = erase_block->writes; -+ gap_end = erase_block->offset + leb_size; -+ while (w) { -+ if (w->offset + w->size < gap_end) { -+ /* There is a gap. Check all 0xff */ -+ off64_t gap_start = w->offset + w->size; -+ size_t size = gap_end - gap_start; -+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, size); -+ if (bytes_read != size) -+ error_exit("read failed in gap"); -+ while (size) -+ if (read_buffer[--size] != 0xff) { -+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number); -+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start); -+ fprintf(stderr, "size = %ld\n" , (long) bytes_read); -+ error_exit("verify 0xff failed"); -+ } -+ } -+ if (lseek64(fd, w->offset, SEEK_SET) != w->offset) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , w->size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, w->size); -+ if (bytes_read != w->size) { -+ fprintf(stderr, "offset = %lld\n" , (long long) w->offset); -+ fprintf(stderr, "size = %ld\n" , (long) w->size); -+ fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read); -+ error_exit("read failed"); -+ } -+ set_random_data(w->random_seed, write_buffer, w->size); -+ if (memcmp(read_buffer, write_buffer, w->size)) -+ error_exit("verify failed"); -+ gap_end = w->offset; -+ w = w->next; -+ } -+ if (gap_end > erase_block->offset) { -+ /* Check all 0xff */ -+ off64_t gap_start = erase_block->offset; -+ size_t size = gap_end - gap_start; -+ if (lseek64(fd, gap_start, SEEK_SET) != gap_start) -+ error_exit("lseek64 failed"); -+ memset(read_buffer, 0 , size); -+ errno = 0; -+ bytes_read = read(fd, read_buffer, size); -+ if (bytes_read != size) -+ error_exit("read failed in gap"); -+ while (size) -+ if (read_buffer[--size] != 0xff) { -+ fprintf(stderr, "block no. = %d\n" , erase_block->block_number); -+ fprintf(stderr, "offset = %lld\n" , (long long) gap_start); -+ fprintf(stderr, "size = %ld\n" , (long) bytes_read); -+ error_exit("verify 0xff failed!"); -+ } -+ } -+} -+ -+static int write_to_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ int page_size = erase_block->volume->ubi_device->info.min_io_size; -+ int leb_size = erase_block->volume->info.leb_size; -+ int next_offset = 0; -+ int space, size; -+ off64_t offset; -+ unsigned seed; -+ struct write_info *w; -+ -+ if (erase_block->writes) -+ next_offset = erase_block->writes->offset_within_block + erase_block->writes->size; -+ space = leb_size - next_offset; -+ if (space <= 0) -+ return 0; /* No space */ -+ if (!get_random_number(10)) { -+ /* 1 time in 10 leave a gap */ -+ next_offset += get_random_number(space); -+ next_offset = (next_offset / page_size) * page_size; -+ space = leb_size - next_offset; -+ } -+ if (get_random_number(2)) -+ size = 1 * page_size; -+ else if (get_random_number(2)) -+ size = 2 * page_size; -+ else if (get_random_number(2)) -+ size = 3 * page_size; -+ else if (get_random_number(2)) -+ size = 4 * page_size; -+ else { -+ if (get_random_number(4)) -+ size = get_random_number(space); -+ else -+ size = space; -+ size = (size / page_size) * page_size; -+ } -+ if (size == 0 || size > space) -+ size = page_size; -+ if (next_offset + size > leb_size) -+ error_exit("internal error"); -+ offset = erase_block->offset + next_offset; -+ if (offset < erase_block->top_of_data) -+ error_exit("internal error!"); -+ if (lseek64(fd, offset, SEEK_SET) != offset) -+ error_exit("lseek64 failed"); -+ /* Do write */ -+ seed = get_next_seed(); -+ if (!seed) -+ seed = 1; -+ set_random_data(seed, write_buffer, size); -+ if (write(fd, write_buffer, size) != size) -+ error_exit("write failed"); -+ erase_block->top_of_data = offset + size; -+ /* Make write info and add to eb */ -+ w = allocate(sizeof(*w)); -+ w->offset_within_block = next_offset; -+ w->offset = offset; -+ w->size = size; -+ w->random_seed = seed; -+ w->next = erase_block->writes; -+ erase_block->writes = w; -+ erase_block->touched = 1; -+ erase_block->erased = 0; -+ total_written += size; -+ return 1; -+} -+ -+static void erase_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ struct write_info *w; -+ uint32_t eb_no; -+ int res; -+ -+ eb_no = erase_block->block_number; -+ res = ioctl(fd, UBI_IOCEBER, &eb_no); -+ if (res) -+ error_exit("Failed to erase an erase block"); -+ /* Remove writes from this eb */ -+ while (erase_block->writes) { -+ w = erase_block->writes; -+ erase_block->writes = erase_block->writes->next; -+ free(w); -+ } -+ erase_block->erased = 1; -+ erase_block->touched = 1; -+ erase_block->top_of_data = erase_block->offset; -+} -+ -+static void operate_on_erase_block(struct erase_block_info *erase_block, int fd) -+{ -+ /* -+ Possible operations: -+ read from it and verify -+ write to it -+ erase it -+ */ -+ int work_done = 1; -+ static int no_work_done_count = 0; -+ -+ if (!get_random_number(10) && no_work_done_count <= 5) { -+ check_erase_block(erase_block, fd); -+ work_done = 0; -+ } else if (get_random_number(100)) { -+ if (!write_to_erase_block(erase_block, fd)) { -+ /* The erase block was full */ -+ if (get_random_number(2) || no_work_done_count > 5) -+ erase_erase_block(erase_block, fd); -+ else -+ work_done = 0; -+ } -+ } else -+ erase_erase_block(erase_block, fd); -+ if (work_done) -+ no_work_done_count = 0; -+ else -+ no_work_done_count += 1; -+} -+ -+static void operate_on_open_volume(struct volume_fd *vol_fd) -+{ -+ /* -+ Possible operations: -+ operate on an erase block -+ close volume -+ */ -+ if (get_random_number(100) == 0) -+ close_volume(vol_fd); -+ else { -+ /* Pick an erase block at random */ -+ int eb_no = get_random_number(vol_fd->volume->info.rsvd_lebs); -+ operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd); -+ } -+} -+ -+static void operate_on_volume(struct volume_info *vol) -+{ -+ /* -+ Possible operations: -+ open it -+ resize it (must close fd's first) <- TODO -+ delete it (must close fd's first) <- TODO -+ */ -+ open_volume(vol); -+} -+ -+static int ubi_major(const char *device_file_name) -+{ -+ struct stat buf; -+ static int maj = 0; -+ -+ if (maj) -+ return maj; -+ if (stat(device_file_name, &buf) == -1) -+ error_exit("Failed to stat ubi device file"); -+ maj = major(buf.st_rdev); -+ return maj; -+} -+ -+static void operate_on_ubi_device(struct ubi_device_info *ubi_device) -+{ -+ /* -+ TODO: -+ Possible operations: -+ create a new volume -+ operate on existing volume -+ */ -+ /* -+ Simplified operation (i.e. only have 1 volume): -+ If there are no volumes create 1 volumne -+ Then operate on the volume -+ */ -+ if (ubi_device->info.vol_count == 0) { -+ /* Create the one-and-only volume we will use */ -+ char dev_name[1024]; -+ int i, n, maj, fd; -+ struct volume_info *s; -+ struct ubi_mkvol_request req; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; /* TODO: What is this? */ -+ req.bytes = ubi_device->info.leb_size * max_ebs_per_vol; -+ if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes) -+ req.bytes = ubi_device->info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = "integ-test-vol"; -+ if (ubi_mkvol(libubi, ubi_device->device_file_name, &req)) -+ error_exit("ubi_mkvol failed"); -+ s = allocate(sizeof(*s)); -+ s->ubi_device = ubi_device; -+ if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info)) -+ error_exit("ubi_get_vol_info failed"); -+ n = s->info.rsvd_lebs; -+ s->erase_blocks = allocate(sizeof(struct erase_block_info) * n); -+ for (i = 0; i < n; ++i) { -+ s->erase_blocks[i].volume = s; -+ s->erase_blocks[i].block_number = i; -+ s->erase_blocks[i].offset = i * (off64_t) s->info.leb_size; -+ s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset; -+ } -+ /* FIXME: Correctly get device file name */ -+ sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id); -+ s->device_file_name = strdup(dev_name); -+ ubi_device->volumes = s; -+ ubi_device->info.vol_count += 1; -+ sleep(1); -+ fd = open(s->device_file_name, O_RDONLY); -+ if (fd == -1) { -+ /* FIXME: Correctly make node */ -+ maj = ubi_major(ubi_device->device_file_name); -+ sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1); -+ system(dev_name); -+ } else if (close(fd) == -1) -+ error_exit("Failed to close volume device file"); -+ } -+ operate_on_volume(ubi_device->volumes); -+} -+ -+static void do_an_operation(void) -+{ -+ int too_few = (open_volume_count < info.dev_count * 3); -+ int too_many = (open_volume_count > info.dev_count * 5); -+ -+ if (too_many || (!too_few && get_random_number(1000) > 0)) { -+ /* Operate on an open volume */ -+ size_t pos; -+ struct open_volume_fd *ofd; -+ pos = get_random_number(open_volume_count); -+ for (ofd = open_volumes; pos && ofd && ofd->next; --pos) -+ ofd = ofd->next; -+ operate_on_open_volume(ofd->vol_fd); -+ } else if (info.dev_count > 0) { -+ /* Operate on a ubi device */ -+ size_t ubi_pos = 0; -+ if (info.dev_count > 1) -+ ubi_pos = get_random_number(info.dev_count - 1); -+ operate_on_ubi_device(&ubi_array[ubi_pos]); -+ } else -+ error_exit("Internal error"); -+} -+ -+static void get_ubi_devices_info(void) -+{ -+ int i, ubi_pos = 0; -+ char dev_name[1024]; -+ size_t buf_size = 1024 * 128; -+ -+ if (ubi_get_info(libubi, &info)) -+ error_exit("ubi_get_info failed"); -+ if (info.dev_count > MAX_UBI_DEVICES) -+ error_exit("Too many ubi devices"); -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) { -+ struct ubi_device_info *s; -+ s = &ubi_array[ubi_pos++]; -+ if (ubi_get_dev_info1(libubi, i, &s->info)) -+ error_exit("ubi_get_dev_info1 failed"); -+ if (s->info.vol_count) -+ error_exit("There are existing volumes"); -+ /* FIXME: Correctly get device file name */ -+ sprintf(dev_name, "/dev/ubi%d", i); -+ s->device_file_name = strdup(dev_name); -+ if (buf_size < s->info.leb_size) -+ buf_size = s->info.leb_size; -+ if (max_ebs_per_vol && s->info.leb_size * max_ebs_per_vol < s->info.avail_bytes) -+ total_space += s->info.leb_size * max_ebs_per_vol; -+ else -+ total_space += s->info.avail_bytes; -+ } -+ write_buffer = allocate(buf_size); -+ read_buffer = allocate(buf_size); -+} -+ -+static void load_ubi(void) -+{ -+ system("rmmod ubi"); -+ if (system(ubi_module_load_string) != 0) -+ error_exit("Failed to load UBI module"); -+ sleep(1); -+} -+ -+static void do_some_operations(void) -+{ -+ unsigned i = 0; -+ total_written = 0; -+ printf("Total space: %llu\n", (unsigned long long) total_space); -+ while (total_written < total_space * 3) { -+ do_an_operation(); -+ if (i++ % 10000 == 0) -+ printf("Total written: %llu\n", (unsigned long long) total_written); -+ } -+ printf("Total written: %llu\n", (unsigned long long) total_written); -+} -+ -+static void reload_ubi(void) -+{ -+ /* Remove module */ -+ if (system("rmmod ubi") != 0) -+ error_exit("Failed to remove UBI module"); -+ /* Install module */ -+ if (system(ubi_module_load_string) != 0) -+ error_exit("Failed to load UBI module"); -+ sleep(1); -+} -+ -+static void check_volume(struct volume_info *vol) -+{ -+ struct erase_block_info *eb = vol->erase_blocks; -+ int pos; -+ int fd; -+ -+ fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); -+ if (fd == -1) -+ error_exit("Failed to open volume device file"); -+ for (pos = 0; pos < vol->info.rsvd_lebs; ++pos) -+ check_erase_block(eb++, fd); -+ if (close(fd) == -1) -+ error_exit("Failed to close volume device file"); -+} -+ -+static void check_ubi_device(struct ubi_device_info *ubi_device) -+{ -+ struct volume_info *vol; -+ -+ vol = ubi_device->volumes; -+ while (vol) { -+ check_volume(vol); -+ vol = vol->next; -+ } -+} -+ -+static void check_ubi(void) -+{ -+ int i; -+ -+ for (i = 0; i < info.dev_count; ++i) -+ check_ubi_device(&ubi_array[i]); -+} -+ -+static int is_all_digits(const char *s) -+{ -+ const char *digits = "0123456789"; -+ if (!s || !*s) -+ return 0; -+ for (;*s;++s) -+ if (!strchr(digits,*s)) -+ return 0; -+ return 1; -+} -+ -+static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -+{ -+ const char *p = NULL; -+ int i = *pos; -+ size_t n = strlen(name); -+ -+ if (strlen(argv[i]) > n) -+ p = argv[i] + n; -+ else if (++i < argc) -+ p = argv[i]; -+ if (!is_all_digits(p)) -+ return 1; -+ *result = atoll(p); -+ *pos = i; -+ return 0; -+} -+ -+static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -+{ -+ const char *p = NULL; -+ int i = *pos; -+ size_t n = strlen(name); -+ -+ if (strlen(argv[i]) > n) -+ p = argv[i] + n; -+ else if (++i < argc) -+ p = argv[i]; -+ if (p && *p == '=') { -+ p += 1; -+ if (!*p && ++i < argc) -+ p = argv[i]; -+ } -+ if (!is_all_digits(p)) -+ return 1; -+ *result = atoll(p); -+ *pos = i; -+ return 0; -+} -+ -+static int remove_all_volumes(void) -+{ -+ int i; -+ -+ for (i = 0; i < info.dev_count; ++i) { -+ struct ubi_device_info *ubi_device = &ubi_array[i]; -+ struct volume_info *vol; -+ vol = ubi_device->volumes; -+ while (vol) { -+ int res = ubi_rmvol(libubi, -+ ubi_device->device_file_name, -+ vol->info.vol_id); -+ if (res) -+ return res; -+ vol = vol->next; -+ } -+ } -+ return 0; -+} -+ -+int main(int argc,char *argv[]) -+{ -+ int i; -+ long long r, repeat = 1; -+ int initial_seed = 1, args_ok = 1; -+ -+ printf("UBI Integrity Test\n"); -+ -+ /* Get arguments */ -+ ubi_module_load_string = 0; -+ for (i = 1; i < argc; ++i) { -+ if (strncmp(argv[i], "-h", 2) == 0) -+ args_ok = 0; -+ else if (strncmp(argv[i], "--help", 6) == 0) -+ args_ok = 0; -+ else if (strncmp(argv[i], "-n", 2) == 0) { -+ if (get_short_arg(&i, "-n", &repeat, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "--repeat", 8) == 0) { -+ if (get_long_arg(&i, "--repeat", &repeat, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "-m", 2) == 0) { -+ if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv)) -+ args_ok = 0; -+ } else if (strncmp(argv[i], "--maxebs", 8) == 0) { -+ if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv)) -+ args_ok = 0; -+ } else if (!ubi_module_load_string) -+ ubi_module_load_string = argv[i]; -+ else -+ args_ok = 0; -+ } -+ if (!args_ok || !ubi_module_load_string) { -+ fprintf(stderr, "Usage is: ubi_integ [] \n"); -+ fprintf(stderr, " Options: \n"); -+ fprintf(stderr, " -h, --help Help\n"); -+ fprintf(stderr, " -n arg, --repeat=arg Repeat test arg times\n"); -+ fprintf(stderr, " -m arg, --maxebs=arg Max no. of erase blocks\n"); -+ return 1; -+ } -+ -+ initial_seed = getpid(); -+ printf("Initial seed = %u\n", (unsigned) initial_seed); -+ next_seed = initial_seed; -+ srand(initial_seed); -+ load_ubi(); -+ -+ libubi = libubi_open(); -+ if (!libubi) -+ error_exit("Failed to open libubi"); -+ -+ get_ubi_devices_info(); -+ -+ r = 0; -+ while (repeat == 0 || r++ < repeat) { -+ printf("Cycle %lld\n", r); -+ do_some_operations(); -+ -+ /* Close all volumes */ -+ while (open_volumes) -+ close_volume(open_volumes->vol_fd); -+ -+ check_ubi(); -+ -+ libubi_close(libubi); -+ -+ reload_ubi(); -+ -+ libubi = libubi_open(); -+ if (!libubi) -+ error_exit("Failed to open libubi"); -+ -+ check_ubi(); -+ } -+ -+ if (remove_all_volumes()) -+ error_exit("Failed to remove all volumes"); -+ -+ libubi_close(libubi); -+ -+ printf("UBI Integrity Test completed ok\n"); -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_basic.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,179 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test basic UBI volume I/O capabilities. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_basic - check basic volume read and update capabilities. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_basic(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_basic()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = type; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ /* Make sure newly created volume contains only 0xFF bytes */ -+ if (check_vol_patt(vol_node, 0xFF)) -+ goto remove; -+ -+ /* Write 0xA5 bytes to the volume */ -+ if (update_vol_patt(vol_node, dev_info.avail_bytes, 0xA5)) -+ goto remove; -+ if (check_vol_patt(vol_node, 0xA5)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/** -+ * test_aligned - test volume alignment feature. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_aligned(int type) -+{ -+ int i, ebsz; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_aligned()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ -+ req.vol_type = type; -+ req.name = name; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * ebsz; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ /* Make sure newly created volume contains only 0xFF bytes */ -+ if (check_vol_patt(vol_node, 0xFF)) -+ goto remove; -+ -+ /* Write 0xA5 bytes to the volume */ -+ if (update_vol_patt(vol_node, req.bytes, 0xA5)) -+ goto remove; -+ if (check_vol_patt(vol_node, 0xA5)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_basic(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_basic(UBI_STATIC_VOLUME)) -+ goto close; -+ if (test_aligned(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_aligned(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_paral.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,249 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * This test does a lot of I/O to volumes in parallel. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_paral" -+#include "common.h" -+ -+#define THREADS_NUM 3 -+#define ITERATIONS 10 -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int iterations = ITERATIONS; -+int total_bytes; -+ -+static long long memory_limit(void) -+{ -+ long long result = 0; -+ FILE *f; -+ -+ f = fopen("/proc/meminfo", "r"); -+ if (!f) -+ return 0; -+ fscanf(f, "%*s %lld", &result); -+ fclose(f); -+ return result * 1024 / 4; -+} -+ -+/** -+ * the_thread - the testing thread. -+ * -+ * @ptr thread number -+ */ -+static void * the_thread(void *ptr) -+{ -+ int fd, iter = iterations, vol_id = (int)ptr; -+ unsigned char *wbuf, *rbuf; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ -+ wbuf = malloc(total_bytes); -+ rbuf = malloc(total_bytes); -+ if (!wbuf || !rbuf) { -+ failed("malloc"); -+ goto free; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id); -+ -+ while (iter--) { -+ int i, ret, written = 0, rd = 0; -+ int bytes = (random() % (total_bytes - 1)) + 1; -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto free; -+ } -+ -+ for (i = 0; i < bytes; i++) -+ wbuf[i] = random() % 255; -+ memset(rbuf, '\0', bytes); -+ -+ do { -+ ret = ubi_update_start(libubi, fd, bytes); -+ if (ret && errno != EBUSY) { -+ failed("ubi_update_start"); -+ err_msg("vol_id %d", vol_id); -+ goto close; -+ } -+ } while (ret); -+ -+ while (written < bytes) { -+ int to_write = random() % (bytes - written); -+ -+ if (to_write == 0) -+ to_write = 1; -+ -+ ret = write(fd, wbuf, to_write); -+ if (ret != to_write) { -+ failed("write"); -+ err_msg("failed to write %d bytes at offset %d " -+ "of volume %d", to_write, written, -+ vol_id); -+ err_msg("update: %d bytes", bytes); -+ goto close; -+ } -+ -+ written += to_write; -+ } -+ -+ close(fd); -+ -+ fd = open(vol_node, O_RDONLY); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto free; -+ } -+ -+ /* read data back and check */ -+ while (rd < bytes) { -+ int to_read = random() % (bytes - rd); -+ -+ if (to_read == 0) -+ to_read = 1; -+ -+ ret = read(fd, rbuf, to_read); -+ if (ret != to_read) { -+ failed("read"); -+ err_msg("failed to read %d bytes at offset %d " -+ "of volume %d", to_read, rd, vol_id); -+ goto close; -+ } -+ -+ rd += to_read; -+ } -+ -+ close(fd); -+ -+ } -+ -+ free(wbuf); -+ free(rbuf); -+ return NULL; -+ -+close: -+ close(fd); -+free: -+ free(wbuf); -+ free(rbuf); -+ return NULL; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int i, ret; -+ pthread_t threads[THREADS_NUM]; -+ struct ubi_mkvol_request req; -+ long long mem_limit; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ req.alignment = 1; -+ mem_limit = memory_limit(); -+ if (mem_limit && mem_limit < dev_info.avail_bytes) -+ total_bytes = req.bytes = -+ (mem_limit / dev_info.leb_size / THREADS_NUM) -+ * dev_info.leb_size; -+ else -+ total_bytes = req.bytes = -+ ((dev_info.avail_lebs - 3) / THREADS_NUM) -+ * dev_info.leb_size; -+ for (i = 0; i < THREADS_NUM; i++) { -+ char name[100]; -+ -+ req.vol_id = i; -+ sprintf(name, TESTNAME":%d", i); -+ req.name = name; -+ req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto remove; -+ } -+ } -+ -+ /* Create one volume with static data to make WL work more */ -+ req.vol_id = THREADS_NUM; -+ req.name = TESTNAME ":static"; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.bytes = 3*dev_info.leb_size; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto remove; -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) { -+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); -+ if (ret) { -+ failed("pthread_create"); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) -+ pthread_join(threads[i], NULL); -+ -+ for (i = 0; i <= THREADS_NUM; i++) { -+ if (ubi_rmvol(libubi, node, i)) { -+ failed("ubi_rmvol"); -+ goto remove; -+ } -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+remove: -+ for (i = 0; i <= THREADS_NUM; i++) -+ ubi_rmvol(libubi, node, i); -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_read.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,388 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume read. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "io_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int fd; -+ -+/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */ -+#define LENGTHES(io, s) \ -+ {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io), \ -+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ -+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ -+ 2*(s)+(io), 3*(s), 3*(s)+(io)}; -+ -+/* -+ * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz - -+ * volume size. -+ */ -+#define OFFSETS(io, s, sz) \ -+ {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io), \ -+ PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ -+ (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ -+ 2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1}; -+ -+/** -+ * test_static - test static volume-specific features. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_static(void) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":io_basic()"; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_vol_info vol_info; -+ int fd, ret; -+ char buf[20]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_STATIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ goto remove; -+ } -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto close; -+ } -+ -+ /* Make sure new static volume contains no data */ -+ if (vol_info.data_bytes != 0) { -+ err_msg("data_bytes = %lld, not zero", vol_info.data_bytes); -+ goto close; -+ } -+ -+ /* Ensure read returns EOF */ -+ ret = read(fd, buf, 1); -+ if (ret < 0) { -+ failed("read"); -+ goto close; -+ } -+ if (ret != 0) { -+ err_msg("read data from free static volume"); -+ goto close; -+ } -+ -+ if (ubi_update_start(libubi, fd, 10)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ -+ ret = write(fd, buf, 10); -+ if (ret < 0) { -+ failed("write"); -+ goto close; -+ } -+ if (ret != 10) { -+ err_msg("written %d bytes", ret); -+ goto close; -+ } -+ -+ if (lseek(fd, 0, SEEK_SET) != 0) { -+ failed("seek"); -+ goto close; -+ } -+ ret = read(fd, buf, 20); -+ if (ret < 0) { -+ failed("read"); -+ goto close; -+ } -+ if (ret != 10) { -+ err_msg("read %d bytes", ret); -+ goto close; -+ } -+ -+ close(fd); -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+close: -+ close(fd); -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/* -+ * A helper function for test_read2(). -+ */ -+static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off) -+{ -+ int i, len1; -+ unsigned char ck_buf[len], buf[len]; -+ off_t new_off; -+ -+ if (off + len > vol_info->data_bytes) -+ len1 = vol_info->data_bytes - off; -+ else -+ len1 = len; -+ -+ if (lseek(fd, off, SEEK_SET) != off) { -+ failed("seek"); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ if (read(fd, buf, len) != len1) { -+ failed("read"); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ -+ new_off = lseek(fd, 0, SEEK_CUR); -+ if (new_off != off + len1) { -+ if (new_off == -1) -+ failed("lseek"); -+ else -+ err_msg("read %d bytes from %lld, but resulting " -+ "offset is %lld", len1, (long long) off, (long long) new_off); -+ return -1; -+ } -+ -+ for (i = 0; i < len1; i++) -+ ck_buf[i] = (unsigned char)(off + i); -+ -+ if (memcmp(buf, ck_buf, len1)) { -+ err_msg("incorrect data read from offset %lld", -+ (long long)off); -+ err_msg("len = %d", len); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * A helper function for test_read1(). -+ */ -+static int test_read2(const struct ubi_vol_info *vol_info, int len) -+{ -+ int i; -+ off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->leb_size, -+ vol_info->data_bytes); -+ -+ for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) { -+ if (test_read3(vol_info, len, offsets[i])) { -+ err_msg("offset = %d", offsets[i]); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * A helper function for test_read(). -+ */ -+static int test_read1(struct ubi_vol_info *vol_info) -+{ -+ int i, written = 0; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->leb_size); -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ /* Write some pattern to the volume */ -+ if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { -+ failed("ubi_update_start"); -+ err_msg("bytes = %lld", vol_info->rsvd_bytes); -+ goto close; -+ } -+ -+ while (written < vol_info->rsvd_bytes) { -+ int i, ret; -+ unsigned char buf[512]; -+ -+ for (i = 0; i < 512; i++) -+ buf[i] = (unsigned char)(written + i); -+ -+ ret = write(fd, buf, 512); -+ if (ret == -1) { -+ failed("write"); -+ err_msg("written = %d, ret = %d", written, ret); -+ goto close; -+ } -+ written += ret; -+ } -+ -+ close(fd); -+ -+ if (ubi_get_vol_info(libubi, vol_node, vol_info)) { -+ failed("ubi_get_vol_info"); -+ return -1; -+ } -+ -+ fd = open(vol_node, O_RDONLY); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) { -+ if (test_read2(vol_info, lengthes[i])) { -+ err_msg("length = %d", lengthes[i]); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_read - test UBI volume reading from different offsets. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_read(int type) -+{ -+ const char *name = TESTNAME ":test_read()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_mkvol_request req; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ struct ubi_vol_info vol_info; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_read1(&vol_info)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_static()) -+ goto close; -+ if (test_read(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_read(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/io_update.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,298 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume update and atomic LEB change -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#define TESTNAME "io_update" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+#define SEQUENCES(io, s) { \ -+ {3*(s)-(io)-1, 1}, \ -+ {512}, \ -+ {666}, \ -+ {2048}, \ -+ {(io), (io), PAGE_SIZE}, \ -+ {(io)+1, (io)+1, PAGE_SIZE}, \ -+ {PAGE_SIZE}, \ -+ {PAGE_SIZE-1}, \ -+ {PAGE_SIZE+(io)}, \ -+ {(s)}, \ -+ {(s)-1}, \ -+ {(s)+1}, \ -+ {(io), (s)+1}, \ -+ {(s)+(io), PAGE_SIZE}, \ -+ {2*(s), PAGE_SIZE}, \ -+ {PAGE_SIZE, 2*(s), 1}, \ -+ {PAGE_SIZE, 2*(s)}, \ -+ {2*(s)-1, 2*(s)-1}, \ -+ {3*(s), PAGE_SIZE + 1}, \ -+ {1, PAGE_SIZE}, \ -+ {(io), (s)} \ -+} -+ -+#define SEQ_SZ 21 -+ -+/* -+ * test_update1 - helper function for test_update(). -+ */ -+static int test_update1(struct ubi_vol_info *vol_info, int leb_change) -+{ -+ long long total_len = leb_change ? vol_info->leb_size -+ : vol_info->rsvd_bytes; -+ int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size, -+ leb_change ? dev_info.min_io_size * 2 -+ : vol_info->leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ unsigned char buf[total_len]; -+ int fd, i, j; -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", node); -+ return -1; -+ } -+ -+ for (i = 0; i < SEQ_SZ; i++) { -+ int ret, stop = 0, len = 0; -+ off_t off = 0; -+ long long test_len; -+ unsigned char buf1[total_len]; -+ -+ /* -+ * test_len is LEB size (if we test atomic LEB change) or -+ * volume size (if we test update). For better test coverage, -+ * use a little smaller LEB change/update length. -+ */ -+ test_len = total_len - (rand() % (total_len / 10)); -+ -+ if (leb_change) { -+ if (ubi_leb_change_start(libubi, fd, 0, test_len, -+ UBI_SHORTTERM)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ } else { -+ if (ubi_update_start(libubi, fd, test_len)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ } -+ -+ for (j = 0; off < test_len; j++) { -+ int n, rnd_len, l; -+ -+ if (!stop) { -+ if (sequences[i][j] != 0) -+ l = len = sequences[i][j]; -+ else -+ stop = 1; -+ } -+ -+ /* -+ * Fill some part of the write buffer with random data, -+ * and the other part with 0xFFs to test how UBI -+ * stripes 0xFFs multiple of I/O unit size. -+ */ -+ if (off + l > test_len) -+ l = test_len - off; -+ rnd_len = rand() % (l + 1); -+ for (n = 0; n < rnd_len; n++) -+ buf[off + n] = (unsigned char)rand(); -+ memset(buf + off + rnd_len, 0xFF, l - rnd_len); -+ -+ /* -+ * Deliberately pass len instead of l (len may be -+ * greater then l if this is the last chunk) because -+ * UBI have to read only l bytes anyway. -+ */ -+ ret = write(fd, buf + off, len); -+ if (ret < 0) { -+ failed("write"); -+ err_msg("failed to write %d bytes at offset " -+ "%lld", len, (long long)off); -+ goto close; -+ } -+ len = l; -+ if (ret != len) { -+ err_msg("failed to write %d bytes at offset " -+ "%lld, wrote %d", len, (long long)off, ret); -+ goto close; -+ } -+ off += len; -+ } -+ -+ /* Check data */ -+ if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { -+ failed("lseek"); -+ err_msg("cannot seek to 0"); -+ goto close; -+ } -+ -+ memset(buf1, 0x01, test_len); -+ -+ if (vol_info->type == UBI_STATIC_VOLUME) -+ /* -+ * Static volume must not let use read more then it -+ * contains. -+ */ -+ ret = read(fd, buf1, test_len + 100); -+ else -+ ret = read(fd, buf1, test_len); -+ if (ret < 0) { -+ failed("read"); -+ err_msg("failed to read %d bytes", test_len); -+ goto close; -+ } -+ if (ret != test_len) { -+ err_msg("failed to read %d bytes, read %d", test_len, ret); -+ goto close; -+ } -+ if (memcmp(buf, buf1, test_len)) { -+ err_msg("data corruption"); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_update - check volume update and atomic LEB change capabilities. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_update(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":io_update()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ struct ubi_vol_info vol_info; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_update1(&vol_info, 0)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (vol_info.type != UBI_STATIC_VOLUME) { -+ if (test_update1(&vol_info, 1)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_update(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_update(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_bad.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,301 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test UBI volume creation and deletion ioctl()s with bad input and in case of -+ * incorrect usage. -+ */ -+ -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_bad" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters. -+ * -+ * This function returns %0 if the test passed and %-1 if not. -+ */ -+static int test_mkvol(void) -+{ -+ int ret, i; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_mkvol()"; -+ -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ /* Bad volume ID */ -+ req.vol_id = -2; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) -+ return -1; -+ -+ req.vol_id = dev_info.max_vol_count; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) -+ return -1; -+ -+ /* Bad alignment */ -+ req.vol_id = 0; -+ req.alignment = 0; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ req.alignment = -1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ req.alignment = dev_info.leb_size + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ -+ if (dev_info.min_io_size > 1) { -+ req.alignment = dev_info.min_io_size + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", -+ req.alignment)) -+ return -1; -+ } -+ -+ /* Bad bytes */ -+ req.alignment = 1; -+ req.bytes = -1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.bytes = 0; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.bytes = dev_info.avail_bytes + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ req.alignment = dev_info.leb_size - dev_info.min_io_size; -+ req.bytes = (dev_info.leb_size - dev_info.leb_size % req.alignment) * -+ dev_info.avail_lebs + 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) -+ return -1; -+ -+ /* Bad vol_type */ -+ req.alignment = 1; -+ req.bytes = dev_info.leb_size; -+ req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d", -+ req.vol_type)) -+ return -1; -+ -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ -+ /* Too long name */ -+ { -+ char name[UBI_VOL_NAME_MAX + 5]; -+ -+ memset(name, 'x', UBI_VOL_NAME_MAX + 1); -+ name[UBI_VOL_NAME_MAX + 1] = '\0'; -+ -+ req.name = name; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d", -+ UBI_VOL_NAME_MAX + 1)) -+ return -1; -+ } -+ -+ /* Try to create 2 volumes with the same ID and name */ -+ req.name = name; -+ req.vol_id = 0; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "volume with ID 0 created twice")) -+ return -1; -+ -+ req.vol_id = 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "volume with name \"%s\" created twice", name)) -+ return -1; -+ -+ if (ubi_rmvol(libubi, node, 0)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Try to use too much space */ -+ req.vol_id = 0; -+ req.bytes = dev_info.avail_bytes; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ req.bytes = 1; -+ req.vol_id = 1; -+ ret = ubi_mkvol(libubi, node, &req); -+ if (check_failed(ret, EEXIST, "ubi_mkvol", -+ "created volume of maximum size %lld, but still " -+ "can create more volumes", dev_info.avail_bytes)) -+ return -1; -+ -+ if (ubi_rmvol(libubi, node, 0)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Try to create too many volumes */ -+ for (i = 0; i < dev_info.max_vol_count; i++) { -+ char nm[strlen(name) + 50]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = 1; -+ req.vol_type = UBI_STATIC_VOLUME; -+ -+ sprintf(nm, "%s:%d", name, i); -+ req.name = nm; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ /* -+ * Note, because of gluebi we may be unable to create -+ * dev_info.max_vol_count devices (MTD restrictions). -+ */ -+ if (errno == ENFILE) -+ break; -+ failed("ubi_mkvol"); -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ -+ return 0; -+ -+remove: -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ return -1; -+} -+ -+/** -+ * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters. -+ * -+ * This function returns %0 if the test passed and %-1 if not. -+ */ -+static int test_rmvol(void) -+{ -+ int ret; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_rmvol()"; -+ -+ /* Bad vol_id */ -+ ret = ubi_rmvol(libubi, node, -1); -+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1")) -+ return -1; -+ -+ ret = ubi_rmvol(libubi, node, dev_info.max_vol_count); -+ if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d", -+ dev_info.max_vol_count)) -+ return -1; -+ -+ /* Try to remove non-existing volume */ -+ ret = ubi_rmvol(libubi, node, 0); -+ if (check_failed(ret, ENODEV, "ubi_rmvol", -+ "removed non-existing volume 0")) -+ return -1; -+ -+ /* Try to remove volume twice */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ ret = ubi_rmvol(libubi, node, req.vol_id); -+ if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice", -+ req.vol_id)) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_mkvol()) -+ goto close; -+ -+ if (test_rmvol()) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_basic.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,250 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test test checks basic volume creation and deletion capabilities. -+ */ -+ -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_basic" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * mkvol_alignment - create volumes with different alignments. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int mkvol_alignment(void) -+{ -+ struct ubi_mkvol_request req; -+ int i, vol_id, ebsz; -+ const char *name = TESTNAME ":mkvol_alignment()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ -+ /* Alignment should actually be multiple of min. I/O size */ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ /* Bear in mind alignment reduces EB size */ -+ ebsz = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = dev_info.avail_lebs * ebsz; -+ -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ err_msg("alignment %d", req.alignment); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, vol_id); -+ return -1; -+} -+ -+/** -+ * mkvol_basic - simple test that checks basic volume creation capability. -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int mkvol_basic(void) -+{ -+ struct ubi_mkvol_request req; -+ struct ubi_vol_info vol_info; -+ int vol_id, ret; -+ const char *name = TESTNAME ":mkvol_basic()"; -+ -+ /* Create dynamic volume of maximum size */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Create static volume of maximum size */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes; -+ req.vol_type = UBI_STATIC_VOLUME; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ vol_id = req.vol_id; -+ if (check_volume(vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Make sure volume does not exist */ -+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); -+ if (ret == 0) { -+ err_msg("removed volume %d exists", vol_id); -+ goto remove; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, vol_id); -+ return -1; -+} -+ -+/** -+ * mkvol_multiple - test multiple volumes creation -+ * -+ * Thus function returns %0 if the test passed and %-1 if not. -+ */ -+static int mkvol_multiple(void) -+{ -+ struct ubi_mkvol_request req; -+ int i, ret, max = dev_info.max_vol_count; -+ const char *name = TESTNAME ":mkvol_multiple()"; -+ -+ /* Create maximum number of volumes */ -+ for (i = 0; i < max; i++) { -+ char nm[strlen(name) + 50]; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = 1; -+ req.vol_type = UBI_STATIC_VOLUME; -+ -+ sprintf(nm, "%s:%d", name, i); -+ req.name = nm; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ if (errno == ENFILE) { -+ max = i; -+ break; -+ } -+ failed("ubi_mkvol"); -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) { -+ err_msg("vol_id %d", i); -+ goto remove; -+ } -+ } -+ -+ for (i = 0; i < max; i++) { -+ struct ubi_vol_info vol_info; -+ -+ if (ubi_rmvol(libubi, node, i)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ /* Make sure volume does not exist */ -+ ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (ret == 0) { -+ err_msg("removed volume %d exists", i); -+ goto remove; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ for (i = 0; i < dev_info.max_vol_count + 1; i++) -+ ubi_rmvol(libubi, node, i); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (mkvol_basic()) -+ goto close; -+ -+ if (mkvol_alignment()) -+ goto close; -+ -+ if (mkvol_multiple()) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/mkvol_paral.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * This test creates and deletes volumes in parallel. -+ */ -+ -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "mkvol_paral" -+#include "common.h" -+ -+#define THREADS_NUM 4 -+#define ITERATIONS 500 -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+static int iterations = ITERATIONS; -+ -+/** -+ * the_thread - the testing thread. -+ * -+ * @ptr thread number -+ */ -+static void * the_thread(void *ptr) -+{ -+ int n = (int)ptr, iter = iterations; -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":the_thread()"; -+ char nm[strlen(name) + 50]; -+ -+ req.alignment = 1; -+ req.bytes = dev_info.avail_bytes/ITERATIONS; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ sprintf(nm, "%s:%d", name, n); -+ req.name = nm; -+ -+ while (iter--) { -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return NULL; -+ } -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return NULL; -+ } -+ } -+ -+ return NULL; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int i, ret; -+ pthread_t threads[THREADS_NUM]; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) { -+ ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); -+ if (ret) { -+ failed("pthread_create"); -+ goto close; -+ } -+ } -+ -+ for (i = 0; i < THREADS_NUM; i++) -+ pthread_join(threads[i], NULL); -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/rsvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,305 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Tes UBI volume re-size. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "rsvol" -+#include "common.h" -+ -+static libubi_t libubi; -+static struct ubi_dev_info dev_info; -+const char *node; -+ -+/** -+ * test_basic - check volume re-size capability. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_basic(int type) -+{ -+ struct ubi_mkvol_request req; -+ const char *name = TESTNAME ":test_basic()"; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = 1; -+ req.bytes = MIN_AVAIL_EBS * dev_info.leb_size; -+ req.vol_type = type; -+ req.name = name; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ req.bytes = dev_info.leb_size; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.leb_size; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ req.bytes -= 1; -+ if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { -+ failed("ubi_rsvol"); -+ goto remove; -+ } -+ -+ if (check_volume(req.vol_id, &req)) -+ goto remove; -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+/* -+ * Helper function for test_rsvol(). -+ */ -+static int test_rsvol1(struct ubi_vol_info *vol_info) -+{ -+ long long bytes; -+ struct ubi_vol_info vol_info1; -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ unsigned char buf[vol_info->rsvd_bytes]; -+ int fd, i, ret; -+ -+ /* Make the volume smaller and check basic volume I/O */ -+ bytes = vol_info->rsvd_bytes - vol_info->leb_size; -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id, -+ &vol_info1)) { -+ failed("ubi_get_vol_info"); -+ return -1; -+ } -+ -+ if (vol_info1.rsvd_bytes != bytes) { -+ err_msg("rsvd_bytes %lld, must be %lld", -+ vol_info1.rsvd_bytes, bytes); -+ return -1; -+ } -+ -+ if (vol_info1.rsvd_lebs != vol_info->rsvd_lebs - 1) { -+ err_msg("rsvd_lebs %d, must be %d", -+ vol_info1.rsvd_lebs, vol_info->rsvd_lebs - 1); -+ return -1; -+ } -+ -+ /* Write data to the volume */ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ vol_info->vol_id); -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", vol_node); -+ return -1; -+ } -+ -+ bytes = vol_info->rsvd_bytes - vol_info->leb_size - 1; -+ if (ubi_update_start(libubi, fd, bytes)) { -+ failed("ubi_update_start"); -+ goto close; -+ } -+ -+ for (i = 0; i < bytes; i++) -+ buf[i] = (unsigned char)i; -+ -+ ret = write(fd, buf, bytes); -+ if (ret != bytes) { -+ failed("write"); -+ goto close; -+ } -+ -+ close(fd); -+ -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ if (ubi_rsvol(libubi, node, vol_info->vol_id, -+ vol_info->leb_size * dev_info.avail_lebs)) { -+ failed("ubi_rsvol"); -+ return -1; -+ } -+ -+ fd = open(vol_node, O_RDWR); -+ if (fd == -1) { -+ failed("open"); -+ err_msg("cannot open \"%s\"\n", vol_node); -+ return -1; -+ } -+ -+ /* Read data back */ -+ if (lseek(fd, 0, SEEK_SET) != 0) { -+ failed("seek"); -+ goto close; -+ } -+ memset(buf, 0, bytes); -+ ret = read(fd, buf, bytes); -+ if (ret != bytes) { -+ failed("read"); -+ goto close; -+ } -+ -+ for (i = 0; i < bytes; i++) { -+ if (buf[i] != (unsigned char)i) { -+ err_msg("bad data"); -+ goto close; -+ } -+ } -+ -+ close(fd); -+ return 0; -+ -+close: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * test_rsvol - test UBI volume re-size. -+ * -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * -+ * Thus function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int test_rsvol(int type) -+{ -+ const char *name = TESTNAME "test_rsvol:()"; -+ int alignments[] = ALIGNMENTS(dev_info.leb_size); -+ char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; -+ struct ubi_mkvol_request req; -+ int i; -+ -+ for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { -+ int leb_size; -+ struct ubi_vol_info vol_info; -+ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.vol_type = type; -+ req.name = name; -+ -+ req.alignment = alignments[i]; -+ req.alignment -= req.alignment % dev_info.min_io_size; -+ if (req.alignment == 0) -+ req.alignment = dev_info.min_io_size; -+ -+ leb_size = dev_info.leb_size - dev_info.leb_size % req.alignment; -+ req.bytes = MIN_AVAIL_EBS * leb_size; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ return -1; -+ } -+ -+ sprintf(vol_node, UBI_VOLUME_PATTERN, dev_info.dev_num, -+ req.vol_id); -+ -+ if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { -+ failed("ubi_get_vol_info"); -+ goto remove; -+ } -+ -+ if (test_rsvol1(&vol_info)) { -+ err_msg("alignment = %d", req.alignment); -+ goto remove; -+ } -+ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ return -1; -+ } -+ } -+ -+ return 0; -+ -+remove: -+ ubi_rmvol(libubi, node, req.vol_id); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto close; -+ } -+ -+ if (test_basic(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_basic(UBI_STATIC_VOLUME)) -+ goto close; -+ if (test_rsvol(UBI_DYNAMIC_VOLUME)) -+ goto close; -+ if (test_rsvol(UBI_STATIC_VOLUME)) -+ goto close; -+ -+ libubi_close(libubi); -+ return 0; -+ -+close: -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/runtests.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,39 @@ -+#!/bin/sh -+ -+ubidev="$1" -+tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update -+io_paral volrefcnt" -+ -+if test -z "$ubidev"; -+then -+ echo "Usage:" -+ echo "$0 " -+ exit 1 -+fi -+ -+ubiname=`echo $ubidev | cut -d/ -f3` -+ -+major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1` -+ -+for minor in `seq 0 4`; do -+ if test ! -e ${ubidev}_${minor} ; -+ then -+ mknod ${ubidev}_${minor} c $major $(($minor + 1)) -+ fi -+done -+ -+if ! test -c "$ubidev"; -+then -+ echo "Error: $ubidev is not character device" -+ exit 1 -+fi -+ -+for t in `echo $tests`; -+do -+ echo "Running $t $ubidev" -+ "./$t" "$ubidev" || exit 1 -+done -+ -+echo SUCCESS -+ -+exit 0 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/tests/ubi-tests/volrefcnt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,122 @@ -+/* -+ * Copyright (c) Nokia Corporation, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * Test volume reference counting - create a volume, open a sysfs file -+ * belonging to the volume, delete the volume but do not close the file, make -+ * sure the file cannot be read, close the file, make sure the volume -+ * disappeard, make sure its sysfs subtree disappeared. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#define TESTNAME "rmvol" -+#include "common.h" -+ -+#define SYSFS_FILE "/sys/class/ubi/ubi%d_%d/usable_eb_size" -+ -+int main(int argc, char * const argv[]) -+{ -+ int ret, fd; -+ char fname[sizeof(SYSFS_FILE) + 20]; -+ const char *node; -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ struct ubi_mkvol_request req; -+ char tmp[100]; -+ -+ if (initial_check(argc, argv)) -+ return 1; -+ -+ node = argv[1]; -+ -+ libubi = libubi_open(); -+ if (libubi == NULL) { -+ failed("libubi_open"); -+ return 1; -+ } -+ -+ if (ubi_get_dev_info(libubi, node, &dev_info)) { -+ failed("ubi_get_dev_info"); -+ goto out_libubi; -+ } -+ -+ /* Create a small dynamic volume */ -+ req.vol_id = UBI_VOL_NUM_AUTO; -+ req.alignment = dev_info.min_io_size; -+ req.bytes = dev_info.leb_size; -+ req.vol_type = UBI_DYNAMIC_VOLUME; -+ req.name = "rmvol"; -+ -+ if (ubi_mkvol(libubi, node, &req)) { -+ failed("ubi_mkvol"); -+ goto out_libubi; -+ } -+ -+ /* Open volume-related sysfs file */ -+ sprintf(fname, SYSFS_FILE, dev_info.dev_num, req.vol_id); -+ fd = open(fname, O_RDONLY); -+ if (fd == -1) { -+ err_msg("cannot open %s", fname); -+ failed("open"); -+ goto out_rmvol; -+ } -+ -+ /* Remove the volume, but do not close the file */ -+ if (ubi_rmvol(libubi, node, req.vol_id)) { -+ failed("ubi_rmvol"); -+ perror("ubi_rmvol"); -+ goto out_close; -+ } -+ -+ /* Try to read from the file, this should fail */ -+ ret = read(fd, tmp, 100); -+ if (ret != -1) { -+ err_msg("read returned %d, expected -1", ret); -+ failed("read"); -+ goto out_close; -+ } -+ -+ /* Close the file and try to open it again, should fail */ -+ close(fd); -+ fd = open(fname, O_RDONLY); -+ if (fd != -1) { -+ err_msg("opened %s again, open returned %d, expected -1", -+ fname, fd); -+ failed("open"); -+ goto out_libubi; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_rmvol: -+ ubi_rmvol(libubi, node, req.vol_id); -+out_libubi: -+ libubi_close(libubi); -+ return 1; -+ -+out_close: -+ close(fd); -+ libubi_close(libubi); -+ return 1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+# -+# Makefile for ubi-utils -+# -+ -+OPTFLAGS := -O2 -g -Wall -+KERNELHDR := ../include -+DESTDIR := /usr/local -+SBINDIR=/usr/sbin -+MANDIR=/usr/share/man -+INCLUDEDIR=/usr/include -+ -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -I./inc -I./src -I$(KERNELHDR) $(OPTFLAGS) -Werror \ -+ -Wwrite-strings -W -std=gnu99 -DPACKAGE_VERSION=\"1.0\" -+ -+PERLPROGS = mkpfi ubicrc32.pl -+ -+NTARGETS = ubiattach ubicrc32 ubidetach ubimkvol ubinfo ubinize \ -+ ubirmvol ubiupdatevol -+TARGETS = pfiflash pddcustomize ubimirror bin2nand nand2bin ubigen \ -+ mkbootenv unubi pfi2bin $(NTARGETS) -+ -+vpath %.c ./src -+ -+%: %.o -+ $(CC) $(LDFLAGS) -g -o $@ $^ -+ -+%.o: %.c -+ $(CC) $(CFLAGS) -g -c -o $@ $< -g -Wp,-MD,.$(shell basename $<).dep -+ -+all: $(TARGETS) -+ make -C new-utils -+ -+IGNORE=${wildcard .*.c.dep} -+-include ${IGNORE} -+ -+$(NTARGETS): -+ make -C new-utils $@ -+ mv new-utils/$@ $@ -+ -+clean: -+ rm -rf *.o $(TARGETS) .*.c.dep -+ make -C new-utils clean -+ -+pddcustomize: pddcustomize.o error.o libubimirror.o bootenv.o hashmap.o \ -+ libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+pfiflash: pfiflash.o libpfiflash.o list.o reader.o error.o libubimirror.o \ -+ bootenv.o hashmap.o pfi.o libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+ubimirror: ubimirror.o error.o libubimirror.o bootenv.o hashmap.o \ -+ libubi.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+nand2bin: nand2bin.o nandecc.o nandcorr.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+bin2nand: bin2nand.o error.o nandecc.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+ubigen: ubigen.o libubigen.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+mkbootenv: mkbootenv.o bootenv.o hashmap.o error.o crc32.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+unubi: unubi.o crc32.o unubi_analyze.o eb_chain.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+pfi2bin: pfi2bin.o peb.o error.o list.o crc32.o libubigen.o bootenv.o \ -+ hashmap.o reader.o pfi.o -+ $(CC) $(LDFLAGS) -o $@ $^ -+ -+install: ${TARGETS} -+ mkdir -p ${DESTDIR}/${SBINDIR} -+ install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/ -+ (cd perl && install ${PERLPROGS} ${DESTDIR}/${SBINDIR}/) -+ -+uninstall: -+ for file in ${TARGETS} ${PERLPROGS}; do \ -+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ -+ done -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/README linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/README ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,236 @@ -+README -+====== -+ -+The programs and libraries in this directory provide a tool-chain to -+generate binary data for embedded systems which can be flashed either -+by a hardware flash programmer, e.g. JTAG debugger, or on the target -+system directly using pfiflash, or ubimkvol, ubirmvol, ubiwritevol. -+ -+The latter is the case when there is already Linux running which has -+build in UBI support. -+ -+Authors: Oliver Lohmann -+ Frank Haverkamp -+ Andreas Arnez -+ -+mkpfi - tool for flash content generation in PFI -+ format -+pfi2bin - conversion tool to transfer a PFI file into a -+ binary image -+pfiflash - tool to update the embedded systems flash using -+ pfi files created by mkpfi -+libbootenv - library for boot-parameter processing -+libpfi - library for partial flash image (PFI) creation -+ and handling -+ubigen - tool to create binary UBI images e.g. for a -+ jtag flashing tool -+nandimg - tool to add OOB data to binary images intended -+ for NAND flash systems -+ubilib - UBI library -+ -+!!! NOTICE !!! -+If you execute ./configure in the top_level directory the helper Makefile -+gets overwritten. Thats actually no problem, but be aware of that. -+ -+1. Build Process -+ -+1.1 Build, install and forget -+ o Build all and everything -+ $make all (takes a while, builds ppc and x86 binaries/libs) -+ o Installation: -+ $make install -+ o Uninstallation: -+ $make uninstall -+ -+ o x86 only would be: -+ $make x86 && make install_x86 -+ -+1.2 Usage for a developer -+ -+ 1.2.1 The build process in detail -+ -+ o If you've checked out the sources from the CVS repository you'll find a -+ directory setup like this: -+ -+ flashutils/ -+ -rw-r--r-- 1 olli olli 1.3K Mar 14 11:53 Makefile -+ -rw-r--r-- 1 olli olli 1.9K Mar 14 10:50 Makefile.am -+ -rwxr-xr-x 1 olli olli 265 Mar 9 00:47 bootstrap -+ -rw-r--r-- 1 olli olli 1.1K Mar 9 16:55 configure.ac -+ drwxr-xr-x 2 olli olli 4.0K Mar 9 00:28 doc -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 inc -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 11:56 lib -+ drwxr-xr-x 17 olli olli 4.0K Mar 13 16:50 src -+ -+ o To generate the initial build templates you have to call the bootstrap -+ script: -+ $ ./bootstrap -+ o Create a directory for the target platform -+ $ mkdir build_x86 -+ o Descend into the directory and call the top-level configure script -+ with the desired options. -+ $ cd build_x86 -+ $ ../configure --prefix=/usr/local [...] -+ o Now you'll find a directory structure like this: -+ -+ flashutils/build_x86/ -+ -rw-r--r-- 1 olli olli 47K Mar 14 13:33 Makefile -+ -rw-r--r-- 1 olli olli 33K Mar 14 13:33 config.log -+ -rwxr-xr-x 1 olli olli 38K Mar 14 13:33 config.status -+ drwxr-xr-x 2 olli olli 4.0K Mar 14 13:33 inc -+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:33 lib -+ -rwxr-xr-x 1 olli olli 202K Mar 14 13:33 libtool -+ -+ o The config.guess script can be used to update the Makefiles in the -+ target directory after a change of the top-level template files -+ (i.e. the Makefile.in files). -+ $ ./config.guess -+ o To compile everything for this platform just invoke make in -+ flashutils/build_x86: -+ $ make -+ or from toplevel: -+ $ make -C ./build_x86 -+ o The build process creates a new directory "bin": -+ flashutils/build_x86/ -+ [...] -+ drwxr-xr-x 3 olli olli 4.0K Mar 14 13:41 bin -+ [...] -+ -+ This directory contains all binary files which will be installed -+ by make install, e.g.: -+ -+ flashutils/build_x86/bin/ -+ -rwxr-xr-x 1 olli olli 7.2K Mar 14 13:41 bin2nand -+ -rwxr-xr-x 1 olli olli 15K Mar 14 13:41 mkbootenv -+ -rwxr-xr-x 1 olli olli 16K Mar 14 13:41 pddcustomize -+ -rwxr-xr-x 1 olli olli 36K Mar 14 13:41 pfi2bin -+ -rwxr-xr-x 1 olli olli 6.8K Mar 14 13:41 pfiflash -+ -rwxr-xr-x 1 olli olli 5.0K Mar 14 13:41 ubicrc32 -+ -rwxr-xr-x 1 olli olli 13K Mar 14 13:41 ubigen -+ -rwxr-xr-x 1 olli olli 6.3K Mar 14 13:41 ubimirror -+ -+ -+ 1.2.2 Modifying and Adding Sources -+ -+ o There is a dedicated directory which contains all source code -+ of the flashutils package, e.g.: -+ -+ flashutils/src/ -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 libbootenv -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 11:42 liberror -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:48 mkpfi -+ drwxr-xr-x 2 olli olli 4.0K Mar 13 16:12 pddcustomize -+ -+ -+ -+ The prefix "lib" is used to mark directories as part of a convenience -+ library. Binaries have no special prefix. -+ -+ o How to add sources? -+ -+ Just create a new directory at flashutils/src/, e.g.: -+ -+ For a binary: -+ $ mkdir rider -+ $ cd rider -+ $ vi rider.c -+ /* do sth with that file... */ -+ -+ For a convenience library (as well as for "normal libs") -+ $ mkdir libworld -+ $ cd libworld -+ $ vi world.c -+ /* do sth with that file... */ -+ -+ o How to register sources in the build process (for binaries)? -+ -+ You have to register your sources at the top-level automake Makefile: -+ -+ In directory flashutils/ -+ $ vi Makefile.am -+ -+ Binaries have to be registered at "bin_PROGRAMS", e.g.: -+ bin_PROGRAMS = bin/pddcustomize \ -+ bin/rider -+ -+ Add the rule how the binary is assembled, e.g.: -+ bin_pddcustomize_SOURCES = \ -+ $(top_srcdir)/src/pddcustomize/pddcustomize.c -+ bin_pddcustomize_LDADD = \ -+ $(top_builddir)/lib/libbootenv.la \ -+ $(top_builddir)/lib/liberror.la -+ -+ bin_rider_SOURCES = \ -+ $(top_srcdir)/src/rider/rider.c -+ -+ This example reflects a simple build process for "rider". "rider" -+ is built without any other dependencies or convenience libraries. -+ The example for pddcustomize is a bit more complicated. -+ "_LDADD" adds some convenience libraris into the link process of -+ "pddcustomize". Imagine, that your "rider" has common code -+ with "dragon_bin" which is held in a library called "libworld". -+ The build rules would like like the following: -+ -+ bin_rider_SOURCES = \ -+ $(top_srcdir)/src/rider/rider.c -+ bin_rider_LDADD = \ -+ $(top_builddir)/lib/libworld.la -+ -+ bin_dragon_SOURCES = \ -+ $(top_srcdir)/src/dragon_bin/dragon_bin.c -+ bin_dragon_LDADD = \ -+ $(top_builddir)/lib/libworld.la -+ -+ Don't forget to add "dragon" to "bin_PROGRAMS"! -+ Don't forget to set the build rule for the "libworld" itself! -+ This is documented in the next section. -+ -+ -+ o How to register sources in the build process (for libraries)? -+ -+ Until now we didn't care about the build process of "libworld". -+ Libraries are handled special in this build process because -+ they are handled as "modules", i.e. they are able to be built -+ without building the binaries in the same step. Additionally, -+ it is possible to assemble complex libraries out of simple ones. -+ That especially makes sense if you want to export (install) a -+ library on a system which uses some common code and makes -+ some adoptions for usability and presents a comfortable interface to -+ the user (see libpfiflash in the sources for an example). -+ -+ o Registering "libworld" as convenience library. -+ -+ Instead of editing the "Makefile.am" in "flashtools/", we have to -+ edit now the "Makefile.am" in "flashtools/lib/": -+ -+ noinst_LTLIBRARIES = libworld.la -+ -+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c -+ -+ o Registering "libworld" as library which gets installed. -+ -+ lib_LTLIBRARIES = libworld.la -+ libworld_la_SOURCES = $(top_srcdir)/src/libworld/world.c -+ libworld_la_LDFLAGS = -no-undefined -version-info 0:0:0 -+ -+ o Header files -+ -+ All header files are stored at "flashutils/inc", regardless -+ if convenience library or not. -+ -+ If you want to export headers you have to specify this in the Makefile.am -+ located at "flashutils/inc", e.g. (this should not be done -+ for convenience libraries): -+ -+ nobase_include_HEADERS = world.h -+ -+ -+ -+Appendix -+ -+A.1. FAQ -+ -+ Q How to call configure to setup a cross-platform build? -+ A $ ./configure --build=i686-pc-linux-gnu --host=ppc-linux \ -+ --prefix=/opt/.../ppcnf/crossroot/ \ -+ --exec-prefix=/opt/..../ppcnf/crossroot/usr -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/UBI.TXT 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,108 @@ -+UBI - Unsorted Block Images -+ -+UBI (Latin: "where?") manages multiple logical volumes on a single -+flash device, specifically supporting NAND flash devices. UBI provides -+a flexible partitioning concept which still allows for wear-levelling -+across the whole flash device. -+ -+In a sense, UBI may be compared to the Logical Volume Manager -+(LVM). Whereas LVM maps logical sector numbers to physical HDD sector -+numbers, UBI maps logical eraseblocks to physical eraseblocks. -+ -+More information may be found in the UBI design documentation: -+ubidesign.pdf. Which can be found here: -+http://www.linux-mtd.infradead.org/doc/ubi.html -+ -+Partitioning/Re-partitioning -+ -+ An UBI volume occupies a certain number of erase blocks. This is -+ limited by a configured maximum volume size, which could also be -+ viewed as the partition size. Each individual UBI volume's size can -+ be changed independently of the other UBI volumes, provided that the -+ sum of all volume sizes doesn't exceed a certain limit. -+ -+ UBI supports dynamic volumes and static volumes. Static volumes are -+ read-only and their contents are protected by CRC check sums. -+ -+Bad eraseblocks handling -+ -+ UBI transparently handles bad eraseblocks. When a physical -+ eraseblock becomes bad, it is substituted by a good physical -+ eraseblock, and the user does not even notice this. -+ -+Scrubbing -+ -+ On a NAND flash bit flips can occur on any write operation, -+ sometimes also on read. If bit flips persist on the device, at first -+ they can still be corrected by ECC, but once they accumulate, -+ correction will become impossible. Thus it is best to actively scrub -+ the affected eraseblock, by first copying it to a free eraseblock -+ and then erasing the original. The UBI layer performs this type of -+ scrubbing under the covers, transparently to the UBI volume users. -+ -+Erase Counts -+ -+ UBI maintains an erase count header per eraseblock. This frees -+ higher-level layers (like file systems) from doing this and allows -+ for centralized erase count management instead. The erase counts are -+ used by the wear-levelling algorithm in the UBI layer. The algorithm -+ itself is exchangeable. -+ -+Booting from NAND -+ -+ For booting directly from NAND flash the hardware must at least be -+ capable of fetching and executing a small portion of the NAND -+ flash. Some NAND flash controllers have this kind of support. They -+ usually limit the window to a few kilobytes in erase block 0. This -+ "initial program loader" (IPL) must then contain sufficient logic to -+ load and execute the next boot phase. -+ -+ Due to bad eraseblocks, which may be randomly scattered over the -+ flash device, it is problematic to store the "secondary program -+ loader" (SPL) statically. Also, due to bit-flips it may become -+ corrupted over time. UBI allows to solve this problem gracefully by -+ storing the SPL in a small static UBI volume. -+ -+UBI volumes vs. static partitions -+ -+ UBI volumes are still very similar to static MTD partitions: -+ -+ * both consist of eraseblocks (logical eraseblocks in case of UBI -+ volumes, and physical eraseblocks in case of static partitions; -+ * both support three basic operations - read, write, erase. -+ -+ But UBI volumes have the following advantages over traditional -+ static MTD partitions: -+ -+ * there are no eraseblock wear-leveling constraints in case of UBI -+ volumes, so the user should not care about this; -+ * there are no bit-flips and bad eraseblocks in case of UBI volumes. -+ -+ So, UBI volumes may be considered as flash devices with relaxed -+ restrictions. -+ -+Where can it be found? -+ -+ Documentation, kernel code and applications can be found in the MTD -+ gits. -+ -+What are the applications for? -+ -+ The applications help to create binary flash images for two -+ purposes: pfi files (partial flash images) for in-system update of -+ UBI volumes, and plain binary images, with or without OOB data in -+ case of NAND, for a manufacturing step. Furthermore some tools -+ are/and will be created that allow flash content analysis after a -+ system has crashed. -+ -+Who did UBI? -+ -+ The original ideas, where UBI is based on, were developed by Andreas -+ Arnez, Frank Haverkamp and Thomas Gleixner. Josh W. Boyer and -+ some others were involved too. The implementation of the kernel -+ layer was done by Artem B. Bityutskiy. The user-space applications -+ and tools were written by Oliver Lohmann with contributions from -+ Frank Haverkamp, Andreas Arnez, and Artem. Joern Engel contributed a -+ patch which modifies JFFS2 so that it can be run on a UBI -+ volume. Thomas Gleixner did modifications to the NAND layer and also -+ some to JFFS2 to make it work. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/doc/unubi.roff 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,123 @@ -+.TH UNUBI 1 "NOVEMBER 2006" FSP "FSP Flashutils" -+.SH NAME -+unubi \- extract volumes/eraseblocks from a raw\-UBI image -+.SH SYNOPSIS -+\fBunubi [\-aevEV] [\-d \fIout\-dir\fB] [\-r \fIvolume\-id\fB] -+[\-b \fIblock\-size\fB] \fIimage\-file -+.SH DESCRIPTION -+.PP -+\fBunubi\fR reads an image file containing blocks of UBI headers and data -+(such as produced from \fBnand2bin\fR) and rebuilds the volumes within. -+The default operation (when no flags are given) is to rebuild all valid -+volumes found in the image. \fBunubi\fR can also read straight from the -+onboard MTD device (ex. /dev/mtdblock/NAND). -+.SH OPTIONS -+.IP "\-a, \-\-analyze" -+When flagged, analysis files are generated within the output directory. These -+may include tables and or graphs detailing statistics gathered from the -+eraseblock data. Files are prefixed `analysis_'. -+ -+See \fBANALYSIS\fR. -+.IP "\-b, \-\-blocksize \fIblock\-size\fR" -+Specify in bytes the \fIimage\-file\fR eraseblock size. Sizes may be -+postfixed with `KiB' or `MiB' to indicate mebibytes or kibibytes -+respectively. Default is 128KiB. -+.IP "\-d, \-\-dir \fIoutput\-dir\fR" -+Specify the output directory. If no directory is specified, the default -+is `unubi_\fIimage\-file\fR' within the curent working directory. If the -+attempt to create the output directory fails, -+.B unubi -+will try to create it in /tmp before aborting. -+.IP "\-e, \-\-eb\-split" -+When flagged, images are created for each eraseblock in \fIimage\-file\fR -+regardless of its validity. Each image is the complete eraseblock, including -+headers and any space to the end of the eraseblock after where the data may -+end. -+ -+Invalid images are named `ebEEEE', where EEEE is the physical index of the -+eraseblock in the image. Valid images are named `ebEEEE_VVV_NNN_RRR' where -+VVV is the known volume ID, NNN is the logical number and RRR is the version -+of the eraseblock data. Note that the version number is in hexadecimal. -+ -+Invalid images may also contain this postfix, if the data in the header -+could be valid (ie. the header contains a resonable volume ID, but the -+header and/or data CRCs are not valid). If this is the case, images are named -+`ebEEEE_VVV_NNN_RRR.reason', so as to distinguish known values from -+non\-definite ones. -+ -+See \fBREASON SUFFIXES\fR. -+.IP "\-r, \-\-rebuild \fIvolume\-id\fR" -+Specify a volume to rebuild. Can be used successively to specify -+several volumes to be rebuilt. -+ -+Images are named `volumeVVV' where VVV is the volume ID. For each missing -+eraseblock, an error message will be printed. -+.IP "\-v, \-\-vol\-split" -+When flagged, images are created for each valid eraseblock in -+\fIimage\-file\fR. Since a vaild eraseblock will have a defined data start and -+data length, only this range will make up the image. -+ -+Images are named `volVVV_NNN_RRR_EEEE', where, for the data in the eraseblock, -+VVV is the volume ID, NNN is the logical number, RRR is the version and EEEE -+is the phyisical index of the eraseblock in the image. -+.IP "\-V, \-\-vol\-split!" -+Same as above, only all images are the complete eraseblock (including headers, -+and raw data, even past the point where the data is supposed to end). -+Overrides \-v when both \-v and \-V are flagged. -+.SH ANALYSIS -+The following files will be generated during the analysis: -+.IP "analysis_ec_hdr.data" -+A space delimited table with these two columns for each eraseblock: the -+eraseblock's index or physical position in the image, and the eraseblock's -+erase count. The third column contains the erase count data sorted. -+.IP "analysis_vid_hdr.data" -+A space delimited table with these four colums for each eraseblock: the -+volume ID, the volume logical number, the leb version, and the data size. -+In addition there are a normalized column representing the volume ID and -+volume logical number, a normalized column representing the leb version, and -+a normalized column representing the data_size. These normalized columns are -+used to better draw the the gnuplot image. -+.IP "analysis_ec_hdr.plot" -+A gnuplot script for quickly viewing a sample output from the respective .data -+file. -+.IP "analysis_vid_hdr.plot" -+A gnuplot script for quickly viewing a sample output from the respective .data -+file. -+.SH REASONS SUFFIXES -+When \-\-eb\-split produces possibly invalid, though usable, eraseblocks, the -+known reason suffixes are: -+.IP ".ec_magic" -+The erase counter header did not contain a valid magic field. -+.IP ".ec_hdr_crc" -+The erase counter header did not contain a vaild header CRC field. -+.IP ".vid_magic" -+The volume ID header did not contain a valid magic field. -+.IP ".vid_hdr_crc" -+The volume ID header did not contain a valid header CRC field. -+.IP ".data_crc" -+The volume ID header did not contain a valid data CRC field. -+.SH EXAMPLES -+To extract and rebuild all valid volumes from demo.img (note the output -+directory will be /home/user/unubi_demo.img): -+.sp 1 -+.RS -+.B /home/user# unubi demo.img -+.sp 1 -+.RE -+To analyze demo.img as well as extract and rebuild volume 7: -+.sp 1 -+.RS -+.B /home/user# unubi \-a \-r 7 demo.img -+.sp 1 -+.RE -+To split demo.img into raw images for each eraseblock into the folder -+/var/eraseblocks: -+.sp 1 -+.RS -+.B /home/user# unubi \-e \-d /var/eraseblocks demo.img -+.SH AUTHORS -+Frank Haverkamp -+.sp 0 -+Drake Dowsett -+.SH CONTACT -+Andreas Arnez -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/inc/libubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,268 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_H__ -+#define __LIBUBI_H__ -+ -+#include -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* UBI version libubi is made for */ -+#define LIBUBI_UBI_VERSION 1 -+ -+/* UBI library descriptor */ -+typedef void * libubi_t; -+ -+/** -+ * struct ubi_mkvol_request - volume creation request. -+ * */ -+struct ubi_mkvol_request -+{ -+ int vol_id; -+ int alignment; -+ long long bytes; -+ int vol_type; -+ const char *name; -+}; -+ -+/** -+ * struct ubi_info - general UBI information. -+ * -+ * @dev_count count of UBI devices in system -+ * @lowest_dev_num lowest UBI device number -+ * @highest_dev_num highest UBI device number -+ * @version UBI version -+ */ -+struct ubi_info -+{ -+ int dev_count; -+ int lowest_dev_num; -+ int highest_dev_num; -+ int version; -+}; -+ -+/** -+ * struct ubi_dev_info - UBI device information. -+ * -+ * @vol_count count of volumes on this UBI device -+ * @lowest_vol_num lowest volume number -+ * @highest_vol_num highest volume number -+ * @total_ebs total number of eraseblocks on this UBI device -+ * @avail_ebs how many eraseblocks are not used and available for new -+ * volumes -+ * @total_bytes @total_ebs * @eb_size -+ * @avail_bytes @avail_ebs * @eb_size -+ * @bad_count count of bad eraseblocks -+ * @eb_size size of UBI eraseblock -+ * @max_ec current highest erase counter value -+ * @bad_rsvd how many physical eraseblocks of the underlying flash -+ * device are reserved for bad eraseblocks handling -+ * @max_vol_count maximum count of volumes on this UBI device -+ * @min_io_size minimum input/output size of the UBI device -+ */ -+struct ubi_dev_info -+{ -+ int dev_num; -+ int vol_count; -+ int lowest_vol_num; -+ int highest_vol_num; -+ int total_ebs; -+ int avail_ebs; -+ long long total_bytes; -+ long long avail_bytes; -+ int bad_count; -+ int eb_size; -+ long long max_ec; -+ int bad_rsvd; -+ int max_vol_count; -+ int min_io_size; -+}; -+ -+/** -+ * struct ubi_vol_info - UBI volume information. -+ * -+ * @dev_num UBI device number the volume resides on -+ * @vol_id ID of this volume -+ * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @alignment alignemnt of this volume -+ * @data_bytes how many data bytes are stored on this volume (equivalent to -+ * @rsvd_bytes for dynamic volumes) -+ * @rsvd_bytes how many bytes are reserved for this volume -+ * @rsvd_ebs how many eraseblocks are reserved for this volume -+ * @eb_size logical eraseblock size of this volume (may be less then -+ * device's logical eraseblock size due to alignment) -+ * @corrupted the volume is corrupted if this flag is not zero -+ * @name volume name (null-terminated) -+ */ -+struct ubi_vol_info -+{ -+ int dev_num; -+ int vol_id; -+ int type; -+ int alignment; -+ long long data_bytes; -+ long long rsvd_bytes; -+ int rsvd_ebs; -+ int eb_size; -+ int corrupted; -+ char name[UBI_VOL_NAME_MAX + 1]; -+}; -+ -+/** -+ * libubi_open - open UBI library. -+ * -+ * This function initializes and opens the UBI library and returns UBI library -+ * descriptor in case of success and %NULL in case of failure. -+ */ -+libubi_t libubi_open(void); -+ -+/** -+ * libubi_close - close UBI library -+ * -+ * @desc UBI library descriptor -+ */ -+void libubi_close(libubi_t desc); -+ -+/** -+ * ubi_get_info - get general UBI information. -+ * -+ * @info pointer to the &struct ubi_info object to fill -+ * @desc UBI library descriptor -+ * -+ * This function fills the passed @info object with general UBI information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_info(libubi_t desc, struct ubi_info *info); -+ -+/** -+ * ubi_mkvol - create an UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to create a volume at -+ * @req UBI volume creation request (defined at ) -+ * -+ * This function creates a UBI volume as described at @req and returns %0 in -+ * case of success and %-1 in case of failure. The assigned volume ID is -+ * returned in @req->vol_id. -+ */ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req); -+ -+/** -+ * ubi_rmvol - remove a UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to remove a volume from -+ * @vol_id ID of the volume to remove -+ * -+ * This function removes volume @vol_id from UBI device @node and returns %0 in -+ * case of success and %-1 in case of failure. -+ */ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id); -+ -+/** -+ * ubi_rsvol - re-size UBI volume. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device owning the volume which should be -+ * re-sized -+ * @vol_id volume ID to re-size -+ * @bytes new volume size in bytes -+ * -+ * This function returns %0 in case of success and %-1 in case of error. -+ */ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes); -+ -+/** -+ * ubi_get_dev_info - get UBI device information. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI character device to fetch information about -+ * @info pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function fills the passed @info object with UBI device information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_dev_info(libubi_t desc, const char *node, -+ struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_dev_info1 - get UBI device information. -+ * -+ * @desc UBI library descriptor -+ * @dev_num UBI device number to fetch information about -+ * @info pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI -+ * device number, not UBI character device. -+ */ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_vol_info - get UBI volume information. -+ * -+ * @desc UBI library descriptor -+ * @node name of the UBI volume character device to fetch information about -+ * @info pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function fills the passed @info object with UBI volume information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_vol_info(libubi_t desc, const char *node, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_get_vol_info1 - get UBI volume information. -+ * -+ * @desc UBI library descriptor -+ * @dev_num UBI device number -+ * @vol_id ID of the UBI volume to fetch information about -+ * @info pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI -+ * volume number, not UBI volume character device. -+ */ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_update_start - start UBI volume update. -+ * -+ * @desc UBI library descriptor -+ * @fd volume character devie file descriptor -+ * @bytes how many bytes will be written to the volume -+ * -+ * This function initiates UBI volume update and returns %0 in case of success -+ * and %-1 in case of error. -+ */ -+int ubi_update_start(libubi_t desc, int fd, long long bytes); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/lib/Makefile.am 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,58 @@ -+AUTOMAKE_OPTIONS = foreign -+INCLUDES=-I$(top_srcdir)/inc -I$(top_srcdir)/../../kernel/include -+ -+# ----------------------------------------------------------------------------- -+# all export libs which shall be generated -+lib_LTLIBRARIES = libubi.la \ -+ libpfiflash.la -+ -+# ----------------------------------------------------------------------------- -+# all convinence libs which shall be generated -+noinst_LTLIBRARIES = libcrc32.la \ -+ libubigen.la \ -+ liberror.la \ -+ liblist.la \ -+ libbootenv.la \ -+ libpfi.la \ -+ libpeb.la \ -+ libreader.la \ -+ libubimirror.la -+ -+# ----------------------------------------------------------------------------- -+# exported libs -+libpfiflash_la_SOURCES = $(top_srcdir)/src/libpfiflash/pfiflash.c -+libpfiflash_la_LDFLAGS = -no-undefined -version-info 1:0:0 -+libpfiflash_la_LIBADD = libreader.la \ -+ libubimirror.la \ -+ libubi.la -+ -+libubi_la_SOURCES = $(top_srcdir)/src/libubi/libubi.c \ -+ $(top_srcdir)/src/libubi/libubi_sysfs.c -+libubi_la_LDFLAGS = -no-undefined -version-info 1:0:0 -+ -+# ----------------------------------------------------------------------------- -+# complex convinence libs, beware for double includes. -+libreader_la_SOURCES = $(top_srcdir)/src/libreader/reader.c -+libreader_la_LIBADD = libpfi.la \ -+ liblist.la \ -+ libpeb.la \ -+ libbootenv.la -+ -+libubigen_la_SOURCES = $(top_srcdir)/src/libubigen/ubigen.c -+libubigen_la_LIBADD = libcrc32.la -+ -+libbootenv_la_SOURCES = $(top_srcdir)/src/libbootenv/bootenv.c \ -+ $(top_srcdir)/src/libbootenv/hashmap.c -+libbootenv_la_LIBADD = libcrc32.la -+ -+libubimirror_la_SOURCES = $(top_srcdir)/src/libubimirror/ubimirror.c -+libubimirror_la_LIBADD = libubi.la -+ -+ -+# ----------------------------------------------------------------------------- -+# simple convinence libs -+libcrc32_la_SOURCES = $(top_srcdir)/src/libcrc32/crc32.c -+liberror_la_SOURCES = $(top_srcdir)/src/liberror/error.c -+liblist_la_SOURCES = $(top_srcdir)/src/liblist/list.c -+libpeb_la_SOURCES = $(top_srcdir)/src/libpeb/peb.c -+libpfi_la_SOURCES = $(top_srcdir)/src/libpfi/pfi.c -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/LICENSE.libiniparser 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+Copyright (c) 2000-2007 by Nicolas Devillard. -+MIT License -+ -+Permission is hereby granted, free of charge, to any person obtaining a -+copy of this software and associated documentation files (the "Software"), -+to deal in the Software without restriction, including without limitation -+the rights to use, copy, modify, merge, publish, distribute, sublicense, -+and/or sell copies of the Software, and to permit persons to whom the -+Software is furnished to do so, subject to the following conditions: -+ -+The above copyright notice and this permission notice shall be included in -+all copies or substantial portions of the Software. -+ -+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+DEALINGS IN THE SOFTWARE. -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,81 @@ -+# -+# Makefile for ubi-utils -+# -+ -+OPTFLAGS := -O2 -Wall -+KERNELHDR := ../../include -+#DESTDIR := /usr/local -+DESTDIR := /nfsroot/user/yrtan -+SBINDIR=/usr/sbin -+MANDIR=/usr/man -+INCLUDEDIR=/usr/include -+CROSS=mipsel-linux- -+CC := $(CROSS)gcc -+CFLAGS := -Iinclude -Isrc -I$(KERNELHDR) $(OPTFLAGS) -Werror -Wall -+ -+LIBS = libubi libmtd libubigen libiniparser libscan -+UTILS = ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ -+ ubidetach ubiformat ubidumpvol ubicrcvol \ -+ ubinize ubicrcsf ubirefimg -+vpath %.c src -+ -+all: $(UTILS) -+ -+# The below cancels existing implicite rule to make programs from .c files, -+# in order to force make using our rule defined below -+%: %.c -+ -+# The below is the rule to get an .o file from a .c file -+%.o: %.c -+ $(CC) $(CFLAGS) $< -c -o $@ -+ -+# And the below is the rule to get final executable from its .o and common.o -+%: libubi.a %.o common.o -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@ -+ -+ubicrcsf: ubicrcsf.o crc32.o -+ $(CC) $(CFLAGS) -o $@ $^ -+ -+ubicrcvol: ubicrcvol.o common.o crc32.o libubi.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lubi -o $@ -+ -+ubicrc32: ubicrc32.o crc32.o -+ $(CC) $(CFLAGS) -o $@ $^ -+ -+ubinize: ubinize.o common.o crc32.o libiniparser.a libubigen.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -liniparser -lubigen -o $@ -+ -+ubiformat: ubiformat.o common.o crc32.o libmtd.a libscan.a libubi.a libubigen.a -+ $(CC) $(CFLAGS) $(filter %.o, $^) -L. -lmtd -lscan -lubi -lubigen -o $@ -+ -+libubi.a: libubi.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libmtd.a: libmtd.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libubigen.a: libubigen.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libiniparser.a: libiniparser.o dictionary.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+libscan.a: libscan.o crc32.o -+ $(AR) crv $@ $^ -+ ranlib $@ -+ -+clean: -+ rm -rf *.o $(addsuffix .a, $(LIBS)) $(UTILS) .*.c.dep -+ -+install: ${UTILS} -+ mkdir -p ${DESTDIR}/${SBINDIR} -+ install -m0755 ${UTILS} ${DESTDIR}/${SBINDIR}/ -+ -+uninstall: -+ for file in ${UTILS}; do \ -+ $(RM) ${DESTDIR}/${SBINDIR}/$$file; \ -+ done -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/README linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/README ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,55 @@ -+This directory contains a new UBI toolchain which is intended to replace -+the old one. All utilities support "-h" option which prints sufficient -+usage information. See the MTD web-site for more information. -+ -+Motivation for new tool-chain. -+ -+I was doing very active UBI development and had to add new features like -+dynamic UBI devices and auto-resize feature. Because of the mess in the -+the old tools I basically could not figure out how to upgrade them. In -+my humble oppinion, they are unmaintainable. The original authors did not -+show enthusiasm when I mailed them and asked to clean-up the tool-chain -+[1]. Thus, I re-implemented them, but I did borrow things from the old -+tool-chain and preserved copyrights and author names. -+ -+I really did try to clean-up the old tool chain, but gave up (see git -+history for confirmation). So, -+ -+1. I found the source codes very difficult to navigate and read, especially -+ those related to pdd, pfi, and bootenv. Try to do this yourself - they -+ are a puzzle. -+2. I foud the concept of PFI needlesly complecated - PFI file is nothing -+ else but the initial configuration .ini file + the contents of the -+ UBI volumes packed into one file, but with some changes of the .ini file's -+ format. The PFI file format is not very nice and it is difficult to parse, -+ especially because the PFI headers do not tell you data star and end for -+ each data chunk, and you have to do additional parsing. -+ -+ So basically, you have .ini file + images, then you transfer this to pfi, -+ which does not add any other information. For .ini you have libraries -+ which may parse them, for pfi - not. Then you have to parse this pfi -+ which adds unneeded and complex code. This all needs lists, hashmaps, -+ and so on - for no reason. -+3. I found the command line options of the utilities to be inconsistent. -+ This is OK when you script your single task and do not touch it anymore. -+ But when you have to use the utilities while developing and testing, -+ It is difficult to remember their inconsistent options. -+4. I found it wrong to add development options to user utilities like -+ "broken update". End users should not see them. -+5. I did not find any consistent style and convention inside which -+ irritated me. -+6. I found it weird to introduce needless "logging infrastructure" instead -+ of just re-directing stdout and stderr to another file. -+7. I found the tool to be rather IBM-setup oriented. For example, the VID -+ header position was hard-coded. Some utilities were just weird, like -+ mkbootenv, which changed some ethernet addresses mentioned in a -+ configuration file. -+8. Finally, it was very difficult to realize what is pfi and pdd, what for, -+ why I need this transiant pfi file when I just want to create an UBI -+ image. There was zero documentation. -+ -+And so on. -+ -+Feb 19, 2008, Artem Bityutskiy. -+ -+[1]. http://lists.infradead.org/pipermail/linux-mtd/2007-December/020134.html -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libiniparser.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,280 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file iniparser.h -+ @author N. Devillard -+ @date Sep 2007 -+ @version 3.0 -+ @brief Parser for ini files. -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: libiniparser.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+*/ -+ -+#ifndef _INIPARSER_H_ -+#define _INIPARSER_H_ -+ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+ -+#include -+#include -+#include -+ -+/* -+ * The following #include is necessary on many Unixes but not Linux. -+ * It is not needed for Windows platforms. -+ * Uncomment it if needed. -+ */ -+/* #include */ -+ -+#include "dictionary.h" -+ -+/*--------------------------------------------------------------------------- -+ Macros -+ ---------------------------------------------------------------------------*/ -+/** For backwards compatibility only */ -+#define iniparser_getstr(d, k) iniparser_getstring(d, k, NULL) -+#define iniparser_setstr iniparser_setstring -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get number of sections in a dictionary -+ @param d Dictionary to examine -+ @return int Number of sections found in dictionary -+ -+ This function returns the number of sections found in a dictionary. -+ The test to recognize sections is done on the string stored in the -+ dictionary: a section name is given as "section" whereas a key is -+ stored as "section:key", thus the test looks for entries that do not -+ contain a colon. -+ -+ This clearly fails in the case a section name contains a colon, but -+ this should simply be avoided. -+ -+ This function returns -1 in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+int iniparser_getnsec(dictionary * d); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get name for section n in a dictionary. -+ @param d Dictionary to examine -+ @param n Section number (from 0 to nsec-1). -+ @return Pointer to char string -+ -+ This function locates the n-th section in a dictionary and returns -+ its name as a pointer to a string statically allocated inside the -+ dictionary. Do not free or modify the returned string! -+ -+ This function returns NULL in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+char * iniparser_getsecname(dictionary * d, int n); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Save a dictionary to a loadable ini file -+ @param d Dictionary to dump -+ @param f Opened file pointer to dump to -+ @return void -+ -+ This function dumps a given dictionary into a loadable ini file. -+ It is Ok to specify @c stderr or @c stdout as output files. -+ */ -+/*--------------------------------------------------------------------------*/ -+ -+void iniparser_dump_ini(dictionary * d, FILE * f); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump. -+ @param f Opened file pointer to dump to. -+ @return void -+ -+ This function prints out the contents of a dictionary, one element by -+ line, onto the provided file pointer. It is OK to specify @c stderr -+ or @c stdout as output files. This function is meant for debugging -+ purposes mostly. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump(dictionary * d, FILE * f); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param def Default value to return if key not found. -+ @return pointer to statically allocated character string -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the pointer passed as 'def' is returned. -+ The returned char pointer is pointing to a string allocated in -+ the dictionary, do not free or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getstring(dictionary * d, const char * key, char * def); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to an int -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ Supported values for integers include the usual C notation -+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x) -+ are supported. Examples: -+ -+ - "42" -> 42 -+ - "042" -> 34 (octal -> decimal) -+ - "0x42" -> 66 (hexa -> decimal) -+ -+ Warning: the conversion may overflow in various ways. Conversion is -+ totally outsourced to strtol(), see the associated man page for overflow -+ handling. -+ -+ Credits: Thanks to A. Becker for suggesting strtol() -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getint(dictionary * d, const char * key, int notfound); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a double -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return double -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ */ -+/*--------------------------------------------------------------------------*/ -+double iniparser_getdouble(dictionary * d, char * key, double notfound); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a boolean -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ A true boolean is found if one of the following is matched: -+ -+ - A string starting with 'y' -+ - A string starting with 'Y' -+ - A string starting with 't' -+ - A string starting with 'T' -+ - A string starting with '1' -+ -+ A false boolean is found if one of the following is matched: -+ -+ - A string starting with 'n' -+ - A string starting with 'N' -+ - A string starting with 'f' -+ - A string starting with 'F' -+ - A string starting with '0' -+ -+ The notfound value returned if no boolean is identified, does not -+ necessarily have to be 0 or 1. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getboolean(dictionary * d, const char * key, int notfound); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set an entry in a dictionary. -+ @param ini Dictionary to modify. -+ @param entry Entry to modify (entry name) -+ @param val New value to associate to the entry. -+ @return int 0 if Ok, -1 otherwise. -+ -+ If the given entry can be found in the dictionary, it is modified to -+ contain the provided value. If it cannot be found, -1 is returned. -+ It is Ok to set val to NULL. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_setstring(dictionary * ini, char * entry, char * val); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete an entry in a dictionary -+ @param ini Dictionary to modify -+ @param entry Entry to delete (entry name) -+ @return void -+ -+ If the given entry can be found, it is deleted from the dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_unset(dictionary * ini, char * entry); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Finds out if a given entry exists in a dictionary -+ @param ini Dictionary to search -+ @param entry Name of the entry to look for -+ @return integer 1 if entry exists, 0 otherwise -+ -+ Finds out if a given entry exists in the dictionary. Since sections -+ are stored as keys with NULL associated values, this is the only way -+ of querying for the presence of sections in a dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_find_entry(dictionary * ini, char * entry) ; -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Parse an ini file and return an allocated dictionary object -+ @param ininame Name of the ini file to read. -+ @return Pointer to newly allocated dictionary -+ -+ This is the parser for ini files. This function is called, providing -+ the name of the file to be read. It returns a dictionary object that -+ should not be accessed directly, but through accessor functions -+ instead. -+ -+ The returned dictionary must be freed using iniparser_freedict(). -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * iniparser_load(const char * ininame); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Free all memory associated to an ini dictionary -+ @param d Dictionary to free -+ @return void -+ -+ Free all memory associated to an ini dictionary. -+ It is mandatory to call this function before the dictionary object -+ gets out of the current context. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_freedict(dictionary * d); -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libmtd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,73 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * MTD library. -+ */ -+ -+#ifndef __LIBMTD_H__ -+#define __LIBMTD_H__ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * struct mtd_info - information about an MTD device. -+ * @num: MTD device number -+ * @major: major number of corresponding character device -+ * @minor: minor number of corresponding character device -+ * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h) -+ * @type_str: static R/O flash type string -+ * @size: device size in bytes -+ * @eb_cnt: count of eraseblocks -+ * @eb_size: eraseblock size -+ * @min_io_size: minimum input/output unit size -+ * @subpage_size: sub-page size (not set by 'mtd_get_info()'!!!) -+ * @rdonly: non-zero if the device is read-only -+ * @allows_bb: non-zero if the MTD device may have bad eraseblocks -+ * @fd: descriptor of the opened MTD character device node -+ */ -+struct mtd_info -+{ -+ int num; -+ int major; -+ int minor; -+ int type; -+ const char *type_str; -+ long long size; -+ int eb_cnt; -+ int eb_size; -+ int min_io_size; -+ int subpage_size; -+ unsigned int rdonly:1; -+ unsigned int allows_bb:1; -+ int fd; -+}; -+ -+int mtd_get_info(const char *node, struct mtd_info *mtd); -+int mtd_erase(const struct mtd_info *mtd, int eb); -+int mtd_is_bad(const struct mtd_info *mtd, int eb); -+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len); -+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __LIBMTD_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libscan.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,112 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI scanning library. -+ */ -+ -+#ifndef __LIBSCAN_H__ -+#define __LIBSCAN_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * If an eraseblock does not contain an erase counter, this value is used -+ * instead of the erase counter. -+ */ -+#define NO_EC 0xFFFFFFFF -+ -+/* -+ * If an eraseblock contains a corrupted erase counter, this value is used -+ * instead of the erase counter. -+ */ -+#define CORRUPT_EC 0xFFFFFFFE -+ -+/* -+ * If an eraseblock does not contain an erase counter, one of these values is -+ * used. -+ * -+ * @EB_EMPTY: the eraseblock appeared to be empty -+ * @EB_CORRUPTED: the eraseblock contains corrupted erase counter header -+ * @EB_ALIEN: the eraseblock contains some non-UBI data -+ * @EC_MAX: maximum allowed erase counter value -+ */ -+enum -+{ -+ EB_EMPTY = 0xFFFFFFFF, -+ EB_CORRUPTED = 0xFFFFFFFE, -+ EB_ALIEN = 0xFFFFFFFD, -+ EB_BAD = 0xFFFFFFFC, -+ EC_MAX = UBI_MAX_ERASECOUNTER, -+}; -+ -+/** -+ * struct ubi_scan_info - UBI scanning information. -+ * @ec: erase counters or eraseblock status for all eraseblocks -+ * @mean_ec: mean erase counter -+ * @ok_cnt: count of eraseblock with correct erase counter header -+ * @empty_cnt: count of supposedly eraseblocks -+ * @corrupted_cnt: count of eraseblocks with corrupted erase counter header -+ * @alien_cnt: count of eraseblock containing non-ubi data -+ * @bad_cnt: count of bad eraseblocks -+ * @bad_cnt: count of non-bad eraseblocks -+ * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means -+ * undefined) -+ * @data_offs: data offset from the found EC headers (%-1 means undefined) -+ */ -+struct ubi_scan_info -+{ -+ uint32_t *ec; -+ long long mean_ec; -+ int ok_cnt; -+ int empty_cnt; -+ int corrupted_cnt; -+ int alien_cnt; -+ int bad_cnt; -+ int good_cnt; -+ int vid_hdr_offs; -+ int data_offs; -+}; -+ -+struct mtd_info; -+ -+/** -+ * ubi_scan - scan an MTD device. -+ * @mtd: information about the MTD device to scan -+ * @info: the result of the scanning is returned here -+ * @verbose: verbose mode: %0 - be silent, %1 - output progress information, -+ * 2 - debugging output mode -+ */ -+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose); -+ -+/** -+ * ubi_scan_free - free scanning information. -+ * @si: scanning information to free -+ */ -+void ubi_scan_free(struct ubi_scan_info *si); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __LIBSCAN_H__ */ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,382 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_H__ -+#define __LIBUBI_H__ -+ -+#include -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* UBI version libubi is made for */ -+#define LIBUBI_UBI_VERSION 1 -+ -+/* UBI library descriptor */ -+typedef void * libubi_t; -+ -+/** -+ * struct ubi_attach_request - MTD device attachement request. -+ * @dev_num: number to assigne to the newly created UBI device -+ * (%UBI_DEV_NUM_AUTO should be used to automatically assign the -+ * number) -+ * @mtd_num: MTD device number to attach -+ * @vid_hdr_offset: VID header offset (%0 means default offset and this is what -+ * most of the users want) -+ */ -+struct ubi_attach_request -+{ -+ int dev_num; -+ int mtd_num; -+ int vid_hdr_offset; -+}; -+ -+/** -+ * struct ubi_mkvol_request - volume creation request. -+ * @vol_id: ID to assign to the new volume (%UBI_VOL_NUM_AUTO should be used to -+ * automatically assign ID) -+ * @alignment: volume alignment -+ * @bytes: volume size in bytes -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @name: volume name -+ */ -+struct ubi_mkvol_request -+{ -+ int vol_id; -+ int alignment; -+ long long bytes; -+ int vol_type; -+ const char *name; -+}; -+ -+/** -+ * struct ubi_info - general UBI information. -+ * @dev_count: count of UBI devices in system -+ * @lowest_dev_num: lowest UBI device number -+ * @highest_dev_num: highest UBI device number -+ * @version: UBI version -+ * @ctrl_major: major number of the UBI control device -+ * @ctrl_minor: minor number of the UBI control device -+ */ -+struct ubi_info -+{ -+ int dev_count; -+ int lowest_dev_num; -+ int highest_dev_num; -+ int version; -+ int ctrl_major; -+ int ctrl_minor; -+}; -+ -+/** -+ * struct ubi_dev_info - UBI device information. -+ * @vol_count: count of volumes on this UBI device -+ * @lowest_vol_num: lowest volume number -+ * @highest_vol_num: highest volume number -+ * @major: major number of corresponding character device -+ * @minor: minor number of corresponding character device -+ * @total_lebs: total number of logical eraseblocks on this UBI device -+ * @avail_lebs: how many logical eraseblocks are not used and available for new -+ * volumes -+ * @total_bytes: @total_lebs * @leb_size -+ * @avail_bytes: @avail_lebs * @leb_size -+ * @bad_count: count of bad physical eraseblocks -+ * @leb_size: logical eraseblock size -+ * @max_ec: current highest erase counter value -+ * @bad_rsvd: how many physical eraseblocks of the underlying flash device are -+ * reserved for bad eraseblocks handling -+ * @max_vol_count: maximum possible number of volumes on this UBI device -+ * @min_io_size: minimum input/output unit size of the UBI device -+ */ -+struct ubi_dev_info -+{ -+ int dev_num; -+ int vol_count; -+ int lowest_vol_num; -+ int highest_vol_num; -+ int major; -+ int minor; -+ int total_lebs; -+ int avail_lebs; -+ long long total_bytes; -+ long long avail_bytes; -+ int bad_count; -+ int leb_size; -+ long long max_ec; -+ int bad_rsvd; -+ int max_vol_count; -+ int min_io_size; -+}; -+ -+/** -+ * struct ubi_vol_info - UBI volume information. -+ * @dev_num: UBI device number the volume resides on -+ * @vol_id: ID of this volume -+ * @major: major number of corresponding volume character device -+ * @minor: minor number of corresponding volume character device -+ * @dev_major: major number of corresponding UBI device character device -+ * @dev_minor: minor number of corresponding UBI device character device -+ * @type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @alignment: alignemnt of this volume -+ * @data_bytes: how many data bytes are stored on this volume (equivalent to -+ * @rsvd_bytes for dynamic volumes) -+ * @rsvd_bytes: how many bytes are reserved for this volume -+ * @rsvd_lebs: how many logical eraseblocks are reserved for this volume -+ * @leb_size: logical eraseblock size of this volume (may be less then -+ * device's logical eraseblock size due to alignment) -+ * @corrupted: non-zero if the volume is corrupted -+ * @name: volume name (null-terminated) -+ */ -+struct ubi_vol_info -+{ -+ int dev_num; -+ int vol_id; -+ int major; -+ int minor; -+ int dev_major; -+ int dev_minor; -+ int type; -+ int alignment; -+ long long data_bytes; -+ long long rsvd_bytes; -+ int rsvd_lebs; -+ int leb_size; -+ int corrupted; -+ char name[UBI_VOL_NAME_MAX + 1]; -+}; -+ -+/** -+ * libubi_open - open UBI library. -+ * @required: if non-zero, libubi will print an error messages if this UBI is -+ * not present in the system -+ * -+ * This function initializes and opens the UBI library and returns UBI library -+ * descriptor in case of success and %NULL in case of failure. -+ */ -+libubi_t libubi_open(int required); -+ -+/** -+ * libubi_close - close UBI library. -+ * @desc UBI library descriptor -+ */ -+void libubi_close(libubi_t desc); -+ -+/** -+ * ubi_get_info - get general UBI information. -+ * @desc: UBI library descriptor -+ * @info: pointer to the &struct ubi_info object to fill -+ * -+ * This function fills the passed @info object with general UBI information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_info(libubi_t desc, struct ubi_info *info); -+ -+/** -+ * mtd_num2ubi_dev - find UBI device by attached MTD device. -+ * @@desc: UBI library descriptor -+ * @mtd_num: MTD device number -+ * @dev_num: UBI device number is returned here -+ * -+ * This function finds UBI device to which MTD device @mtd_num is attached. -+ * Returns %0 if the UBI device was found and %-1 if not. -+ */ -+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num); -+ -+/** -+ * ubi_attach_mtd - attach MTD device to UBI. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @req: MTD attach request. -+ * -+ * This function creates a new UBI device by attaching an MTD device as -+ * described by @req. Returns %0 in case of success and %-1 in case of failure. -+ * The newly created UBI device number is returned in @req->dev_num. -+ */ -+int ubi_attach_mtd(libubi_t desc, const char *node, -+ struct ubi_attach_request *req); -+ -+/** -+ * ubi_detach_mtd - detach an MTD device. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @mtd_num: MTD device number to detach -+ * -+ * This function detaches MTD device number @mtd_num from UBI, which means the -+ * corresponding UBI device is removed. Returns zero in case of success and %-1 -+ * in case of failure. -+ */ -+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num); -+ -+/** -+ * ubi_remove_dev - remove an UBI device. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI control character device node -+ * @ubi_dev: UBI device number to remove -+ * -+ * This function removes UBI device number @ubi_dev and returns zero in case of -+ * success and %-1 in case of failure. -+ */ -+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev); -+ -+/** -+ * ubi_mkvol - create an UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to create a volume at -+ * @req: UBI volume creation request -+ * -+ * This function creates a UBI volume as described at @req and returns %0 in -+ * case of success and %-1 in case of failure. The assigned volume ID is -+ * returned in @req->vol_id. -+ */ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req); -+ -+/** -+ * ubi_rmvol - remove a UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to remove a volume from -+ * @vol_id: ID of the volume to remove -+ * -+ * This function removes volume @vol_id from UBI device @node and returns %0 in -+ * case of success and %-1 in case of failure. -+ */ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id); -+ -+/** -+ * ubi_rsvol - re-size UBI volume. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device owning the volume which should be -+ * re-sized -+ * @vol_id: volume ID to re-size -+ * @bytes: new volume size in bytes -+ * -+ * This function returns %0 in case of success and %-1 in case of error. -+ */ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes); -+ -+/** -+ * ubi_node_type - test UBI node type. -+ * @desc: UBI library descriptor -+ * @node: the node to test -+ * -+ * This function tests whether @node is a UBI device or volume node and returns -+ * %1 if this is an UBI device node, %2 if this is a volume node, and %-1 if -+ * this is not an UBI node or if an error occurred (the latter is indicated by -+ * a non-zero errno). -+ */ -+int ubi_node_type(libubi_t desc, const char *node); -+ -+/** -+ * ubi_get_dev_info - get UBI device information. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI character device to fetch information about -+ * @info: pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function fills the passed @info object with UBI device information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_dev_info(libubi_t desc, const char *node, -+ struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_dev_info1 - get UBI device information. -+ * @desc: UBI library descriptor -+ * @dev_num: UBI device number to fetch information about -+ * @info: pointer to the &struct ubi_dev_info object to fill -+ * -+ * This function is identical to 'ubi_get_dev_info()' except that it accepts UBI -+ * device number, not UBI character device. -+ */ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info); -+ -+/** -+ * ubi_get_vol_info - get UBI volume information. -+ * @desc: UBI library descriptor -+ * @node: name of the UBI volume character device to fetch information about -+ * @info: pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function fills the passed @info object with UBI volume information and -+ * returns %0 in case of success and %-1 in case of failure. -+ */ -+int ubi_get_vol_info(libubi_t desc, const char *node, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_get_vol_info1 - get UBI volume information. -+ * @desc: UBI library descriptor -+ * @dev_num: UBI device number -+ * @vol_id: ID of the UBI volume to fetch information about -+ * @info: pointer to the &struct ubi_vol_info object to fill -+ * -+ * This function is identical to 'ubi_get_vol_info()' except that it accepts UBI -+ * volume number, not UBI volume character device. -+ */ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info); -+ -+/** -+ * ubi_update_start - start UBI volume update. -+ * @desc: UBI library descriptor -+ * @fd: volume character devie file descriptor -+ * @bytes: how many bytes will be written to the volume -+ * -+ * This function initiates UBI volume update and returns %0 in case of success -+ * and %-1 in case of error. The caller is assumed to write @bytes data to the -+ * volume @fd afterwards. -+ */ -+int ubi_update_start(libubi_t desc, int fd, long long bytes); -+ -+ -+/** -+ * ubi_leb_read_start -+ * @fd: volume character devie file descriptor -+ * @leb: structure pointer for volume dump request -+ * -+ * This function call "UBI_IOCLEBREAD" ioctl. -+ * return %1 means the LEB is not mapped, no need to dump -+ * return %0 LEB read done successful -+ * return any others error -+ */ -+int ubi_leb_read_start(int fd, struct ubi_leb *leb); -+ -+/** -+ * ubi_leb_change_start - start atomic LEB change. -+ * @desc: UBI library descriptor -+ * @fd: volume character devie file descriptor -+ * @lnum: LEB number to change -+ * @bytes: how many bytes of new data will be written to the LEB -+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * -+ * This function initiates atomic LEB change operation and returns %0 in case -+ * of success and %-1 in case of error. he caller is assumed to write @bytes -+ * data to the volume @fd afterwards. -+ */ -+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/include/libubigen.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Frank Haverkamp -+ * Artem Bityutskiy -+ */ -+ -+#ifndef __LIBUBIGEN_H__ -+#define __LIBUBIGEN_H__ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * struct ubigen_info - libubigen information. -+ * @leb_size: logical eraseblock size -+ * @peb_size: size of the physical eraseblock -+ * @min_io_size: minimum input/output unit size -+ * @vid_hdr_offs: offset of the VID header -+ * @data_offs: data offset -+ * @ubi_ver: UBI version -+ * @vtbl_size: volume table size -+ * @max_volumes: maximum amount of volumes -+ */ -+struct ubigen_info -+{ -+ int leb_size; -+ int peb_size; -+ int min_io_size; -+ int vid_hdr_offs; -+ int data_offs; -+ int ubi_ver; -+ int vtbl_size; -+ int max_volumes; -+}; -+ -+/** -+ * struct ubigen_vol_info - information about a volume. -+ * @id: volume id -+ * @type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @usable_leb_size: LEB size accessible for volume users -+ * @name: volume name -+ * @name_len: volume name length -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @used_ebs: total number of used logical eraseblocks in this volume (relevant -+ * for static volumes only) -+ * @bytes: size of the volume contents in bytes (relevant for static volumes -+ * only) -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ */ -+struct ubigen_vol_info -+{ -+ int id; -+ int type; -+ int alignment; -+ int data_pad; -+ int usable_leb_size; -+ const char *name; -+ int name_len; -+ int compat; -+ int used_ebs; -+ long long bytes; -+ uint8_t flags; -+}; -+ -+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, -+ int subpage_size, int vid_hdr_offs, int ubi_ver); -+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui); -+void ubigen_init_ec_hdr(const struct ubigen_info *ui, -+ struct ubi_ec_hdr *hdr, long long ec); -+int ubigen_get_vtbl_size(const struct ubigen_info *ui); -+int ubigen_add_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vtbl_record *vtbl); -+int ubigen_write_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, long long ec, -+ long long bytes, int in, int out); -+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2, -+ long long ec1, long long ec2, -+ struct ubi_vtbl_record *vtbl, int fd); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBIGEN_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,194 @@ -+/* -+ * Copyright (C) 2007, 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * This file contains various common stuff used by UBI utilities. -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/** -+ * get_multiplier - convert size specifier to an integer multiplier. -+ * @str: the size specifier string -+ * -+ * This function parses the @str size specifier, which may be one of -+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive -+ * size multiplier in case of success and %-1 in case of failure. -+ */ -+static int get_multiplier(const char *str) -+{ -+ if (!str) -+ return 1; -+ -+ /* Remove spaces before the specifier */ -+ while (*str == ' ' || *str == '\t') -+ str += 1; -+ -+ if (!strcmp(str, "KiB")) -+ return 1024; -+ if (!strcmp(str, "MiB")) -+ return 1024 * 1024; -+ if (!strcmp(str, "GiB")) -+ return 1024 * 1024 * 1024; -+ -+ /* Handle deprecated stuff */ -+ if (!strcmp(str, "KB") || !strcmp(str, "Kib") || !strcmp(str, "kib") || -+ !strcmp(str, "kiB")) { -+ fprintf(stderr, "Warning: use \"KiB\" instead of \"%s\" to " -+ "specify Kilobytes - support will be removed\n", str); -+ return 1024; -+ } -+ if (!strcmp(str, "MB") || !strcmp(str, "Mib") || !strcmp(str, "mb")) { -+ fprintf(stderr, "Warning: use \"MiB\" instead of \"%s\", " -+ "this support will be removed\n", str); -+ return 1024*1024; -+ } -+ if (!strcmp(str, "GB") || !strcmp(str, "Gib") || !strcmp(str, "gb")) { -+ fprintf(stderr, "Warning: use \"GiB\" instead of \"%s\", " -+ "this support will be removed\n", str); -+ return 1024*1024*1024; -+ } -+ -+ return -1; -+} -+ -+/** -+ * ubiutils_get_bytes - convert a string containing amount of bytes into an -+ * integer -+ * @str: string to convert -+ * -+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' -+ * size specifiers. Returns positive amount of bytes in case of success and %-1 -+ * in case of failure. -+ */ -+long long ubiutils_get_bytes(const char *str) -+{ -+ char *endp; -+ long long bytes = strtoull(str, &endp, 0); -+ -+ if (endp == str || bytes < 0) { -+ fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str); -+ return -1; -+ } -+ -+ if (*endp != '\0') { -+ int mult = get_multiplier(endp); -+ -+ if (mult == -1) { -+ fprintf(stderr, "bad size specifier: \"%s\" - " -+ "should be 'KiB', 'MiB' or 'GiB'\n", endp); -+ return -1; -+ } -+ bytes *= mult; -+ } -+ -+ return bytes; -+} -+ -+/** -+ * ubiutils_print_bytes - print bytes. -+ * @bytes: variable to print -+ * @bracket: whether brackets have to be put or not -+ * -+ * This is a helper function which prints amount of bytes in a human-readable -+ * form, i.e., it prints the exact amount of bytes following by the approximate -+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes -+ * is. -+ */ -+void ubiutils_print_bytes(long long bytes, int bracket) -+{ -+ const char *p; -+ -+ if (bracket) -+ p = " ("; -+ else -+ p = ", "; -+ -+ printf("%lld bytes", bytes); -+ -+ if (bytes > 1024 * 1024 * 1024) -+ printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024)); -+ else if (bytes > 1024 * 1024) -+ printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024)); -+ else if (bytes > 1024 && bytes != 0) -+ printf("%s%.1f KiB", p, (double)bytes / 1024); -+ else -+ return; -+ -+ if (bracket) -+ printf(")"); -+} -+ -+/** -+ * ubiutils_print_text - print text and fold it. -+ * @stream: file stream to print to -+ * @text: text to print -+ * @width: maximum allowed text width -+ * -+ * Print text and fold it so that each line would not have more then @width -+ * characters. -+ */ -+void ubiutils_print_text(FILE *stream, const char *text, int width) -+{ -+ int pos, bpos = 0; -+ const char *p; -+ char line[1024]; -+ -+ if (width > 1023) { -+ fprintf(stream, "%s\n", text); -+ return; -+ } -+ p = text; -+ pos = 0; -+ while (p[pos]) { -+ while (!isspace(p[pos])) { -+ line[pos] = p[pos]; -+ if (!p[pos]) -+ break; -+ ++pos; -+ if (pos == width) { -+ line[pos] = '\0'; -+ fprintf(stream, "%s\n", line); -+ p += pos; -+ pos = 0; -+ } -+ } -+ while (pos < width) { -+ line[pos] = p[pos]; -+ if (!p[pos]) { -+ bpos = pos; -+ break; -+ } -+ if (isspace(p[pos])) -+ bpos = pos; -+ ++pos; -+ } -+ line[bpos] = '\0'; -+ fprintf(stream, "%s\n", line); -+ p += bpos; -+ pos = 0; -+ while (p[pos] && isspace(p[pos])) -+ ++p; -+ } -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/common.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+/* -+ * Copyright (c) Artem Bityutskiy, 2007, 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef __UBI_UTILS_COMMON_H__ -+#define __UBI_UTILS_COMMON_H__ -+ -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define MIN(a ,b) ((a) < (b) ? (a) : (b)) -+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -+ -+/* Verbose messages */ -+#define verbose(verbose, fmt, ...) do { \ -+ if (verbose) \ -+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+ -+/* Normal messages */ -+#define normsg(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+#define normsg_cont(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \ -+} while(0) -+#define normsg_cont(fmt, ...) do { \ -+ printf(PROGRAM_NAME ": " fmt, ##__VA_ARGS__); \ -+} while(0) -+ -+/* Error messages */ -+#define errmsg(fmt, ...) ({ \ -+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \ -+ -1; \ -+}) -+ -+/* System error messages */ -+#define sys_errmsg(fmt, ...) ({ \ -+ int _err = errno, _i; \ -+ fprintf(stderr, PROGRAM_NAME ": error!: " fmt "\n", ##__VA_ARGS__); \ -+ for (_i = 0; _i < sizeof(PROGRAM_NAME) + 1; _i++) \ -+ fprintf(stderr, " "); \ -+ fprintf(stderr, "error %d (%s)\n", _err, strerror(_err)); \ -+ -1; \ -+}) -+ -+/* Warnings */ -+#define warnmsg(fmt, ...) do { \ -+ fprintf(stderr, PROGRAM_NAME ": warning!: " fmt "\n", ##__VA_ARGS__); \ -+} while(0) -+ -+static inline int is_power_of_2(unsigned long long n) -+{ -+ return (n != 0 && ((n & (n - 1)) == 0)); -+} -+ -+long long ubiutils_get_bytes(const char *str); -+void ubiutils_print_bytes(long long bytes, int bracket); -+void ubiutils_print_text(FILE *stream, const char *txt, int len); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__UBI_UTILS_COMMON_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+#include -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,19 @@ -+#ifndef CRC32_H -+#define CRC32_H -+ -+#include -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+ -+ static inline uint32_t -+crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,405 @@ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file dictionary.c -+ @author N. Devillard -+ @date Sep 2007 -+ @version $Revision: 1.1.1.1 $ -+ @brief Implements a dictionary for string variables. -+ -+ This module implements a simple dictionary object, i.e. a list -+ of string/string associations. This object is useful to store e.g. -+ informations retrieved from a configuration file (ini files). -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: dictionary.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+*/ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+#include "dictionary.h" -+ -+#include -+#include -+#include -+#include -+ -+/** Maximum value size for integers and doubles. */ -+#define MAXVALSZ 1024 -+ -+/** Minimal allocated number of entries in a dictionary */ -+#define DICTMINSZ 128 -+ -+/** Invalid key token */ -+#define DICT_INVALID_KEY ((char*)-1) -+ -+/*--------------------------------------------------------------------------- -+ Private functions -+ ---------------------------------------------------------------------------*/ -+ -+/* Doubles the allocated size associated to a pointer */ -+/* 'size' is the current allocated size. */ -+static void * mem_double(void * ptr, int size) -+{ -+ void * newptr ; -+ -+ newptr = calloc(2*size, 1); -+ if (newptr==NULL) { -+ return NULL ; -+ } -+ memcpy(newptr, ptr, size); -+ free(ptr); -+ return newptr ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Duplicate a string -+ @param s String to duplicate -+ @return Pointer to a newly allocated string, to be freed with free() -+ -+ This is a replacement for strdup(). This implementation is provided -+ for systems that do not have it. -+ */ -+/*--------------------------------------------------------------------------*/ -+static char * xstrdup(char * s) -+{ -+ char * t ; -+ if (!s) -+ return NULL ; -+ t = malloc(strlen(s)+1) ; -+ if (t) { -+ strcpy(t,s); -+ } -+ return t ; -+} -+ -+/*--------------------------------------------------------------------------- -+ Function codes -+ ---------------------------------------------------------------------------*/ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Compute the hash key for a string. -+ @param key Character string to use for key. -+ @return 1 unsigned int on at least 32 bits. -+ -+ This hash function has been taken from an Article in Dr Dobbs Journal. -+ This is normally a collision-free function, distributing keys evenly. -+ The key is stored anyway in the struct so that collision can be avoided -+ by comparing the key itself in last resort. -+ */ -+/*--------------------------------------------------------------------------*/ -+unsigned dictionary_hash(char * key) -+{ -+ int len ; -+ unsigned hash ; -+ int i ; -+ -+ len = strlen(key); -+ for (hash=0, i=0 ; i>6) ; -+ } -+ hash += (hash <<3); -+ hash ^= (hash >>11); -+ hash += (hash <<15); -+ return hash ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Create a new dictionary object. -+ @param size Optional initial size of the dictionary. -+ @return 1 newly allocated dictionary objet. -+ -+ This function allocates a new dictionary object of given size and returns -+ it. If you do not know in advance (roughly) the number of entries in the -+ dictionary, give size=0. -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * dictionary_new(int size) -+{ -+ dictionary * d ; -+ -+ /* If no size was specified, allocate space for DICTMINSZ */ -+ if (sizesize = size ; -+ d->val = (char **)calloc(size, sizeof(char*)); -+ d->key = (char **)calloc(size, sizeof(char*)); -+ d->hash = (unsigned int *)calloc(size, sizeof(unsigned)); -+ return d ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a dictionary object -+ @param d dictionary object to deallocate. -+ @return void -+ -+ Deallocate a dictionary object and all memory associated to it. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_del(dictionary * d) -+{ -+ int i ; -+ -+ if (d==NULL) return ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]!=NULL) -+ free(d->key[i]); -+ if (d->val[i]!=NULL) -+ free(d->val[i]); -+ } -+ free(d->val); -+ free(d->key); -+ free(d->hash); -+ free(d); -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get a value from a dictionary. -+ @param d dictionary object to search. -+ @param key Key to look for in the dictionary. -+ @param def Default value to return if key not found. -+ @return 1 pointer to internally allocated character string. -+ -+ This function locates a key in a dictionary and returns a pointer to its -+ value, or the passed 'def' pointer if no such key can be found in -+ dictionary. The returned character pointer points to data internal to the -+ dictionary object, you should not try to free it or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * dictionary_get(dictionary * d, char * key, char * def) -+{ -+ unsigned hash ; -+ int i ; -+ -+ hash = dictionary_hash(key); -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ /* Compare hash */ -+ if (hash==d->hash[i]) { -+ /* Compare string, to avoid hash collisions */ -+ if (!strcmp(key, d->key[i])) { -+ return d->val[i] ; -+ } -+ } -+ } -+ return def ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set a value in a dictionary. -+ @param d dictionary object to modify. -+ @param key Key to modify or add. -+ @param val Value to add. -+ @return int 0 if Ok, anything else otherwise -+ -+ If the given key is found in the dictionary, the associated value is -+ replaced by the provided one. If the key cannot be found in the -+ dictionary, it is added to it. -+ -+ It is Ok to provide a NULL value for val, but NULL values for the dictionary -+ or the key are considered as errors: the function will return immediately -+ in such a case. -+ -+ Notice that if you dictionary_set a variable to NULL, a call to -+ dictionary_get will return a NULL value: the variable will be found, and -+ its value (NULL) is returned. In other words, setting the variable -+ content to NULL is equivalent to deleting the variable from the -+ dictionary. It is not possible (in this implementation) to have a key in -+ the dictionary without value. -+ -+ This function returns non-zero in case of failure. -+ */ -+/*--------------------------------------------------------------------------*/ -+int dictionary_set(dictionary * d, char * key, char * val) -+{ -+ int i ; -+ unsigned hash ; -+ -+ if (d==NULL || key==NULL) return -1 ; -+ -+ /* Compute hash for this key */ -+ hash = dictionary_hash(key) ; -+ /* Find if value is already in dictionary */ -+ if (d->n>0) { -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (hash==d->hash[i]) { /* Same hash value */ -+ if (!strcmp(key, d->key[i])) { /* Same key */ -+ /* Found a value: modify and return */ -+ if (d->val[i]!=NULL) -+ free(d->val[i]); -+ d->val[i] = val ? xstrdup(val) : NULL ; -+ /* Value has been modified: return */ -+ return 0 ; -+ } -+ } -+ } -+ } -+ /* Add a new value */ -+ /* See if dictionary needs to grow */ -+ if (d->n==d->size) { -+ -+ /* Reached maximum size: reallocate dictionary */ -+ d->val = (char **)mem_double(d->val, d->size * sizeof(char*)) ; -+ d->key = (char **)mem_double(d->key, d->size * sizeof(char*)) ; -+ d->hash = (unsigned int *)mem_double(d->hash, d->size * sizeof(unsigned)) ; -+ if ((d->val==NULL) || (d->key==NULL) || (d->hash==NULL)) { -+ /* Cannot grow dictionary */ -+ return -1 ; -+ } -+ /* Double size */ -+ d->size *= 2 ; -+ } -+ -+ /* Insert key in the first empty slot */ -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) { -+ /* Add key here */ -+ break ; -+ } -+ } -+ /* Copy key */ -+ d->key[i] = xstrdup(key); -+ d->val[i] = val ? xstrdup(val) : NULL ; -+ d->hash[i] = hash; -+ d->n ++ ; -+ return 0 ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a key in a dictionary -+ @param d dictionary object to modify. -+ @param key Key to remove. -+ @return void -+ -+ This function deletes a key in a dictionary. Nothing is done if the -+ key cannot be found. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_unset(dictionary * d, char * key) -+{ -+ unsigned hash ; -+ int i ; -+ -+ if (key == NULL) { -+ return; -+ } -+ -+ hash = dictionary_hash(key); -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ /* Compare hash */ -+ if (hash==d->hash[i]) { -+ /* Compare string, to avoid hash collisions */ -+ if (!strcmp(key, d->key[i])) { -+ /* Found key */ -+ break ; -+ } -+ } -+ } -+ if (i>=d->size) -+ /* Key not found */ -+ return ; -+ -+ free(d->key[i]); -+ d->key[i] = NULL ; -+ if (d->val[i]!=NULL) { -+ free(d->val[i]); -+ d->val[i] = NULL ; -+ } -+ d->hash[i] = 0 ; -+ d->n -- ; -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump -+ @param f Opened file pointer. -+ @return void -+ -+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out -+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as -+ output file pointers. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_dump(dictionary * d, FILE * out) -+{ -+ int i ; -+ -+ if (d==NULL || out==NULL) return ; -+ if (d->n<1) { -+ fprintf(out, "empty dictionary\n"); -+ return ; -+ } -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]) { -+ fprintf(out, "%20s\t[%s]\n", -+ d->key[i], -+ d->val[i] ? d->val[i] : "UNDEF"); -+ } -+ } -+ return ; -+} -+ -+ -+/* Test code */ -+#ifdef TESTDIC -+#define NVALS 20000 -+int main(int argc, char *argv[]) -+{ -+ dictionary * d ; -+ char * val ; -+ int i ; -+ char cval[90] ; -+ -+ /* Allocate dictionary */ -+ printf("allocating...\n"); -+ d = dictionary_new(0); -+ -+ /* Set values in dictionary */ -+ printf("setting %d values...\n", NVALS); -+ for (i=0 ; in != 0) { -+ printf("error deleting values\n"); -+ } -+ printf("deallocating...\n"); -+ dictionary_del(d); -+ return 0 ; -+} -+#endif -+/* vim: set ts=4 et sw=4 tw=75 */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/dictionary.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,174 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file dictionary.h -+ @author N. Devillard -+ @date Sep 2007 -+ @version $Revision: 1.1.1.1 $ -+ @brief Implements a dictionary for string variables. -+ -+ This module implements a simple dictionary object, i.e. a list -+ of string/string associations. This object is useful to store e.g. -+ informations retrieved from a configuration file (ini files). -+*/ -+/*--------------------------------------------------------------------------*/ -+ -+/* -+ $Id: dictionary.h,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Author: yrtan $ -+ $Date: 2008-05-13 07:15:32 $ -+ $Revision: 1.1.1.1 $ -+*/ -+ -+#ifndef _DICTIONARY_H_ -+#define _DICTIONARY_H_ -+ -+/*--------------------------------------------------------------------------- -+ Includes -+ ---------------------------------------------------------------------------*/ -+ -+#include -+#include -+#include -+#include -+ -+/*--------------------------------------------------------------------------- -+ New types -+ ---------------------------------------------------------------------------*/ -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dictionary object -+ -+ This object contains a list of string/string associations. Each -+ association is identified by a unique string key. Looking up values -+ in the dictionary is speeded up by the use of a (hopefully collision-free) -+ hash function. -+ */ -+/*-------------------------------------------------------------------------*/ -+typedef struct _dictionary_ { -+ int n ; /** Number of entries in dictionary */ -+ int size ; /** Storage size */ -+ char ** val ; /** List of string values */ -+ char ** key ; /** List of string keys */ -+ unsigned * hash ; /** List of hash values for keys */ -+} dictionary ; -+ -+ -+/*--------------------------------------------------------------------------- -+ Function prototypes -+ ---------------------------------------------------------------------------*/ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Compute the hash key for a string. -+ @param key Character string to use for key. -+ @return 1 unsigned int on at least 32 bits. -+ -+ This hash function has been taken from an Article in Dr Dobbs Journal. -+ This is normally a collision-free function, distributing keys evenly. -+ The key is stored anyway in the struct so that collision can be avoided -+ by comparing the key itself in last resort. -+ */ -+/*--------------------------------------------------------------------------*/ -+unsigned dictionary_hash(char * key); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Create a new dictionary object. -+ @param size Optional initial size of the dictionary. -+ @return 1 newly allocated dictionary objet. -+ -+ This function allocates a new dictionary object of given size and returns -+ it. If you do not know in advance (roughly) the number of entries in the -+ dictionary, give size=0. -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * dictionary_new(int size); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a dictionary object -+ @param d dictionary object to deallocate. -+ @return void -+ -+ Deallocate a dictionary object and all memory associated to it. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_del(dictionary * vd); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get a value from a dictionary. -+ @param d dictionary object to search. -+ @param key Key to look for in the dictionary. -+ @param def Default value to return if key not found. -+ @return 1 pointer to internally allocated character string. -+ -+ This function locates a key in a dictionary and returns a pointer to its -+ value, or the passed 'def' pointer if no such key can be found in -+ dictionary. The returned character pointer points to data internal to the -+ dictionary object, you should not try to free it or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * dictionary_get(dictionary * d, char * key, char * def); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set a value in a dictionary. -+ @param d dictionary object to modify. -+ @param key Key to modify or add. -+ @param val Value to add. -+ @return int 0 if Ok, anything else otherwise -+ -+ If the given key is found in the dictionary, the associated value is -+ replaced by the provided one. If the key cannot be found in the -+ dictionary, it is added to it. -+ -+ It is Ok to provide a NULL value for val, but NULL values for the dictionary -+ or the key are considered as errors: the function will return immediately -+ in such a case. -+ -+ Notice that if you dictionary_set a variable to NULL, a call to -+ dictionary_get will return a NULL value: the variable will be found, and -+ its value (NULL) is returned. In other words, setting the variable -+ content to NULL is equivalent to deleting the variable from the -+ dictionary. It is not possible (in this implementation) to have a key in -+ the dictionary without value. -+ -+ This function returns non-zero in case of failure. -+ */ -+/*--------------------------------------------------------------------------*/ -+int dictionary_set(dictionary * vd, char * key, char * val); -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete a key in a dictionary -+ @param d dictionary object to modify. -+ @param key Key to remove. -+ @return void -+ -+ This function deletes a key in a dictionary. Nothing is done if the -+ key cannot be found. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_unset(dictionary * d, char * key); -+ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump -+ @param f Opened file pointer. -+ @return void -+ -+ Dumps a dictionary onto an opened file pointer. Key pairs are printed out -+ as @c [Key]=[Value], one per line. It is Ok to provide stdout or stderr as -+ output file pointers. -+ */ -+/*--------------------------------------------------------------------------*/ -+void dictionary_dump(dictionary * d, FILE * out); -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libiniparser.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,646 @@ -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @file iniparser.c -+ @author N. Devillard -+ @date Sep 2007 -+ @version 3.0 -+ @brief Parser for ini files. -+*/ -+/*--------------------------------------------------------------------------*/ -+/* -+ $Id: libiniparser.c,v 1.1.1.1 2008-05-13 07:15:32 yrtan Exp $ -+ $Revision: 1.1.1.1 $ -+ $Date: 2008-05-13 07:15:32 $ -+*/ -+/*---------------------------- Includes ------------------------------------*/ -+#include -+#include -+ -+/*---------------------------- Defines -------------------------------------*/ -+#define ASCIILINESZ (1024) -+#define INI_INVALID_KEY ((char*)-1) -+ -+/*--------------------------------------------------------------------------- -+ Private to this module -+ ---------------------------------------------------------------------------*/ -+/** -+ * This enum stores the status for each parsed line (internal use only). -+ */ -+typedef enum _line_status_ { -+ LINE_UNPROCESSED, -+ LINE_ERROR, -+ LINE_EMPTY, -+ LINE_COMMENT, -+ LINE_SECTION, -+ LINE_VALUE -+} line_status ; -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Convert a string to lowercase. -+ @param s String to convert. -+ @return ptr to statically allocated string. -+ -+ This function returns a pointer to a statically allocated string -+ containing a lowercased version of the input string. Do not free -+ or modify the returned string! Since the returned string is statically -+ allocated, it will be modified at each function call (not re-entrant). -+ */ -+/*--------------------------------------------------------------------------*/ -+static char * strlwc(const char * s) -+{ -+ static char l[ASCIILINESZ+1]; -+ int i ; -+ -+ if (s==NULL) return NULL ; -+ memset(l, 0, ASCIILINESZ+1); -+ i=0 ; -+ while (s[i] && i l) { -+ if (!isspace((int)*(last-1))) -+ break ; -+ last -- ; -+ } -+ *last = (char)0; -+ return (char*)l ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get number of sections in a dictionary -+ @param d Dictionary to examine -+ @return int Number of sections found in dictionary -+ -+ This function returns the number of sections found in a dictionary. -+ The test to recognize sections is done on the string stored in the -+ dictionary: a section name is given as "section" whereas a key is -+ stored as "section:key", thus the test looks for entries that do not -+ contain a colon. -+ -+ This clearly fails in the case a section name contains a colon, but -+ this should simply be avoided. -+ -+ This function returns -1 in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getnsec(dictionary * d) -+{ -+ int i ; -+ int nsec ; -+ -+ if (d==NULL) return -1 ; -+ nsec=0 ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (strchr(d->key[i], ':')==NULL) { -+ nsec ++ ; -+ } -+ } -+ return nsec ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get name for section n in a dictionary. -+ @param d Dictionary to examine -+ @param n Section number (from 0 to nsec-1). -+ @return Pointer to char string -+ -+ This function locates the n-th section in a dictionary and returns -+ its name as a pointer to a string statically allocated inside the -+ dictionary. Do not free or modify the returned string! -+ -+ This function returns NULL in case of error. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getsecname(dictionary * d, int n) -+{ -+ int i ; -+ int foundsec ; -+ -+ if (d==NULL || n<0) return NULL ; -+ foundsec=0 ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (strchr(d->key[i], ':')==NULL) { -+ foundsec++ ; -+ if (foundsec>n) -+ break ; -+ } -+ } -+ if (foundsec<=n) { -+ return NULL ; -+ } -+ return d->key[i] ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Dump a dictionary to an opened file pointer. -+ @param d Dictionary to dump. -+ @param f Opened file pointer to dump to. -+ @return void -+ -+ This function prints out the contents of a dictionary, one element by -+ line, onto the provided file pointer. It is OK to specify @c stderr -+ or @c stdout as output files. This function is meant for debugging -+ purposes mostly. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump(dictionary * d, FILE * f) -+{ -+ int i ; -+ -+ if (d==NULL || f==NULL) return ; -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ if (d->val[i]!=NULL) { -+ fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]); -+ } else { -+ fprintf(f, "[%s]=UNDEF\n", d->key[i]); -+ } -+ } -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Save a dictionary to a loadable ini file -+ @param d Dictionary to dump -+ @param f Opened file pointer to dump to -+ @return void -+ -+ This function dumps a given dictionary into a loadable ini file. -+ It is Ok to specify @c stderr or @c stdout as output files. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_dump_ini(dictionary * d, FILE * f) -+{ -+ int i, j ; -+ char keym[ASCIILINESZ+1]; -+ int nsec ; -+ char * secname ; -+ int seclen ; -+ -+ if (d==NULL || f==NULL) return ; -+ -+ nsec = iniparser_getnsec(d); -+ if (nsec<1) { -+ /* No section in file: dump all keys as they are */ -+ for (i=0 ; isize ; i++) { -+ if (d->key[i]==NULL) -+ continue ; -+ fprintf(f, "%s = %s\n", d->key[i], d->val[i]); -+ } -+ return ; -+ } -+ for (i=0 ; isize ; j++) { -+ if (d->key[j]==NULL) -+ continue ; -+ if (!strncmp(d->key[j], keym, seclen+1)) { -+ fprintf(f, -+ "%-30s = %s\n", -+ d->key[j]+seclen+1, -+ d->val[j] ? d->val[j] : ""); -+ } -+ } -+ } -+ fprintf(f, "\n"); -+ return ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param def Default value to return if key not found. -+ @return pointer to statically allocated character string -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the pointer passed as 'def' is returned. -+ The returned char pointer is pointing to a string allocated in -+ the dictionary, do not free or modify it. -+ */ -+/*--------------------------------------------------------------------------*/ -+char * iniparser_getstring(dictionary * d, const char * key, char * def) -+{ -+ char * lc_key ; -+ char * sval ; -+ -+ if (d==NULL || key==NULL) -+ return def ; -+ -+ lc_key = strlwc(key); -+ sval = dictionary_get(d, lc_key, def); -+ return sval ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to an int -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ Supported values for integers include the usual C notation -+ so decimal, octal (starting with 0) and hexadecimal (starting with 0x) -+ are supported. Examples: -+ -+ "42" -> 42 -+ "042" -> 34 (octal -> decimal) -+ "0x42" -> 66 (hexa -> decimal) -+ -+ Warning: the conversion may overflow in various ways. Conversion is -+ totally outsourced to strtol(), see the associated man page for overflow -+ handling. -+ -+ Credits: Thanks to A. Becker for suggesting strtol() -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getint(dictionary * d, const char * key, int notfound) -+{ -+ char * str ; -+ -+ str = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (str==INI_INVALID_KEY) return notfound ; -+ return (int)strtol(str, NULL, 0); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a double -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return double -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ */ -+/*--------------------------------------------------------------------------*/ -+double iniparser_getdouble(dictionary * d, char * key, double notfound) -+{ -+ char * str ; -+ -+ str = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (str==INI_INVALID_KEY) return notfound ; -+ return atof(str); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Get the string associated to a key, convert to a boolean -+ @param d Dictionary to search -+ @param key Key string to look for -+ @param notfound Value to return in case of error -+ @return integer -+ -+ This function queries a dictionary for a key. A key as read from an -+ ini file is given as "section:key". If the key cannot be found, -+ the notfound value is returned. -+ -+ A true boolean is found if one of the following is matched: -+ -+ - A string starting with 'y' -+ - A string starting with 'Y' -+ - A string starting with 't' -+ - A string starting with 'T' -+ - A string starting with '1' -+ -+ A false boolean is found if one of the following is matched: -+ -+ - A string starting with 'n' -+ - A string starting with 'N' -+ - A string starting with 'f' -+ - A string starting with 'F' -+ - A string starting with '0' -+ -+ The notfound value returned if no boolean is identified, does not -+ necessarily have to be 0 or 1. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_getboolean(dictionary * d, const char * key, int notfound) -+{ -+ char * c ; -+ int ret ; -+ -+ c = iniparser_getstring(d, key, INI_INVALID_KEY); -+ if (c==INI_INVALID_KEY) return notfound ; -+ if (c[0]=='y' || c[0]=='Y' || c[0]=='1' || c[0]=='t' || c[0]=='T') { -+ ret = 1 ; -+ } else if (c[0]=='n' || c[0]=='N' || c[0]=='0' || c[0]=='f' || c[0]=='F') { -+ ret = 0 ; -+ } else { -+ ret = notfound ; -+ } -+ return ret; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Finds out if a given entry exists in a dictionary -+ @param ini Dictionary to search -+ @param entry Name of the entry to look for -+ @return integer 1 if entry exists, 0 otherwise -+ -+ Finds out if a given entry exists in the dictionary. Since sections -+ are stored as keys with NULL associated values, this is the only way -+ of querying for the presence of sections in a dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_find_entry( -+ dictionary * ini, -+ char * entry -+) -+{ -+ int found=0 ; -+ if (iniparser_getstring(ini, entry, INI_INVALID_KEY)!=INI_INVALID_KEY) { -+ found = 1 ; -+ } -+ return found ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Set an entry in a dictionary. -+ @param ini Dictionary to modify. -+ @param entry Entry to modify (entry name) -+ @param val New value to associate to the entry. -+ @return int 0 if Ok, -1 otherwise. -+ -+ If the given entry can be found in the dictionary, it is modified to -+ contain the provided value. If it cannot be found, -1 is returned. -+ It is Ok to set val to NULL. -+ */ -+/*--------------------------------------------------------------------------*/ -+int iniparser_set(dictionary * ini, char * entry, char * val) -+{ -+ return dictionary_set(ini, strlwc(entry), val) ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Delete an entry in a dictionary -+ @param ini Dictionary to modify -+ @param entry Entry to delete (entry name) -+ @return void -+ -+ If the given entry can be found, it is deleted from the dictionary. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_unset(dictionary * ini, char * entry) -+{ -+ dictionary_unset(ini, strlwc(entry)); -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Load a single line from an INI file -+ @param input_line Input line, may be concatenated multi-line input -+ @param section Output space to store section -+ @param key Output space to store key -+ @param value Output space to store value -+ @return line_status value -+ */ -+/*--------------------------------------------------------------------------*/ -+static line_status iniparser_line( -+ char * input_line, -+ char * section, -+ char * key, -+ char * value) -+{ -+ line_status sta ; -+ char line[ASCIILINESZ+1]; -+ int len ; -+ -+ strcpy(line, strstrip(input_line)); -+ len = (int)strlen(line); -+ -+ sta = LINE_UNPROCESSED ; -+ if (len<1) { -+ /* Empty line */ -+ sta = LINE_EMPTY ; -+ } else if (line[0]=='#') { -+ /* Comment line */ -+ sta = LINE_COMMENT ; -+ } else if (line[0]=='[' && line[len-1]==']') { -+ /* Section name */ -+ sscanf(line, "[%[^]]", section); -+ strcpy(section, strstrip(section)); -+ strcpy(section, strlwc(section)); -+ sta = LINE_SECTION ; -+ } else if (sscanf (line, "%[^=] = \"%[^\"]\"", key, value) == 2 -+ || sscanf (line, "%[^=] = '%[^\']'", key, value) == 2 -+ || sscanf (line, "%[^=] = %[^;#]", key, value) == 2) { -+ /* Usual key=value, with or without comments */ -+ strcpy(key, strstrip(key)); -+ strcpy(key, strlwc(key)); -+ strcpy(value, strstrip(value)); -+ /* -+ * sscanf cannot handle '' or "" as empty values -+ * this is done here -+ */ -+ if (!strcmp(value, "\"\"") || (!strcmp(value, "''"))) { -+ value[0]=0 ; -+ } -+ sta = LINE_VALUE ; -+ } else if (sscanf(line, "%[^=] = %[;#]", key, value)==2 -+ || sscanf(line, "%[^=] %[=]", key, value) == 2) { -+ /* -+ * Special cases: -+ * key= -+ * key=; -+ * key=# -+ */ -+ strcpy(key, strstrip(key)); -+ strcpy(key, strlwc(key)); -+ value[0]=0 ; -+ sta = LINE_VALUE ; -+ } else { -+ /* Generate syntax error */ -+ sta = LINE_ERROR ; -+ } -+ return sta ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Parse an ini file and return an allocated dictionary object -+ @param ininame Name of the ini file to read. -+ @return Pointer to newly allocated dictionary -+ -+ This is the parser for ini files. This function is called, providing -+ the name of the file to be read. It returns a dictionary object that -+ should not be accessed directly, but through accessor functions -+ instead. -+ -+ The returned dictionary must be freed using iniparser_freedict(). -+ */ -+/*--------------------------------------------------------------------------*/ -+dictionary * iniparser_load(const char * ininame) -+{ -+ FILE * in ; -+ -+ char line [ASCIILINESZ+1] ; -+ char section [ASCIILINESZ+1] ; -+ char key [ASCIILINESZ+1] ; -+ char tmp [ASCIILINESZ+1] ; -+ char val [ASCIILINESZ+1] ; -+ -+ int last=0 ; -+ int len ; -+ int lineno=0 ; -+ int errs=0; -+ -+ dictionary * dict ; -+ -+ if ((in=fopen(ininame, "r"))==NULL) { -+ fprintf(stderr, "iniparser: cannot open %s\n", ininame); -+ return NULL ; -+ } -+ -+ dict = dictionary_new(0) ; -+ if (!dict) { -+ fclose(in); -+ return NULL ; -+ } -+ -+ memset(line, 0, ASCIILINESZ); -+ memset(section, 0, ASCIILINESZ); -+ memset(key, 0, ASCIILINESZ); -+ memset(val, 0, ASCIILINESZ); -+ last=0 ; -+ -+ while (fgets(line+last, ASCIILINESZ-last, in)!=NULL) { -+ lineno++ ; -+ len = (int)strlen(line)-1; -+ /* Safety check against buffer overflows */ -+ if (line[len]!='\n') { -+ fprintf(stderr, -+ "iniparser: input line too long in %s (%d)\n", -+ ininame, -+ lineno); -+ dictionary_del(dict); -+ fclose(in); -+ return NULL ; -+ } -+ /* Get rid of \n and spaces at end of line */ -+ while ((len>=0) && -+ ((line[len]=='\n') || (isspace(line[len])))) { -+ line[len]=0 ; -+ len-- ; -+ } -+ /* Detect multi-line */ -+ if (line[len]=='\\') { -+ /* Multi-line value */ -+ last=len ; -+ continue ; -+ } else { -+ last=0 ; -+ } -+ switch (iniparser_line(line, section, key, val)) { -+ case LINE_EMPTY: -+ case LINE_COMMENT: -+ break ; -+ -+ case LINE_SECTION: -+ errs = dictionary_set(dict, section, NULL); -+ break ; -+ -+ case LINE_VALUE: -+ sprintf(tmp, "%s:%s", section, key); -+ errs = dictionary_set(dict, tmp, val) ; -+ break ; -+ -+ case LINE_ERROR: -+ fprintf(stderr, "iniparser: syntax error in %s (%d):\n", -+ ininame, -+ lineno); -+ fprintf(stderr, "-> %s\n", line); -+ errs++ ; -+ break; -+ -+ default: -+ break ; -+ } -+ memset(line, 0, ASCIILINESZ); -+ last=0; -+ if (errs<0) { -+ fprintf(stderr, "iniparser: memory allocation failure\n"); -+ break ; -+ } -+ } -+ if (errs) { -+ dictionary_del(dict); -+ dict = NULL ; -+ } -+ fclose(in); -+ return dict ; -+} -+ -+/*-------------------------------------------------------------------------*/ -+/** -+ @brief Free all memory associated to an ini dictionary -+ @param d Dictionary to free -+ @return void -+ -+ Free all memory associated to an ini dictionary. -+ It is mandatory to call this function before the dictionary object -+ gets out of the current context. -+ */ -+/*--------------------------------------------------------------------------*/ -+void iniparser_freedict(dictionary * d) -+{ -+ dictionary_del(d); -+} -+ -+/* vim: set ts=4 et sw=4 tw=75 */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libmtd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,314 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * MTD library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "common.h" -+ -+#define PROGRAM_NAME "libmtd" -+#define MTD_DEV_MAJOR 90 -+ -+/** -+ * mtd_get_info - get information about an MTD device. -+ * @node: name of the MTD device node -+ * @mtd: the MTD device information is returned here -+ * -+ * This function gets information about MTD device defined by the @node device -+ * node file and saves this information in the @mtd object. Returns %0 in case -+ * of success and %-1 in case of failure. -+ */ -+int mtd_get_info(const char *node, struct mtd_info *mtd) -+{ -+ struct stat st; -+ struct mtd_info_user ui; -+ int ret; -+ loff_t offs = 0; -+ -+ if (stat(node, &st)) -+ return sys_errmsg("cannot open \"%s\"", node); -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ mtd->major = major(st.st_rdev); -+ mtd->minor = minor(st.st_rdev); -+ -+ if (mtd->major != MTD_DEV_MAJOR) { -+ errno = EINVAL; -+ return errmsg("\"%s\" has major number %d, MTD devices have " -+ "major %d", node, mtd->major, MTD_DEV_MAJOR); -+ } -+ -+ mtd->num = mtd->minor / 2; -+ mtd->rdonly = mtd->minor & 1; -+ -+ mtd->fd = open(node, O_RDWR); -+ if (mtd->fd == -1) -+ return sys_errmsg("cannot open \"%s\"", node); -+ -+ if (ioctl(mtd->fd, MEMGETINFO, &ui)) { -+ sys_errmsg("MEMGETINFO ioctl request failed"); -+ goto out_close; -+ } -+ -+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &offs); -+ if (ret == -1) { -+ if (errno != EOPNOTSUPP) { -+ sys_errmsg("MEMGETBADBLOCK ioctl failed"); -+ goto out_close; -+ } -+ errno = 0; -+ mtd->allows_bb = 0; -+ } else -+ mtd->allows_bb = 1; -+ -+ mtd->type = ui.type; -+ mtd->size = ui.size; -+ mtd->eb_size = ui.erasesize; -+ mtd->min_io_size = ui.writesize; -+ -+ if (mtd->min_io_size <= 0) { -+ errmsg("mtd%d (%s) has insane min. I/O unit size %d", -+ mtd->num, node, mtd->min_io_size); -+ goto out_close; -+ } -+ if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) { -+ errmsg("mtd%d (%s) has insane eraseblock size %d", -+ mtd->num, node, mtd->eb_size); -+ goto out_close; -+ } -+ if (mtd->size <= 0 || mtd->size < mtd->eb_size) { -+ errmsg("mtd%d (%s) has insane size %lld", -+ mtd->num, node, mtd->size); -+ goto out_close; -+ } -+ mtd->eb_cnt = mtd->size / mtd->eb_size; -+ -+ switch(mtd->type) { -+ case MTD_ABSENT: -+ errmsg("mtd%d (%s) is removable and is not present", -+ mtd->num, node); -+ goto out_close; -+ case MTD_RAM: -+ mtd->type_str = "RAM-based"; -+ break; -+ case MTD_ROM: -+ mtd->type_str = "ROM"; -+ break; -+ case MTD_NORFLASH: -+ mtd->type_str = "NOR"; -+ break; -+ case MTD_NANDFLASH: -+ mtd->type_str = "NAND"; -+ break; -+ case MTD_DATAFLASH: -+ mtd->type_str = "DataFlash"; -+ break; -+ case MTD_UBIVOLUME: -+ mtd->type_str = "UBI-emulated MTD"; -+ break; -+ default: -+ mtd->type_str = "Unknown flash type"; -+ break; -+ } -+ -+ if (!(ui.flags & MTD_WRITEABLE)) -+ mtd->rdonly = 1; -+ -+ return 0; -+ -+out_close: -+ close(mtd->fd); -+ return -1; -+} -+ -+/** -+ * mtd_erase - erase an eraseblock. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to erase -+ * -+ * This function erases the eraseblock and returns %0 in case of success and -+ * %-1 in case of failure. -+ */ -+int mtd_erase(const struct mtd_info *mtd, int eb) -+{ -+ struct erase_info_user ei; -+ -+ ei.start = eb * mtd->eb_size;; -+ ei.length = mtd->eb_size; -+ return ioctl(mtd->fd, MEMERASE, &ei); -+} -+ -+/** -+ * mtd_is_bad - check if eraseblock is bad. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to check -+ * -+ * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes, -+ * and %-1 in case of failure. -+ */ -+int mtd_is_bad(const struct mtd_info *mtd, int eb) -+{ -+ int ret; -+ loff_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (!mtd->allows_bb) -+ return 0; -+ -+ seek = eb * mtd->eb_size; -+ ret = ioctl(mtd->fd, MEMGETBADBLOCK, &seek); -+ if (ret == -1) { -+ sys_errmsg("MEMGETBADBLOCK ioctl failed for " -+ "eraseblock %d (mtd%d)", eb, mtd->num); -+ return -1; -+ } -+ -+ return ret; -+} -+ -+/** -+ * mtd_read - read data from an MTD device. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to read from -+ * @offs: offset withing the eraseblock to read from -+ * @buf: buffer to read data to -+ * @len: how many bytes to read -+ * -+ * This function reads @len bytes of data from eraseblock @eb and offset @offs -+ * of the MTD device defined by @mtd and stores the read data at buffer @buf. -+ * Returns %0 in case of success and %-1 in case of failure. -+ */ -+int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len) -+{ -+ int ret, rd = 0; -+ off_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ if (offs < 0 || offs + len > mtd->eb_size) { -+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", -+ offs, len, mtd->num, mtd->eb_size); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ /* Seek to the beginning of the eraseblock */ -+ seek = eb * mtd->eb_size + offs; -+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek mtd%d to offset %llu", -+ mtd->num, (unsigned long long)seek); -+ return -1; -+ } -+ -+ while (rd < len) { -+ ret = read(mtd->fd, buf, len); -+ if (ret < 0) { -+ sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)", -+ len, mtd->num, eb, offs); -+ return -1; -+ } -+ rd += ret; -+ } -+ -+ return 0; -+} -+ -+/** -+ * mtd_write - write data to an MTD device. -+ * @mtd: MTD device description object -+ * @eb: eraseblock to write to -+ * @offs: offset withing the eraseblock to write to -+ * @buf: buffer to write -+ * @len: how many bytes to write -+ * -+ * This function writes @len bytes of data to eraseblock @eb and offset @offs -+ * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in -+ * case of failure. -+ */ -+int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len) -+{ -+ int ret; -+ off_t seek; -+ -+ if (eb < 0 || eb >= mtd->eb_cnt) { -+ errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", -+ eb, mtd->num, mtd->eb_cnt); -+ errno = EINVAL; -+ return -1; -+ } -+ if (offs < 0 || offs + len > mtd->eb_size) { -+ errmsg("bad offset %d or length %d, mtd%d eraseblock size is %d", -+ offs, len, mtd->num, mtd->eb_size); -+ errno = EINVAL; -+ return -1; -+ } -+#if 0 -+ if (offs % mtd->subpage_size) { -+ errmsg("write offset %d is not aligned to mtd%d min. I/O size %d", -+ offs, mtd->num, mtd->subpage_size); -+ errno = EINVAL; -+ return -1; -+ } -+ if (len % mtd->subpage_size) { -+ errmsg("write length %d is not aligned to mtd%d min. I/O size %d", -+ len, mtd->num, mtd->subpage_size); -+ errno = EINVAL; -+ return -1; -+ } -+#endif -+ -+ /* Seek to the beginning of the eraseblock */ -+ seek = eb * mtd->eb_size + offs; -+ if (lseek(mtd->fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek mtd%d to offset %llu", -+ mtd->num, (unsigned long long)seek); -+ return -1; -+ } -+ -+ ret = write(mtd->fd, buf, len); -+ if (ret != len) { -+ sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)", -+ len, mtd->num, eb, offs); -+ return -1; -+ } -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libscan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,225 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI scanning library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_NAME "libscan" -+ -+static int all_ff(const void *buf, int len) -+{ -+ int i; -+ const uint8_t *p = buf; -+ -+ for (i = 0; i < len; i++) -+ if (p[i] != 0xFF) -+ return 0; -+ return 1; -+} -+ -+int ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info, int verbose) -+{ -+ int eb, v = (verbose == 2), pr = (verbose == 1); -+ struct ubi_scan_info *si; -+ unsigned long long sum = 0; -+ -+ si = calloc(1, sizeof(struct ubi_scan_info)); -+ if (!si) -+ return sys_errmsg("cannot allocate %zd bytes of memory", -+ sizeof(struct ubi_scan_info)); -+ -+ si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t)); -+ if (!si->ec) { -+ sys_errmsg("cannot allocate %zd bytes of memory", -+ sizeof(struct ubi_scan_info)); -+ goto out_si; -+ } -+ -+ si->vid_hdr_offs = si->data_offs = -1; -+ -+ verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt); -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ int ret; -+ uint32_t crc; -+ struct ubi_ec_hdr hdr; -+ unsigned long long ec; -+ -+ if (v) { -+ normsg_cont("scanning eraseblock %d", eb); -+ fflush(stdout); -+ } -+ if (pr) { -+ printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1) * 100 / mtd->eb_cnt); -+ fflush(stdout); -+ } -+ -+ ret = mtd_is_bad(mtd, eb); -+ if (ret == -1) -+ goto out_ec; -+ if (ret) { -+ si->bad_cnt += 1; -+ si->ec[eb] = EB_BAD; -+ if (v) -+ printf(": bad\n"); -+ continue; -+ } -+ -+ ret = mtd_read(mtd, eb, 0, &hdr, sizeof(struct ubi_ec_hdr));; -+ if (ret < 0) -+ goto out_ec; -+ -+ /* Check the EC header */ -+ if (be32_to_cpu(hdr.magic) != UBI_EC_HDR_MAGIC) { -+ if (all_ff(&hdr, sizeof(struct ubi_ec_hdr))) { -+ si->empty_cnt += 1; -+ si->ec[eb] = EB_EMPTY; -+ if (v) -+ printf(": empty\n"); -+ } else { -+ si->alien_cnt += 1; -+ si->ec[eb] = EB_ALIEN; -+ if (v) -+ printf(": alien\n"); -+ } -+ continue; -+ } -+ -+ crc = crc32(UBI_CRC32_INIT, &hdr, UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(hdr.hdr_crc) != crc) { -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ if (v) -+ printf(": bad CRC %#08x, should be %#08x\n", -+ crc, be32_to_cpu(hdr.hdr_crc)); -+ continue; -+ } -+ -+ ec = be64_to_cpu(hdr.ec); -+ if (ec > EC_MAX) { -+ if (pr) -+ printf("\n"); -+ errmsg("erase counter in EB %d is %llu, while this " -+ "program expects them to be less than %u", -+ eb, ec, EC_MAX); -+ goto out_ec; -+ } -+ -+ if (si->vid_hdr_offs == -1) { -+ si->vid_hdr_offs = be32_to_cpu(hdr.vid_hdr_offset); -+ si->data_offs = be32_to_cpu(hdr.data_offset); -+ if (si->data_offs % mtd->min_io_size) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("bad data offset %d at eraseblock %d (n" -+ "of multiple of min. I/O unit size %d)", -+ si->data_offs, eb, mtd->min_io_size); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ -+ } -+ } else { -+ if (be32_to_cpu(hdr.vid_hdr_offset) != si->vid_hdr_offs) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("inconsistent VID header offset: was " -+ "%d, but is %d in eraseblock %d", -+ si->vid_hdr_offs, -+ be32_to_cpu(hdr.vid_hdr_offset), eb); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ } -+ if (be32_to_cpu(hdr.data_offset) != si->data_offs) { -+ if (pr) -+ printf("\n"); -+ if (v) -+ printf(": corrupted because of the below\n"); -+ warnmsg("inconsistent data offset: was %d, but" -+ " is %d in eraseblock %d", -+ si->data_offs, -+ be32_to_cpu(hdr.data_offset), eb); -+ warnmsg("treat eraseblock %d as corrupted", eb); -+ si->corrupted_cnt += 1; -+ si->ec[eb] = EB_CORRUPTED; -+ continue; -+ } -+ } -+ -+ si->ok_cnt += 1; -+ si->ec[eb] = ec; -+ if (v) -+ printf(": OK, erase counter %u\n", si->ec[eb]); -+ } -+ -+ if (si->ok_cnt != 0) { -+ /* Calculate mean erase counter */ -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ if (si->ec[eb] > EC_MAX) -+ continue; -+ sum += si->ec[eb]; -+ } -+ si->mean_ec = sum / si->ok_cnt; -+ } -+ -+ si->good_cnt = mtd->eb_cnt - si->bad_cnt; -+ verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d " -+ "alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt, -+ si->empty_cnt, si->alien_cnt, si->bad_cnt); -+ -+ *info = si; -+ if (pr) -+ printf("\n"); -+ return 0; -+ -+out_ec: -+ free(si->ec); -+out_si: -+ free(si); -+ *info = NULL; -+ return -1; -+} -+ -+void ubi_scan_free(struct ubi_scan_info *si) -+{ -+ free(si->ec); -+ free(si); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1154 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "libubi_int.h" -+#include "common.h" -+ -+#define PROGRAM_NAME "libubi" -+ -+/** -+ * mkpath - compose full path from 2 given components. -+ * @path: the first component -+ * @name: the second component -+ * -+ * This function returns the resulting path in case of success and %NULL in -+ * case of failure. -+ */ -+static char *mkpath(const char *path, const char *name) -+{ -+ char *n; -+ int len1 = strlen(path); -+ int len2 = strlen(name); -+ -+ n = malloc(len1 + len2 + 2); -+ if (!n) { -+ sys_errmsg("cannot allocate %d bytes", len1 + len2 + 2); -+ return NULL; -+ } -+ -+ memcpy(n, path, len1); -+ if (n[len1 - 1] != '/') -+ n[len1++] = '/'; -+ -+ memcpy(n + len1, name, len2 + 1); -+ return n; -+} -+ -+/** -+ * read_positive_ll - read a positive 'long long' value from a file. -+ * @file: the file to read from -+ * @value: the result is stored here -+ * -+ * This function reads file @file and interprets its contents as a positive -+ * 'long long' integer. If this is not true, it fails with %EINVAL error code. -+ * Returns %0 in case of success and %-1 in case of failure. -+ */ -+static int read_positive_ll(const char *file, long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, 50); -+ if (rd == -1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ if (rd == 50) { -+ errmsg("contents of \"%s\" is too long", file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (sscanf(buf, "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ errmsg("cannot read integer from \"%s\"\n", file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (*value < 0) { -+ errmsg("negative value %lld in \"%s\"", *value, file); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (close(fd)) -+ return sys_errmsg("close failed on \"%s\"", file); -+ -+ return 0; -+ -+out_error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * read_positive_int - read a positive 'int' value from a file. -+ * @file: the file to read from -+ * @value: the result is stored here -+ * -+ * This function is the same as 'read_positive_ll()', but it reads an 'int' -+ * value, not 'long long'. -+ */ -+static int read_positive_int(const char *file, int *value) -+{ -+ long long res; -+ -+ if (read_positive_ll(file, &res)) -+ return -1; -+ -+ /* Make sure the value is not too big */ -+ if (res > INT_MAX) { -+ errmsg("value %lld read from file \"%s\" is out of range", -+ res, file); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ *value = res; -+ return 0; -+} -+ -+/** -+ * read_data - read data from a file. -+ * @file: the file to read from -+ * @buf: the buffer to read to -+ * @buf_len: buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. Note, if the file contains more then @buf_len bytes of -+ * date, this function fails with %EINVAL error code. -+ */ -+static int read_data(const char *file, void *buf, int buf_len) -+{ -+ int fd, rd, tmp, tmp1; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ -+ /* Make sure all data is read */ -+ tmp1 = read(fd, &tmp, 1); -+ if (tmp1 == 1) { -+ sys_errmsg("cannot read \"%s\"", file); -+ goto out_error; -+ } -+ if (tmp1) { -+ errmsg("file \"%s\" contains too much data (> %d bytes)", -+ file, buf_len); -+ errno = EINVAL; -+ goto out_error; -+ } -+ -+ if (close(fd)) { -+ sys_errmsg("close failed on \"%s\"", file); -+ return -1; -+ } -+ -+ return rd; -+ -+out_error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * read_major - read major and minor numbers from a file. -+ * @file: name of the file to read from -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns % in case of succes, and %-1 in case of failure. -+ */ -+static int read_major(const char *file, int *major, int *minor) -+{ -+ int ret; -+ char buf[50]; -+ -+ ret = read_data(file, buf, 50); -+ if (ret < 0) -+ return ret; -+ -+ ret = sscanf(buf, "%d:%d\n", major, minor); -+ if (ret != 2) { -+ errno = EINVAL; -+ return errmsg("\"%s\" does not have major:minor format", file); -+ } -+ -+ if (*major < 0 || *minor < 0) { -+ errno = EINVAL; -+ return errmsg("bad major:minor %d:%d in \"%s\"", -+ *major, *minor, file); -+ } -+ -+ return 0; -+} -+ -+/** -+ * dev_read_int - read a positive 'int' value from an UBI device sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_int(const char *patt, int dev_num, int *value) -+{ -+ char file[strlen(patt) + 50]; -+ -+ sprintf(file, patt, dev_num); -+ return read_positive_int(file, value); -+} -+ -+/** -+ * vol_read_int - read a positive 'int' value from an UBI volume sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_positive_int(file, value); -+} -+ -+/** -+ * dev_read_ll - read a positive 'long long' value from an UBI device sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_ll(const char *patt, int dev_num, long long *value) -+{ -+ char file[strlen(patt) + 50]; -+ -+ sprintf(file, patt, dev_num); -+ return read_positive_ll(file, value); -+} -+ -+/** -+ * vol_read_ll - read a positive 'long long' value from an UBI volume sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @value: the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_positive_ll(file, value); -+} -+ -+/** -+ * vol_read_data - read data from an UBI volume's sysfs file. -+ * @patt: file pattern to read from -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @buf: buffer to read to -+ * @buf_len: buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len) -+{ -+ char file[strlen(patt) + 100]; -+ -+ sprintf(file, patt, dev_num, vol_id); -+ return read_data(file, buf, buf_len); -+} -+ -+/** -+ * dev_get_major - get major and minor numbers of an UBI device. -+ * @lib: libubi descriptor -+ * @dev_num: UBI device number -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int dev_get_major(struct libubi *lib, int dev_num, int *major, int *minor) -+{ -+ char file[strlen(lib->dev_dev) + 50]; -+ -+ sprintf(file, lib->dev_dev, dev_num); -+ return read_major(file, major, minor); -+} -+ -+/** -+ * vol_get_major - get major and minor numbers of an UBI volume. -+ * @lib: libubi descriptor -+ * @dev_num: UBI device number -+ * @vol_id: volume ID -+ * @major: major number is returned here -+ * @minor: minor number is returned here -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int vol_get_major(struct libubi *lib, int dev_num, int vol_id, -+ int *major, int *minor) -+{ -+ char file[strlen(lib->vol_dev) + 100]; -+ -+ sprintf(file, lib->vol_dev, dev_num, vol_id); -+ return read_major(file, major, minor); -+} -+ -+/** -+ * vol_node2nums - find UBI device number and volume ID by volume device node -+ * file. -+ * @lib: UBI library descriptor -+ * @node: UBI character device node name -+ * @dev_num: UBI device number is returned here -+ * @vol_id: volume ID is returned hers -+ * -+ * This function returns zero in case of succes and %-1 in case of failure. -+ */ -+static int vol_node2nums(struct libubi *lib, const char *node, int *dev_num, -+ int *vol_id) -+{ -+ struct stat st; -+ struct ubi_info info; -+ int i, fd, major, minor; -+ char file[strlen(lib->ubi_vol) + 100]; -+ -+ if (lstat(node, &st)) -+ return -1; -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ major = major(st.st_rdev); -+ minor = minor(st.st_rdev); -+ -+ if (minor == 0) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a volume character device", node); -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) -+ break; -+ } -+ -+ if (i > info.highest_dev_num) { -+ errno = ENODEV; -+ return -1; -+ } -+ -+ /* Make sure this UBI volume exists */ -+ sprintf(file, lib->ubi_vol, i, minor - 1); -+ fd = open(file, O_RDONLY); -+ if (fd == -1) { -+ errno = ENODEV; -+ return -1; -+ } -+ -+ *dev_num = i; -+ *vol_id = minor - 1; -+ errno = 0; -+ return 0; -+} -+ -+/** -+ * dev_node2num - find UBI device number by its character device node. -+ * @lib: UBI library descriptor -+ * @node: UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int dev_node2num(struct libubi *lib, const char *node, int *dev_num) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not a character device", node); -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor != 0) { -+ errno = EINVAL; -+ return errmsg("\"%s\" is not an UBI character device", node); -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) { -+ if (minor1 != 0) { -+ errmsg("UBI character device minor number is " -+ "%d, but must be 0", minor1); -+ errno = EINVAL; -+ return -1; -+ } -+ errno = 0; -+ *dev_num = i; -+ return 0; -+ } -+ } -+ -+ errno = ENODEV; -+ return -1; -+} -+ -+int mtd_num2ubi_dev(libubi_t desc, int mtd_num, int *dev_num) -+{ -+ struct ubi_info info; -+ int i, ret, mtd_num1; -+ struct libubi *lib = desc; -+ -+ if (ubi_get_info(desc, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ ret = dev_read_int(lib->dev_mtd_num, i, &mtd_num1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (mtd_num1 == mtd_num) { -+ errno = 0; -+ *dev_num = i; -+ return 0; -+ } -+ } -+ -+ errno = 0; -+ return -1; -+} -+ -+libubi_t libubi_open(int required) -+{ -+ int fd, version; -+ struct libubi *lib; -+ -+ lib = calloc(1, sizeof(struct libubi)); -+ if (!lib) -+ return NULL; -+ -+ /* TODO: this must be discovered instead */ -+ lib->sysfs = strdup("/sys"); -+ if (!lib->sysfs) -+ goto out_error; -+ -+ lib->sysfs_ctrl = mkpath(lib->sysfs, SYSFS_CTRL); -+ if (!lib->sysfs_ctrl) -+ goto out_error; -+ -+ lib->ctrl_dev = mkpath(lib->sysfs_ctrl, CTRL_DEV); -+ if (!lib->ctrl_dev) -+ goto out_error; -+ -+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); -+ if (!lib->sysfs_ubi) -+ goto out_error; -+ -+ /* Make sure UBI is present */ -+ fd = open(lib->sysfs_ubi, O_RDONLY); -+ if (fd == -1) { -+ if (required) -+ errmsg("cannot open \"%s\", UBI does not seem to " -+ "exist in system", lib->sysfs_ubi); -+ goto out_error; -+ } -+ -+ if (close(fd)) { -+ sys_errmsg("close failed on \"%s\"", lib->sysfs_ubi); -+ goto out_error; -+ } -+ -+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); -+ if (!lib->ubi_dev) -+ goto out_error; -+ -+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); -+ if (!lib->ubi_version) -+ goto out_error; -+ -+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); -+ if (!lib->dev_dev) -+ goto out_error; -+ -+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); -+ if (!lib->dev_avail_ebs) -+ goto out_error; -+ -+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); -+ if (!lib->dev_total_ebs) -+ goto out_error; -+ -+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); -+ if (!lib->dev_bad_count) -+ goto out_error; -+ -+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); -+ if (!lib->dev_eb_size) -+ goto out_error; -+ -+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC); -+ if (!lib->dev_max_ec) -+ goto out_error; -+ -+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD); -+ if (!lib->dev_bad_rsvd) -+ goto out_error; -+ -+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS); -+ if (!lib->dev_max_vols) -+ goto out_error; -+ -+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE); -+ if (!lib->dev_min_io_size) -+ goto out_error; -+ -+ lib->dev_mtd_num = mkpath(lib->ubi_dev, DEV_MTD_NUM); -+ if (!lib->dev_mtd_num) -+ goto out_error; -+ -+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT); -+ if (!lib->ubi_vol) -+ goto out_error; -+ -+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE); -+ if (!lib->vol_type) -+ goto out_error; -+ -+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV); -+ if (!lib->vol_dev) -+ goto out_error; -+ -+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT); -+ if (!lib->vol_alignment) -+ goto out_error; -+ -+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES); -+ if (!lib->vol_data_bytes) -+ goto out_error; -+ -+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS); -+ if (!lib->vol_rsvd_ebs) -+ goto out_error; -+ -+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE); -+ if (!lib->vol_eb_size) -+ goto out_error; -+ -+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED); -+ if (!lib->vol_corrupted) -+ goto out_error; -+ -+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME); -+ if (!lib->vol_name) -+ goto out_error; -+ -+ if (read_positive_int(lib->ubi_version, &version)) -+ goto out_error; -+ if (version != LIBUBI_UBI_VERSION) { -+ errmsg("this library was made for UBI version %d, but UBI " -+ "version %d is detected\n", LIBUBI_UBI_VERSION, version); -+ goto out_error; -+ } -+ -+ return lib; -+ -+out_error: -+ libubi_close((libubi_t)lib); -+ return NULL; -+} -+ -+void libubi_close(libubi_t desc) -+{ -+ struct libubi *lib = (struct libubi *)desc; -+ -+ free(lib->vol_name); -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_mtd_num); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->ctrl_dev); -+ free(lib->sysfs_ctrl); -+ free(lib->sysfs); -+ free(lib); -+} -+ -+int ubi_attach_mtd(libubi_t desc, const char *node, -+ struct ubi_attach_request *req) -+{ -+ int fd, ret; -+ struct ubi_attach_req r; -+ -+ memset(&r, sizeof(struct ubi_attach_req), '\0'); -+ -+ desc = desc; -+ r.ubi_num = req->dev_num; -+ r.mtd_num = req->mtd_num; -+ r.vid_hdr_offset = req->vid_hdr_offset; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCATT, &r); -+ close(fd); -+ if (ret == -1) -+ return -1; -+ -+ req->dev_num = r.ubi_num; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+ return ret; -+} -+ -+int ubi_detach_mtd(libubi_t desc, const char *node, int mtd_num) -+{ -+ int ret, ubi_dev; -+ -+ ret = mtd_num2ubi_dev(desc, mtd_num, &ubi_dev); -+ if (ret == -1) { -+ errno = ENODEV; -+ return ret; -+ } -+ -+ return ubi_remove_dev(desc, node, ubi_dev); -+} -+ -+int ubi_remove_dev(libubi_t desc, const char *node, int ubi_dev) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ ret = ioctl(fd, UBI_IOCDET, &ubi_dev); -+ if (ret == -1) -+ goto out_close; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_node_type(libubi_t desc, const char *node) -+{ -+ struct stat st; -+ struct ubi_info info; -+ int i, fd, major, minor; -+ struct libubi *lib = (struct libubi *)desc; -+ char file[strlen(lib->ubi_vol) + 100]; -+ -+ if (lstat(node, &st)) -+ return -1; -+ -+ if (!S_ISCHR(st.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(st.st_rdev); -+ minor = minor(st.st_rdev); -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ -+ ret = dev_get_major(lib, i, &major1, &minor1); -+ if (ret) { -+ if (errno == ENOENT) -+ continue; -+ return -1; -+ } -+ -+ if (major1 == major) -+ break; -+ } -+ -+ if (i > info.highest_dev_num) { -+ /* -+ * The character device node does not correspond to any -+ * existing UBI device or volume, but we do not want to return -+ * any error number in this case, to indicate the fact that it -+ * could be a UBI device/volume, but it doesn't. -+ */ -+ errno = 0; -+ return -1; -+ } -+ -+ if (minor == 0) -+ return 1; -+ -+ /* This is supposdely an UBI volume device node */ -+ sprintf(file, lib->ubi_vol, i, minor - 1); -+ fd = open(file, O_RDONLY); -+ if (fd == -1) { -+ errno = 0; -+ return -1; -+ } -+ -+ return 2; -+} -+ -+int ubi_get_info(libubi_t desc, struct ubi_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_info)); -+ -+ if (read_major(lib->ctrl_dev, &info->ctrl_major, &info->ctrl_minor)) { -+ /* -+ * Older UBI versions did not have control device, so we do not -+ * panic here for compatibility reasons. May be few years later -+ * we could return -1 here, but for now just set major:minor to -+ * -1. -+ */ -+ info->ctrl_major = info->ctrl_minor = -1; -+ } -+ -+ /* -+ * We have to scan the UBI sysfs directory to identify how many UBI -+ * devices are present. -+ */ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return sys_errmsg("cannot open %s", lib->sysfs_ubi); -+ -+ info->lowest_dev_num = INT_MAX; -+ while (1) { -+ int dev_num, ret; -+ char tmp_buf[256]; -+ -+ errno = 0; -+ dirent = readdir(sysfs_ubi); -+ if (!dirent) -+ break; -+ -+ if (strlen(dirent->d_name) > 256) { -+ errmsg("invalid entry in %s: \"%s\"", -+ lib->sysfs_ubi, dirent->d_name); -+ goto out_close; -+ } -+ -+ ret = sscanf(dirent->d_name, UBI_DEV_NAME_PATT"%s", -+ &dev_num, tmp_buf); -+ if (ret == 1) { -+ info->dev_count += 1; -+ if (dev_num > info->highest_dev_num) -+ info->highest_dev_num = dev_num; -+ if (dev_num < info->lowest_dev_num) -+ info->lowest_dev_num = dev_num; -+ } -+ } -+ -+ if (!dirent && errno) { -+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); -+ goto out_close; -+ } -+ -+ if (closedir(sysfs_ubi)) -+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi); -+ -+ if (info->lowest_dev_num == INT_MAX) -+ info->lowest_dev_num = 0; -+ -+ if (read_positive_int(lib->ubi_version, &info->version)) -+ return -1; -+ -+ return 0; -+ -+out_close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) -+{ -+ int fd, ret; -+ struct ubi_mkvol_req r; -+ size_t n; -+ -+ memset(&r, sizeof(struct ubi_mkvol_req), '\0'); -+ -+ desc = desc; -+ r.vol_id = req->vol_id; -+ r.alignment = req->alignment; -+ r.bytes = req->bytes; -+ r.vol_type = req->vol_type; -+ -+ n = strlen(req->name); -+ if (n > UBI_MAX_VOLUME_NAME) -+ return -1; -+ -+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1); -+ r.name_len = n; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCMKVOL, &r); -+ if (ret == -1) -+ goto out_close; -+ -+ req->vol_id = r.vol_id; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); -+ if (ret == -1) -+ goto out_close; -+ -+#ifdef UDEV_SETTLE_HACK -+ if (system("udevsettle") == -1) -+ return -1; -+#endif -+ -+out_close: -+ close(fd); -+ return ret; -+} -+ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) -+{ -+ int fd, ret; -+ struct ubi_rsvol_req req; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ req.bytes = bytes; -+ req.vol_id = vol_id; -+ -+ ret = ioctl(fd, UBI_IOCRSVOL, &req); -+ close(fd); -+ return ret; -+} -+ -+int ubi_update_start(libubi_t desc, int fd, long long bytes) -+{ -+ desc = desc; -+ if (ioctl(fd, UBI_IOCVOLUP, &bytes)) -+ return -1; -+ return 0; -+} -+ -+int ubi_leb_read_start(int fd, struct ubi_leb *leb) -+{ -+ return ioctl(fd, UBI_IOCLEBREAD, leb); -+} -+ -+int ubi_leb_change_start(libubi_t desc, int fd, int lnum, int bytes, int dtype) -+{ -+ struct ubi_leb_change_req req; -+ -+ desc = desc; -+ memset(&req, 0, sizeof(struct ubi_leb_change_req)); -+ req.lnum = lnum; -+ req.bytes = bytes; -+ req.dtype = dtype; -+ -+ if (ioctl(fd, UBI_IOCEBCH, &req)) -+ return -1; -+ return 0; -+} -+ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_dev_info)); -+ info->dev_num = dev_num; -+ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_vol_num = INT_MAX; -+ -+ while (1) { -+ int vol_id, ret, devno; -+ char tmp_buf[256]; -+ -+ errno = 0; -+ dirent = readdir(sysfs_ubi); -+ if (!dirent) -+ break; -+ -+ if (strlen(dirent->d_name) > 256) { -+ errmsg("invalid entry in %s: \"%s\"", -+ lib->sysfs_ubi, dirent->d_name); -+ goto out_close; -+ } -+ -+ ret = sscanf(dirent->d_name, UBI_VOL_NAME_PATT"%s", &devno, &vol_id, tmp_buf); -+ if (ret == 2 && devno == dev_num) { -+ info->vol_count += 1; -+ if (vol_id > info->highest_vol_num) -+ info->highest_vol_num = vol_id; -+ if (vol_id < info->lowest_vol_num) -+ info->lowest_vol_num = vol_id; -+ } -+ } -+ -+ if (!dirent && errno) { -+ sys_errmsg("readdir failed on \"%s\"", lib->sysfs_ubi); -+ goto out_close; -+ } -+ -+ if (closedir(sysfs_ubi)) -+ return sys_errmsg("closedir failed on \"%s\"", lib->sysfs_ubi); -+ -+ if (info->lowest_vol_num == INT_MAX) -+ info->lowest_vol_num = 0; -+ -+ if (dev_get_major(lib, dev_num, &info->major, &info->minor)) -+ return -1; -+ -+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_lebs)) -+ return -1; -+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_lebs)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count)) -+ return -1; -+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->leb_size)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd)) -+ return -1; -+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec)) -+ return -1; -+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count)) -+ return -1; -+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) -+ return -1; -+ -+ info->avail_bytes = info->avail_lebs * info->leb_size; -+ info->total_bytes = info->total_lebs * info->leb_size; -+ -+ return 0; -+ -+out_close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) -+{ -+ int dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ if (dev_node2num(lib, node, &dev_num)) -+ return -1; -+ -+ return ubi_get_dev_info1(desc, dev_num, info); -+} -+ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info) -+{ -+ int ret; -+ struct libubi *lib = (struct libubi *)desc; -+ char buf[50]; -+ -+ memset(info, '\0', sizeof(struct ubi_vol_info)); -+ info->dev_num = dev_num; -+ info->vol_id = vol_id; -+ -+ if (dev_get_major(lib, dev_num, &info->dev_major, &info->dev_minor)) -+ return -1; -+ if (vol_get_major(lib, dev_num, vol_id, &info->major, &info->minor)) -+ return -1; -+ -+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, buf, 50); -+ if (ret < 0) -+ return -1; -+ -+ if (strncmp(buf, "static\n", ret) == 0) -+ info->type = UBI_STATIC_VOLUME; -+ else if (strncmp(buf, "dynamic\n", ret) == 0) -+ info->type = UBI_DYNAMIC_VOLUME; -+ else { -+ errmsg("bad value at \"%s\"", buf); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id, -+ &info->alignment); -+ if (ret) -+ return -1; -+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id, -+ &info->data_bytes); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_lebs); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->leb_size); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id, -+ &info->corrupted); -+ if (ret) -+ return -1; -+ info->rsvd_bytes = info->leb_size * info->rsvd_lebs; -+ -+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, -+ UBI_VOL_NAME_MAX + 2); -+ if (ret < 0) -+ return -1; -+ -+ info->name[ret - 1] = '\0'; -+ return 0; -+} -+ -+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) -+{ -+ int vol_id, dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ if (vol_node2nums(lib, node, &dev_num, &vol_id)) -+ return -1; -+ -+ return ubi_get_vol_info1(desc, dev_num, vol_id, info); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubi_int.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_INT_H__ -+#define __LIBUBI_INT_H__ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * The below are pre-define UBI file and directory names. -+ * -+ * Note, older kernels put 'ubiX_Y' directories straight to '/sys/class/ubi/'. -+ * New kernels puts 'ubiX_Y' directories to '/sys/class/ubi/ubiX/', which is -+ * saner. And for compatibility reasons it also puts symlinks to 'ubiX_Y' -+ * directories to '/sys/class/ubi/'. For now libubi assumes old layout. -+ */ -+ -+#define SYSFS_UBI "class/ubi" -+#define SYSFS_CTRL "class/misc/ubi_ctrl/" -+ -+#define CTRL_DEV "dev" -+ -+#define UBI_VER "version" -+#define UBI_DEV_NAME_PATT "ubi%d" -+ -+#define DEV_DEV "dev" -+#define DEV_AVAIL_EBS "avail_eraseblocks" -+#define DEV_TOTAL_EBS "total_eraseblocks" -+#define DEV_BAD_COUNT "bad_peb_count" -+#define DEV_EB_SIZE "eraseblock_size" -+#define DEV_MAX_EC "max_ec" -+#define DEV_MAX_RSVD "reserved_for_bad" -+#define DEV_MAX_VOLS "max_vol_count" -+#define DEV_MIN_IO_SIZE "min_io_size" -+#define DEV_MTD_NUM "mtd_num" -+ -+#define UBI_VOL_NAME_PATT "ubi%d_%d" -+#define VOL_TYPE "type" -+#define VOL_DEV "dev" -+#define VOL_ALIGNMENT "alignment" -+#define VOL_DATA_BYTES "data_bytes" -+#define VOL_RSVD_EBS "reserved_ebs" -+#define VOL_EB_SIZE "usable_eb_size" -+#define VOL_CORRUPTED "corrupted" -+#define VOL_NAME "name" -+ -+/** -+ * libubi - UBI library description data structure. -+ * @sysfs: sysfs file system path -+ * @sysfs_ctrl: UBI control device directory in sysfs -+ * @ctrl_dev: UBI control device major/minor numbers sysfs file -+ * @sysfs_ubi: UBI directory in sysfs -+ * @ubi_dev: UBI device sysfs directory pattern -+ * @ubi_version: UBI version file sysfs path -+ * @dev_dev: UBI device major/minor numbers file pattern -+ * @dev_avail_ebs: count of available eraseblocks sysfs path pattern -+ * @dev_total_ebs: total eraseblocks count sysfs path pattern -+ * @dev_bad_count: count of bad eraseblocks sysfs path pattern -+ * @dev_eb_size: size of UBI device's eraseblocks sysfs path pattern -+ * @dev_max_ec: maximum erase counter sysfs path pattern -+ * @dev_bad_rsvd: count of physical eraseblock reserved for bad eraseblocks -+ * handling -+ * @dev_max_vols: maximum volumes number count sysfs path pattern -+ * @dev_min_io_size: minimum I/O unit size sysfs path pattern -+ * @ubi_vol: UBI volume sysfs directory pattern -+ * @vol_type: volume type sysfs path pattern -+ * @vol_dev: volume major/minor numbers file pattern -+ * @vol_alignment: volume alignment sysfs path pattern -+ * @vol_data_bytes: volume data size sysfs path pattern -+ * @vol_rsvd_ebs: volume reserved size sysfs path pattern -+ * @vol_eb_size: volume eraseblock size sysfs path pattern -+ * @vol_corrupted: volume corruption flag sysfs path pattern -+ * @vol_name: volume name sysfs path pattern -+ */ -+struct libubi -+{ -+ char *sysfs; -+ char *sysfs_ctrl; -+ char *ctrl_dev; -+ char *sysfs_ubi; -+ char *ubi_dev; -+ char *ubi_version; -+ char *dev_dev; -+ char *dev_avail_ebs; -+ char *dev_total_ebs; -+ char *dev_bad_count; -+ char *dev_eb_size; -+ char *dev_max_ec; -+ char *dev_bad_rsvd; -+ char *dev_max_vols; -+ char *dev_min_io_size; -+ char *dev_mtd_num; -+ char *ubi_vol; -+ char *vol_type; -+ char *vol_dev; -+ char *vol_alignment; -+ char *vol_data_bytes; -+ char *vol_rsvd_ebs; -+ char *vol_eb_size; -+ char *vol_corrupted; -+ char *vol_name; -+ char *vol_max_count; -+}; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_INT_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/libubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,335 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Generating UBI images. -+ * -+ * Authors: Oliver Lohmann -+ * Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include "crc32.h" -+#include "common.h" -+ -+#define PROGRAM_NAME "libubigen" -+ -+/** -+ * ubigen_info_init - initialize libubigen. -+ * @ui: libubigen information -+ * @peb_size: flash physical eraseblock size -+ * @min_io_size: flash minimum input/output unit size -+ * @subpage_size: flash sub-page, if present (has to be equivalent to -+ * @min_io_size if does not exist) -+ * @vid_hdr_offs: offset of the VID header -+ * @ubi_ver: UBI version -+ */ -+void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size, -+ int subpage_size, int vid_hdr_offs, int ubi_ver) -+{ -+ if (!vid_hdr_offs) { -+ vid_hdr_offs = UBI_EC_HDR_SIZE + subpage_size - 1; -+ vid_hdr_offs /= subpage_size; -+ vid_hdr_offs *= subpage_size; -+ } -+ -+ ui->peb_size = peb_size; -+ ui->min_io_size = min_io_size; -+ ui->vid_hdr_offs = vid_hdr_offs; -+ ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1; -+ ui->data_offs /= min_io_size; -+ ui->data_offs *= min_io_size; -+ ui->leb_size = peb_size - ui->data_offs; -+ ui->ubi_ver = ubi_ver; -+ -+ ui->max_volumes = ui->leb_size / UBI_VTBL_RECORD_SIZE; -+ if (ui->max_volumes > UBI_MAX_VOLUMES) -+ ui->max_volumes = UBI_MAX_VOLUMES; -+ ui->vtbl_size = ui->max_volumes * UBI_VTBL_RECORD_SIZE; -+} -+ -+/** -+ * ubigen_create_empty_vtbl - creates empty volume table. -+ * -+ * This function creates an empty volume table and returns a pointer to it in -+ * case of success and %NULL in case of failure. The returned object has to be -+ * freed with 'free()' call. -+ */ -+struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui) -+{ -+ struct ubi_vtbl_record *vtbl; -+ int i; -+ -+ vtbl = calloc(1, ui->vtbl_size); -+ if (!vtbl) { -+ sys_errmsg("cannot allocate %d bytes of memory", ui->vtbl_size); -+ return NULL; -+ } -+ -+ for (i = 0; i < ui->max_volumes; i++) { -+ uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i], -+ UBI_VTBL_RECORD_SIZE_CRC); -+ vtbl[i].crc = cpu_to_be32(crc); -+ } -+ -+ return vtbl; -+} -+ -+/** -+ * ubigen_add_volume - add a volume to the volume table. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @vtbl: volume table to add to -+ * -+ * This function adds volume described by input parameters to the volume table -+ * @vtbl. -+ */ -+int ubigen_add_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vtbl_record *vtbl) -+{ -+ struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id]; -+ uint32_t tmp; -+ -+ if (vi->id >= ui->max_volumes) -+ return errmsg("too high volume id %d, max. volumes is %d", -+ vi->id, ui->max_volumes); -+ -+ if (vi->alignment >= ui->leb_size) -+ return errmsg("too large alignment %d, max is %d (LEB size)", -+ vi->alignment, ui->leb_size); -+ -+ memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record)); -+ tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size; -+ vtbl_rec->reserved_pebs = cpu_to_be32(tmp); -+ vtbl_rec->alignment = cpu_to_be32(vi->alignment); -+ vtbl_rec->vol_type = vi->type; -+ tmp = ui->leb_size % vi->alignment; -+ vtbl_rec->data_pad = cpu_to_be32(tmp); -+ vtbl_rec->flags = vi->flags; -+ -+ memcpy(vtbl_rec->name, vi->name, vi->name_len); -+ vtbl_rec->name[vi->name_len] = '\0'; -+ vtbl_rec->name_len = cpu_to_be16(vi->name_len); -+ -+ tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); -+ vtbl_rec->crc = cpu_to_be32(tmp); -+ return 0; -+} -+ -+/** -+ * ubigen_init_ec_hdr - initialize EC header. -+ * @ui: libubigen information -+ * @hdr: the EC header to initialize -+ * @ec: erase counter value -+ */ -+void ubigen_init_ec_hdr(const struct ubigen_info *ui, -+ struct ubi_ec_hdr *hdr, long long ec) -+{ -+ uint32_t crc; -+ -+ memset(hdr, '\0', sizeof(struct ubi_ec_hdr)); -+ -+ hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); -+ hdr->version = ui->ubi_ver; -+ hdr->ec = cpu_to_be64(ec); -+ hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs); -+ -+ hdr->data_offset = cpu_to_be32(ui->data_offs); -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+} -+ -+/** -+ * init_vid_hdr - initialize VID header. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @hdr: the VID header to initialize -+ * @lnum: logical eraseblock number -+ * @data: the contents of the LEB (static volumes only) -+ * @data_size: amount of data in this LEB (static volumes only) -+ * -+ * Note, @used_ebs, @data and @data_size are ignored in case of dynamic -+ * volumes. -+ */ -+static void init_vid_hdr(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, -+ struct ubi_vid_hdr *hdr, int lnum, -+ const void *data, int data_size) -+{ -+ uint32_t crc; -+ -+ memset(hdr, '\0', sizeof(struct ubi_vid_hdr)); -+ -+ hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); -+ hdr->version = ui->ubi_ver; -+ hdr->vol_type = vi->type; -+ hdr->vol_id = cpu_to_be32(vi->id); -+ hdr->lnum = cpu_to_be32(lnum); -+ hdr->data_pad = cpu_to_be32(vi->data_pad); -+ hdr->compat = vi->compat; -+ -+ if (vi->type == UBI_VID_STATIC) { -+ hdr->data_size = cpu_to_be32(data_size); -+ hdr->used_ebs = cpu_to_be32(vi->used_ebs); -+ crc = crc32(UBI_CRC32_INIT, data, data_size); -+ hdr->data_crc = cpu_to_be32(crc); -+ } -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+} -+ -+/** -+ * ubigen_write_volume - write UBI volume. -+ * @ui: libubigen information -+ * @vi: volume information -+ * @ec: erase coutner value to put to EC headers -+ * @bytes: volume size in bytes -+ * @in: input file descriptor (has to be properly seeked) -+ * @out: output file descriptor -+ * -+ * This function reads the contents of the volume from the input file @in and -+ * writes the UBI volume to the output file @out. Returns zero on success and -+ * %-1 on failure. -+ */ -+int ubigen_write_volume(const struct ubigen_info *ui, -+ const struct ubigen_vol_info *vi, long long ec, -+ long long bytes, int in, int out) -+{ -+ int len = vi->usable_leb_size, rd, lnum = 0; -+ char inbuf[ui->leb_size+sizeof(unsigned int)], outbuf[ui->peb_size]; -+ -+ if (vi->id >= ui->max_volumes) -+ return errmsg("too high volume id %d, max. volumes is %d", -+ vi->id, ui->max_volumes); -+ -+ if (vi->alignment >= ui->leb_size) -+ return errmsg("too large alignment %d, max is %d (LEB size)", -+ vi->alignment, ui->leb_size); -+ -+ memset(outbuf, 0xFF, ui->data_offs); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec); -+ -+ while (bytes) { -+ int l; -+ struct ubi_vid_hdr *vid_hdr; -+ -+ if (bytes < len) -+ len = bytes; -+ bytes -= len; -+ -+ l = len; -+ do { -+ rd = read(in, inbuf + len - l, sizeof(unsigned int)); -+ if (rd != sizeof(unsigned int)) -+ return sys_errmsg("cannot read leb lnum from the input file"); -+ -+ rd = read(in, inbuf + len - l + sizeof(unsigned int), l); -+ if (rd != l) -+ return sys_errmsg("cannot read %d bytes from the input file", l); -+ -+ l -= rd; -+ } while (l); -+ -+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); -+ lnum = ((unsigned int *)inbuf)[0]; -+ init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf+sizeof(unsigned int), len); -+ -+ memcpy(outbuf + ui->data_offs, inbuf+sizeof(unsigned int), len); -+ memset(outbuf + ui->data_offs + len, 0xFF, -+ ui->peb_size - ui->data_offs - len); -+ -+ if (write(out, outbuf, ui->peb_size) != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes to the output file", ui->peb_size); -+ -+// lnum += 1; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubigen_write_layout_vol - write UBI layout volume -+ * @ui: libubigen information -+ * @peb1: physical eraseblock number to write the first volume table copy -+ * @peb2: physical eraseblock number to write the second volume table copy -+ * @ec1: erase counter value for @peb1 -+ * @ec2: erase counter value for @peb1 -+ * @vtbl: volume table -+ * @fd: output file descriptor seeked to the proper position -+ * -+ * This function creates the UBI layout volume which contains 2 copies of the -+ * volume table. Returns zero in case of success and %-1 in case of failure. -+ */ -+int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2, -+ long long ec1, long long ec2, -+ struct ubi_vtbl_record *vtbl, int fd) -+{ -+ int ret; -+ struct ubigen_vol_info vi; -+ char outbuf[ui->peb_size]; -+ struct ubi_vid_hdr *vid_hdr; -+ off_t seek; -+ -+ vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS; -+ vi.id = UBI_LAYOUT_VOLUME_ID; -+ vi.alignment = UBI_LAYOUT_VOLUME_ALIGN; -+ vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN; -+ vi.usable_leb_size = ui->leb_size - vi.data_pad; -+ vi.data_pad = ui->leb_size - vi.usable_leb_size; -+ vi.type = UBI_LAYOUT_VOLUME_TYPE; -+ vi.name = UBI_LAYOUT_VOLUME_NAME; -+ vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME); -+ vi.compat = UBI_LAYOUT_VOLUME_COMPAT; -+ -+ memset(outbuf, 0xFF, ui->data_offs); -+ vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]); -+ memcpy(outbuf + ui->data_offs, vtbl, ui->vtbl_size); -+ memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF, -+ ui->peb_size - ui->data_offs - ui->vtbl_size); -+ -+ seek = peb1 * ui->peb_size; -+ if (lseek(fd, seek, SEEK_SET) != seek) -+ return sys_errmsg("cannot seek output file"); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1); -+ init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0); -+ ret = write(fd, outbuf, ui->peb_size); -+ if (ret != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes", ui->peb_size); -+ -+ seek = peb2 * ui->peb_size; -+ if (lseek(fd, seek, SEEK_SET) != seek) -+ return sys_errmsg("cannot seek output file"); -+ ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2); -+ init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0); -+ ret = write(fd, outbuf, ui->peb_size); -+ if (ret != ui->peb_size) -+ return sys_errmsg("cannot write %d bytes", ui->peb_size); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiattach.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,205 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to attach MTD devices to UBI. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubiattach" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int mtdn; -+ int vidoffs; -+ const char *node; -+}; -+ -+static struct args args = { -+ .devn = UBI_DEV_NUM_AUTO, -+ .mtdn = -1, -+ .vidoffs = 0, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to attach MTD device to UBI."; -+ -+static const char *optionsstr = -+"-d, --devn= the number to assign to the newly created UBI device\n" -+" (the number is assigned automatically if this is not\n" -+" specified\n" -+"-m, --mtdn= MTD device number to attach\n" -+"-O, --vid-hdr-offset VID header offset (do not specify this unless you\n" -+" really know what you do and the optimal defaults will\n" -+" be used)\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-m ] [-d ]\n" -+"\t\t[--mtdn=] [--devn ]\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - attach MTD device 0 (mtd0) to UBI\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI and\n" -+" and create UBI device number 3 (ubi3)"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "m:d:O:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'm': -+ args.mtdn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.mtdn < 0) -+ return errmsg("bad MTD device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'O': -+ args.vidoffs = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vidoffs <= 0) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("UBI control device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI control device specified (use -h for help)"); -+ -+ if (args.mtdn == -1) -+ return errmsg("MTD device number was not specified (use -h for help)"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_info ubi_info; -+ struct ubi_dev_info dev_info; -+ struct ubi_attach_request req; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ /* -+ * Make sure the kernel is fresh enough and this feature is supported. -+ */ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) { -+ sys_errmsg("cannot get UBI information"); -+ goto out_libubi; -+ } -+ -+ if (ubi_info.ctrl_major == -1) { -+ errmsg("MTD attach/detach feature is not supported by your kernel"); -+ goto out_libubi; -+ } -+ -+ req.dev_num = args.devn; -+ req.mtd_num = args.mtdn; -+ req.vid_hdr_offset = args.vidoffs; -+ -+ err = ubi_attach_mtd(libubi, args.node, &req); -+ if (err) { -+ sys_errmsg("cannot attach mtd%d", args.mtdn); -+ goto out_libubi; -+ } -+ -+ /* Print some information about the new UBI device */ -+ err = ubi_get_dev_info1(libubi, req.dev_num, &dev_info); -+ if (err) { -+ sys_errmsg("cannot get information about newly created UBI device"); -+ goto out_libubi; -+ } -+ -+ printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs); -+ ubiutils_print_bytes(dev_info.total_bytes, 0); -+ printf("), available %d LEBs (", dev_info.avail_lebs); -+ ubiutils_print_bytes(dev_info.avail_bytes, 0); -+ printf("), LEB size "); -+ ubiutils_print_bytes(dev_info.leb_size, 1); -+ printf("\n"); -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,124 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Calculate CRC32 with UBI start value (0xFFFFFFFF) for a given binary image. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "crc32.h" -+#include "common.h" -+ -+#define BUFSIZE 4096 -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubicrc32" -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to calculate CRC32 with UBI start value (0xFFFFFFFF)"; -+ -+static const char *optionsstr = -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [--help]"; -+ -+static const struct option long_options[] = { -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err = 0; -+ uint32_t crc = UBI_CRC32_INIT; -+ char buf[BUFSIZE]; -+ FILE *fp; -+ -+ if (argc > 1) { -+ fp = fopen(argv[1], "r"); -+ if (!fp) -+ return sys_errmsg("cannot open \"%s\"", argv[1]); -+ } else -+ fp = stdin; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return err; -+ -+ while (!feof(fp)) { -+ size_t read; -+ -+ read = fread(buf, 1, BUFSIZE, fp); -+ if (ferror(fp)) { -+ sys_errmsg("cannot read input file"); -+ err = -1; -+ goto out_close; -+ } -+ crc = crc32(crc, buf, read); -+ } -+ -+ printf("0x%08x\n", crc); -+ -+out_close: -+ if (fp != stdin) -+ fclose(fp); -+ return err; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcsf.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,94 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to generate input file CRC -+ * -+ * Authors: Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubicrcsf" -+#define UBI_LEB_SIZE 258048 -+#define BUF_SIZE (UBI_LEB_SIZE + sizeof(unsigned int)) -+ -+/* -+ * usage: $ubicrcsf ubifs.img -+ */ -+int main(int argc, char * const argv[]) -+{ -+ int err, ifd, tmp, i; -+ int crc_sum = 0; -+ struct stat st; -+ char *buf=NULL; -+ -+ buf = malloc(BUF_SIZE); -+ if(buf==NULL){ -+ printf("no mem\n"); -+ goto out_free; -+ } -+ -+ err = stat(argv[1], &st); -+ if (err < 0) { -+ printf("stat failed on \"%s\"", argv[1]); -+ goto out_free; -+ } -+ -+ ifd = open(argv[1], O_RDONLY); -+ if (ifd == -1) { -+ printf("cannot open \"%s\"", argv[1]); -+ goto out_close; -+ } -+ -+ tmp = st.st_size/BUF_SIZE; -+ -+ for( i=0; i< tmp; i++ ){ -+ err = read(ifd, buf, BUF_SIZE); -+ if (err != BUF_SIZE) { -+ printf("read error\n"); -+ goto out_close; -+ } -+ crc_sum = crc32(crc_sum, &buf[sizeof(unsigned int)], UBI_LEB_SIZE); -+ } -+ -+ printf("CRC sum: %d\n",crc_sum); -+ free(buf); -+ close(ifd); -+ return 0; -+out_close: -+ close(ifd); -+out_free: -+ free(buf); -+ return -1; -+} -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubicrcvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,221 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ * Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubicrcfatvol" -+ -+struct args { -+ const char *node; -+ long long size; -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to read UBI volumes data and generate CRC."; -+ -+static const char *optionsstr = -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"-s, --read size\n" -+; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-s] [-h] [-V] [--help]\n" -+"\t\t\t[--version] \n\n" -+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 \n"; -+ -+struct option long_options[] = { -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:sh?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 's': -+ args.size = ubiutils_get_bytes(optarg); -+ if (args.size <= 0) -+ return errmsg("bad read size: \"%s\"", optarg); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ -+ return 0; -+} -+ -+static int crc_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int fd; -+ struct ubi_leb leb; -+ int i, tmp; -+ int crc_sum = 0; -+ -+ leb.buf = malloc(vol_info->leb_size); -+ if (!leb.buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ fd = open(args.node, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ for(i=0; i < vol_info->rsvd_lebs ; i++){ -+ leb.lnum = i; -+ tmp = ubi_leb_read_start(fd, &leb); -+ if(tmp == 1) -+ continue; -+ else if(tmp == 0){ -+ crc_sum = crc32(crc_sum, leb.buf, vol_info->leb_size); -+ }else{ -+ printf("LEB %d read error\n", i); -+ goto out_close; -+ } -+ } -+ -+ close(fd); -+ free(leb.buf); -+ printf("CRC sum: %d\n",crc_sum); -+ return 0; -+ goto out_close; -+out_close: -+ close(fd); -+out_free: -+ free(leb.buf); -+ return -1; -+} -+ -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ err = crc_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+ -+} -+ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidetach.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,181 @@ -+/* -+ * Copyright (C) 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to delete UBI devices (detach MTD devices from UBI). -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubidetach" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int mtdn; -+ const char *node; -+}; -+ -+static struct args args = { -+ .devn = UBI_DEV_NUM_AUTO, -+ .mtdn = -1, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+" - a tool to remove UBI devices (detach MTD devices from UBI)"; -+ -+static const char *optionsstr = -+"-d, --devn= UBI device number to delete\n" -+"-m, --mtdn= or altrnatively, MTD device number to detach -\n" -+" this will delete corresponding UBI device\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-d ] [-m ]\n" -+"\t\t[--devn ] [--mtdn=]\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi_ctrl -d 2 - delete UBI device 2 (ubi2)\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi_ctrl -m 0 - detach MTD device 0 (mtd0)"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "m:d:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'm': -+ args.mtdn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.mtdn < 0) -+ return errmsg("bad MTD device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("UBI control device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI control device specified (use -h for help)"); -+ -+ if (args.mtdn == -1 && args.devn == -1) -+ return errmsg("neither MTD nor UBI devices were specified (use -h for help)"); -+ -+ if (args.mtdn != -1 && args.devn != -1) -+ return errmsg("specify either MTD or UBI device (use -h for help)"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_info ubi_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ /* -+ * Make sure the kernel is fresh enough and this feature is supported. -+ */ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) { -+ sys_errmsg("cannot get UBI information"); -+ goto out_libubi; -+ } -+ -+ if (ubi_info.ctrl_major == -1) { -+ errmsg("MTD detach/detach feature is not supported by your kernel"); -+ goto out_libubi; -+ } -+ -+ if (args.devn != -1) { -+ err = ubi_remove_dev(libubi, args.node, args.devn); -+ if (err) { -+ sys_errmsg("cannot remove ubi%d", args.devn); -+ goto out_libubi; -+ } -+ } else { -+ err = ubi_detach_mtd(libubi, args.node, args.mtdn); -+ if (err) { -+ sys_errmsg("cannot detach mtd%d", args.mtdn); -+ goto out_libubi; -+ } -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubidumpvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ * Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubidumpvol" -+ -+struct args { -+ int truncate; -+ const char *node; -+ const char *img; -+ /* For deprecated -d and -B options handling */ -+ int devn; -+ char dev_name[256]; -+ int broken_update; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to write data to UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= ID of UBI volume to update\n" -+"-t, --truncate truncate volume (wipe it out)\n" -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following are compatibility options which are deprecated, do not use them\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\"\n" -+"-B, --broken-update broken update, this is for testing"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" -+"\t\t\t[--version] \n\n" -+ "Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - dump UBI volume /dev/ubi0_1 to file \"fs.img\" \n"; -+ -+struct option long_options[] = { -+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ args.truncate = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ { -+ char *endp; -+ -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ } -+ -+ case 'B': -+ /* Handle deprecated -B option */ -+ warnmsg("-B is depricated and will be removed, do not use it"); -+ args.broken_update = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 2) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ args.img = argv[optind + 1]; -+ -+ return 0; -+} -+ -+static int dump_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int err, fd, ifd; -+ struct ubi_leb leb; -+ int i, tmp; -+ -+ leb.buf = malloc(vol_info->leb_size); -+ if (!leb.buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ fd = open(args.node, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ ifd = open(args.img, O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ifd == -1) { -+ sys_errmsg("cannot open \"%s\"", args.img); -+ goto out_close1; -+ } -+ -+ for(i=0; i < vol_info->rsvd_lebs; i++){ -+ leb.lnum = i; -+ tmp = ubi_leb_read_start(fd, &leb); -+ if(tmp == 1) -+ continue; -+ else if(tmp == 0){ -+ // write lnum -+ err = write(ifd, (char *)&leb.lnum, sizeof(leb.lnum)); -+ if (err != sizeof(leb.lnum)){ -+ perror("Image file write error\n"); -+ goto out_close; -+ } -+ // write LEB data -+ err = write(ifd, leb.buf, vol_info->leb_size); -+ if (err != vol_info->leb_size){ -+ perror("Image file write error\n"); -+ goto out_close; -+ } -+ }else{ -+ printf("LEB %d read error\n", i); -+ goto out_close; -+ } -+ } -+ -+ close(ifd); -+ close(fd); -+ free(leb.buf); -+ printf("Dump Volume succeed\n"); -+ return 0; -+ goto out_close; -+out_close: -+ close(ifd); -+out_close1: -+ close(fd); -+out_free: -+ free(leb.buf); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ if (!args.img && !args.truncate) -+ return errmsg("incorrect arguments, use -h for help"); -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ err = dump_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiformat.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,712 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to format MTD devices into UBI and flash UBI images. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include "crc32.h" -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubiformat" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ unsigned int yes:1; -+ unsigned int quiet:1; -+ unsigned int verbose:1; -+ unsigned int override_ec:1; -+ unsigned int novtbl:1; -+ int subpage_size; -+ int vid_hdr_offs; -+ int ubi_ver; -+ long long ec; -+ const char *image; -+ const char *node; -+}; -+ -+static struct args args = -+{ -+ .ubi_ver = 1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to format MTD devices and flash UBI images"; -+ -+static const char *optionsstr = -+"-s, --sub-page-size= minimum input/output unit used for UBI\n" -+" headers, e.g. sub-page size in case of NAND\n" -+" flash (equivalent to the minimum input/output\n" -+" unit size by default)\n" -+"-O, --vid-hdr-offset= offset if the VID header from start of the\n" -+" physical eraseblock (default is the next\n" -+" minimum I/O unit or sub-page after the EC\n" -+" header)\n" -+"-n, --no-volume-table only erase all eraseblock and preserve erase\n" -+" counters, do not write empty volume table\n" -+"-f, --flash-image= flash image file\n" -+"-e, --erase-counter= use as the erase counter value for all\n" -+" eraseblocks\n" -+"-y, --yes assume the answer is \"yes\" for all question\n" -+" this program would otherwise ask\n" -+"-q, --quiet suppress progress percentage information\n" -+"-v, --verbose be verbose\n" -+"-x, --ubi-ver= UBI version number to put to EC headers\n" -+" (default is 1)\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [-V] [-y] [-q] [-v]\n" -+"\t\t\t[-x ] [-E ] [-s ] [-O ] [-n]\n" -+"\t\t\t[--help] [--version] [--yes] [--verbose] [--quiet]\n" -+"\t\t\t[--ec=] [--vid-hdr-offset=]\n" -+"\t\t\t[--ubi-ver=] [--no-volume-table]\n\n" -+ -+"Example 1: " PROGRAM_NAME " /dev/mtd0 -y - format MTD device number 0 and do\n" -+" not ask questions.\n" -+"Example 2: " PROGRAM_NAME " /dev/mtd0 -q -e 0 - format MTD device number 0,\n" -+" be quiet and force erase counter value 0."; -+ -+static const struct option long_options[] = { -+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "no-volume-table", .has_arg = 0, .flag = NULL, .val = 'n' }, -+ { .name = "flash-image", .has_arg = 0, .flag = NULL, .val = 'f' }, -+ { .name = "yes", .has_arg = 0, .flag = NULL, .val = 'y' }, -+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, -+ { .name = "quiet", .has_arg = 0, .flag = NULL, .val = 'q' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "nh?Vyqve:x:s:O:f:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 's': -+ args.subpage_size = ubiutils_get_bytes(optarg); -+ if (args.subpage_size <= 0) -+ return errmsg("bad sub-page size: \"%s\"", optarg); -+ if (!is_power_of_2(args.subpage_size)) -+ return errmsg("sub-page size should be power of 2"); -+ break; -+ -+ case 'O': -+ args.vid_hdr_offs = strtoul(optarg, &endp, 0); -+ if (args.vid_hdr_offs <= 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ break; -+ -+ case 'e': -+ args.ec = strtoull(optarg, &endp, 0); -+ if (args.ec <= 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad erase counter value: \"%s\"", optarg); -+ if (args.ec >= EC_MAX) -+ return errmsg("too high erase %llu, counter, max is %u", args.ec, EC_MAX); -+ args.override_ec = 1; -+ break; -+ -+ case 'f': -+ args.image = optarg; -+ break; -+ -+ case 'n': -+ args.novtbl = 1; -+ break; -+ -+ case 'y': -+ args.yes = 1; -+ break; -+ -+ case 'q': -+ args.quiet = 1; -+ break; -+ -+ case 'x': -+ args.ubi_ver = strtoul(optarg, &endp, 0); -+ if (args.ubi_ver < 0 || *endp != '\0' || endp == optarg) -+ return errmsg("bad UBI version: \"%s\"", optarg); -+ break; -+ -+ case 'v': -+ args.verbose = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (args.quiet && args.verbose) -+ return errmsg("using \"-q\" and \"-v\" at the same time does not make sense"); -+ -+ if (optind == argc) -+ return errmsg("MTD device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one MTD device specified (use -h for help)"); -+ -+ if (args.image && args.novtbl) -+ return errmsg("-n cannot be used together with -f"); -+ -+ args.node = argv[optind]; -+ return 0; -+} -+ -+static int want_exit(void) -+{ -+ char buf[4]; -+ -+ while (1) { -+ normsg_cont("continue? (yes/no) "); -+ scanf("%3s", buf); -+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) -+ return 0; -+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) -+ return 1; -+ } -+} -+ -+static int answer_is_yes(void) -+{ -+ char buf[4]; -+ -+ while (1) { -+ scanf("%3s", buf); -+ if (!strncmp(buf, "yes", 3) || !strncmp(buf, "y", 1)) -+ return 1; -+ if (!strncmp(buf, "no", 2) || !strncmp(buf, "n", 1)) -+ return 0; -+ } -+} -+ -+static void print_bad_eraseblocks(const struct mtd_info *mtd, -+ const struct ubi_scan_info *si) -+{ -+ int first = 1, eb; -+ -+ if (si->bad_cnt == 0) -+ return; -+ -+ normsg_cont("bad eraseblocks: "); -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ if (si->ec[eb] != EB_BAD) -+ continue; -+ if (first) { -+ printf("%d", eb); -+ first = 0; -+ } else -+ printf(", %d", eb); -+ } -+ printf("\n"); -+} -+ -+static int change_ec(struct ubi_ec_hdr *hdr, long long ec) -+{ -+ uint32_t crc; -+ -+ /* Check the EC header */ -+ if (be32_to_cpu(hdr->magic) != UBI_EC_HDR_MAGIC) -+ return errmsg("mad UBI magic %#08x, should be %#08x", -+ be32_to_cpu(hdr->magic), UBI_EC_HDR_MAGIC); -+ -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(hdr->hdr_crc) != crc) -+ return errmsg("bad CRC %#08x, should be %#08x\n", -+ crc, be32_to_cpu(hdr->hdr_crc)); -+ -+ hdr->ec = cpu_to_be64(ec); -+ crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC); -+ hdr->hdr_crc = cpu_to_be32(crc); -+ -+ return 0; -+} -+ -+static int drop_ffs(const struct mtd_info *mtd, const void *buf, int len) -+{ -+ int i; -+ -+ for (i = len - 1; i >= 0; i--) -+ if (((const uint8_t *)buf)[i] != 0xFF) -+ break; -+ -+ /* The resulting length must be aligned to the minimum flash I/O size */ -+ len = i + 1; -+ len = (len + mtd->min_io_size - 1) / mtd->min_io_size; -+ len *= mtd->min_io_size; -+ return len; -+} -+ -+static int flash_image(const struct mtd_info *mtd, const struct ubigen_info *ui, -+ struct ubi_scan_info *si) -+{ -+ int fd, img_ebs, eb, written_ebs = 0, divisor; -+ struct stat st; -+ -+ if (stat(args.image, &st)) -+ return sys_errmsg("cannot open \"%s\"", args.image); -+ -+ img_ebs = st.st_size / mtd->eb_size; -+ if (img_ebs > si->good_cnt) -+ return sys_errmsg("file \"%s\" is too large (%lld bytes)", -+ args.image, (long long)st.st_size); -+ -+ if (st.st_size % mtd->eb_size) -+ return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of eraseblock size (%d bytes)", -+ args.image, (long long)st.st_size, mtd->eb_size); -+ -+ fd = open(args.image, O_RDONLY); -+ if (fd == -1) -+ return sys_errmsg("cannot open \"%s\"", args.image); -+ -+ verbose(args.verbose, "will write %d eraseblocks", img_ebs); -+ divisor = img_ebs; -+ for (eb = 0; eb < mtd->eb_cnt; eb++) { -+ int err, new_len; -+ char buf[mtd->eb_size]; -+ long long ec; -+ -+ if (!args.quiet && !args.verbose) { -+ printf("\r" PROGRAM_NAME ": flashing eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1) * 100 / divisor); -+ fflush(stdout); -+ } -+ -+ if (si->ec[eb] == EB_BAD) { -+ divisor += 1; -+ continue; -+ } -+ -+ if (args.verbose) { -+ normsg_cont("eraseblock %d: erase", eb); -+ fflush(stdout); -+ } -+ -+ err = mtd_erase(mtd, eb); -+ if (err) { -+ sys_errmsg("failed to erase eraseblock %d", eb); -+ goto out_close; -+ } -+ -+ if (read(fd, buf, mtd->eb_size) != mtd->eb_size) { -+ sys_errmsg("failed to read eraseblock %d from \"%s\"", -+ written_ebs, args.image); -+ goto out_close; -+ } -+ -+ -+ if (si->ec[eb] <= EC_MAX) -+ ec = si->ec[eb] + 1; -+ else if (!args.override_ec) -+ ec = si->mean_ec; -+ else -+ ec = args.ec; -+ -+ if (args.verbose) { -+ printf(", change EC to %lld", ec); -+ fflush(stdout); -+ } -+ -+ err = change_ec((struct ubi_ec_hdr *)buf, ec); -+ if (err) { -+ errmsg("bad EC header at eraseblock %d of \"%s\"", -+ written_ebs, args.image); -+ goto out_close; -+ } -+ -+ if (args.verbose) { -+ printf(", write data\n"); -+ fflush(stdout); -+ } -+ -+ new_len = drop_ffs(mtd, buf, mtd->eb_size); -+ -+ err = mtd_write(mtd, eb, 0, buf, new_len); -+ if (err) { -+ sys_errmsg("cannot write eraseblock %d", eb); -+ goto out_close; -+ } -+ if (++written_ebs >= img_ebs) -+ break; -+ } -+ -+ if (!args.quiet && !args.verbose) -+ printf("\n"); -+ close(fd); -+ return eb + 1; -+ -+out_close: -+ close(fd); -+ return -1; -+} -+ -+static int format(const struct mtd_info *mtd, const struct ubigen_info *ui, -+ const struct ubi_scan_info *si, int start_eb, int novtbl) -+{ -+ int eb, err, write_size; -+ struct ubi_ec_hdr *hdr; -+ struct ubi_vtbl_record *vtbl; -+ int eb1 = -1, eb2 = -1; -+ long long ec1 = -1, ec2 = -1; -+ -+ write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1; -+ write_size /= mtd->subpage_size; -+ write_size *= mtd->subpage_size; -+ hdr = malloc(write_size); -+ if (!hdr) -+ return sys_errmsg("cannot allocate %d bytes of memory", write_size); -+ -+ memset(hdr, 0xFF, write_size); -+ -+ for (eb = start_eb; eb < mtd->eb_cnt; eb++) { -+ long long ec; -+ -+ if (!args.quiet && !args.verbose) { -+ printf("\r" PROGRAM_NAME ": formatting eraseblock %d -- %2lld %% complete ", -+ eb, (long long)(eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb)); -+ fflush(stdout); -+ } -+ -+ if (si->ec[eb] == EB_BAD) -+ continue; -+ -+ if (si->ec[eb] <= EC_MAX) -+ ec = si->ec[eb] + 1; -+ else if (!args.override_ec) -+ ec = si->mean_ec; -+ else -+ ec = args.ec; -+ ubigen_init_ec_hdr(ui, hdr, ec); -+ -+ if (args.verbose) { -+ normsg_cont("eraseblock %d: erase", eb); -+ fflush(stdout); -+ } -+ -+ err = mtd_erase(mtd, eb); -+ if (err) { -+ sys_errmsg("failed to erase eraseblock %d", eb); -+ goto out_free; -+ } -+ -+ if ((eb1 == -1 || eb2 == -1) && !novtbl) { -+ if (eb1 == -1) { -+ eb1 = eb; -+ ec1 = ec; -+ } else if (eb2 == -1) { -+ eb2 = eb; -+ ec2 = ec; -+ } -+ if (args.verbose) -+ printf(", do not write EC, leave for vtbl\n"); -+ continue; -+ } -+ -+ if (args.verbose) { -+ printf(", write EC %lld\n", ec); -+ fflush(stdout); -+ } -+ -+ err = mtd_write(mtd, eb, 0, hdr, write_size); -+ if (err) { -+ sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d", -+ write_size, eb); -+ if (args.subpage_size != mtd->min_io_size) -+ normsg("may be %d is incorrect?", args.subpage_size); -+ goto out_free; -+ } -+ } -+ -+ if (!args.quiet && !args.verbose) -+ printf("\n"); -+ -+ if (!novtbl) { -+ if (eb1 == -1 || eb2 == -1) { -+ errmsg("no eraseblocks for volume table"); -+ goto out_free; -+ } -+ -+ verbose(args.verbose, "write volume table to eraseblocks %d and %d", eb1, eb2); -+ vtbl = ubigen_create_empty_vtbl(ui); -+ if (!vtbl) -+ goto out_free; -+ -+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, mtd->fd); -+ free(vtbl); -+ if (err) { -+ errmsg("cannot write layout volume"); -+ goto out_free; -+ } -+ } -+ -+ free(hdr); -+ return 0; -+ -+out_free: -+ free(hdr); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err, verbose; -+ struct mtd_info mtd; -+ libubi_t libubi; -+ struct ubigen_info ui; -+ struct ubi_scan_info *si; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ err = mtd_get_info(args.node, &mtd); -+ if (err) -+ return errmsg("cannot get information about \"%s\"", args.node); -+ -+ if (args.subpage_size == 0) -+ args.subpage_size = mtd.min_io_size; -+ else { -+ if (args.subpage_size > mtd.min_io_size) { -+ errmsg("sub-page cannot be larger than min. I/O unit"); -+ goto out_close; -+ } -+ -+ if (mtd.min_io_size % args.subpage_size) { -+ errmsg("min. I/O unit size should be multiple of sub-page size"); -+ goto out_close; -+ } -+ } -+ -+ /* Validate VID header offset if it was specified */ -+ if (args.vid_hdr_offs != 0) { -+ if (args.vid_hdr_offs % 8) { -+ errmsg("VID header offset has to be multiple of min. I/O unit size"); -+ goto out_close; -+ } -+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE > mtd.eb_size) { -+ errmsg("bad VID header offset"); -+ goto out_close; -+ } -+ } -+ -+ /* -+ * Because of MTD interface limitations 'mtd_get_info()' cannot get -+ * sub-page so we force the user to pass it via the command line. Let's -+ * hope the user passed us something sane. -+ */ -+ mtd.subpage_size = args.subpage_size; -+ -+ if (mtd.rdonly) { -+ errmsg("mtd%d (%s) is a read-only device", mtd.num, args.node); -+ goto out_close; -+ } -+ -+ /* Make sure this MTD device is not attached to UBI */ -+ libubi = libubi_open(0); -+ if (libubi) { -+ int ubi_dev_num; -+ -+ err = mtd_num2ubi_dev(libubi, mtd.num, &ubi_dev_num); -+ libubi_close(libubi); -+ if (!err) { -+ errmsg("please, first detach mtd%d (%s) from ubi%d", -+ mtd.num, args.node, ubi_dev_num); -+ goto out_close; -+ } -+ } -+ -+ if (!args.quiet) { -+ normsg_cont("mtd%d (%s), size ", mtd.num, mtd.type_str); -+ ubiutils_print_bytes(mtd.size, 1); -+ printf(", %d eraseblocks of ", mtd.eb_size); -+ ubiutils_print_bytes(mtd.eb_size, 1); -+ printf(", min. I/O size %d bytes\n", mtd.min_io_size); -+ } -+ -+ if (args.quiet) -+ verbose = 0; -+ else if (args.verbose) -+ verbose = 2; -+ else -+ verbose = 1; -+ err = ubi_scan(&mtd, &si, verbose); -+ if (err) { -+ errmsg("failed to scan mtd%d (%s)", mtd.num, args.node); -+ goto out_close; -+ } -+ -+ if (si->good_cnt == 0) { -+ errmsg("all %d eraseblocks are bad", si->bad_cnt); -+ goto out_free; -+ } -+ -+ if (si->good_cnt < 2 && (!args.novtbl || args.image)) { -+ errmsg("too few non-bad eraseblocks (%d) on mtd%d", si->good_cnt, mtd.num); -+ goto out_free; -+ } -+ -+ if (!args.quiet) { -+ if (si->ok_cnt) -+ normsg("%d eraseblocks have valid erase counter, mean value is %lld", -+ si->ok_cnt, si->mean_ec); -+ if (si->empty_cnt) -+ normsg("%d eraseblocks are supposedly empty", si->empty_cnt); -+ if (si->corrupted_cnt) -+ normsg("%d corrupted erase counters", si->corrupted_cnt); -+ print_bad_eraseblocks(&mtd, si); -+ } -+ -+ if (si->alien_cnt) { -+ if (!args.yes || !args.quiet) -+ warnmsg("%d of %d eraseblocks contain non-ubifs data", -+ si->alien_cnt, si->good_cnt); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ } -+ -+ if (!args.override_ec && si->empty_cnt < si->good_cnt) { -+ int percent = ((double)si->ok_cnt)/si->good_cnt * 100; -+ -+ /* -+ * Make sure the majority of eraseblocks have valid -+ * erase counters. -+ */ -+ if (percent < 50) { -+ if (!args.yes || !args.quiet) -+ warnmsg("only %d of %d eraseblocks have valid erase counter", -+ si->ok_cnt, si->good_cnt); -+ normsg("erase counter 0 will be used for all eraseblocks"); -+ normsg("note, arbitrary erase counter value may be specified using -e option"); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ args.ec = 0; -+ args.override_ec = 1; -+ } else if (percent < 95) { -+ if (!args.yes || !args.quiet) -+ warnmsg("only %d of %d eraseblocks have valid erase counter", -+ si->ok_cnt, si->good_cnt); -+ normsg("mean erase counter %lld will be used for the rest of eraseblock", -+ si->mean_ec); -+ if (!args.yes && want_exit()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ goto out_free; -+ } -+ args.ec = si->mean_ec; -+ args.override_ec = 1; -+ } -+ } -+ -+ if (!args.quiet && args.override_ec) -+ normsg("use erase counter %lld for all eraseblocks", args.ec); -+ -+ ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, args.subpage_size, -+ args.vid_hdr_offs, args.ubi_ver); -+ -+ if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) { -+ /* -+ * Hmm, what we read from flash and what we calculated using -+ * min. I/O unit size and sub-page size differs. -+ */ -+ if (!args.yes || !args.quiet) { -+ warnmsg("VID header and data offsets on flash are %d and %d, " -+ "which is different to calculated offsets %d and %d", -+ si->vid_hdr_offs, si->data_offs, ui.vid_hdr_offs, -+ ui.data_offs); -+ normsg_cont("use old offsets %d and %d? (yes/no) ", -+ si->vid_hdr_offs, si->data_offs); -+ } -+ if (args.yes || answer_is_yes()) { -+ if (args.yes && !args.quiet) -+ printf("yes\n"); -+ ui.vid_hdr_offs = si->vid_hdr_offs; -+ ui.data_offs = si->data_offs; -+ } -+ } -+ -+ if (args.image) { -+ err = flash_image(&mtd, &ui, si); -+ if (err < 0) -+ goto out_free; -+ -+ err = format(&mtd, &ui, si, err, 1); -+ if (err) -+ goto out_free; -+ } else { -+ err = format(&mtd, &ui, si, 0, args.novtbl); -+ if (err) -+ goto out_free; -+ } -+ -+ ubi_scan_free(si); -+ close(mtd.fd); -+ return 0; -+ -+out_free: -+ ubi_scan_free(si); -+out_close: -+ close(mtd.fd); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubimkvol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,310 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to create UBI volumes. -+ * -+ * Authors: Artem Bityutskiy -+ * Frank Haverkamp -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubimkvol" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int vol_id; -+ int vol_type; -+ long long bytes; -+ int lebs; -+ int alignment; -+ const char *name; -+ int nlen; -+ const char *node; -+ int maxavs; -+ /* For deprecated -d option handling */ -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .vol_type = UBI_DYNAMIC_VOLUME, -+ .bytes = -1, -+ .lebs = -1, -+ .alignment = 1, -+ .vol_id = UBI_VOL_NUM_AUTO, -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to create UBI volumes."; -+ -+static const char *optionsstr = -+"-a, --alignment= volume alignment (default is 1)\n" -+"-n, --vol_id= UBI volume ID, if not specified, the volume ID\n" -+" will be assigned automatically\n" -+"-N, --name= volume name\n" -+"-s, --size= volume size volume size in bytes, kilobytes (KiB)\n" -+" or megabytes (MiB)\n" -+"-S, --lebs= alternative way to give volume size in logical\n" -+" eraseblocks\n" -+"-m, --maxavsize set volume size to maximum available size\n" -+"-t, --type= volume type (dynamic, static), default is dynamic\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following is a compatibility option which is deprecated, do not use it\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\""; -+ -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-h] [-a ] [-n ] [-N ]\n" -+"\t\t\t[-s ] [-S ] [-t ] [-V] [-m]\n" -+"\t\t\t[--alignment=][--vol_id=] [--name=]\n" -+"\t\t\t[--size=] [--lebs=] [--type=] [--help]\n" -+"\t\t\t[--version] [--maxavsize]\n\n" -+"Example: " PROGRAM_NAME "/dev/ubi0 -s 20MiB -N config_data - create a 20 Megabytes volume\n" -+" named \"config_data\" on UBI device /dev/ubi0."; -+ -+static const struct option long_options[] = { -+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'a' }, -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "name", .has_arg = 1, .flag = NULL, .val = 'N' }, -+ { .name = "size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "lebs", .has_arg = 1, .flag = NULL, .val = 'S' }, -+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { .name = "maxavsize", .has_arg = 0, .flag = NULL, .val = 'm' }, -+ /* Deprecated -d option */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int param_sanity_check(void) -+{ -+ int len; -+ -+ if (args.bytes == -1 && !args.maxavs && args.lebs == -1) -+ return errmsg("volume size was not specified (use -h for help)"); -+ -+ if ((args.bytes != -1 && (args.maxavs || args.lebs != -1)) || -+ (args.lebs != -1 && (args.maxavs || args.bytes != -1)) || -+ (args.maxavs && (args.bytes != -1 || args.lebs != -1))) -+ return errmsg("size specified with more then one option"); -+ -+ if (args.name == NULL) -+ return errmsg("volume name was not specified (use -h for help)"); -+ -+ len = strlen(args.name); -+ if (len > UBI_MAX_VOLUME_NAME) -+ return errmsg("too long name (%d symbols), max is %d", len, UBI_MAX_VOLUME_NAME); -+ -+ return 0; -+} -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "a:n:N:s:S:t:h?Vmd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ if (!strcmp(optarg, "dynamic")) -+ args.vol_type = UBI_DYNAMIC_VOLUME; -+ else if (!strcmp(optarg, "static")) -+ args.vol_type = UBI_STATIC_VOLUME; -+ else -+ return errmsg("bad volume type: \"%s\"", optarg); -+ break; -+ -+ case 's': -+ args.bytes = ubiutils_get_bytes(optarg); -+ if (args.bytes <= 0) -+ return errmsg("bad volume size: \"%s\"", optarg); -+ break; -+ -+ case 'S': -+ args.lebs = strtoull(optarg, &endp, 0); -+ if (endp == optarg || args.lebs <= 0 || *endp != '\0') -+ return errmsg("bad LEB count: \"%s\"", optarg); -+ break; -+ -+ case 'a': -+ args.alignment = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.alignment <= 0) -+ return errmsg("bad volume alignment: \"%s\"", optarg); -+ break; -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) -+ return errmsg("bad volume ID: " "\"%s\"", optarg); -+ break; -+ -+ case 'd': -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ -+ case 'N': -+ args.name = optarg; -+ args.nlen = strlen(args.name); -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case 'm': -+ args.maxavs = 1; -+ break; -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 1) -+ return errmsg("more then one UBI device specified (use -h for help)"); -+ -+ args.node = argv[optind]; -+ } -+ -+ if (param_sanity_check()) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_dev_info dev_info; -+ struct ubi_vol_info vol_info; -+ struct ubi_mkvol_request req; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return err; -+ -+ libubi = libubi_open(1); -+ if (!libubi) -+ return sys_errmsg("cannot open libubi"); -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 2) { -+ errmsg("\"%s\" is an UBI volume node, not an UBI device node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI device node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_dev_info(libubi, args.node, &dev_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI device \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ if (args.maxavs) { -+ args.bytes = dev_info.avail_bytes; -+ printf("Set volume size to %lld\n", args.bytes); -+ } -+ -+ if (args.lebs != -1) { -+ args.bytes = dev_info.leb_size; -+ args.bytes -= dev_info.leb_size % args.alignment; -+ args.bytes *= args.lebs; -+ } -+ -+ req.vol_id = args.vol_id; -+ req.alignment = args.alignment; -+ req.bytes = args.bytes; -+ req.vol_type = args.vol_type; -+ req.name = args.name; -+ -+ err = ubi_mkvol(libubi, args.node, &req); -+ if (err < 0) { -+ sys_errmsg("cannot UBI create volume"); -+ goto out_libubi; -+ } -+ -+ args.vol_id = req.vol_id; -+ -+ /* Print information about the created device */ -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, args.vol_id, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about newly created UBI volume"); -+ goto out_libubi; -+ } -+ -+ printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs); -+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0); -+ printf("), LEB size "); -+ ubiutils_print_bytes(vol_info.leb_size, 1); -+ printf(", %s, name \"%s\", alignment %d\n", -+ req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static", -+ vol_info.name, vol_info.alignment); -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinfo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,409 @@ -+/* -+ * Copyright (C) 2007, 2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * An utility to get UBI information. -+ * -+ * Author: Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubinfo" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int devn; -+ int vol_id; -+ int all; -+ const char *node; -+}; -+ -+static struct args args = { -+ .vol_id = -1, -+ .devn = -1, -+ .all = 0, -+ .node = NULL, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to print UBI information."; -+ -+static const char *optionsstr = -+"-d, --devn= UBI device number to get information about\n" -+"-n, --vol_id= ID of UBI volume to print information about\n" -+"-a, --all print information about all devices and volumes,\n" -+" or about all volumes if the UBI device was\n" -+" specified\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage 1: " PROGRAM_NAME " [-d ] [-n ] [-a] [-h] [-V] [--vol_id=]\n" -+"\t\t[--devn ] [--all] [--help] [--version]\n" -+"Usage 2: " PROGRAM_NAME " [-a] [-h] [-V] [--all] [--help] [--version]\n" -+"Usage 3: " PROGRAM_NAME " [-h] [-V] [--help] [--version]\n\n" -+"Example 1: " PROGRAM_NAME " - (no arguments) print general UBI information\n" -+"Example 2: " PROGRAM_NAME " -d 1 - print information about UBI device number 1\n" -+"Example 3: " PROGRAM_NAME " /dev/ubi0 -a - print information about all volumes of UBI\n" -+" device /dev/ubi0\n" -+"Example 4: " PROGRAM_NAME " /dev/ubi1_0 - print information about UBI volume /dev/ubi1_0\n" -+"Example 5: " PROGRAM_NAME " -a - print all information\n"; -+ -+static const struct option long_options[] = { -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "all", .has_arg = 0, .flag = NULL, .val = 'a' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "an:d:hV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'a': -+ args.all = 1; -+ break; -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) -+ return errmsg("bad volume ID: " "\"%s\"", optarg); -+ break; -+ -+ case 'd': -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: \"%s\"", optarg); -+ -+ break; -+ -+ case 'h': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc - 1) -+ args.node = argv[optind]; -+ else if (optind < argc) -+ return errmsg("more then one UBI devices specified (use -h for help)"); -+ -+ return 0; -+} -+ -+static int translate_dev(libubi_t libubi, const char *node) -+{ -+ int err; -+ -+ err = ubi_node_type(libubi, node); -+ if (err == -1) { -+ if (errno) -+ return errmsg("unrecognized device node \"%s\"", node); -+ return errmsg("\"%s\" does not correspond to any UBI device or volume", node); -+ } -+ -+ if (err == 1) { -+ struct ubi_dev_info dev_info; -+ -+ err = ubi_get_dev_info(libubi, node, &dev_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI device \"%s\"", node); -+ -+ args.devn = dev_info.dev_num; -+ } else { -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_vol_info(libubi, node, &vol_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI volume \"%s\"", node); -+ -+ if (args.vol_id != -1) -+ return errmsg("both volume character device node (\"%s\") and " -+ "volume ID (%d) are specify, use only one of them" -+ "(use -h for help)", node, args.vol_id); -+ -+ args.devn = vol_info.dev_num; -+ args.vol_id = vol_info.vol_id; -+ } -+ -+ return 0; -+} -+ -+static int print_vol_info(libubi_t libubi, int dev_num, int vol_id) -+{ -+ int err; -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_vol_info1(libubi, dev_num, vol_id, &vol_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI volume %d on ubi%d", -+ vol_id, dev_num); -+ -+ printf("Volume ID: %d (on ubi%d)\n", vol_info.vol_id, vol_info.dev_num); -+ printf("Type: %s\n", -+ vol_info.type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static"); -+ printf("Alignment: %d\n", vol_info.alignment); -+ -+ printf("Size: %d LEBs (", vol_info.rsvd_lebs); -+ ubiutils_print_bytes(vol_info.rsvd_bytes, 0); -+ printf(")\n"); -+ -+ if (vol_info.type == UBI_STATIC_VOLUME) { -+ printf("Data bytes: "); -+ ubiutils_print_bytes(vol_info.data_bytes, 1); -+ } -+ printf("State: %s\n", vol_info.corrupted ? "corrupted" : "OK"); -+ printf("Name: %s\n", vol_info.name); -+ printf("Character device major/minor: %d:%d\n", -+ vol_info.major, vol_info.minor); -+ -+ return 0; -+} -+ -+static int print_dev_info(libubi_t libubi, int dev_num, int all) -+{ -+ int i, err, first = 1; -+ struct ubi_dev_info dev_info; -+ struct ubi_vol_info vol_info; -+ -+ err = ubi_get_dev_info1(libubi, dev_num, &dev_info); -+ if (err) -+ return sys_errmsg("cannot get information about UBI device %d", dev_num); -+ -+ printf("ubi%d:\n", dev_info.dev_num); -+ printf("Volumes count: %d\n", dev_info.vol_count); -+ printf("Logical eraseblock size: %d\n", dev_info.leb_size); -+ -+ printf("Total amount of logical eraseblocks: %d (", dev_info.total_lebs); -+ ubiutils_print_bytes(dev_info.total_bytes, 0); -+ printf(")\n"); -+ -+ printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs); -+ ubiutils_print_bytes(dev_info.avail_bytes, 0); -+ printf(")\n"); -+ -+ printf("Maximum count of volumes %d\n", dev_info.max_vol_count); -+ printf("Count of bad physical eraseblocks: %d\n", dev_info.bad_count); -+ printf("Count of reserved physical eraseblocks: %d\n", dev_info.bad_rsvd); -+ printf("Current maximum erase counter value: %lld\n", dev_info.max_ec); -+ printf("Minimum input/output unit size: %d bytes\n", dev_info.min_io_size); -+ printf("Character device major/minor: %d:%d\n", -+ dev_info.major, dev_info.minor); -+ -+ if (dev_info.vol_count == 0) -+ return 0; -+ -+ printf("Present volumes: "); -+ for (i = dev_info.lowest_vol_num; -+ i <= dev_info.highest_vol_num; i++) { -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe volume %d on ubi%d", -+ i, dev_info.dev_num); -+ } -+ -+ if (!first) -+ printf(", %d", i); -+ else { -+ printf("%d", i); -+ first = 0; -+ } -+ } -+ printf("\n"); -+ -+ if (!all) -+ return 0; -+ -+ first = 1; -+ printf("\n"); -+ -+ for (i = dev_info.lowest_vol_num; -+ i <= dev_info.highest_vol_num; i++) { -+ if(!first) -+ printf("-----------------------------------\n"); -+ err = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe volume %d on ubi%d", -+ i, dev_info.dev_num); -+ } -+ first = 0; -+ -+ err = print_vol_info(libubi, dev_info.dev_num, i); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+static int print_general_info(libubi_t libubi, int all) -+{ -+ int i, err, first = 1; -+ struct ubi_info ubi_info; -+ struct ubi_dev_info dev_info; -+ -+ err = ubi_get_info(libubi, &ubi_info); -+ if (err) -+ return sys_errmsg("cannot get UBI information"); -+ -+ printf("UBI version: %d\n", ubi_info.version); -+ printf("Count of UBI devices: %d\n", ubi_info.dev_count); -+ if (ubi_info.ctrl_major != -1) -+ printf("UBI control device major/minor: %d:%d\n", -+ ubi_info.ctrl_major, ubi_info.ctrl_minor); -+ else -+ printf("UBI control device is not supported by this kernel\n"); -+ -+ if (ubi_info.dev_count == 0) -+ return 0; -+ -+ printf("Present UBI devices: "); -+ for (i = ubi_info.lowest_dev_num; -+ i <= ubi_info.highest_dev_num; i++) { -+ err = ubi_get_dev_info1(libubi, i, &dev_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe UBI device %d", i); -+ } -+ -+ if (!first) -+ printf(", ubi%d", i); -+ else { -+ printf("ubi%d", i); -+ first = 0; -+ } -+ } -+ printf("\n"); -+ -+ if (!all) -+ return 0; -+ -+ first = 1; -+ printf("\n"); -+ -+ for (i = ubi_info.lowest_dev_num; -+ i <= ubi_info.highest_dev_num; i++) { -+ if(!first) -+ printf("\n===================================\n\n"); -+ err = ubi_get_dev_info1(libubi, i, &dev_info); -+ if (err == -1) { -+ if (errno == ENOENT) -+ continue; -+ -+ return sys_errmsg("libubi failed to probe UBI device %d", i); -+ } -+ first = 0; -+ -+ err = print_dev_info(libubi, i, all); -+ if (err) -+ return err; -+ } -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ if (!args.node && args.devn != -1) -+ return errmsg("specify either device number or node file (use -h for help)"); -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ if (args.node) { -+ /* -+ * A character device was specified, translate this into UBI -+ * device number and volume ID. -+ */ -+ err = translate_dev(libubi, args.node); -+ if (err) -+ goto out_libubi; -+ } -+ -+ if (args.vol_id != -1 && args.devn == -1) { -+ errmsg("volume ID is specified, but UBI device number is not " -+ "(use -h for help)\n"); -+ goto out_libubi; -+ } -+ -+ if (args.devn != -1 && args.vol_id != -1) { -+ print_vol_info(libubi, args.devn, args.vol_id); -+ goto out; -+ } -+ -+ if (args.devn == -1 && args.vol_id == -1) -+ err = print_general_info(libubi, args.all); -+ else if (args.devn != -1 && args.vol_id == -1) -+ err = print_dev_info(libubi, args.devn, args.all); -+ -+ if (err) -+ goto out_libubi; -+ -+out: -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubinize.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,582 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Generate UBI images. -+ * -+ * Authors: Artem Bityutskiy -+ * Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubinize" -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+" - a tool to generate UBI images. An UBI image may contain one or more UBI " -+"volumes which have to be defined in the input configuration ini-file. The " -+"ini file defines all the UBI volumes - their characteristics and the and the " -+"contents, but it does not define the characteristics of the flash the UBI " -+"image is generated for. Instead, the flash characteristics are defined via " -+"the command-line options. Note, if not sure about some of the command-line " -+"parameters, do not specify them and let the utility to use default values."; -+ -+static const char *optionsstr = -+"-o, --output= output file name\n" -+"-p, --peb-size= size of the physical eraseblock of the flash\n" -+" this UBI image is created for in bytes,\n" -+" kilobytes (KiB), or megabytes (MiB)\n" -+" (mandatory parameter)\n" -+"-m, --min-io-size= minimum input/output unit size of the flash\n" -+" in bytes\n" -+"-s, --sub-page-size= minimum input/output unit used for UBI\n" -+" headers, e.g. sub-page size in case of NAND\n" -+" flash (equivalent to the minimum input/output\n" -+" unit size by default)\n" -+"-O, --vid-hdr-offset= offset if the VID header from start of the\n" -+" physical eraseblock (default is the next\n" -+" minimum I/O unit or sub-page after the EC\n" -+" header)\n" -+"-e, --erase-counter= the erase counter value to put to EC headers\n" -+" (default is 0)\n" -+"-x, --ubi-ver= UBI version number to put to EC headers\n" -+" (default is 1)\n" -+"-v, --verbose be verbose\n" -+"-h, --help print help message\n" -+"-V, --version print program version"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-o filename] [-h] [-V] [--output=] [--help]\n" -+"\t\t[--version] ini-file\n" -+"Example: " PROGRAM_NAME " -o ubi.img cfg.ini - create UBI image 'ubi.img' as\n" -+" described by configuration file 'cfg.ini'"; -+ -+static const char *ini_doc = "INI-file format.\n" -+"The input configuration ini-file describes all the volumes which have to\n" -+"be included to the output UBI image. Each volume is described in its own\n" -+"section which may be named arbitrarily. The section consists on\n" -+"\"key=value\" pairs, for example:\n\n" -+"[jffs2-volume]\n" -+"mode=ubi\n" -+"image=../jffs2.img\n" -+"vol_id=1\n" -+"vol_size=30MiB\n" -+"vol_type=dynamic\n" -+"vol_name=jffs2_volume\n" -+"vol_flags=autoresize\n" -+"vol_alignment=1\n\n" -+"This example configuration file tells the utility to create an UBI image\n" -+"with one volume with ID 1, volume size 30MiB, the volume is dynamic, has\n" -+"name \"jffs2_volume\", \"autoresize\" volume flag, and alignment 1. The\n" -+"\"image=../jffs2.img\" line tells the utility to take the contents of the\n" -+"volume from the \"../jffs2.img\" file. The size of the image file has to be\n" -+"less or equivalent to the volume size (30MiB). The \"mode=ubi\" line is\n" -+"mandatory and just tells that the section describes an UBI volume - other\n" -+"section modes may be added in the future.\n" -+"Notes:\n" -+" * size in vol_size might be specified kilobytes (KiB), megabytes (MiB),\n" -+" gigabytes (GiB) or bytes (no modifier);\n" -+" * if \"vol_size\" key is absent, the volume size is assumed to be\n" -+" equivalent to the size of the image file (defined by \"image\" key);\n" -+" * if the \"image\" is absent, the volume is assumed to be empty;\n" -+" * volume alignment must not be greater than the logical eraseblock size;\n" -+" * one ini file may contain arbitrary number of sections, the utility will\n" -+" put all the volumes which are described by these section to the output\n" -+" UBI image file."; -+ -+struct option long_options[] = { -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "peb-size", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "min-io-size", .has_arg = 1, .flag = NULL, .val = 'm' }, -+ { .name = "sub-page-size", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "erase-counter", .has_arg = 1, .flag = NULL, .val = 'e' }, -+ { .name = "ubi-ver", .has_arg = 1, .flag = NULL, .val = 'x' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+struct args { -+ const char *f_in; -+ const char *f_out; -+ int out_fd; -+ int peb_size; -+ int min_io_size; -+ int subpage_size; -+ int vid_hdr_offs; -+ int ec; -+ int ubi_ver; -+ int verbose; -+ dictionary *dict; -+}; -+ -+static struct args args = { -+ .peb_size = -1, -+ .min_io_size = -1, -+ .subpage_size = -1, -+ .ubi_ver = 1, -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "o:p:m:s:O:e:x:vhV", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'o': -+ args.out_fd = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, -+ S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ if (args.out_fd == -1) -+ return sys_errmsg("cannot open file \"%s\"", optarg); -+ args.f_out = optarg; -+ break; -+ -+ case 'p': -+ args.peb_size = ubiutils_get_bytes(optarg); -+ if (args.peb_size <= 0) -+ return errmsg("bad physical eraseblock size: \"%s\"", optarg); -+ break; -+ -+ case 'm': -+ args.min_io_size = ubiutils_get_bytes(optarg); -+ if (args.min_io_size <= 0) -+ return errmsg("bad min. I/O unit size: \"%s\"", optarg); -+ if (!is_power_of_2(args.min_io_size)) -+ return errmsg("min. I/O unit size should be power of 2"); -+ break; -+ -+ case 's': -+ args.subpage_size = ubiutils_get_bytes(optarg); -+ if (args.subpage_size <= 0) -+ return errmsg("bad sub-page size: \"%s\"", optarg); -+ if (!is_power_of_2(args.subpage_size)) -+ return errmsg("sub-page size should be power of 2"); -+ break; -+ -+ case 'O': -+ args.vid_hdr_offs = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vid_hdr_offs < 0) -+ return errmsg("bad VID header offset: \"%s\"", optarg); -+ break; -+ -+ case 'e': -+ args.ec = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.ec < 0) -+ return errmsg("bad erase counter value: \"%s\"", optarg); -+ break; -+ -+ case 'x': -+ args.ubi_ver = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.ubi_ver < 0) -+ return errmsg("bad UBI version: \"%s\"", optarg); -+ break; -+ -+ case 'v': -+ args.verbose = 1; -+ break; -+ -+ case 'h': -+ ubiutils_print_text(stderr, doc, 80); -+ fprintf(stderr, "\n%s\n\n", ini_doc); -+ fprintf(stderr, "%s\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ if (optind == argc) -+ return errmsg("input configuration file was not specified (use -h for help)"); -+ -+ if (optind != argc - 1) -+ return errmsg("more then one configuration file was specified (use -h for help)"); -+ -+ args.f_in = argv[optind]; -+ -+ if (args.peb_size < 0) -+ return errmsg("physical eraseblock size was not specified (use -h for help)"); -+ -+ if (args.peb_size > 1024*1024) -+ return errmsg("too high physical eraseblock size %d", args.peb_size); -+ -+ if (args.min_io_size < 0) -+ return errmsg("min. I/O unit size was not specified (use -h for help)"); -+ -+ if (args.subpage_size < 0) -+ args.subpage_size = args.min_io_size; -+ -+ if (args.subpage_size > args.min_io_size) -+ return errmsg("sub-page cannot be larger then min. I/O unit"); -+ -+ if (args.peb_size % args.min_io_size) -+ return errmsg("physical eraseblock should be multiple of min. I/O units"); -+ -+ if (args.min_io_size % args.subpage_size) -+ return errmsg("min. I/O unit size should be multiple of sub-page size"); -+ -+ if (!args.f_out) -+ return errmsg("output file was not specified (use -h for help)"); -+ -+ if (args.vid_hdr_offs) { -+ if (args.vid_hdr_offs + UBI_VID_HDR_SIZE >= args.peb_size) -+ return errmsg("bad VID header position"); -+ if (args.vid_hdr_offs % 8) -+ return errmsg("VID header offset has to be multiple of min. I/O unit size"); -+ } -+ -+ return 0; -+} -+ -+static int read_section(const char *sname, struct ubigen_vol_info *vi, -+ const char **img) -+{ -+ char buf[256]; -+ const char *p; -+ -+ *img = NULL; -+ -+ if (strlen(sname) > 128) -+ return errmsg("too long section name \"%s\"", sname); -+ -+ /* Make sure mode is UBI, otherwise ignore this section */ -+ sprintf(buf, "%s:mode", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) { -+ errmsg("\"mode\" key not found in section \"%s\"", sname); -+ errmsg("the \"mode\" key is mandatory and has to be " -+ "\"mode=ubi\" if the section describes an UBI volume"); -+ return -1; -+ } -+ -+ /* If mode is not UBI, skip this section */ -+ if (strcmp(p, "ubi")) { -+ verbose(args.verbose, "skip non-ubi section \"%s\"", sname); -+ return 1; -+ } -+ -+ verbose(args.verbose, "mode=ubi, keep parsing"); -+ -+ /* Fetch the name of the volume image file */ -+ sprintf(buf, "%s:image", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) -+ *img = p; -+ -+ /* Fetch volume id */ -+ sprintf(buf, "%s:vol_id", sname); -+ vi->id = iniparser_getint(args.dict, buf, -1); -+ if (vi->id == -1) -+ return errmsg("\"vol_id\" key not found in section \"%s\"", sname); -+ -+ if (vi->id < 0) -+ return errmsg("negative volume ID %d", vi->id); -+ -+ if (vi->id >= UBI_MAX_VOLUMES) -+ return errmsg("too high volume ID %d, max. is %d", vi->id, UBI_MAX_VOLUMES); -+ -+ verbose(args.verbose, "volume ID: %d", vi->id); -+ -+ /* Fetch volume size */ -+ sprintf(buf, "%s:vol_size", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) { -+ vi->bytes = ubiutils_get_bytes(p); -+ if (vi->bytes <= 0) -+ return errmsg("bad \"vol_size\" key: \"%s\"", p); -+ -+ verbose(args.verbose, "volume size: %lld bytes", vi->bytes); -+ } else { -+ struct stat st; -+ -+ if (!*img) -+ return errmsg("neither image file (\"image=\") nor volume size (\"vol_size=\") specified"); -+ -+ if (stat(*img, &st)) -+ return sys_errmsg("cannot stat \"%s\"", *img); -+ -+ vi->bytes = st.st_size; -+ -+ if (vi->bytes == 0) -+ return errmsg("file \"%s\" referred from section \"%s\" is empty", *img, sname); -+ -+ normsg_cont("volume size was not specified in section \"%s\", assume ", sname); -+ ubiutils_print_bytes(vi->bytes, 1); -+ printf("\n"); -+ } -+ -+ /* Fetch volume type */ -+ sprintf(buf, "%s:vol_type", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) { -+ normsg("volume type was not specified in " -+ "section \"%s\", assume \"dynamic\"\n", sname); -+ vi->type = UBI_VID_DYNAMIC; -+ } else { -+ if (!strcmp(p, "static")) -+ vi->type = UBI_VID_STATIC; -+ else if (!strcmp(p, "dynamic")) -+ vi->type = UBI_VID_DYNAMIC; -+ else -+ return errmsg("invalid volume type \"%s\"", p); -+ } -+ -+ verbose(args.verbose, "volume type: %s", -+ vi->type == UBI_VID_DYNAMIC ? "dynamic" : "static"); -+ -+ /* Fetch volume name */ -+ sprintf(buf, "%s:vol_name", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (!p) -+ return errmsg("\"vol_name\" key not found in section \"%s\"", sname); -+ -+ vi->name = p; -+ vi->name_len = strlen(p); -+ if (vi->name_len > UBI_VOL_NAME_MAX) -+ return errmsg("too long volume name in section \"%s\", max. is %d characters", -+ vi->name, UBI_VOL_NAME_MAX); -+ -+ verbose(args.verbose, "volume name: %s", p); -+ -+ /* Fetch volume alignment */ -+ sprintf(buf, "%s:vol_alignment", sname); -+ vi->alignment = iniparser_getint(args.dict, buf, -1); -+ if (vi->alignment == -1) { -+ normsg("volume alignment was not specified in section " -+ "\"%s\", assume 1", sname); -+ vi->alignment = 1; -+ } else if (vi->id < 0) -+ return errmsg("negative volume alignement %d", vi->alignment); -+ -+ verbose(args.verbose, "volume alignment: %d", vi->alignment); -+ -+ /* Fetch volume flags */ -+ sprintf(buf, "%s:vol_flags", sname); -+ p = iniparser_getstring(args.dict, buf, NULL); -+ if (p) { -+ if (!strcmp(p, "autoresize")) { -+ verbose(args.verbose, "autoresize flags found"); -+ vi->flags |= UBI_VTBL_AUTORESIZE_FLG; -+ } else { -+ return errmsg("unknown flags \"%s\" in section \"%s\"", p, sname); -+ } -+ } -+ -+ return 0; -+} -+ -+static void init_vol_info(const struct ubigen_info *ui, -+ struct ubigen_vol_info *vi) -+{ -+ vi->data_pad = ui->leb_size % vi->alignment; -+ vi->usable_leb_size = ui->leb_size - vi->data_pad; -+ vi->used_ebs = (vi->bytes + vi->usable_leb_size - 1) / vi->usable_leb_size; -+ vi->compat = 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err = -1, sects, i, volumes, autoresize_was_already = 0; -+ struct ubigen_info ui; -+ struct ubi_vtbl_record *vtbl; -+ off_t seek; -+ int tmp; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ ubigen_info_init(&ui, args.peb_size, args.min_io_size, -+ args.subpage_size, args.vid_hdr_offs, -+ args.ubi_ver); -+ -+ verbose(args.verbose, "LEB size: %d", ui.leb_size); -+ verbose(args.verbose, "PEB size: %d", ui.peb_size); -+ verbose(args.verbose, "min. I/O size: %d", ui.min_io_size); -+ verbose(args.verbose, "sub-page size: %d", ui.min_io_size); -+ verbose(args.verbose, "VID offset: %d", ui.vid_hdr_offs); -+ verbose(args.verbose, "data offset: %d", ui.data_offs); -+ -+ vtbl = ubigen_create_empty_vtbl(&ui); -+ if (!vtbl) -+ goto out; -+ -+ args.dict = iniparser_load(args.f_in); -+ if (!args.dict) { -+ errmsg("cannot load the input ini file \"%s\"", args.f_in); -+ goto out_vtbl; -+ } -+ -+ verbose(args.verbose, "loaded the ini-file \"%s\"", args.f_in); -+ -+ /* Each section describes one volume */ -+ sects = iniparser_getnsec(args.dict); -+ if (sects == -1) { -+ errmsg("ini-file parsing error (iniparser_getnsec)"); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "count of sections: %d", sects); -+ if (sects == 0) { -+ errmsg("no sections found the ini-file \"%s\"", args.f_in); -+ goto out_dict; -+ } -+ -+ /* -+ * Skip 2 PEBs at the beginning of the file for the volume table which -+ * will be written later. -+ */ -+ seek = ui.peb_size * 2; -+ if (lseek(args.out_fd, seek, SEEK_SET) != seek) { -+ sys_errmsg("cannot seek file \"%s\"", args.f_out); -+ goto out_dict; -+ } -+ -+ for (i = 0; i < sects; i++) { -+ const char *sname = iniparser_getsecname(args.dict, i); -+ struct ubigen_vol_info vi; -+ const char *img = NULL; -+ struct stat st; -+ int fd; -+ -+ if (!sname) { -+ errmsg("ini-file parsing error (iniparser_getsecname)"); -+ goto out_dict; -+ } -+ -+ if (args.verbose) -+ printf("\n"); -+ verbose(args.verbose, "parsing section \"%s\"", sname); -+ -+ err = read_section(sname, &vi, &img); -+ if (err == -1) -+ goto out_dict; -+ if (!err) -+ volumes += 1; -+ init_vol_info(&ui, &vi); -+ -+ if (vi.id >= ui.max_volumes) -+ return errmsg("too high volume ID %d, max. is %d", -+ vi.id, ui.max_volumes); -+ -+ verbose(args.verbose, "adding volume %d", vi.id); -+ -+ /* Make sure only one volume has auto-resize flag */ -+ if (vi.flags & UBI_VTBL_AUTORESIZE_FLG) { -+ if (autoresize_was_already) -+ return errmsg("only one volume is allowed " -+ "to have auto-resize flag"); -+ autoresize_was_already = 1; -+ } -+ -+ err = ubigen_add_volume(&ui, &vi, vtbl); -+ if (err) { -+ errmsg("cannot add volume for section \"%s\"", sname); -+ goto out_dict; -+ } -+ -+ if (!img) -+ continue; -+ -+ if (stat(img, &st)) { -+ sys_errmsg("cannot stat \"%s\"", img); -+ goto out_dict; -+ } -+ -+ /* -+ * Make sure the image size is not larger then the volume size. -+ */ -+ tmp = (st.st_size / (ui.leb_size + sizeof(unsigned int))) * sizeof(unsigned int); -+ if (st.st_size - tmp> vi.bytes) { -+ errmsg("error in section \"%s\": size of the image file \"%s\" " -+ "is %lld, which is larger then the volume size %lld", -+ sname, img, (long long)st.st_size, vi.bytes); -+ goto out_dict; -+ } -+ -+ fd = open(img, O_RDONLY); -+ if (fd == -1) { -+ sys_errmsg("cannot open \"%s\"", img); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "writing volume %d", vi.id); -+ verbose(args.verbose, "image file: %s", img); -+ -+ err = ubigen_write_volume(&ui, &vi, args.ec, st.st_size-tmp, fd, args.out_fd); -+ close(fd); -+ if (err) { -+ errmsg("cannot write volume for section \"%s\"", sname); -+ goto out_dict; -+ } -+ -+ if (args.verbose) -+ printf("\n"); -+ } -+ -+ verbose(args.verbose, "writing layout volume"); -+ -+ err = ubigen_write_layout_vol(&ui, 0, 1, args.ec, args.ec, vtbl, args.out_fd); -+ if (err) { -+ errmsg("cannot write layout volume"); -+ goto out_dict; -+ } -+ -+ verbose(args.verbose, "done"); -+ -+ iniparser_freedict(args.dict); -+ free(vtbl); -+ close(args.out_fd); -+ return 0; -+ -+out_dict: -+ iniparser_freedict(args.dict); -+out_vtbl: -+ free(vtbl); -+out: -+ close(args.out_fd); -+ remove(args.f_out); -+ return err; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubirefimg.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,99 @@ -+/* -+ * An utility to reformat the image file generated by mkfs.ubifs -+ * -+ * Authors: Yurong Tan (Nancy) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubirefimg" -+#define UBI_LEB_SIZE 258048 -+ -+/* -+ * sourcefile usually generated by mkfs.ubifs. -+ * usage: #ubirefimg sourcefile outputfile -+ */ -+int main(int argc, char * const argv[]) -+{ -+ int err, ifd, ofd, i, j, tmp; -+ struct stat st; -+ unsigned char *buf=NULL; -+ -+ buf = malloc(UBI_LEB_SIZE); -+ if(buf==NULL){ -+ printf("no mem\n"); -+ goto out_free; -+ } -+ -+ err = stat(argv[1], &st); -+ if (err < 0) { -+ printf("stat failed on \"%s\"", argv[1]); -+ goto out_free; -+ } -+ -+ ifd = open(argv[1], O_RDONLY); -+ if (ifd == -1) { -+ printf("cannot open \"%s\"", argv[1]); -+ goto out_close; -+ } -+ -+ ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); -+ if (ofd == -1) { -+ printf("cannot create \"%s\"", argv[2]); -+ goto out_close; -+ } -+ -+ tmp = st.st_size/UBI_LEB_SIZE; -+ -+ for( i=0; i< tmp; i++ ){ -+ err = read(ifd, buf, UBI_LEB_SIZE); -+ if (err != UBI_LEB_SIZE) { -+ printf("read error\n"); -+ goto out_close1; -+ } -+ for(j=0; j -+ * Frank Haverkamp -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.0" -+#define PROGRAM_NAME "ubirmvol" -+ -+/* The variables below are set by command line arguments */ -+struct args { -+ int vol_id; -+ const char *node; -+ /* For deprecated -d option handling */ -+ int devn; -+ char dev_name[256]; -+}; -+ -+static struct args args = { -+ .vol_id = -1, -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to remove UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= volume ID to remove\n" -+"-h, -?, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following is a compatibility option which is deprecated, do not use it\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\""; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-n ] [--vol_id=] [-h] [--help]\n\n" -+"Example: " PROGRAM_NAME "/dev/ubi0 -n 1 - remove UBI volume 1 from UBI device corresponding\n" -+" to the node file /dev/ubi0."; -+ -+static const struct option long_options[] = { -+ { .name = "vol_id", .has_arg = 1, .flag = NULL, .val = 'n' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d option */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { NULL, 0, NULL, 0}, -+}; -+ -+static int param_sanity_check(void) -+{ -+ if (args.vol_id == -1) { -+ errmsg("volume ID is was not specified"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ char *endp; -+ -+ key = getopt_long(argc, argv, "n:h?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ -+ case 'n': -+ args.vol_id = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.vol_id < 0) { -+ errmsg("bad volume ID: " "\"%s\"", optarg); -+ return -1; -+ } -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ errmsg("parameter is missing"); -+ return -1; -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) { -+ errmsg("UBI device name was not specified (use -h for help)"); -+ return -1; -+ } else if (optind != argc - 1) { -+ errmsg("more then one UBI device specified (use -h for help)"); -+ return -1; -+ } -+ -+ args.node = argv[optind]; -+ } -+ -+ -+ if (param_sanity_check()) -+ return -1; -+ -+ return 0; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) -+ return sys_errmsg("cannot open libubi"); -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 2) { -+ errmsg("\"%s\" is an UBI volume node, not an UBI device node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI device node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_rmvol(libubi, args.node, args.vol_id); -+ if (err) { -+ sys_errmsg("cannot UBI remove volume"); -+ goto out_libubi; -+ } -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/new-utils/src/ubiupdatevol.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,335 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * An utility to update UBI volumes. -+ * -+ * Authors: Frank Haverkamp -+ * Joshua W. Boyer -+ * Artem Bityutskiy -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "common.h" -+ -+#define PROGRAM_VERSION "1.1" -+#define PROGRAM_NAME "ubiupdatevol" -+ -+struct args { -+ int truncate; -+ const char *node; -+ const char *img; -+ /* For deprecated -d and -B options handling */ -+ int devn; -+ char dev_name[256]; -+ int broken_update; -+}; -+ -+static struct args args = { -+ .devn = -1, -+}; -+ -+static const char *doc = PROGRAM_NAME " version " PROGRAM_VERSION -+ " - a tool to write data to UBI volumes."; -+ -+static const char *optionsstr = -+"-n, --vol_id= ID of UBI volume to update\n" -+"-t, --truncate truncate volume (wipe it out)\n" -+"-h, --help print help message\n" -+"-V, --version print program version\n\n" -+"The following are compatibility options which are deprecated, do not use them\n" -+"-d, --devn= UBI device number - may be used instead of the UBI\n" -+" device node name in which case the utility assumes\n" -+" that the device node is \"/dev/ubi\"\n" -+"-B, --broken-update broken update, this is for testing"; -+ -+static const char *usage = -+"Usage: " PROGRAM_NAME " [-t] [-h] [-V] [--truncate] [--help]\n" -+"\t\t\t[--version] \n\n" -+"Example 1: " PROGRAM_NAME " /dev/ubi0_1 fs.img - write file \"fs.img\" to UBI volume /dev/ubi0_1\n" -+"Example 2: " PROGRAM_NAME " /dev/ubi0_1 -t - wipe out UBI volume /dev/ubi0_1"; -+ -+struct option long_options[] = { -+ { .name = "truncate", .has_arg = 0, .flag = NULL, .val = 't' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ /* Deprecated -d and -B options */ -+ { .name = "devn", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static int parse_opt(int argc, char * const argv[]) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "n:th?Vd:", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 't': -+ args.truncate = 1; -+ break; -+ -+ case 'h': -+ case '?': -+ fprintf(stderr, "%s\n\n", doc); -+ fprintf(stderr, "%s\n\n", usage); -+ fprintf(stderr, "%s\n", optionsstr); -+ exit(EXIT_SUCCESS); -+ -+ case 'd': -+ { -+ char *endp; -+ -+ /* Handle deprecated -d option */ -+ warnmsg("-d is depricated and will be removed, do not use it"); -+ args.devn = strtoul(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || args.devn < 0) -+ return errmsg("bad UBI device number: " "\"%s\"", optarg); -+ break; -+ } -+ -+ case 'B': -+ /* Handle deprecated -B option */ -+ warnmsg("-B is depricated and will be removed, do not use it"); -+ args.broken_update = 1; -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(EXIT_SUCCESS); -+ -+ case ':': -+ return errmsg("parameter is missing"); -+ -+ default: -+ fprintf(stderr, "Use -h for help\n"); -+ return -1; -+ } -+ } -+ -+ /* Handle deprecated -d option */ -+ if (args.devn != -1) { -+ sprintf(args.dev_name, "/dev/ubi%d", args.devn); -+ args.node = args.dev_name; -+ } else { -+ if (optind == argc) -+ return errmsg("UBI device name was not specified (use -h for help)"); -+ else if (optind != argc - 2 && !args.truncate) -+ return errmsg("specify UBI device name and image file name as first 2 " -+ "parameters (use -h for help)"); -+ } -+ -+ args.node = argv[optind]; -+ args.img = argv[optind + 1]; -+ -+ return 0; -+} -+ -+static int truncate_volume(libubi_t libubi) -+{ -+ int err, fd; -+ -+ fd = open(args.node, O_RDWR); -+ if (fd == -1) -+ return sys_errmsg("cannot open \"%s\"", args.node); -+ -+ err = ubi_update_start(libubi, fd, 0); -+ if (err) { -+ sys_errmsg("cannot truncate volume \"%s\"", args.node); -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ -+static int ubi_write(int fd, const void *buf, int len) -+{ -+ int ret; -+ -+ while (len) { -+ ret = write(fd, buf, len); -+ if (ret < 0) { -+ if (errno == EINTR) { -+ warnmsg("do not interrupt me!"); -+ continue; -+ } -+ return sys_errmsg("cannot write %d bytes to volume \"%s\"", -+ len, args.node); -+ } -+ -+ if (ret == 0) -+ return errmsg("cannot write %d bytes to volume \"%s\"", len, args.node); -+ -+ len -= ret; -+ buf += ret; -+ } -+ -+ return 0; -+} -+ -+static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info) -+{ -+ int err, fd, ifd; -+ long long bytes, tmp; -+ struct stat st; -+ char *buf; -+ -+ buf = malloc(vol_info->leb_size+sizeof(unsigned int)); -+ if (!buf) -+ return errmsg("cannot allocate %d bytes of memory", vol_info->leb_size); -+ -+ err = stat(args.img, &st); -+ if (err < 0) { -+ errmsg("stat failed on \"%s\"", args.img); -+ goto out_free; -+ } -+ -+ bytes = st.st_size; -+ tmp = bytes / (vol_info->leb_size + sizeof(unsigned int)) * sizeof(unsigned int); -+ bytes -= tmp; -+ if (bytes > vol_info->rsvd_bytes ) { -+ errmsg("\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)", -+ args.img, bytes, args.node, vol_info->rsvd_bytes); -+ goto out_free; -+ } -+ -+ /* A hack to handle deprecated -B option */ -+ if (args.broken_update) -+ bytes = 1; -+ -+ fd = open(args.node, O_RDWR); -+ if (fd == -1) { -+ sys_errmsg("cannot open UBI volume \"%s\"", args.node); -+ goto out_free; -+ } -+ -+ ifd = open(args.img, O_RDONLY); -+ if (ifd == -1) { -+ sys_errmsg("cannot open \"%s\"", args.img); -+ goto out_close1; -+ } -+ -+ err = ubi_update_start(libubi, fd, bytes); -+ if (err) { -+ sys_errmsg("cannot start volume \"%s\" update", args.node); -+ goto out_close; -+ } -+ -+ bytes += tmp; -+ while (bytes) { -+ int tocopy = vol_info->leb_size + sizeof(unsigned int) ; -+ -+ if (tocopy > bytes) -+ tocopy = bytes; -+ -+ err = read(ifd, buf, tocopy); -+ if (err != tocopy) { -+ if (errno == EINTR) { -+ warnmsg("do not interrupt me!"); -+ continue; -+ } else { -+ sys_errmsg("cannot read %d bytes from \"%s\"", -+ tocopy, args.img); -+ goto out_close; -+ } -+ } -+ -+ err = ubi_write(fd, buf, tocopy-sizeof(unsigned int)); -+ if (err) -+ goto out_close; -+ -+ bytes -= tocopy; -+ } -+ -+ close(ifd); -+ close(fd); -+ free(buf); -+ return 0; -+ -+out_close: -+ close(ifd); -+out_close1: -+ close(fd); -+out_free: -+ free(buf); -+ return -1; -+} -+ -+int main(int argc, char * const argv[]) -+{ -+ int err; -+ libubi_t libubi; -+ struct ubi_vol_info vol_info; -+ -+ err = parse_opt(argc, argv); -+ if (err) -+ return -1; -+ -+ libubi = libubi_open(1); -+ if (libubi == NULL) { -+ sys_errmsg("cannot open libubi"); -+ goto out_libubi; -+ } -+ -+ err = ubi_node_type(libubi, args.node); -+ if (err == 1) { -+ errmsg("\"%s\" is an UBI device node, not an UBI volume node", -+ args.node); -+ goto out_libubi; -+ } else if (err < 0) { -+ errmsg("\"%s\" is not an UBI volume node", args.node); -+ goto out_libubi; -+ } -+ -+ err = ubi_get_vol_info(libubi, args.node, &vol_info); -+ if (err) { -+ sys_errmsg("cannot get information about UBI volume \"%s\"", -+ args.node); -+ goto out_libubi; -+ } -+ -+ if (args.truncate) -+ err = truncate_volume(libubi); -+ else -+ err = update_volume(libubi, &vol_info); -+ if (err) -+ goto out_libubi; -+ -+ libubi_close(libubi); -+ return 0; -+ -+out_libubi: -+ libubi_close(libubi); -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f128_nand_sample.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,38 @@ -+[targets] -+complete=ipl,spl,bootenv,kernel,rootfs -+bootcode=spl,bootenv -+ -+# Build sections -+[ipl] -+image=ipl.bin -+raw_starts=0x00000000 -+raw_total_size=128kiB -+ -+[spl] -+image=u-boot.bin -+ubi_ids=2,3 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=spl_0,spl_1 -+ -+[bootenv] -+bootenv_file=bootenv_complete.txt -+ubi_ids=4,5 -+ubi_size=128kiB -+ubi_type=static -+ubi_names=bootenv_0,bootenv_1 -+ -+[kernel] -+image=vmlinux.bin -+ubi_ids=6,7 -+ubi_size=6MiB -+ubi_type=static -+ubi_names=kernel_0,kernel_1 -+ -+[rootfs] -+image=rootfs.bin -+ubi_ids=8,9 -+ubi_alignment=2kiB -+ubi_size=16MiB -+ubi_type=dynamic -+ubi_names=rootfs_0,rootfs_1 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/f64_nor_sample.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,39 @@ -+[targets] -+complete=ipl,spl,bootenv,kernel,rootfs -+bootcode=spl,bootenv -+rootfs=rootfs -+ -+# Build sections -+[ipl] -+image=ipl.bin -+raw_starts=0x02FE0000, 0x03FE0000 -+raw_total_size=128kiB -+ -+[spl] -+image=u-boot.bin -+ubi_ids=2,3 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=spl_0,spl_1 -+ -+[bootenv] -+bootenv_file=bootenv_complete.txt -+ubi_ids=4,5 -+ubi_size=128kiB -+ubi_type=static -+ubi_names=bootenv_0,bootenv_1 -+ -+[kernel] -+image=vmlinux.bin -+ubi_ids=6,7 -+ubi_size=6MiB -+ubi_type=static -+ubi_names=kernel_0,kernel_1 -+ -+[rootfs] -+image=rootfs.bin -+ubi_ids=8,9 -+ubi_alignment=2kiB -+ubi_size=16128kiB -+ubi_type=dynamic -+ubi_names=rootfs_0,rootfs_1 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/mkpfi 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,723 @@ -+#!/usr/bin/perl -+# -+# Copyright (c) International Business Machines Corp., 2006 -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+# the GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+# -+ -+# -+# mkpfi -+# -+# This perl program is assembles PFI files from a config file. -+# -+# Author: Oliver Lohmann (oliloh@de.ibm.com) -+# -+use warnings; -+use strict; -+use lib "/usr/lib/perl5"; # Please change this path as you need it, or -+ # make a proposal how this could be done -+ # nicer. -+use Getopt::Long; -+use Pod::Usage; -+use Config::IniFiles; -+use File::Temp; -+ -+# ---------------------------------------------------------------------------- -+# Versions -+our $version : unique = "0.1"; -+our $pfi_version : unique = "0x1"; -+ -+# ---------------------------------------------------------------------------- -+# Globals -+my $verbose = 0; -+my $cfg; -+ -+my %opts = (); -+my %files = (config => ""); -+my @tmp_files; -+ -+my %tools = (ubicrc32 => "ubicrc32"); -+ -+# ---------------------------------------------------------------------------- -+# Processing the input sections -+# -+# The idea is to combine each section entry with a function -+# in order to allow some kind of preprocessing for the values -+# before they are written into the PFI file. -+# This is especially useful to be more verbose and -+# user-friendly in the layout file. -+# -+# All key-function hashes are applied after the general -+# validation of the configuration file. -+# If any mandatory key is missing in a section the user -+# will be informed and the PFI creation process is aborted. -+# -+# Default keys will be checked for their presence inside the config -+# file. If they are missing, they will be generated with appr. values. -+ -+# Mandatory keys for UBI volumes. -+my %ubi_keys = ("ubi_ids" => \&check_id_list, -+ "ubi_size" => \&replace_num, -+ "ubi_type" => \&replace_type, -+ "ubi_names" => \&remove_spaces, -+ "ubi_alignment" => \&replace_num); -+ -+# Mandatory keys for RAW sections. -+my %raw_keys = ("raw_starts" => \&expand_starts, -+ "raw_total_size" => \&replace_num); -+ -+# Common default keys for documentation and control purposes. -+my %common_keys = ("flags" => \&replace_num, -+ "label" => \&do_nothing); -+ -+# Define any defaults here. Values which maintained in this default -+# region need not to be specified by the user explicitly. -+my %def_ubi_keys = ("ubi_alignment" => [\&set_default, "0x1"]); -+my %def_raw_keys = (); -+my %def_common_keys = ("flags" => [\&set_default, "0x0"], -+ "label" => [\&generate_label, ""]); -+ -+# ---------------------------------------------------------------------------- -+# Input keys, actually the path to the input data. -+ -+my %input_keys = ("image" => \&do_nothing); -+ -+# Placeholder keys allow the replacement via a special -+# purpose function. E.g. the bootenv_file key will be used -+# to generate bootenv binary data from an text file and -+# replace the bootenv_file key with an image key to handle it -+# in the same way in the further creation process. -+my %input_placeholder_keys = ("bootenv_file" => \&create_bootenv_image); -+ -+# ---------------------------------------------------------------------------- -+# Helper -+ -+# @brief Get current time string. -+sub get_date { -+ my $tmp = scalar localtime; -+ $tmp =~ s/ /_/g; -+ return $tmp; -+} -+ -+# @brief Print an info message to stdout. -+sub INFO($) { -+ my $str = shift; -+ -+ if (!$verbose) { -+ return; -+ } -+ -+ print STDOUT $str; -+} -+ -+# @brief Print an error message to stderr. -+sub ERR($) { -+ my $str = shift; -+ print STDERR $str; -+} -+ -+# @brief Print a warning message to stderr. -+sub WARN($) { -+ my $str = shift; -+ print STDERR $str; -+} -+ -+sub parse_command_line($) { -+ my $opt = shift; -+ my $result = GetOptions( "help" => \$$opt{'help'}, -+ "man" => \$$opt{'man'}, -+ "config=s" => \$$opt{'config'}, -+ "verbose" => \$$opt{'verbose'}, -+ ) or pod2usage(2); -+ pod2usage(1) if defined ($$opt{help}); -+ pod2usage(-verbose => 2) if defined ($$opt{man}); -+ -+ $verbose = $$opt{verbose} if defined $$opt{verbose}; -+ -+ if (!defined $$opt{config}) { -+ ERR("[ ERROR: No config file specified. Aborting...\n"); -+ exit 1; -+ } -+ -+} -+ -+# @brief Check if all needed tools are in PATH. -+sub check_tools { -+ my $err = 0; -+ my $key; -+ -+ foreach $key (keys %tools) { -+ if (`which $tools{$key}` eq "") { -+ ERR("\n") if ($err == 0); -+ ERR("! Please add the tool \'$tools{$key}\' " . -+ "to your path!\n"); -+ $err = 1; -+ } -+ } -+ die "[ ERROR: Did not find all needed tools!\n" if $err; -+} -+ -+sub open_cfg_file($) { -+ my $fname = shift; -+ my $res = new Config::IniFiles( -file => $fname ); -+ -+ die "[ ERROR: Cannot load your config file!\n" if (!defined $res); -+ return $res; -+} -+ -+sub set_default($$$$) { -+ my ($cfg, $section, $parameter, $def_value) = @_; -+ $cfg->newval($section, $parameter, $def_value); -+ return; -+} -+ -+sub generate_label($$$$) { -+ my ($cfg, $section, $parameter, $def_value) = @_; -+ my $new_label = $def_value . $section; -+ $new_label .= "_" . get_date; -+ $cfg->newval($section, $parameter, $new_label); -+ return; -+} -+ -+# @brief Converts any num to a unified hex string, i.e the resulting value -+# always starts with "0x" and is aligned to 8 hexdigits. -+# @return Returns 0 on success, otherwise an error occured. -+# -+sub any_num_to_hex($$) { -+ my $val = shift; -+ my $res = shift; -+ -+ # M(iB) -+ if ($val =~ m/([0-9]+)[Mm][i]?[Bb]?/g) { -+ $$res = sprintf("0x%08x", $1 * 1024 * 1024); -+ } -+ # k(iB) -+ elsif ($val =~ m/([0-9]+)[kK][i]?[Bb]?/g) { -+ $$res = sprintf("0x%08x", $1 * 1024); -+ } -+ # hex -+ elsif ($val =~ m/0x?([0-9a-fA-F]+)/g) { -+ $$res = sprintf("0x%08x", hex $1); -+ } -+ # decimal -+ elsif ($val =~ m/^([0-9]+)$/g) { -+ $$res = sprintf("0x%08x", $1); -+ } -+ else { -+ $$res = ""; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+sub remove_spaces($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my ($start, @starts, @new_starts); -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $val =~ s/ //g; # spaces -+ $cfg->newval($section, $parameter, $val); -+} -+ -+sub expand_starts($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my ($start, @starts, @new_starts); -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $val =~ s/ //g; # spaces -+ @starts = split(/,/, $val); -+ -+ foreach $start (@starts) { -+ if (any_num_to_hex($start, \$res) != 0) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Expecting a list of numeric " . -+ "values for parameter: $parameter\n"); -+ exit 1; -+ } -+ push (@new_starts, $res); -+ } -+ $res = join(',', @starts); -+ -+ $cfg->newval($section, $parameter, $res); -+} -+ -+sub check_id_list($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ if (!($val =~ m/^[0-9]+[,0-9]*/)) { -+ ERR("[ ERROR: Syntax error in 'ubi_ids' in " . -+ "section '$section': $val\n"); -+ ERR("[ Aborting... "); -+ exit 1; -+ } -+} -+ -+sub replace_type($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res; -+ -+ $res = lc($val); -+ grep {$res eq $_} ('static', 'dynamic') -+ or die "[ ERROR: Unknown UBI Volume Type in " . -+ "section '$section': $val\n"; -+ -+ $cfg->newval($section, $parameter, $res); -+} -+ -+ -+sub replace_num($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $val = $cfg->val($section, $parameter); -+ my $res = ""; -+ -+ if (any_num_to_hex($val, \$res) != 0) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Expecting a numeric value " . -+ "for parameter: $parameter\n"); -+ exit 1; -+ } -+ $cfg->newval($section, $parameter, $res); -+} -+ -+sub do_nothing($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ return; -+} -+ -+sub bootenv_sanity_check($) { -+ my $env = shift; # hash array containing bootenv -+ my %pdd = (); -+ -+ defined($$env{'pdd'}) or return "'pdd' not defined"; -+ foreach (split /,/, $$env{'pdd'}) { -+ defined($$env{$_}) or return "undefined '$_' in pdd"; -+ $pdd{$_} = 1; -+ } -+ -+ defined $$env{'pdd_preserve'} or -+ return ""; -+ foreach (split /,/, $$env{'pdd_preserve'}) { -+ defined($pdd{$_}) -+ or return "pdd_preserve field '$_' not in pdd"; -+ } -+ return ""; -+} -+ -+sub create_bootenv_image($$$) { -+ my ($cfg, $section, $parameter) = @_; -+ my $txt_fn = $cfg->val($section, "bootenv_file"); -+ my $in; -+ -+ my %value = (); -+ my @key = (); -+ -+ open $in, "<", $txt_fn -+ or die "[ ERROR: can't open bootenv file '$txt_fn'.\n"; -+ while (<$in>) { -+ next if (/^\s*(\#.*)?$/); # Skip comments/whitespace. -+ -+ if (/^(\S+?)\+\=(.*)$/) { -+ defined($value{$1}) or -+ die "$txt_fn:$.: error: appending to" . -+ " non-existent '$1'\n"; -+ $value{$1} .= $2; -+ } elsif (/^(\S+?)\=(.*)$/) { -+ not defined($value{$1}) or -+ die "$txt_fn:$.: error: trying to" . -+ " redefine '$1'\n"; -+ push @key, $1; -+ $value{$1} = $2; -+ } else { -+ die "$txt_fn:$.: error: unrecognized syntax\n"; -+ } -+ } -+ close $in; -+ -+ $_ = &bootenv_sanity_check(\%value) -+ and die "$txt_fn: error: $_\n"; -+ -+ my $tmp_file = new File::Temp(); -+ push (@tmp_files, $tmp_file); -+ -+ foreach (@key) { -+ print $tmp_file "$_=", $value{$_}, "\0"; -+ } -+ close $tmp_file; -+ -+ $cfg->newval($section, "image", $tmp_file-> filename); -+} -+ -+sub process_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my $i; -+ -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ if (defined($$keys{$parameters[$i]})) { -+ $$keys{$parameters[$i]}->($cfg, $section, -+ $parameters[$i]); -+ } -+ } -+ -+} -+ -+sub is_in_keylist($$) { -+ my ($key, $keys) = @_; -+ my $i; -+ -+ for ($i = 0; $i < scalar(@$keys); $i++) { -+ if ($$keys[$i] eq $key) { -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+sub check_default_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my $key; -+ -+ foreach $key (keys %$keys) { -+ if (!is_in_keylist($key, \@parameters)) { -+ $$keys{$key}[0]-> -+ ($cfg, $section, $key, $$keys{$key}[1]); -+ } -+ } -+ -+} -+ -+ -+ -+sub check_keys($$$) { -+ my ($cfg, $section, $keys) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my ($i, $key, $err); -+ -+ $err = 0; -+ for ($i = 0 ; $i < scalar(@$keys) ; $i++ ) { -+ if (!is_in_keylist($$keys[$i], \@parameters)) { -+ ERR("[ ERROR: [$section]\n") if $err == 0; -+ $err = 1; -+ ERR("[ Missing key '$$keys[$i]'\n"); -+ } -+ } -+ -+ if ($err) { -+ ERR("[ Aborting...\n"); -+ exit 1; -+ } -+} -+ -+sub push_pfi_data($$$$$) { -+ my ($cfg, $section, $pfi_infos, $keys, $mode) = @_; -+ my ($tmp, $i, $hdr); -+ -+ my %pfi_info = (); -+ $pfi_info{'mode'} = $mode; -+ $pfi_info{'image'} = $cfg->val($section, "image"); -+ -+ # Build the PFI header -+ $hdr = sprintf("PFI!\n"); -+ $hdr .= sprintf("version=0x%08x\n", hex $pfi_version); -+ $hdr .= sprintf("mode=$mode\n"); -+ -+ # calculate the size of the binary data part -+ $tmp = -s $cfg->val($section, "image"); -+ if (!defined $tmp) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Missing input image: " -+ . $cfg->val($section, "image") . "\n"); -+ exit 1; -+ } -+ # Check for the image to fit into the given space -+ my $quota; -+ if ($mode eq 'raw') { -+ $quota = oct $cfg->val($section, "raw_total_size"); -+ } elsif ($mode eq 'ubi') { -+ $quota = oct $cfg->val($section, "ubi_size"); -+ } -+ $tmp <= $quota -+ or die "[ERROR: image file too big: " . -+ $cfg->val($section, "image") . "\n"; -+ $pfi_info{'size'} = $tmp; -+ -+ $hdr .= sprintf("size=0x%08x\n", $tmp); -+ -+ my $img_file = $cfg->val($section, "image"); -+ my $crc32 = `$tools{'ubicrc32'} $img_file 2>&1`; -+ if (any_num_to_hex($crc32, \$tmp) != 0) { -+ die "[ ERROR: $tools{'ubicrc32'} returned with errors"; -+ } -+ $hdr .= sprintf("crc=$tmp\n"); -+ -+ -+ # Process all remaining keys -+ for ($i = 0; $i < scalar (@$keys); $i++) { -+ if ($$keys[$i] eq "image") { # special case image input file -+ if (! -e ($tmp = $cfg->val($section, "image"))) { -+ ERR("[ ERROR: [$section]\n"); -+ ERR("[ Cannot find input file $tmp\n"); -+ exit 1; -+ } -+ next; -+ } -+ $hdr .= sprintf("%s=%s\n", $$keys[$i], -+ $cfg->val($section, $$keys[$i])); -+ } -+ -+ $hdr .= sprintf("\n"); # end marker for PFI-header -+ -+ $pfi_info{'header'} = $hdr; -+ -+ # store in the header list -+ push @$pfi_infos, \%pfi_info; -+} -+ -+sub process_section($$$$$$) { -+ my ($cfg, $section, $pfi_infos, $custom_keys, -+ $def_custom_keys, $mode) = @_; -+ my @keys = (keys %common_keys, keys %$custom_keys); -+ my @complete_keys = (@keys, keys %input_keys); -+ -+ # set defaults if necessary -+ check_default_keys($cfg, $section, $def_custom_keys); -+ check_default_keys($cfg, $section, \%def_common_keys); -+ -+ # check for placeholders... -+ process_keys($cfg, $section, \%input_placeholder_keys); -+ -+ # VALIDATE layout.cfg entries -+ check_keys($cfg, $section, \@complete_keys); -+ -+ # execute linked functions (if any) -+ process_keys($cfg, $section, \%common_keys); -+ process_keys($cfg, $section, $custom_keys); -+ -+ push_pfi_data($cfg, $section, $pfi_infos, \@keys, $mode); -+} -+ -+sub get_section_info($$) { -+ my ($cfg, $section) = @_; -+ my @parameters = $cfg->Parameters($section); -+ my ($ubi, $raw, $i, @res); -+ -+ $ubi = $raw = 0; -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ if ($parameters[$i] =~ m/ubi_/gi) { -+ $ubi = 1; -+ @res = (\%ubi_keys, \%def_ubi_keys, "ubi"); -+ } -+ if ($parameters[$i] =~ m/raw_/gi) { -+ $raw = 1; -+ @res = (\%raw_keys, \%def_raw_keys, "raw"); -+ } -+ } -+ -+ if (($ubi + $raw) != 1) { # double definition in section -+ ERR("[ ERROR: Layout error in section '$section'\n"); -+ exit 1; -+ } -+ -+ return @res; -+} -+ -+sub mk_target_list($$) { -+ my $val = shift; -+ my $tmp = shift; -+ my $complete = 0; -+ -+ if ($val =~ m/\((.*)\)/g) { -+ $val = $1; -+ $complete = 1; -+ } -+ $val =~ s/ //g; # spaces -+ -+ @$tmp = split(/,/, $val); -+ -+ return $complete; -+} -+ -+sub copy_bytes($$$) { -+ my ($in, $out, $to_copy) = @_; -+ -+ while ($to_copy) { -+ my $buf; -+ my $bufsize = 1024*1024; -+ -+ $bufsize < $to_copy or $bufsize = $to_copy; -+ read($in, $buf, $bufsize) == $bufsize -+ or die "[ ERROR: Image file shrunk during operation\n"; -+ print $out $buf; -+ $to_copy -= $bufsize; -+ } -+} -+ -+sub write_target($$) { -+ my ($pfi_infos, $target) = @_; -+ my ($pfi_info); -+ -+ INFO("[ Writting target pfi file: '$target.pfi'...\n"); -+ if (-e "$target.pfi") { -+ WARN("! Replaced old pfi...\n"); -+ `rm -f $target.pfi`; -+ } -+ open(FILE, ">", "$target.pfi") -+ or die "[ ERROR: Cannot create output file: $target.pfi\n"; -+ binmode(FILE); -+ -+ # @FIXME sort by mode (first raw, then ubi) -+ # Currently this ordering is based on a string comparism. :-) -+ @$pfi_infos = sort {(lc $$a{'mode'}) cmp (lc $$b{'mode'})} @$pfi_infos; -+ -+ # Print all headers first -+ foreach $pfi_info (@$pfi_infos) { -+ print FILE $$pfi_info{'header'}; -+ -+ } -+ # Print the linked data sections -+ print FILE "DATA\n"; -+ foreach $pfi_info (@$pfi_infos) { -+ open(IMAGE, "<", $$pfi_info{'image'}) -+ or die "[ ERROR: Cannot open input image: " . -+ "$$pfi_info{'image'}" . "\n"; -+ binmode(IMAGE); -+ ©_bytes(\*IMAGE, \*FILE, $$pfi_info{'size'}); -+ close(IMAGE) or die "[ ERROR: Cannot close input image: " . -+ "$$pfi_info{'image'}" . "\n"; -+ } -+ close(FILE) or die "[ ERROR: Cannot close output file: $target.pfi\n"; -+} -+ -+sub process_config($) { -+ my $cfg = shift; -+ my @sections = $cfg->Sections; -+ my ($i, $j, $keylist, $def_keylist, $mode, $tmp, -+ @tlist, $complete,@pfi_infos); -+ -+ my @parameters = $cfg->Parameters("targets") or -+ die "[ ERROR: Config file has no 'targets' section!\n"; -+ -+ for ($i = 0 ; $i < scalar(@parameters) ; $i++ ) { -+ INFO("[ Processing target '$parameters[$i]'...\n"); -+ @pfi_infos = (); -+ -+ # get a list of subtargets -+ $complete = mk_target_list($cfg->val("targets", -+ $parameters[$i]), \@tlist); -+ # build all subtargets -+ for ($j = 0 ; $j < scalar(@tlist) ; $j++ ) { -+ ($keylist, $def_keylist, $mode) -+ = get_section_info($cfg, $tlist[$j]); -+ process_section($cfg, $tlist[$j], -+ \@pfi_infos, -+ $keylist, $def_keylist, $mode); -+ } -+ -+ write_target(\@pfi_infos, $parameters[$i]); -+ } -+ -+ INFO("[ Success.\n"); -+ -+ -+} -+ -+sub clear_files() { -+ # @FIXME: -+ # Works implicitly and Fedora seems to have removed -+ # the cleanup call. Thus for now, inactive. -+ # File::Temp::cleanup(); -+} -+ -+require 5.008_000; # Tested with version 5.8.0. -+select STDOUT; $| = 1; # make STDOUT output unbuffered -+select STDERR; $| = 1; # make STDERR output unbuffered -+ -+parse_command_line(\%opts); -+check_tools; -+$cfg = open_cfg_file($opts{config}); -+process_config($cfg); -+clear_files; -+ -+__END__ -+ -+ -+=head1 NAME -+ -+mkpfi - Using GetOpt::Long, Pod::Usage, Config::IniFiles -+ -+ -+=head1 SYNOPSIS -+ -+mkpfi [OPTIONS ...] -+ -+ -+ OPTION -+ -+ [--config] [--help] [--man] -+ -+ -+=head1 ABSTRACT -+ -+Perl script for generating pdd pfi files from given config files. -+ -+=head1 OPTIONS -+ -+=over -+ -+=item B<--help> -+ -+Print out brief help message. -+ -+=item B<--usage> -+ -+Print usage. -+ -+=item B<--config> -+ -+Config input file. -+ -+=item B<--man> -+ -+Print manual page, same as 'perldoc mkpfi'. -+ -+=item B<--verbose> -+ -+Be verbose! -+ -+=back -+ -+=head1 BUGS -+ -+Report via MTD mailing list -+ -+ -+=head1 SEE ALSO -+ -+http://www.linux-mtd.infradead.org/ -+ -+ -+=head1 AUTHOR -+ -+Oliver Lohmann (oliloh@de.ibm.com) -+ -+=cut -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/perl/ubicrc32.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,74 @@ -+#!/usr/bin/perl -w -+ -+# Subroutine crc32(): Calculates the CRC on a given string. -+ -+{ -+ my @table = (); -+ -+ # @brief Calculate CRC32 for a given string. -+ sub crc32 -+ { -+ unless (@table) { -+ # Initialize the CRC table -+ my $poly = 0xEDB88320; -+ @table = (); -+ -+ for my $i (0..255) { -+ my $c = $i; -+ -+ for my $j (0..7) { -+ $c = ($c & 1) ? (($c >> 1) ^ $poly) : ($c >> 1); -+ } -+ $table[$i] = $c; -+ } -+ } -+ my $s = shift; # string to calculate the CRC for -+ my $crc = shift; # CRC start value -+ -+ defined($crc) -+ or $crc = 0xffffffff; # Default CRC start value -+ -+ for (my $i = 0; $i < length($s); $i++) { -+ $crc = $table[($crc ^ ord(substr($s, $i, 1))) & 0xff] -+ ^ ($crc >> 8); -+ } -+ return $crc; -+ } -+} -+ -+sub crc32_on_file -+{ -+ my $file = shift; -+ -+ my $crc32 = crc32(''); -+ my $buf = ''; -+ my $ret = 0; -+ -+ while ($ret = read($file, $buf, 8192)) { -+ $crc32 = crc32($buf, $crc32); -+ } -+ defined($ret) -+ or return undef; -+ printf("0x%x\n", $crc32); -+} -+ -+ -+# Main routine: Calculate the CRCs on the given files and print the -+# results. -+ -+{ -+ if (@ARGV) { -+ while (my $path = shift) { -+ my $file; -+ open $file, "<", $path -+ or die "Error opening '$path'.\n"; -+ -+ &crc32_on_file($file) -+ or die "Error reading from '$path'.\n"; -+ close $file; -+ } -+ } else { -+ &crc32_on_file(\*STDIN) -+ or die "Error reading from stdin.\n"; -+ } -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,75 @@ -+# -+# Makefile -+# -+# Testcase for UBI pfi update. -+# -+# Author: Frank Haverkamp -+# -+ -+card = test -+mkpfi_cfg = test.cfg -+ -+# -+# Some default values you might want to overwrite. Try it if you need -+# it and add more if needed. Note that no real sanity checking is done -+# on those values. If you do it wrong your card has no valid PDD data. -+# -+ -+PATH := $(PATH):/opt/ppc/usr/bin:../perl:.. -+ -+dd = dd -+sed = sed -+bin2nand = bin2nand -+ubigen = ubigen -+mkpfi = mkpfi -v -+pfi2bin = pfi2bin -v -+ -+vmlinux_bin ?= test_vmlinux.bin -+rootfs_bin ?= test_rootfs.bin -+spl_bin ?= test_u-boot.bin -+pdd_txt ?= pdd.txt -+ -+flashtype ?= nand -+pagesize ?= 2048 -+ -+compl ?= $(card)_complete -+compl_pfi ?= $(compl).pfi -+compl_img ?= $(compl).img -+ -+compl_nand2048_mif=$(compl).$(flashtype)$(pagesize).mif -+compl_nand2048_img=$(compl).$(flashtype)$(pagesize).img -+ -+all: $(compl_pfi) $(compl_nand2048_mif) -+ -+$(compl_pfi): $(vmlinux_bin) $(rootfs_bin) $(spl_bin) -+ $(mkpfi) -c $(mkpfi_cfg) -+ -+# Binary data and out of band data (OOB) -+# -+$(compl_nand2048_mif): $(compl_img) -+ $(bin2nand) -p $(pagesize) -o $(compl_nand2048_mif) $< -+ -+# Binary data only -+# -+$(compl_img): $(compl_pfi) -+ $(pfi2bin) -j $(pdd_txt) -o $@ $< -+ -+# -+# Default data -+# -+# If the binary data is not available in the current working directory -+# we try to create symlinks to our test data. -+# -+$(vmlinux_bin) $(rootfs_bin) $(spl_bin): -+ @echo -+ @echo "No $@ found, will use defaults !" -+ @echo -+ @echo "OR press CTRL-C to provide your own $@" && \ -+ sleep 1 && \ -+ $(dd) if=/dev/urandom of=$@ bs=1M count=1 -+ -+clean: -+ $(RM) *.pfi *~ -+ -+distclean: clean -+ $(RM) *.bin *.mif *.oob *.img -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/README linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/README ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/README 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+README -+====== -+ -+This procedure creates a test pfi which should be flashed to our -+system with pfiflash. The testcase should read the data back and -+compare with the original. -+ -+We should try not forget to run these tests before we release -+a new version of UBI. -+ -+Frank -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/TODO 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,5 @@ -+TODO -+==== -+ -+ * Range checking is broken, reserving 2M and offering 3M binary data -+ ... works!? No! -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/bin2nand2bin_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,184 @@ -+#!/bin/sh -+# -+# Testcase for nand2bin and bin2nand. Generate testdata and inject -+# biterrors. Convert data back and compare with original data. -+# -+# Conversion: -+# bin -> bin2nand -> mif -> nand2bin -> img -+# -+ -+inject_biterror=./scripts/inject_biterror.pl -+ -+pagesize=2048 -+oobsize=64 -+ -+# Create test data -+dd if=/dev/urandom of=testblock.bin bs=131072 count=1 -+ -+echo "Test conversion without bitflips ..." -+ -+echo -n "Convert bin to mif ... " -+bin2nand --pagesize=${pagesize} -o testblock.mif testblock.bin -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Convert mif to bin ... " -+nand2bin --pagesize=${pagesize} -o testblock.img testblock.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Comparing data ... " -+diff testblock.bin testblock.img -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo "Test conversion with uncorrectable ECC erors ..." -+echo -n "Inject biterror at offset $ioffs ... " -+${inject_biterror} --offset=0 --bitmask=0x81 \ -+ --input=testblock.mif \ -+ --output=testblock_bitflip.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo "Convert mif to bin ... " -+rm testblock.img -+nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+else -+ echo "ok" -+fi -+ -+echo -n "Comparing data, must fail due to uncorrectable ECC ... " -+diff testblock.bin testblock.img -+if [ $? -ne "0" ]; then -+ echo "ok" # Must fail! -+else -+ echo "failed!" -+ exit 1 -+fi -+ -+echo "Test bitflips in data ... " -+for offs in `seq 0 255` ; do -+ -+ cp testblock.mif testblock_bitflip.mif -+ -+ for xoffs in 0 256 512 768 ; do -+ let ioffs=$offs+$xoffs -+ -+ cp testblock_bitflip.mif testblock_bitflip_tmp.mif -+ echo -n "Inject biterror at offset $ioffs ... " -+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ -+ --input=testblock_bitflip_tmp.mif \ -+ --output=testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ done -+ -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ hexdump testblock.bin > testblock.bin.txt -+ hexdump testblock.img > testblock.img.txt -+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ # Without correction -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data must differ, correction is disabled ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ echo "ok" # must fail -+ else -+ echo "failed!" -+ exit 1 -+ fi -+done -+ -+echo "Test bitflips in OOB data ... " -+for offs in `seq 0 $oobsize` ; do -+ -+ let ioffs=$pagesize+$offs -+ -+ echo -n "Inject biterror at offset $ioffs ... " -+ ${inject_biterror} --offset=${ioffs} --bitmask=0x01 \ -+ --input=testblock.mif \ -+ --output=testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo "Convert mif to bin ... " -+ rm testblock.img -+ nand2bin --correct-ecc --pagesize=${pagesize} -o testblock.img \ -+ testblock_bitflip.mif -+ if [ $? -ne "0" ]; then -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+ -+ echo -n "Comparing data ... " -+ diff testblock.bin testblock.img -+ if [ $? -ne "0" ]; then -+ hexdump testblock.bin > testblock.bin.txt -+ hexdump testblock.img > testblock.img.txt -+ echo "Use tkdiff testblock.bin.txt testblock.img.txt to compare" -+ echo "failed!" -+ exit 1 -+ else -+ echo "ok" -+ fi -+done -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/inject_biterror.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,94 @@ -+#!/usr/bin/perl -w -+# -+# 2007 Frank Haverkamp -+# -+# Program for bit-error injection. I am sure that perl experts do it -+# in 1 line. Please let me know how it is done right ;-). -+# -+ -+use strict; -+use warnings; -+use Getopt::Long; -+use Pod::Usage; -+ -+my $i; -+my $help; -+my $result; -+my $offset = 0; -+my $bitmask = 0x01; -+my $in = "input.mif"; -+my $out = "output.mif"; -+ -+$result = GetOptions ("offset=i" => \$offset, # numeric -+ "bitmask=o" => \$bitmask, # numeric -+ "input=s" => \$in, # string -+ "output=s" => \$out, # string -+ "help|?" => \$help) or pod2usage(2); -+ -+pod2usage(1) if $help; -+ -+my $buf; -+ -+open(my $in_fh, "<", $in) -+ or die "Cannot open file $in: $!"; -+binmode $in_fh; -+ -+open(my $out_fh, ">", $out) or -+ die "Cannot open file $out: $!"; -+binmode $out_fh; -+ -+$i = 0; -+while (sysread($in_fh, $buf, 1)) { -+ -+ $buf = pack('C', unpack('C', $buf) ^ $bitmask) if ($i == $offset); -+ syswrite($out_fh, $buf, 1) or -+ die "Cannot write to offset $offset: $!"; -+ $i++; -+} -+ -+close $in_fh; -+close $out_fh; -+ -+__END__ -+ -+=head1 NAME -+ -+inject_biterrors.pl -+ -+=head1 SYNOPSIS -+ -+inject_biterror.pl [options] -+ -+=head1 OPTIONS -+ -+=over 8 -+ -+=item B<--help> -+ -+Print a brief help message and exits. -+ -+=item B<--offset>=I -+ -+Byte-offset where bit-error should be injected. -+ -+=item B<--bitmask>=I -+ -+Bit-mask where to inject errors in the byte. -+ -+=item B<--input>=I -+ -+Input file. -+ -+=item B<--output>=I -+ -+Output file. -+ -+=back -+ -+=head1 DESCRIPTION -+ -+B will read the given input file and inject -+biterrors at the I specified. The location of the biterrors -+are defined by the I parameter. -+ -+=cut -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/jffs2_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,91 @@ -+#!/bin/sh -+# -+# Testcase for JFFS2 verification. We do not want to see any -+# kernel errors occuring when this is executed. -+# -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+echo "***********************************************************************" -+echo "* jffs2 testing ... *" -+echo "***********************************************************************" -+ -+ulimit -c unlimited -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ dd if=/dev/urandom of=test.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "Copy to different file ... " -+ dd if=test.bin of=new.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing files ... " -+ cmp test.bin new.bin -+ dd if=test.bin of=new.bin bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ dd if=/dev/urandom of=foo bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+for i in `seq 5000`; do -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1) ... " -+ dd if=/dev/zero of=foo bs=$i count=1; -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool JFFS2 using system! *" -+echo "***********************************************************************" -+ -+exit_success -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/mkdevs.pl 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,32 @@ -+#!/usr/bin/perl -w -+ -+# -+# Author: Artem B. Bityutskiy -+# -+# A small scrip which creates UBI device nodes in /dev. UBI allocates -+# major number dynamically, so the script looks at /proc/devices to find -+# out UBI's major number. -+# -+ -+ -+my $proc = '/proc/devices'; -+my $regexp = '(\d+) (ubi\d+)$'; -+ -+ -+open FILE, "<", $proc or die "Cannot open $proc file: $!\n"; -+my @file = ; -+close FILE; -+ -+foreach (@file) { -+ next if not m/$regexp/g; -+ print "found $2\n"; -+ -+ system("rm -rf /dev/$2"); -+ system("mknod /dev/$2 c $1 0"); -+ -+ for (my $i = 0; $i < 128; $i += 1) { -+ system("rm -rf /dev/$2_$i"); -+ my $j = $i + 1; -+ system("mknod /dev/$2_$i c $1 $j"); -+ } -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/pdd.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+pdd=flash_type,flash_size,flash_eraseblock_size,flash_page_size,card_serialnumber,card_type,ethaddr,eth1addr,eth0,eth1,total,card_hardwarelevel -+pdd_preserve=ethaddr,eth1addr,card_serialnumber -+# To be personalized -+ethaddr=00:04:34:56:78:9A -+eth1addr=00:04:34:56:78:9B -+card_serialnumber=SN0 -+# Static for this card type -+total=102M -+card_type=nand_driven_testcard -+card_hardwarelevel=0 -+eth0=bcm5222,eth0,0 -+eth1=bcm5222,eth0,1 -+flash_type=NAND -+flash_size=0x08000000 -+flash_eraseblock_size=0x00020000 -+flash_page_size=0x00000800 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/run_all.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,101 @@ -+#!/bin/sh -+ -+exit_success () -+{ -+ echo "UBI Utils Test Scripts - SUCCESS!" -+ exit 0 -+} -+ -+exit_failure () -+{ -+ echo $1 -+ echo "UBI Utils Test Scripts - FAILED!" -+ exit 1 -+} -+ -+echo UBI Utils Test Scripts -+ -+devno=$1 -+logfile=temp-test-log.txt -+ -+if test -z "$devno"; -+then -+ echo "Usage is $0 " -+ exit 1 -+fi -+ -+cwd=`pwd` || exit_failure "pwd failed" -+ -+log="${cwd}/${logfile}" -+ -+PATH=$PATH:$cwd:.. -+ -+cat /dev/null > $log || exit_failure "Failed to create $log" -+ -+echo "Setting up for jffs2_test.sh" | tee -a $log -+ -+avail=`cat /sys/class/ubi/ubi${devno}/avail_eraseblocks` -+size=`cat /sys/class/ubi/ubi${devno}/eraseblock_size` -+ -+bytes=`expr $avail \* $size` -+ -+ubimkvol -d$devno -s$bytes -n0 -Njtstvol || exit_failure "ubimkvol failed" -+ -+mkdir -p /mnt/test_file_system || exit_failure "mkdir failed" -+ -+mtd=`cat /proc/mtd | grep jtstvol | cut -d: -f1` -+ -+if test -z "$mtd"; -+then -+ exit_failure "mtd device not found" -+fi -+ -+mount -t jffs2 $mtd /mnt/test_file_system || exit_failure "mount failed" -+ -+cd /mnt/test_file_system || exit_failure "cd failed" -+ -+echo Running jffs2_test.sh | tee -a $log -+ -+jffs2_test.sh >> $log 2>&1 || exit_failure "jffs2_test.sh failed" -+ -+rm -f * -+ -+cd $cwd || exit_failure "cd failed" -+ -+umount /mnt/test_file_system || exit_failure "umount failed" -+ -+ubirmvol -d$devno -n0 || exit_failure "ubirmvol failed" -+ -+major=`cat /sys/class/ubi/ubi${devno}/dev | cut -d: -f1` -+ -+for minor in `seq 0 32`; do -+ if test ! -e /dev/ubi${devno}_$minor ; -+ then -+ mknod /dev/ubi${devno}_$minor c $major $(($minor + 1)) -+ fi -+done -+ -+rm -f testdata.bin readdata.bin -+ -+echo Running ubi_jffs2_test.sh | tee -a $log -+ -+ubi_jffs2_test.sh >> $log 2>&1 || exit_failure "ubi_jffs2_test.sh failed" -+ -+echo Running ubi_test.sh | tee -a $log -+ -+ubi_test.sh >> $log 2>&1 || exit_failure "ubi_test.sh failed" -+ -+for minor in `seq 0 32`; do -+ if test -e /sys/class/ubi/ubi${devno}/$minor; -+ then -+ ubirmvol -d$devno -n$minor || exit_failure "ubirmvol failed" -+ fi -+done -+ -+echo Running ubi_tools_test.sh | tee -a $log -+ -+ubi_tools_test.sh >> $log 2>&1 || exit_failure "ubi_tools_test failed" -+ -+rm -f $log -+ -+exit_success -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/test.cfg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,23 @@ -+[targets] -+test_complete=spl,kernel,rootfs -+ -+[spl] -+image=test_u-boot.bin -+ubi_ids=10,11 -+ubi_size=1MiB -+ubi_type=static -+ubi_names=test_spl_0,test_spl_1 -+ -+[kernel] -+image=test_vmlinux.bin -+ubi_ids=12,13 -+ubi_size=2MiB -+ubi_type=static -+ubi_names=test_kernel_0,test_kernel_1 -+ -+[rootfs] -+image=test_rootfs.bin -+ubi_ids=14,15 -+ubi_size=2MiB -+ubi_type=dynamic -+ubi_names=test_rootfs_0,test_rootfs_1 -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_jffs2_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,411 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read and JFFS2 on top of UBI -+# testcases. -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# 1.1 Added fixup for delayed device node creation by udev -+# This points to a problem in the tools, mabe in the desing -+# Tue Oct 31 14:14:54 CET 2006 -+# -+ -+VERSION="1.1" -+ -+export PATH=$PATH:/bin:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+ITERATIONS=250 -+ALIGNMENT=2048 -+ -+UBIMKVOL="ubimkvol -a $ALIGNMENT" -+UBIRMVOL=ubirmvol -+UBIUPDATEVOL=ubiupdatevol -+ -+SIZE_512K=524288 -+SIZE_1M=1310720 -+ -+MINVOL=10 -+MAXVOL=12 -+ -+TLOG=/dev/null -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq $MINVOL $MAXVOL`; do -+ echo " -> mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# -+# FIXME Udev needs some time until the device nodes are created. -+# This will cause trouble if after ubimkvol an update attempt -+# is started immediately, since the device node is not yet -+# available. We should either fix the tools with inotify or -+# other ideas or figure out a different way to solve the problem -+# e.g. to use ubi0 and make the volume device nodes obsolete... -+# -+udev_wait () -+{ -+ echo -n "FIXME Waiting for udev to create/delete device node " -+ grep 2\.6\.5 /proc/version > /dev/null -+ if [ $? -eq "0" ]; then -+ for i in `seq 0 5`; do -+ sleep 1; echo -n "."; -+ done -+ echo " ok" -+ fi -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o \ -+ -e /sys/class/ubi/ubi0/$volume -o \ -+ -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo "*** Truncate volume if it exists ... " -+ echo " $UBIUPDATEVOL -d0 -n$volume -t" -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ # udev_wait -+ fi -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @volume: Volume number -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+writevol_test () -+{ -+ volume=$1 -+ size=$2 -+ type=$3 -+ -+ echo "*** Write volume test with size $size" -+ -+### Make sure that volume exist, delete existing volume, create new -+ -+ delete_volume $volume -+ -+ echo "*** Try to create volume" -+ echo " $UBIMKVOL -d0 -n$volume -t$type -NNEW$volume -s $size ... " -+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ udev_wait -+ -+### Try to create same volume again -+ echo -n "*** Try to create some volume again, this must fail ... " -+ $UBIMKVOL -d0 -n$volume -t$type -N"NEW$volume" -s $size -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Now create test data, write it, read it, compare it -+ echo -n "*** Create test data ... " -+ dd if=/dev/urandom of=testdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Now writing data to volume ... " -+ echo " $UBIUPDATEVOL -d0 -n$volume testdata.bin" -+ ls -l testdata.bin -+ $UBIUPDATEVOL -d0 -n$volume testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Download data with dd bs=1 ... " -+ dd if=/dev/ubi0_$volume of=readdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Comparing data ... " -+ cmp readdata.bin testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Now truncate volume ... " -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+jffs2_torture () -+{ -+ cat /dev/null > TLOG -+ -+ echo "*** Torture test ... " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/urandom of=test.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ exit_failure -+ fi -+ #passed -+ -+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG" -+ exit_failure -+ fi -+ #passed -+ -+ #echo "Comparing files ... " -+ cmp test.bin new.bin -+ dd if=test.bin of=new.bin bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ #passed -+ #echo -n "." -+ done -+ -+ echo -n "step0:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/urandom of=foo bs=$i count=1 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/urandom of=foo bs=$i count=1) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step1:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/zero of=foo bs=1 count=$i 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=1 count=$i) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step2:ok " -+ -+ for i in `seq $iterations`; do -+ dd if=/dev/zero of=foo bs=$i count=16 2>> $TLOG -+ if [ $? -ne "0" ] ; then -+ echo "Testing $i byte (dd if=/dev/zero of=foo bs=$i count=1024) ... " -+ exit_failure -+ fi -+ #passed -+ done -+ -+ echo -n "step3:ok " -+ -+ passed -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @volume: Volume number -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+jffs2_test () -+{ -+ name=$1 -+ iterations=$2 -+ directory=`pwd` -+ -+ ### Setup -+ ulimit -c unlimited -+ -+ echo -n "*** Create directory /mnt/$name ... " -+ mkdir -p /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** mount -t jffs2 mtd:$name /mnt/$name ... " -+ mount -t jffs2 mtd:$name /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** change directory ... " -+ cd /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ls -+ echo "*** list directory ... " -+ ls -la -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Torture -+ echo -n "*** touch I_WAS_HERE ... " -+ touch I_WAS_HERE -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ jffs2_torture -+ -+ echo "*** list directory ... " -+ ls -la -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Cleanup -+ echo -n "*** go back ... " -+ cd $directory -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ ### Still mounted, ubiupdatevol must fail! -+ -+ echo -n "*** $UBIUPDATEVOL -d0 -n$volume -t must fail! ..." -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** umount /mnt/$name ... " -+ umount /mnt/$name -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ return -+} -+ -+echo "***********************************************************************" -+echo "* UBI JFFS2 Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on Artems hardware" -+fi -+ -+for volume in `seq $MINVOL $MAXVOL`; do -+ echo -n "************ VOLUME $volume NEW$volume " -+ echo "******************************************" -+ writevol_test $volume $SIZE_1M dynamic -+ jffs2_test NEW$volume $ITERATIONS -+ delete_volume $volume -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,328 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read test script -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# 1.1 Use ubiupdatevol instead of ubiwritevol -+# -+ -+VERSION="1.1" -+ -+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+UBIMKVOL=ubimkvol -+UBIRMVOL=ubirmvol -+UBIUPDATEVOL=ubiupdatevol -+ -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+SIZE_512K=524288 -+SIZE_1M=1310720 -+ -+SELF=$0 -+MINVOL=10 -+MAXVOL=12 -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq 0 $MAXVOL`; do -+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo -n "*** Truncate volume if it exists ... " -+ $UBIUPDATEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+mkvol_rmvol_test () -+{ -+ type=$1 -+ -+### Test if volume delete on non-existing volumes fails nicely -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Delete if exist or not $i ... " -+ -+ delete_volume $i -+ passed -+ done -+ -+### Now deleting volumes must fail -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Trying to delete non existing UBI Volume $i ... " -+ -+ $UBIRMVOL -d0 -n$i -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Test if volume creation works ok -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Creating UBI Volume $i ... " -+ echo " $UBIMKVOL -d0 -n$i -t$type -NNEW$i -s $SIZE_512K" -+ -+ $UBIMKVOL -d0 -n$i -t$type -N"NEW$i" -s $SIZE_512K -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Now deleting volumes must be ok -+ -+ for i in `seq $MINVOL $MAXVOL`; do -+ echo "*** Trying to delete UBI Volume $i ... " -+ -+ $UBIRMVOL -d0 -n$i -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ done -+ -+### Now allocate too large volume -+ -+ echo -n "*** Try to create too large volume" -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s 800000000 -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+# writevol_test - Tests volume creation and writing data to it. -+# -+# @size: Size of random data to write -+# @type: Volume type static or dynamic -+# -+writevol_test () -+{ -+ size=$1 -+ type=$2 -+ -+ echo "*** Write volume test with size $size" -+ -+### Make sure that volume exist, delete existing volume, create new -+ -+ delete_volume $MINVOL -+ -+ echo -n "*** Try to create volume ... " -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Try to create same volume again -+ echo -n "*** Try to create some volume again, this must fail ... " -+ $UBIMKVOL -d0 -n$MINVOL -t$type -N"NEW$MINVOL" -s $SIZE_1M -+ if [ $? -eq "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+### Now create test data, write it, read it, compare it -+ echo -n "*** Create test data ... " -+ dd if=/dev/urandom of=testdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo "*** Now writing data to volume ... " -+ # sleep 5 -+ ls -l testdata.bin -+ echo " $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin" -+ $UBIUPDATEVOL -d0 -n$MINVOL testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ if [ $type = "static" ] ; then -+ echo "*** Download data with cat ... " -+ cat /dev/ubi0_$MINVOL > readdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ else -+ echo "*** Download data with dd bs=1 ... " -+ dd if=/dev/ubi0_$MINVOL of=readdata.bin bs=$size count=1 -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ # Size 1 does not work with this test ... -+ # -+ #echo "*** Download data with dd bs=$size ... " -+ #dd if=/dev/ubi0_$MINVOL of=readdata2.bin bs=$size count=1 -+ #if [ $? -ne "0" ] ; then -+ # exit_failure -+ #fi -+ #passed -+ -+ #echo -n "*** Comparing data (1) ... " -+ #cmp readdata.bin readdata2.bin -+ #if [ $? -ne "0" ] ; then -+ # exit_failure -+ #fi -+ #passed -+ fi -+ -+ echo -n "*** Comparing data ... " -+ cmp readdata.bin testdata.bin -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+} -+ -+echo "***********************************************************************" -+echo "* UBI Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on Artems hardware" -+fi -+ -+echo "***********************************************************************" -+echo "* mkvol/rmvol testing for static volumes ... *" -+echo "***********************************************************************" -+ -+mkvol_rmvol_test static -+ -+echo "***********************************************************************" -+echo "* mkvol/rmvol testing for dynamic volumes ... *" -+echo "***********************************************************************" -+ -+mkvol_rmvol_test dynamic -+ -+echo "***********************************************************************" -+echo "* write to static volumes ... *" -+echo "***********************************************************************" -+ -+# 10 Erase blocks = (128 KiB - 64 * 2) * 10 -+# = 1309440 bytes -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+for size in 262144 131073 131072 2048 1 4096 12800 31313 ; do -+ writevol_test $size static -+done -+ -+echo "***********************************************************************" -+echo "* write to dynamic volumes ... *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+for size in 131073 131072 2048 1 4096 12800 31313 262144 ; do -+ writevol_test $size dynamic -+done -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/ubi_tools_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,252 @@ -+#!/bin/sh -+# -+# UBI Volume creation/deletion/write/read test script. -+# Uses our flash update tools and the associated toolchain for flash -+# image creation. -+# -+# Written in shell language to reduce dependencies to more sophisticated -+# interpreters, which may not be available on some stupid platforms. -+# -+# Author: Frank Haverkamp -+# -+# 1.0 Initial version -+# -+ -+VERSION="1.0" -+ -+export PATH=$PATH:~/bin:/usr/local/bin:/home/dedekind/work/prj/ubi/tools/flashutils/bin/ -+ -+UBIMKVOL=ubimkvol -+UBIRMVOL=ubirmvol -+UBIWRITEVOL=ubiupdatevol -+PFIFLASH=pfiflash -+CMP=cmp -+ -+MAXVOL=32 -+ -+test_pfi=test_complete.pfi -+real_pfi=example_complete.pfi -+ -+# 128 KiB 131072 -+# 256 KiB 262144 -+# 512 KiB 524288 -+ -+# -+# To have a standardized output I define the following function to be -+# used when a test was ok or when it failed. -+# -+failed () -+{ -+ echo "FAILED" -+} -+ -+passed () -+{ -+ echo "PASSED" -+} -+ -+# -+# Print sucess message. Consider to exit with zero as return code. -+# -+exit_success () -+{ -+ echo "SUCCESS" -+ exit 0 -+} -+ -+# -+# Print failure message. Consider to exit with non zero return code. -+# -+exit_failure () -+{ -+ echo "FAILED" -+ exit 1 -+} -+ -+############################################################################### -+# -+# START -+# -+############################################################################### -+ -+fix_sysfs_issue () -+{ -+ echo -n "*** Fixing the sysfs issue with the /dev nodes ... " -+ -+ minor=0 -+ major=`grep ubi0 /proc/devices | sed -e 's/\(.*\) ubi0/\1/'` -+ -+ rm -rf /dev/ubi0 -+ mknod /dev/ubi0 c $major 0 -+ -+ for minor in `seq 0 $MAXVOL`; do -+ ### echo " mknod /dev/ubi0_$minor c $major $(($minor + 1))" -+ rm -rf /dev/ubi0_$minor -+ mknod /dev/ubi0_$minor c $major $(($minor + 1)) -+ done -+ passed -+} -+ -+# delete_volume - Delete a volume. If it does not exist, do not try -+# to delete it. -+# @id: volume id -+# -+delete_volume () -+{ -+ volume=$1 -+ -+ ### FIXME broken sysfs!!!! -+ if [ -e /sys/class/ubi/$volume -o -e /sys/class/ubi/ubi0/$volume -o -e /sys/class/ubi/ubi0_$volume ]; then -+ -+ echo -n "*** Truncate volume if it exists ... " -+ $UBIWRITEVOL -d0 -n$volume -t -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ -+ echo -n "*** Delete volume if it exists ... " -+ $UBIRMVOL -d0 -n$volume -+ if [ $? -ne "0" ] ; then -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+echo "***********************************************************************" -+echo "* UBI Tools Testing starts now ... *" -+echo "* Good luck! *" -+echo "***********************************************************************" -+ -+# Set to zero if not running on example hardware -+grep ubi /proc/devices > /dev/null -+if [ $? -ne "0" ]; then -+ echo "No UBI found in /proc/devices! I am broken!" -+ exit_failure -+fi -+ -+# Set to zero if not running on example hardware -+grep 1142 /proc/cpuinfo > /dev/null -+if [ $? -eq "0" ]; then -+ echo "Running on example hardware" -+ mount -o remount,rw / / -+ sleep 1 -+ fix_sysfs_issue -+else -+ echo "Running on other hardware" -+fi -+ -+### Test basic stuff -+pfiflash_basic () -+{ -+ echo "Calling pfiflash with test-data ... " -+ echo " $PFIFLASH $test_pfi" -+ $PFIFLASH $test_pfi -+ if [ $? -ne "0" ]; then -+ echo "Uhhh something went wrong!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 10 and 11 ... " -+ $CMP /dev/ubi0_10 /dev/ubi0_11 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_10 test_u-boot.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 12 and 13 ... " -+ $CMP /dev/ubi0_12 /dev/ubi0_13 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_12 test_vmlinux.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 14 and 15 ... " -+ $CMP /dev/ubi0_14 /dev/ubi0_15 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+} -+ -+### Test each and everything -+pfiflash_advanced () -+{ -+ if [ -e example_complete.pfi ]; then -+ echo "Calling pfiflash with real data ... " -+ $PFIFLASH -p overwrite --complete example_complete.pfi -+ if [ $? -ne "0" ]; then -+ echo "Uhhh something went wrong!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 2 and 3 ... " -+ $CMP /dev/ubi0_2 /dev/ubi0_3 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_2 u-boot.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Testing if data is correct 6 and 7 ... " -+ $CMP /dev/ubi0_6 /dev/ubi0_7 -+ if [ $? -ne "0" ]; then -+ echo "Mirrored volumes not equal!" -+ exit_failure -+ fi -+ passed -+ -+ echo "Comparing against original data ... " -+ $CMP /dev/ubi0_6 vmlinux.bin -+ if [ $? -ne "0" ]; then -+ echo "Compared volume not equal!" -+ exit_failure -+ fi -+ passed -+ fi -+} -+ -+echo "***********************************************************************" -+echo "* Testing pfiflash ... *" -+echo "***********************************************************************" -+echo "VERSION: $VERSION" -+ -+pfiflash_basic -+pfiflash_advanced -+ -+echo "***********************************************************************" -+echo "* Congratulations, no errors found! *" -+echo "* Have fun with your cool UBI system! *" -+echo "***********************************************************************" -+ -+exit_success -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/scripts/unubi_test.sh 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,105 @@ -+#!/bin/sh -+# -+# Use raw NAND data, extract UBI image and apply tool to it. -+# Test basic functionality. -+# -+# 2007 Frank Haverkamp -+# -+ -+version=1.1 -+ -+image=data.mif -+oob=oob.bin -+data=data.bin -+pagesize=2048 -+volmax=31 -+datadir=unubi_data -+ -+# general arguments e.g. debug enablement -+# unubi_args="-D" -+ -+echo "------------------------------------------------------------------------" -+echo "Testcase: ${0} Version: ${version}" -+echo "------------------------------------------------------------------------" -+echo "Testing nand2bin ..." -+echo " Input: ${image}" -+echo " Data: ${data}" -+echo " OOB: ${oob}" -+echo " Pagesize: ${pagesize}" -+nand2bin --pagesize ${pagesize} -o ${data} -O ${oob} ${image} -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Testing unubi ..." -+echo "------------------------------------------------------------------------" -+unubi --version -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Trying to extract first ${volmax} volumes ..." -+echo "------------------------------------------------------------------------" -+mkdir -p ${datadir}/volumes -+for v in `seq 0 ${volmax}` ; do -+ unubi ${unubi_args} -r${v} -d${datadir}/volumes ${data} -+ echo -n "." -+done -+echo "ok" -+ls -l ${datadir}/volumes -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Extracting graphics ..." -+echo "------------------------------------------------------------------------" -+unubi -a -d${datadir} ${data} -+echo "Use gnuplot to display:" -+ls ${datadir}/*.plot -+ls ${datadir}/*.data -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "eb-split" -+echo "------------------------------------------------------------------------" -+unubi -e -d${datadir}/eb-split ${data} -+ls -l ${datadir}/eb-split -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "vol-split" -+echo "------------------------------------------------------------------------" -+unubi -v -d${datadir}/vol-split ${data} -+ls -l ${datadir}/vol-split -+echo -+echo "The generated images contain only the data (126KiB in our " -+echo "case) not including the UBI erase count and volume info " -+echo "header. For dynamic volumes the data should be the full " -+echo "126KiB. Unubi cannot know how much of the data is valid. " -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "!vol-split" -+echo "------------------------------------------------------------------------" -+unubi -V -d${datadir}/vol-split! ${data} -+ls -l ${datadir}/vol-split\! -+echo -+echo "The generated images contain the full block data of 128KiB " -+echo "including the UBI erase count and volume information header." -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Extracting volume info table ..." -+echo "------------------------------------------------------------------------" -+unubi -i -d${datadir} ${data} -+echo "I strongly hope that empty ubi blocks are filled with 0xff! " -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Table 0" -+echo "------------------------------------------------------------------------" -+cat ${datadir}/vol_info_table0 -+echo -+ -+echo "------------------------------------------------------------------------" -+echo "Table 1" -+echo "------------------------------------------------------------------------" -+cat ${datadir}/vol_info_table1 -+echo -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bin2nand.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,344 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+/* -+ * Create a flashable NAND image from a binary image -+ * -+ * History: -+ * 1.0 Initial release (tglx) -+ * 1.1 Understands hex and dec input parameters (tglx) -+ * 1.2 Generates separated OOB data, if needed. (oloh) -+ * 1.3 Padds data/oob to a given size. (oloh) -+ * 1.4 Removed argp because we want to use uClibc. -+ * 1.5 Minor cleanup -+ * 1.6 written variable not initialized (-j did not work) (haver) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "error.h" -+#include "config.h" -+#include "nandecc.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define CHECK_ENDP(option, endp) do { \ -+ if (*endp) { \ -+ fprintf(stderr, \ -+ "Parse error option \'%s\'. " \ -+ "No correct numeric value.\n" \ -+ , option); \ -+ exit(EXIT_FAILURE); \ -+ } \ -+} while(0) -+ -+typedef enum action_t { -+ ACT_NORMAL = 0x00000001, -+} action_t; -+ -+#define PAGESIZE 2048 -+#define PADDING 0 /* 0 means, do not adjust anything */ -+#define BUFSIZE 4096 -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "bin2nand - a tool for adding OOB information to a " -+ "binary input file.\n"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright informatoin.\n" -+" -j, --padding= Padding in Byte/Mi/ki. Default = no padding\n" -+" -p, --pagesize= Pagesize in Byte/Mi/ki. Default = 2048\n" -+" -o, --output= Output filename. Interleaved Data/OOB if\n" -+" output-oob not specified.\n" -+" -q, --output-oob= Write OOB data in separate file.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: bin2nand [-c?V] [-j ] [-p ] [-o ] [-q ]\n" -+" [--copyright] [--padding=] [--pagesize=]\n" -+" [--output=] [--output-oob=] [--help] [--usage]\n" -+" [--version]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "padding", .has_arg = 1, .flag = NULL, .val = 'j' }, -+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "output-oob", .has_arg = 1, .flag = NULL, .val = 'q' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp. 2006"; -+ -+typedef struct myargs { -+ action_t action; -+ -+ size_t pagesize; -+ size_t padding; -+ -+ FILE* fp_in; -+ char *file_out_data; /* Either: Data and OOB interleaved -+ or plain data */ -+ char *file_out_oob; /* OOB Data only. */ -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+ -+static int ustrtoull(const char *cp, char **endp, unsigned int base) -+{ -+ unsigned long long res = strtoull(cp, endp, base); -+ -+ switch (**endp) { -+ case 'G': -+ res *= 1024; -+ case 'M': -+ res *= 1024; -+ case 'k': -+ case 'K': -+ res *= 1024; -+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */ -+ if ((*endp)[1] == 'i') -+ (*endp) += 2; -+ } -+ return res; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ char* endp; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cj:p:o:q:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'p': /* pagesize */ -+ args->pagesize = (size_t) -+ ustrtoull(optarg, &endp, 0); -+ CHECK_ENDP("p", endp); -+ break; -+ case 'j': /* padding */ -+ args->padding = (size_t) -+ ustrtoull(optarg, &endp, 0); -+ CHECK_ENDP("j", endp); -+ break; -+ case 'o': /* output */ -+ args->file_out_data = optarg; -+ break; -+ case 'q': /* output oob */ -+ args->file_out_oob = optarg; -+ break; -+ case '?': /* help */ -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ exit(0); -+ break; -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ case 'c': -+ printf("%s\n", copyright); -+ exit(0); -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ err_quit("Cannot open file %s for input\n", -+ argv[optind++]); -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+process_page(uint8_t* buf, size_t pagesize, -+ FILE *fp_data, FILE* fp_oob, size_t* written) -+{ -+ int eccpoi, oobsize; -+ size_t i; -+ uint8_t oobbuf[64]; -+ -+ memset(oobbuf, 0xff, sizeof(oobbuf)); -+ -+ switch(pagesize) { -+ case 2048: oobsize = 64; eccpoi = 64 / 2; break; -+ case 512: oobsize = 16; eccpoi = 16 / 2; break; -+ default: -+ err_msg("Unsupported page size: %d\n", pagesize); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) { -+ oobbuf[eccpoi++] = 0x0; -+ /* Calculate ECC */ -+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); -+ } -+ -+ /* write data */ -+ *written += fwrite(buf, 1, pagesize, fp_data); -+ -+ /* either separate oob or interleave with data */ -+ if (fp_oob) { -+ i = fwrite(oobbuf, 1, oobsize, fp_oob); -+ if (ferror(fp_oob)) { -+ err_msg("IO error\n"); -+ return -EIO; -+ } -+ } -+ else { -+ i = fwrite(oobbuf, 1, oobsize, fp_data); -+ if (ferror(fp_data)) { -+ err_msg("IO error\n"); -+ return -EIO; -+ } -+ } -+ -+ return 0; -+} -+ -+int main (int argc, char** argv) -+{ -+ int rc = -1; -+ int res = 0; -+ size_t written = 0, read; -+ myargs args = { -+ .action = ACT_NORMAL, -+ .pagesize = PAGESIZE, -+ .padding = PADDING, -+ .fp_in = NULL, -+ .file_out_data = NULL, -+ .file_out_oob = NULL, -+ }; -+ -+ FILE* fp_out_data = stdout; -+ FILE* fp_out_oob = NULL; -+ -+ parse_opt(argc, argv, &args); -+ -+ uint8_t* buf = calloc(1, BUFSIZE); -+ if (!buf) { -+ err_quit("Cannot allocate page buffer.\n"); -+ } -+ -+ if (!args.fp_in) { -+ err_msg("No input image specified!\n"); -+ goto err; -+ } -+ -+ if (args.file_out_data) { -+ fp_out_data = fopen(args.file_out_data, "wb"); -+ if (fp_out_data == NULL) { -+ err_sys("Cannot open file %s for output\n", -+ args.file_out_data); -+ goto err; -+ } -+ } -+ -+ if (args.file_out_oob) { -+ fp_out_oob = fopen(args.file_out_oob, "wb"); -+ if (fp_out_oob == NULL) { -+ err_sys("Cannot open file %s for output\n", -+ args.file_out_oob); -+ goto err; -+ } -+ } -+ -+ -+ while(1) { -+ read = fread(buf, 1, args.pagesize, args.fp_in); -+ if (feof(args.fp_in) && read == 0) -+ break; -+ -+ if (read < args.pagesize) { -+ err_msg("Image not page aligned\n"); -+ goto err; -+ } -+ -+ if (ferror(args.fp_in)) { -+ err_msg("Read error\n"); -+ goto err; -+ } -+ -+ res = process_page(buf, args.pagesize, fp_out_data, -+ fp_out_oob, &written); -+ if (res != 0) -+ goto err; -+ } -+ -+ while (written < args.padding) { -+ memset(buf, 0xff, args.pagesize); -+ res = process_page(buf, args.pagesize, fp_out_data, -+ fp_out_oob, &written); -+ if (res != 0) -+ goto err; -+ } -+ -+ rc = 0; -+err: -+ free(buf); -+ -+ if (args.fp_in) -+ fclose(args.fp_in); -+ -+ if (fp_out_oob) -+ fclose(fp_out_oob); -+ -+ if (fp_out_data && fp_out_data != stdout) -+ fclose(fp_out_data); -+ -+ if (rc != 0) { -+ err_msg("Error during conversion. rc: %d\n", rc); -+ if (args.file_out_data) -+ remove(args.file_out_data); -+ if (args.file_out_oob) -+ remove(args.file_out_oob); -+ } -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1032 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "hashmap.h" -+#include "error.h" -+ -+#include -+#include "crc32.h" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#define BOOTENV_MAXLINE 512 /* max line size of a bootenv.txt file */ -+ -+/* Structures */ -+struct bootenv { -+ hashmap_t map; ///< Pointer to hashmap which holds data structure. -+}; -+ -+struct bootenv_list { -+ hashmap_t head; ///< Pointer to list which holds the data structure. -+}; -+ -+/** -+ * @brief Remove the '\n' from a given line. -+ * @param line Input/Output line. -+ * @param size Size of the line. -+ * @param fp File Pointer. -+ * @return 0 -+ * @return or error -+ */ -+static int -+remove_lf(char *line, size_t size, FILE* fp) -+{ -+ size_t i; -+ -+ for (i = 0; i < size; i++) { -+ if (line[i] == '\n') { -+ line[i] = '\0'; -+ return 0; -+ } -+ } -+ -+ if (!feof(fp)) { -+ return BOOTENV_EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * @brief Determine if a line contains only WS. -+ * @param line The line to process. -+ * @param size Size of input line. -+ * @return 1 Yes, only WS. -+ * @return 0 No, contains data. -+ */ -+static int -+is_ws(const char *line, size_t size) -+{ -+ size_t i = 0; -+ -+ while (i < size) { -+ switch (line[i]) { -+ case '\n': -+ return 1; -+ case '#': -+ return 1; -+ case ' ': -+ i++; -+ continue; -+ case '\t': -+ i++; -+ continue; -+ default: /* any other char -> no cmnt */ -+ return 0; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+/* ------------------------------------------------------------------------- */ -+ -+/** -+ * @brief Build a list from a comma seperated value string. -+ * @param list Pointer to hashmap structure which shall store -+ * the list. -+ * @param value Comma seperated value string. -+ * @return 0 -+ * @return or error. -+ */ -+static int -+build_list_definition(hashmap_t list, const char *value) -+{ -+ int rc = 0; -+ char *str = NULL; -+ char *ptr = NULL; -+ size_t len, i, j; -+ -+ /* str: val1,val2 , val4,...,valN */ -+ len = strlen(value); -+ str = (char*) malloc((len+1) * sizeof(char)); -+ -+ /* 1. reformat string: remove spaces */ -+ for (i = 0, j = 0; i < len; i++) { -+ if (value[i] == ' ') -+ continue; -+ -+ str[j] = value[i]; -+ j++; -+ } -+ str[j] = '\0'; -+ -+ /* str: val1,val2,val4,...,valN\0*/ -+ /* 2. replace ',' seperator with '\0' */ -+ len = strlen(str); -+ for (i = 0; i < len; i++) { -+ if (str[i] == ',') { -+ str[i] = '\0'; -+ } -+ } -+ -+ /* str: val1\0val2\0val4\0...\0valN\0*/ -+ /* 3. insert definitions into a hash map, using it like a list */ -+ i = j = 0; -+ ptr = str; -+ while (((i = strlen(ptr)) > 0) && (j < len)) { -+ rc = hashmap_add(list, ptr, ""); -+ if (rc != 0) { -+ free(str); -+ return rc; -+ } -+ j += i+1; -+ if (j < len) -+ ptr += i+1; -+ } -+ -+ free(str); -+ return rc; -+} -+ -+/** -+ * @brief Extract a key value pair and add it to a hashmap -+ * @param str Input string which contains a key value pair. -+ * @param env The updated handle which contains the new pair. -+ * @return 0 -+ * @return or error -+ * @note The input string format is: "key=value" -+ */ -+static int -+extract_pair(const char *str, bootenv_t env) -+{ -+ int rc = 0; -+ char *key = NULL; -+ char *val = NULL; -+ -+ key = strdup(str); -+ if (key == NULL) -+ return -ENOMEM; -+ -+ val = strstr(key, "="); -+ if (val == NULL) { -+ rc = BOOTENV_EBADENTRY; -+ goto err; -+ } -+ -+ *val = '\0'; /* split strings */ -+ val++; -+ -+ rc = bootenv_set(env, key, val); -+ -+ err: -+ free(key); -+ return rc; -+} -+ -+int -+bootenv_destroy(bootenv_t* env) -+{ -+ int rc = 0; -+ -+ if (env == NULL || *env == NULL) -+ return -EINVAL; -+ -+ bootenv_t tmp = *env; -+ -+ rc = hashmap_free(tmp->map); -+ if (rc != 0) -+ return rc; -+ -+ free(tmp); -+ return rc; -+} -+ -+int -+bootenv_create(bootenv_t* env) -+{ -+ bootenv_t res; -+ res = (bootenv_t) calloc(1, sizeof(struct bootenv)); -+ -+ if (res == NULL) -+ return -ENOMEM; -+ -+ res->map = hashmap_new(); -+ -+ if (res->map == NULL) { -+ free(res); -+ return -ENOMEM; -+ } -+ -+ *env = res; -+ -+ return 0; -+} -+ -+ -+/** -+ * @brief Read a formatted buffer and scan it for valid bootenv -+ * key/value pairs. Add those pairs into a hashmap. -+ * @param env Hashmap which shall be used to hold the data. -+ * @param buf Formatted buffer. -+ * @param size Size of the buffer. -+ * @return 0 -+ * @return or error -+ */ -+static int -+rd_buffer(bootenv_t env, const char *buf, size_t size) -+{ -+ const char *curr = buf; /* ptr to current key/value pair */ -+ uint32_t i, j; /* current length, chars processed */ -+ -+ if (buf[size - 1] != '\0') /* must end in '\0' */ -+ return BOOTENV_EFMT; -+ -+ for (j = 0; j < size; j += i, curr += i) { -+ /* strlen returns the size of the string upto -+ but not including the null terminator; -+ adding 1 to account for '\0' */ -+ i = strlen(curr) + 1; -+ -+ if (i == 1) -+ return 0; /* no string found */ -+ -+ if (extract_pair(curr, env) != 0) -+ return BOOTENV_EINVAL; -+ } -+ -+ return 0; -+} -+ -+ -+int -+bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t* ret_crc) -+{ -+ int rc; -+ char *buf = NULL; -+ size_t i = 0; -+ uint32_t crc32_table[256]; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ /* allocate temp buffer */ -+ buf = (char*) calloc(1, size * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ /* FIXME Andreas, please review this I removed size-1 and -+ * replaced it by just size, I saw the kernel image starting -+ * with a 0x0060.... and not with the 0x60.... what it should -+ * be. Is this a tools problem or is it a problem here where -+ * fp is moved not to the right place due to the former size-1 -+ * here. -+ */ -+ while((i < size) && (!feof(fp))) { -+ int c = fgetc(fp); -+ if (c == EOF) { -+ /* FIXME isn't this dangerous, to update -+ the boot envs with incomplete data? */ -+ buf[i++] = '\0'; -+ break; /* we have enough */ -+ } -+ if (ferror(fp)) { -+ rc = -EIO; -+ goto err; -+ } -+ -+ buf[i++] = (char)c; -+ } -+ -+ /* calculate crc to return */ -+ if (ret_crc != NULL) { -+ init_crc32_table(crc32_table); -+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); -+ } -+ -+ /* transfer to hashmap */ -+ rc = rd_buffer(env, buf, size); -+ -+err: -+ free(buf); -+ return rc; -+} -+ -+ -+/** -+ * If we have a single file containing the boot-parameter size should -+ * be specified either as the size of the file or as BOOTENV_MAXSIZE. -+ * If the bootparameter are in the middle of a file we need the exact -+ * length of the data. -+ */ -+int -+bootenv_read(FILE* fp, bootenv_t env, size_t size) -+{ -+ return bootenv_read_crc(fp, env, size, NULL); -+} -+ -+ -+int -+bootenv_read_txt(FILE* fp, bootenv_t env) -+{ -+ int rc = 0; -+ char *buf = NULL; -+ char *line = NULL; -+ char *lstart = NULL; -+ char *curr = NULL; -+ size_t len; -+ size_t size; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ size = BOOTENV_MAXSIZE; -+ -+ /* allocate temp buffers */ -+ buf = (char*) calloc(1, size * sizeof(char)); -+ lstart = line = (char*) calloc(1, size * sizeof(char)); -+ if ((buf == NULL) || (line == NULL)) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ curr = buf; -+ while ((line = fgets(line, size, fp)) != NULL) { -+ if (is_ws(line, size)) { -+ continue; -+ } -+ rc = remove_lf(line, BOOTENV_MAXSIZE, fp); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ /* copy new line to binary buffer */ -+ len = strlen(line); -+ if (len > size) { -+ rc = -EFBIG; -+ goto err; -+ } -+ size -= len; /* track remaining space */ -+ -+ memcpy(curr, line, len); -+ curr += len + 1; /* for \0 seperator */ -+ } -+ -+ rc = rd_buffer(env, buf, BOOTENV_MAXSIZE); -+err: -+ if (buf != NULL) -+ free(buf); -+ if (lstart != NULL) -+ free(lstart); -+ return rc; -+} -+ -+static int -+fill_output_buffer(bootenv_t env, char *buf, size_t buf_size_max ubi_unused, -+ size_t *written) -+{ -+ int rc = 0; -+ size_t keys_size, i; -+ size_t wr = 0; -+ const char **keys = NULL; -+ const char *val = NULL; -+ -+ rc = bootenv_get_key_vector(env, &keys_size, 1, &keys); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < keys_size; i++) { -+ if (wr > BOOTENV_MAXSIZE) { -+ rc = -ENOSPC; -+ goto err; -+ } -+ -+ rc = bootenv_get(env, keys[i], &val); -+ if (rc != 0) -+ goto err; -+ -+ wr += snprintf(buf + wr, BOOTENV_MAXSIZE - wr, -+ "%s=%s", keys[i], val); -+ wr++; /* for \0 */ -+ } -+ -+ *written = wr; -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ -+ return rc; -+} -+ -+int -+bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc) -+{ -+ int rc = 0; -+ size_t size = 0; -+ char *buf = NULL; -+ uint32_t crc32_table[256]; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ -+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, &size); -+ if (rc != 0) -+ goto err; -+ -+ /* calculate crc to return */ -+ if (ret_crc != NULL) { -+ init_crc32_table(crc32_table); -+ *ret_crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, size); -+ } -+ -+ if (fwrite(buf, size, 1, fp) != 1) { -+ rc = -EIO; -+ goto err; -+ } -+ -+err: -+ if (buf != NULL) -+ free(buf); -+ return rc; -+} -+ -+int -+bootenv_write(FILE* fp, bootenv_t env) -+{ -+ return bootenv_write_crc(fp, env, NULL); -+} -+ -+int -+bootenv_compare(bootenv_t first, bootenv_t second) -+{ -+ int rc; -+ size_t written_first, written_second; -+ char *buf_first, *buf_second; -+ -+ if (first == NULL || second == NULL) -+ return -EINVAL; -+ -+ buf_first = malloc(BOOTENV_MAXSIZE); -+ if (!buf_first) -+ return -ENOMEM; -+ buf_second = malloc(BOOTENV_MAXSIZE); -+ if (!buf_second) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ rc = fill_output_buffer(first, buf_first, BOOTENV_MAXSIZE, -+ &written_first); -+ if (rc < 0) -+ goto err; -+ rc = fill_output_buffer(second, buf_second, BOOTENV_MAXSIZE, -+ &written_second); -+ if (rc < 0) -+ goto err; -+ -+ if (written_first != written_second) { -+ rc = 1; -+ goto err; -+ } -+ -+ rc = memcmp(buf_first, buf_second, written_first); -+ if (rc != 0) { -+ rc = 2; -+ goto err; -+ } -+ -+err: -+ if (buf_first) -+ free(buf_first); -+ if (buf_second) -+ free(buf_second); -+ -+ return rc; -+} -+ -+int -+bootenv_size(bootenv_t env, size_t *size) -+{ -+ int rc = 0; -+ char *buf = NULL; -+ -+ if (env == NULL) -+ return -EINVAL; -+ -+ buf = (char*) calloc(1, BOOTENV_MAXSIZE * sizeof(char)); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ rc = fill_output_buffer(env, buf, BOOTENV_MAXSIZE, size); -+ if (rc != 0) -+ goto err; -+ -+err: -+ if (buf != NULL) -+ free(buf); -+ return rc; -+} -+ -+int -+bootenv_write_txt(FILE* fp, bootenv_t env) -+{ -+ int rc = 0; -+ size_t size, wr, i; -+ const char **keys = NULL; -+ const char *key = NULL; -+ const char *val = NULL; -+ -+ if ((fp == NULL) || (env == NULL)) -+ return -EINVAL; -+ -+ rc = bootenv_get_key_vector(env, &size, 1, &keys); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < size; i++) { -+ key = keys[i]; -+ rc = bootenv_get(env, key, &val); -+ if (rc != 0) -+ goto err; -+ -+ wr = fprintf(fp, "%s=%s\n", key, val); -+ if (wr != strlen(key) + strlen(val) + 2) { -+ rc = -EIO; -+ goto err; -+ } -+ } -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ return rc; -+} -+ -+int -+bootenv_valid(bootenv_t env ubi_unused) -+{ -+ /* @FIXME No sanity check implemented. */ -+ return 0; -+} -+ -+int -+bootenv_copy_bootenv(bootenv_t in, bootenv_t *out) -+{ -+ int rc = 0; -+ const char *tmp = NULL; -+ const char **keys = NULL; -+ size_t vec_size, i; -+ -+ if ((in == NULL) || (out == NULL)) -+ return -EINVAL; -+ -+ /* purge output var for sure... */ -+ rc = bootenv_destroy(out); -+ if (rc != 0) -+ return rc; -+ -+ /* create the new map */ -+ rc = bootenv_create(out); -+ if (rc != 0) -+ goto err; -+ -+ /* get the key list from the input map */ -+ rc = bootenv_get_key_vector(in, &vec_size, 0, &keys); -+ if (rc != 0) -+ goto err; -+ -+ if (vec_size != hashmap_size(in->map)) { -+ rc = BOOTENV_ECOPY; -+ goto err; -+ } -+ -+ /* make a deep copy of the hashmap */ -+ for (i = 0; i < vec_size; i++) { -+ rc = bootenv_get(in, keys[i], &tmp); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_set(*out, keys[i], tmp); -+ if (rc != 0) -+ goto err; -+ } -+ -+err: -+ if (keys != NULL) -+ free(keys); -+ -+ return rc; -+} -+ -+/* ------------------------------------------------------------------------- */ -+ -+ -+int -+bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, -+ int *warnings, char *err_buf ubi_unused, -+ size_t err_buf_size ubi_unused) -+{ -+ bootenv_list_t l_old = NULL; -+ bootenv_list_t l_new = NULL; -+ const char *pdd_old = NULL; -+ const char *pdd_new = NULL; -+ const char *tmp = NULL; -+ const char **vec_old = NULL; -+ const char **vec_new = NULL; -+ const char **pdd_up_vec = NULL; -+ size_t vec_old_size, vec_new_size, pdd_up_vec_size, i; -+ int rc = 0; -+ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ /* get the pdd strings, e.g.: -+ * pdd_old=a,b,c -+ * pdd_new=a,c,d,e */ -+ rc = bootenv_get(env_old, "pdd", &pdd_old); -+ if (rc != 0) -+ goto err; -+ rc = bootenv_get(env_new, "pdd", &pdd_new); -+ if (rc != 0) -+ goto err; -+ -+ /* put it into a list and then convert it to an vector */ -+ rc = bootenv_list_create(&l_old); -+ if (rc != 0) -+ goto err; -+ rc = bootenv_list_create(&l_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_import(l_old, pdd_old); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_import(l_new, pdd_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_to_vector(l_old, &vec_old_size, &vec_old); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_list_to_vector(l_new, &vec_new_size, &vec_new); -+ if (rc != 0) -+ goto err; -+ -+ rc = bootenv_copy_bootenv(env_new, env_res); -+ if (rc != 0) -+ goto err; -+ -+ /* calculate the update vector between the old and new pdd */ -+ pdd_up_vec = hashmap_get_update_key_vector(vec_old, vec_old_size, -+ vec_new, vec_new_size, &pdd_up_vec_size); -+ -+ if (pdd_up_vec == NULL) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ if (pdd_up_vec_size != 0) { -+ /* need to warn the user about the unset of -+ * some pdd/bootenv values */ -+ *warnings = BOOTENV_WPDD_STRING_DIFFERS; -+ -+ /* remove all entries in the new bootenv load */ -+ for (i = 0; i < pdd_up_vec_size; i++) { -+ bootenv_unset(*env_res, pdd_up_vec[i]); -+ } -+ } -+ -+ /* generate the keep array and copy old pdd values to new bootenv */ -+ for (i = 0; i < vec_old_size; i++) { -+ rc = bootenv_get(env_old, vec_old[i], &tmp); -+ if (rc != 0) { -+ rc = BOOTENV_EPDDINVAL; -+ goto err; -+ } -+ rc = bootenv_set(*env_res, vec_old[i], tmp); -+ if (rc != 0) { -+ goto err; -+ } -+ } -+ /* put the old pdd string into the result map */ -+ rc = bootenv_set(*env_res, "pdd", pdd_old); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ -+err: -+ if (vec_old != NULL) -+ free(vec_old); -+ if (vec_new != NULL) -+ free(vec_new); -+ if (pdd_up_vec != NULL) -+ free(pdd_up_vec); -+ -+ bootenv_list_destroy(&l_old); -+ bootenv_list_destroy(&l_new); -+ return rc; -+} -+ -+ -+int -+bootenv_pdd_overwrite(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings ubi_unused, -+ char *err_buf ubi_unused, size_t err_buf_size ubi_unused) -+{ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ return bootenv_copy_bootenv(env_new, env_res); -+} -+ -+int -+bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, bootenv_t *env_res, -+ int *warnings ubi_unused, char *err_buf, size_t err_buf_size) -+{ -+ if ((env_old == NULL) || (env_new == NULL) || (env_res == NULL)) -+ return -EINVAL; -+ -+ snprintf(err_buf, err_buf_size, "The PDD merge operation is not " -+ "implemented. Contact: "); -+ -+ return BOOTENV_ENOTIMPL; -+} -+ -+/* ------------------------------------------------------------------------- */ -+ -+int -+bootenv_get(bootenv_t env, const char *key, const char **value) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ *value = hashmap_lookup(env->map, key); -+ if (*value == NULL) -+ return BOOTENV_ENOTFOUND; -+ -+ return 0; -+} -+ -+int -+bootenv_get_num(bootenv_t env, const char *key, uint32_t *value) -+{ -+ char *endptr = NULL; -+ const char *str; -+ -+ if (env == NULL) -+ return 0; -+ -+ str = hashmap_lookup(env->map, key); -+ if (!str) -+ return -EINVAL; -+ -+ *value = strtoul(str, &endptr, 0); -+ -+ if (*endptr == '\0') { -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+int -+bootenv_set(bootenv_t env, const char *key, const char *value) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_add(env->map, key, value); -+} -+ -+int -+bootenv_unset(bootenv_t env, const char *key) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_remove(env->map, key); -+} -+ -+int -+bootenv_get_key_vector(bootenv_t env, size_t* size, int sort, -+ const char ***vector) -+{ -+ if ((env == NULL) || (size == NULL)) -+ return -EINVAL; -+ -+ *vector = hashmap_get_key_vector(env->map, size, sort); -+ -+ if (*vector == NULL) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+int -+bootenv_dump(bootenv_t env) -+{ -+ if (env == NULL) -+ return -EINVAL; -+ -+ return hashmap_dump(env->map); -+} -+ -+int -+bootenv_list_create(bootenv_list_t *list) -+{ -+ bootenv_list_t res; -+ res = (bootenv_list_t) calloc(1, sizeof(struct bootenv_list)); -+ -+ if (res == NULL) -+ return -ENOMEM; -+ -+ res->head = hashmap_new(); -+ -+ if (res->head == NULL) { -+ free(res); -+ return -ENOMEM; -+ } -+ -+ *list = res; -+ return 0; -+} -+ -+int -+bootenv_list_destroy(bootenv_list_t *list) -+{ -+ int rc = 0; -+ -+ if (list == NULL) -+ return -EINVAL; -+ -+ bootenv_list_t tmp = *list; -+ if (tmp == 0) -+ return 0; -+ -+ rc = hashmap_free(tmp->head); -+ if (rc != 0) -+ return rc; -+ -+ free(tmp); -+ *list = NULL; -+ return 0; -+} -+ -+int -+bootenv_list_import(bootenv_list_t list, const char *str) -+{ -+ if (list == NULL) -+ return -EINVAL; -+ -+ return build_list_definition(list->head, str); -+} -+ -+int -+bootenv_list_export(bootenv_list_t list, char **string) -+{ -+ size_t size, i, j, bufsize, tmp, rc = 0; -+ const char **items; -+ -+ if (list == NULL) -+ return -EINVAL; -+ -+ bufsize = BOOTENV_MAXLINE; -+ char *res = (char*) malloc(bufsize * sizeof(char)); -+ if (res == NULL) -+ return -ENOMEM; -+ -+ rc = bootenv_list_to_vector(list, &size, &items); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ j = 0; -+ for (i = 0; i < size; i++) { -+ tmp = strlen(items[i]); -+ if (j >= bufsize) { -+ bufsize += BOOTENV_MAXLINE; -+ res = (char*) realloc(res, bufsize * sizeof(char)); -+ if (res == NULL) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ } -+ memcpy(res + j, items[i], tmp); -+ j += tmp; -+ if (i < (size - 1)) { -+ res[j] = ','; -+ j++; -+ } -+ } -+ j++; -+ res[j] = '\0'; -+ free(items); -+ *string = res; -+ return 0; -+err: -+ free(items); -+ return rc; -+} -+ -+int -+bootenv_list_add(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_add(list->head, item, ""); -+} -+ -+int -+bootenv_list_remove(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_remove(list->head, item); -+} -+ -+int -+bootenv_list_is_in(bootenv_list_t list, const char *item) -+{ -+ if ((list == NULL) || (item == NULL)) -+ return -EINVAL; -+ -+ return hashmap_lookup(list->head, item) != NULL ? 1 : 0; -+} -+ -+int -+bootenv_list_to_vector(bootenv_list_t list, size_t *size, const char ***vector) -+{ -+ if ((list == NULL) || (size == NULL)) -+ return -EINVAL; -+ -+ *vector = hashmap_get_key_vector(list->head, size, 1); -+ if (*vector == NULL) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+int -+bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, -+ uint32_t **vector) -+{ -+ int rc = 0; -+ size_t i; -+ uint32_t* res = NULL; -+ char *endptr = NULL; -+ const char **a = NULL; -+ -+ rc = bootenv_list_to_vector(list, size, &a); -+ if (rc != 0) -+ goto err; -+ -+ res = (uint32_t*) malloc (*size * sizeof(uint32_t)); -+ if (!res) -+ goto err; -+ -+ for (i = 0; i < *size; i++) { -+ res[i] = strtoul(a[i], &endptr, 0); -+ if (*endptr != '\0') -+ goto err; -+ } -+ -+ if (a) -+ free(a); -+ *vector = res; -+ return 0; -+ -+err: -+ if (a) -+ free(a); -+ if (res) -+ free(res); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/bootenv.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,434 @@ -+#ifndef __BOOTENV_H__ -+#define __BOOTENV_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include /* FILE */ -+#include -+#include -+ -+/* DOXYGEN DOCUMENTATION */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * @file bootenv.h -+ * @author oliloh@de.ibm.com -+ * @version 1.3 -+ * -+ * 1.3 Some renaming -+ */ -+ -+/** -+ * @mainpage Usage -+ * -+ * @section intro Introduction -+ * This library provides all functionality to handle with the so-called -+ * platform description data (PDD) and the bootparameters defined in -+ * U-Boot. It is able to apply the defined PDD operations in PDD update -+ * scenarios. For more information about the PDD and bootparameter -+ * environment "bootenv" confer the PDD documentation. -+ * -+ * @section ret Return codes -+ * This library defines some return codes which will be delivered classified -+ * as warnings or errors. See the "Defines" section for details and numeric -+ * values. -+ * -+ * @section benv Bootenv format description -+ * There are two different input formats: -+ * - text files -+ * - binary files -+ * -+ * @subsection txt Text Files -+ * Text files have to be specified like: -+ * @verbatim key1=value1,value2,value7\n key2=value55,value1\n key4=value1\n@endverbatim -+ * -+ * @subsection bin Binary files -+ * Binary files have to be specified like: -+ * @verbatimkey1=value1,value2,value7\0key2=value55,value1\0... @endverbatim -+ * You can confer the U-Boot documentation for more details. -+ * -+ * @section benvlists Bootenv lists format description. -+ * Values referenced in the preceeding subsection can be -+ * defined like lists: -+ * @verbatim value1,value2,value3 @endverbatim -+ * There are some situation where a conversion of a comma -+ * seperated list can be useful, e.g. to get a list -+ * of defined PDD entries. -+ */ -+ -+#define BOOTENV_MAXSIZE (1024 * 100) /* max 100kiB space for bootenv */ -+ -+/** -+ * @def BOOTENV_ECRC -+ * @brief Given binary file is to large. -+ * @def BOOTENV_EFMT -+ * @brief Given bootenv section has an invalid format -+ * @def BOOTENV_EBADENTRY -+ * @brief Bad entry in the bootenv section. -+ * @def BOOTENV_EINVAL -+ * @brief Invalid bootenv defintion. -+ * @def BOOTENV_ENOPDD -+ * @brief Given bootenv sectoin has no PDD defintion string (pdd=...). -+ * @def BOOTENV_EPDDINVAL -+ * @brief Given bootenv section has an invalid PDD defintion. -+ * @def BOOTENV_ENOTIMPL -+ * @brief Functionality not implemented. -+ * @def BOOTENV_ECOPY -+ * @brief Bootenv memory copy error -+ * @def BOOTENV_ENOTFOUND -+ * @brief Given key has has no value. -+ * @def BOOTENV_EMAX -+ * @brief Highest error value. -+ */ -+#define BOOTENV_ETOOBIG 1 -+#define BOOTENV_EFMT 2 -+#define BOOTENV_EBADENTRY 3 -+#define BOOTENV_EINVAL 4 -+#define BOOTENV_ENOPDD 5 -+#define BOOTENV_EPDDINVAL 6 -+#define BOOTENV_ENOTIMPL 7 -+#define BOOTENV_ECOPY 8 -+#define BOOTENV_ENOTFOUND 9 -+#define BOOTENV_EMAX 10 -+ -+/** -+ * @def BOOTENV_W -+ * @brief A warning which is handled internally as an error -+ * but can be recovered by manual effort. -+ * @def BOOTENV_WPDD_STRING_DIFFERS -+ * @brief The PDD strings of old and new PDD differ and -+ * can cause update problems, because new PDD values -+ * are removed from the bootenv section completely. -+ */ -+#define BOOTENV_W 20 -+#define BOOTENV_WPDD_STRING_DIFFERS 21 -+#define BOOTENV_WMAX 22 /* highest warning value */ -+ -+ -+typedef struct bootenv *bootenv_t; -+ /**< A bootenv library handle. */ -+ -+typedef struct bootenv_list *bootenv_list_t; -+ /**< A handle for a value list. */ -+ -+typedef int(*pdd_func_t)(bootenv_t, bootenv_t, bootenv_t*, -+ int*, char*, size_t); -+ -+ -+/** -+ * @brief Get a new handle. -+ * @return 0 -+ * @return or error -+ * */ -+int bootenv_create(bootenv_t *env); -+ -+/** -+ * @brief Cleanup structure. -+ * @param env Bootenv structure which shall be destroyed. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_destroy(bootenv_t *env); -+ -+/** -+ * @brief Copy a bootenv handle. -+ * @param in The input bootenv. -+ * @param out The copied output bootenv. Discards old data. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_copy_bootenv(bootenv_t in, bootenv_t *out); -+ -+/** -+ * @brief Looks for a value inside the bootenv data. -+ * @param env Handle to a bootenv structure. -+ * @param key The key. -+ * @return NULL key not found -+ * @return !NULL ptr to value -+ */ -+int bootenv_get(bootenv_t env, const char *key, const char **value); -+ -+ -+/** -+ * @brief Looks for a value inside the bootenv data and converts it to num. -+ * @param env Handle to a bootenv structure. -+ * @param key The key. -+ * @param value A pointer to the resulting numerical value -+ * @return NULL key not found -+ * @return !NULL ptr to value -+ */ -+int bootenv_get_num(bootenv_t env, const char *key, uint32_t *value); -+ -+/** -+ * @brief Set a bootenv value by key. -+ * @param env Handle to a bootenv structure. -+ * @param key Key. -+ * @param value Value to set. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_set(bootenv_t env, const char *key, const char *value); -+ -+/** -+ * @brief Remove the given key (and its value) from a bootenv structure. -+ * @param env Handle to a bootenv structure. -+ * @param key Key. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_unset(bootenv_t env, const char *key); -+ -+ -+/** -+ * @brief Get a vector of all keys which are currently set -+ * within a bootenv handle. -+ * @param env Handle to a bootenv structure. -+ * @param size The size of the allocated array structure. -+ * @param sort Flag, if set the vector is sorted ascending. -+ * @return NULL on error. -+ * @return !NULL a pointer to the first element the allocated vector. -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_get_key_vector(bootenv_t env, size_t *size, int sort, -+ const char ***vector); -+ -+/** -+ * @brief Calculate the size in bytes which are necessary to write the -+ * current bootenv section in a *binary file. -+ * @param env bootenv handle. -+ * @param size The size in bytes of the bootenv handle. -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_size(bootenv_t env, size_t *size); -+ -+/** -+ * @brief Read a binary bootenv file. -+ * @param fp File pointer to input stream. -+ * @param env bootenv handle. -+ * @param size maximum data size. -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_read(FILE* fp, bootenv_t env, size_t size); -+ -+/** -+ * @param ret_crc return value of crc of read data -+ */ -+int bootenv_read_crc(FILE* fp, bootenv_t env, size_t size, uint32_t *ret_crc); -+ -+/** -+ * @brief Read bootenv data from an text/ascii file. -+ * @param fp File pointer to ascii PDD file. -+ * @param env bootenv handle -+ * @return 0 -+ * @return or ERROR. -+ */ -+int bootenv_read_txt(FILE* fp, bootenv_t env); -+ -+/** -+ * @brief Write a bootenv structure to the given location (binary). -+ * @param fp Filepointer to binary file. -+ * @param env Bootenv structure which shall be written. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_write(FILE* fp, bootenv_t env); -+ -+/** -+ * @param ret_crc return value of crc of read data -+ */ -+int bootenv_write_crc(FILE* fp, bootenv_t env, uint32_t* ret_crc); -+ -+/** -+ * @brief Write a bootenv structure to the given location (text). -+ * @param fp Filepointer to text file. -+ * @param env Bootenv structure which shall be written. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_write_txt(FILE* fp, bootenv_t env); -+ -+/** -+ * @brief Compare bootenvs using memcmp(). -+ * @param first First bootenv. -+ * @param second Second bootenv. -+ * @return 0 if bootenvs are equal -+ * @return < 0 if error -+ * @return > 0 if unequal -+ */ -+int bootenv_compare(bootenv_t first, bootenv_t second); -+ -+/** -+ * @brief Prototype for a PDD handling funtion -+ */ -+ -+/** -+ * @brief The PDD keep operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of PDD keep. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_keep(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+ -+/** -+ * @brief The PDD merge operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of merge-pdd. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_merge(bootenv_t env_old, bootenv_t env_new, -+ bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief The PDD overwrite operation. -+ * @param env_old The old bootenv structure. -+ * @param env_new The new bootenv structure. -+ * @param env_res The result of overwrite-pdd. -+ * @param warnings A flag which marks any warnings. -+ * @return 0 -+ * @return or error -+ * @note For a complete documentation about the algorithm confer the -+ * PDD documentation. -+ */ -+int bootenv_pdd_overwrite(bootenv_t env_new, -+ bootenv_t env_old, bootenv_t *env_res, int *warnings, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Dump a bootenv structure to stdout. (Debug) -+ * @param env Handle to a bootenv structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_dump(bootenv_t env); -+ -+/** -+ * @brief Validate a bootenv structure. -+ * @param env Handle to a bootenv structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_valid(bootenv_t env); -+ -+/** -+ * @brief Create a new bootenv list structure. -+ * @return NULL on error -+ * @return or a new list handle. -+ * @note This structure is used to store values in a list. -+ * A useful addition when handling PDD strings. -+ */ -+int bootenv_list_create(bootenv_list_t *list); -+ -+/** -+ * @brief Destroy a bootenv list structure -+ * @param list Handle to a bootenv list structure. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_destroy(bootenv_list_t *list); -+ -+/** -+ * @brief Import a list from a comma seperated string -+ * @param list Handle to a bootenv list structure. -+ * @param str Comma seperated string list. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_import(bootenv_list_t list, const char *str); -+ -+/** -+ * @brief Export a list to a string of comma seperated values. -+ * @param list Handle to a bootenv list structure. -+ * @return NULL one error -+ * @return or pointer to a newly allocated string. -+ * @warning Free the allocated memory by yourself! -+ */ -+int bootenv_list_export(bootenv_list_t list, char **string); -+ -+/** -+ * @brief Add an item to the list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_add(bootenv_list_t list, const char *item); -+ -+/** -+ * @brief Remove an item from the list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 0 -+ * @return or error -+ */ -+int bootenv_list_remove(bootenv_list_t list, const char *item); -+ -+/** -+ * @brief Check if a given item is in a given list. -+ * @param list A handle of a list structure. -+ * @param item An item. -+ * @return 1 Item is in list. -+ * @return 0 Item is not in list. -+ */ -+int bootenv_list_is_in(bootenv_list_t list, const char *item); -+ -+ -+/** -+ * @brief Convert a list into a vector of all values inside the list. -+ * @param list Handle to a bootenv structure. -+ * @param size The size of the allocated vector structure. -+ * @return 0 -+ * @return or error -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_list_to_vector(bootenv_list_t list, size_t *size, -+ const char ***vector); -+ -+/** -+ * @brief Convert a list into a vector of all values inside the list. -+ * @param list Handle to a bootenv structure. -+ * @param size The size of the allocated vector structure. -+ * @return 0 -+ * @return or error -+ * @warning Free the allocate memory yourself! -+ */ -+int bootenv_list_to_num_vector(bootenv_list_t list, size_t *size, -+ uint32_t **vector); -+ -+#ifdef __cplusplus -+} -+#endif -+#endif /*__BOOTENV_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/config.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/config.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/config.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/config.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+#ifndef __CONFIG_H__ -+#define __CONFIG_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ */ -+ -+#define PACKAGE_BUGREPORT \ -+ "haver@vnet.ibm.com, dedekind@linutronix.de, or tglx@linutronix.de" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,83 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Thomas Gleixner -+ */ -+ -+/* -+ * CRC32 functions -+ * -+ * Can be compiled as seperate object, but is included into the ipl source -+ * so gcc can inline the functions. We optimize for size so the omission of -+ * the function frame is helpful. -+ * -+ */ -+ -+#include -+#include -+ -+/* CRC polynomial */ -+#define CRC_POLY 0xEDB88320 -+ -+/** -+ * init_crc32_table - Initialize crc table -+ * -+ * @table: pointer to the CRC table which must be initialized -+ * -+ * Create CRC32 table for given polynomial. The table is created with -+ * the lowest order term in the highest order bit. So the x^32 term -+ * has to implied in the crc calculation function. -+ */ -+void init_crc32_table(uint32_t *table) -+{ -+ uint32_t crc; -+ int i, j; -+ -+ for (i = 0; i < 256; i++) { -+ crc = i; -+ for (j = 8; j > 0; j--) { -+ if (crc & 1) -+ crc = (crc >> 1) ^ CRC_POLY; -+ else -+ crc >>= 1; -+ } -+ table[i] = crc; -+ } -+} -+ -+/** -+ * clc_crc32 - Calculate CRC32 over a buffer -+ * -+ * @table: pointer to the CRC table -+ * @crc: initial crc value -+ * @buf: pointer to the buffer -+ * @len: number of bytes to calc -+ * -+ * Returns the updated crc value. -+ * -+ * The algorithm resembles a hardware shift register, but calculates 8 -+ * bit at once. -+ */ -+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, -+ int len) -+{ -+ const unsigned char *p = buf; -+ -+ while(--len >= 0) -+ crc = table[(crc ^ *p++) & 0xff] ^ (crc >> 8); -+ return crc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+#ifndef __CRC32_H__ -+#define __CRC32_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Thomas Gleixner -+ * -+ * CRC32 functions -+ * -+ * Can be compiled as seperate object, but is included into the ipl source -+ * so gcc can inline the functions. We optimize for size so the omission of -+ * the function frame is helpful. -+ * -+ */ -+#include -+ -+void init_crc32_table(uint32_t *table); -+uint32_t clc_crc32(uint32_t *table, uint32_t crc, void *buf, int len); -+ -+#endif /* __CRC32_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/eb_chain.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,281 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Drake Dowsett, dowsett@de.ibm.com -+ * Contact: Andreas Arnez, arnez@de.ibm.com -+ */ -+ -+/* see eb_chain.h */ -+ -+#include -+#include -+#include -+#include -+#include "unubi_analyze.h" -+#include "crc32.h" -+ -+#define COPY(dst, src) \ -+ do { \ -+ dst = malloc(sizeof(*dst)); \ -+ if (dst == NULL) \ -+ return -ENOMEM; \ -+ memcpy(dst, src, sizeof(*dst)); \ -+ } while (0) -+ -+ -+/** -+ * inserts an eb_info into the chain starting at head, then searching -+ * linearly for the correct position; -+ * new should contain valid vid and ec headers and the data_crc should -+ * already have been checked before insertion, otherwise the chain -+ * could be have un an undesired manner; -+ * returns -ENOMEM if alloc fails, otherwise SHOULD always return 0, -+ * if not, the code reached the last line and returned -EAGAIN, -+ * meaning there is a bug or a case not being handled here; -+ **/ -+int -+eb_chain_insert(struct eb_info **head, struct eb_info *new) -+{ -+ uint32_t vol, num, ver; -+ uint32_t new_vol, new_num, new_ver; -+ struct eb_info *prev, *cur, *hist, *ins; -+ struct eb_info **prev_ptr; -+ -+ if ((head == NULL) || (new == NULL)) -+ return 0; -+ -+ if (*head == NULL) { -+ COPY(*head, new); -+ (*head)->next = NULL; -+ return 0; -+ } -+ -+ new_vol = be32_to_cpu(new->vid.vol_id); -+ new_num = be32_to_cpu(new->vid.lnum); -+ new_ver = be32_to_cpu(new->vid.leb_ver); -+ -+ /** TRAVERSE HORIZONTALY **/ -+ -+ cur = *head; -+ prev = NULL; -+ -+ /* traverse until vol_id/lnum align */ -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ while ((new_vol > vol) || ((new_vol == vol) && (new_num > num))) { -+ /* insert new at end of chain */ -+ if (cur->next == NULL) { -+ COPY(ins, new); -+ ins->next = NULL; -+ cur->next = ins; -+ return 0; -+ } -+ -+ prev = cur; -+ cur = cur->next; -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ } -+ -+ if (prev == NULL) -+ prev_ptr = head; -+ else -+ prev_ptr = &(prev->next); -+ -+ /* insert new into the middle of chain */ -+ if ((new_vol != vol) || (new_num != num)) { -+ COPY(ins, new); -+ ins->next = cur; -+ *prev_ptr = ins; -+ return 0; -+ } -+ -+ /** TRAVERSE VERTICALY **/ -+ -+ hist = cur; -+ prev = NULL; -+ -+ /* traverse until versions align */ -+ ver = be32_to_cpu(cur->vid.leb_ver); -+ while (new_ver < ver) { -+ /* insert new at bottom of history */ -+ if (hist->older == NULL) { -+ COPY(ins, new); -+ ins->next = NULL; -+ ins->older = NULL; -+ hist->older = ins; -+ return 0; -+ } -+ -+ prev = hist; -+ hist = hist->older; -+ ver = be32_to_cpu(hist->vid.leb_ver); -+ } -+ -+ if (prev == NULL) { -+ /* replace active version */ -+ COPY(ins, new); -+ ins->next = hist->next; -+ *prev_ptr = ins; -+ -+ /* place cur in vertical histroy */ -+ ins->older = hist; -+ hist->next = NULL; -+ return 0; -+ } -+ -+ /* insert between versions, beneath active version */ -+ COPY(ins, new); -+ ins->next = NULL; -+ ins->older = prev->older; -+ prev->older = ins; -+ return 0; -+} -+ -+ -+/** -+ * sets the pointer at pos to the position of the first entry in the chain -+ * with of vol_id and, if given, with the same lnum as *lnum; -+ * if there is no entry in the chain, then *pos is NULL on return; -+ * always returns 0; -+ **/ -+int -+eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, -+ struct eb_info **pos) -+{ -+ uint32_t vol, num; -+ struct eb_info *cur; -+ -+ if ((head == NULL) || (*head == NULL) || (pos == NULL)) -+ return 0; -+ -+ *pos = NULL; -+ -+ cur = *head; -+ while (cur != NULL) { -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = be32_to_cpu(cur->vid.lnum); -+ -+ if ((vol_id == vol) && ((lnum == NULL) || (*lnum == num))) { -+ *pos = cur; -+ return 0; -+ } -+ -+ cur = cur->next; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * prints to stream, the vol_id, lnum and leb_ver for each entry in the -+ * chain, starting at head; -+ * this is intended for debuging purposes; -+ * always returns 0; -+ * -+ * FIXME I do not like the double list traversion ... -+ **/ -+int -+eb_chain_print(FILE* stream, struct eb_info *head) -+{ -+ struct eb_info *cur; -+ -+ if (stream == NULL) -+ stream = stdout; -+ -+ if (head == NULL) { -+ fprintf(stream, "EMPTY\n"); -+ return 0; -+ } -+ /* 012345678012345678012345678012301230123 0123 01234567 0123457 01234567*/ -+ fprintf(stream, "VOL_ID LNUM LEB_VER EC VID DAT PBLK PADDR DSIZE EC\n"); -+ cur = head; -+ while (cur != NULL) { -+ struct eb_info *hist; -+ -+ fprintf(stream, "%08x %-8u %08x %-4s%-4s", -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), -+ cur->ec_crc_ok ? "ok":"bad", -+ cur->vid_crc_ok ? "ok":"bad"); -+ if (cur->vid.vol_type == UBI_VID_STATIC) -+ fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"bad"); -+ else fprintf(stream, "%-4s", cur->data_crc_ok ? "ok":"ign"); -+ fprintf(stream, " %-4d %08x %-8u %-8llu\n", cur->phys_block, -+ cur->phys_addr, be32_to_cpu(cur->vid.data_size), -+ (unsigned long long)be64_to_cpu(cur->ec.ec)); -+ -+ hist = cur->older; -+ while (hist != NULL) { -+ fprintf(stream, "%08x %-8u %08x %-4s%-4s", -+ be32_to_cpu(hist->vid.vol_id), -+ be32_to_cpu(hist->vid.lnum), -+ be32_to_cpu(hist->vid.leb_ver), -+ hist->ec_crc_ok ? "ok":"bad", -+ hist->vid_crc_ok ? "ok":"bad"); -+ if (hist->vid.vol_type == UBI_VID_STATIC) -+ fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"bad"); -+ else fprintf(stream, "%-4s", hist->data_crc_ok ? "ok":"ign"); -+ fprintf(stream, " %-4d %08x %-8u %-8llu (*)\n", -+ hist->phys_block, hist->phys_addr, -+ be32_to_cpu(hist->vid.data_size), -+ (unsigned long long)be64_to_cpu(hist->ec.ec)); -+ -+ hist = hist->older; -+ } -+ cur = cur->next; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * frees the memory of the entire chain, starting at head; -+ * head will be NULL on return; -+ * always returns 0; -+ **/ -+int -+eb_chain_destroy(struct eb_info **head) -+{ -+ if (head == NULL) -+ return 0; -+ -+ while (*head != NULL) { -+ struct eb_info *cur; -+ struct eb_info *hist; -+ -+ cur = *head; -+ *head = (*head)->next; -+ -+ hist = cur->older; -+ while (hist != NULL) { -+ struct eb_info *temp; -+ -+ temp = hist; -+ hist = hist->older; -+ free(temp); -+ } -+ free(cur); -+ } -+ return 0; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,240 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "error.h" -+ -+#define MAXLINE 4096 -+#define MAXWIDTH 80 -+ -+static FILE *logfp = NULL; -+ -+static void err_doit(int, int, const char *, va_list); -+ -+int -+read_procfile(FILE *fp_out, const char *procfile) -+{ -+ FILE *fp; -+ -+ if (!fp_out) -+ return -ENXIO; -+ -+ fp = fopen(procfile, "r"); -+ if (!fp) -+ return -ENOENT; -+ -+ while(!feof(fp)) { -+ int c = fgetc(fp); -+ -+ if (c == EOF) -+ return 0; -+ -+ if (putc(c, fp_out) == EOF) -+ return -EIO; -+ -+ if (ferror(fp)) -+ return -EIO; -+ } -+ return fclose(fp); -+} -+ -+void -+error_initlog(const char *logfile) -+{ -+ if (!logfile) -+ return; -+ -+ logfp = fopen(logfile, "a+"); -+ read_procfile(logfp, "/proc/cpuinfo"); -+} -+ -+void -+info_msg(const char *fmt, ...) -+{ -+ FILE* fpout; -+ char buf[MAXLINE + 1]; -+ va_list ap; -+ int n; -+ -+ fpout = stdout; -+ -+ va_start(ap, fmt); -+ vsnprintf(buf, MAXLINE, fmt, ap); -+ n = strlen(buf); -+ strcat(buf, "\n"); -+ -+ fputs(buf, fpout); -+ fflush(fpout); -+ if (fpout != stdout) -+ fclose(fpout); -+ -+ va_end(ap); -+ return; -+} -+ -+void -+__err_ret(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_INFO, fmt, ap); -+ va_end(ap); -+ return; -+} -+ -+void -+__err_sys(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_ERR, fmt, ap); -+ va_end(ap); -+ exit(EXIT_FAILURE); -+} -+ -+ -+void -+__err_msg(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(0, LOG_INFO, fmt, ap); -+ va_end(ap); -+ -+ return; -+} -+ -+void -+__err_quit(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(0, LOG_ERR, fmt, ap); -+ va_end(ap); -+ exit(EXIT_FAILURE); -+} -+ -+void -+__err_dump(const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start(ap, fmt); -+ err_doit(1, LOG_ERR, fmt, ap); -+ va_end(ap); -+ abort(); /* dump core and terminate */ -+ exit(EXIT_FAILURE); /* shouldn't get here */ -+} -+ -+/** -+ * If a logfile is used we must not print on stderr and stdout -+ * anymore. Since pfilfash might be used in a server context, it is -+ * even dangerous to write to those descriptors. -+ */ -+static void -+err_doit(int errnoflag, int level __attribute__((unused)), -+ const char *fmt, va_list ap) -+{ -+ FILE* fpout; -+ int errno_save, n; -+ char buf[MAXLINE + 1]; -+ fpout = stderr; -+ -+ errno_save = errno; /* value caller might want printed */ -+ -+ vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ -+ -+ n = strlen(buf); -+ -+ if (errnoflag) -+ snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); -+ strcat(buf, "\n"); -+ -+ if (logfp) { -+ fputs(buf, logfp); -+ fflush(logfp); -+ return; /* exit when logging completes */ -+ } -+ -+ if (fpout == stderr) { -+ /* perform line wrap when outputting to stderr */ -+ int word_len, post_len, chars; -+ char *buf_ptr; -+ const char *frmt = "%*s%n %n"; -+ -+ chars = 0; -+ buf_ptr = buf; -+ while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) { -+ int i; -+ char word[word_len + 1]; -+ char post[post_len + 1]; -+ -+ strncpy(word, buf_ptr, word_len); -+ word[word_len] = '\0'; -+ buf_ptr += word_len; -+ post_len -= word_len; -+ -+ if (chars + word_len > MAXWIDTH) { -+ fputc('\n', fpout); -+ chars = 0; -+ } -+ fputs(word, fpout); -+ chars += word_len; -+ -+ if (post_len > 0) { -+ strncpy(post, buf_ptr, post_len); -+ post[post_len] = '\0'; -+ buf_ptr += post_len; -+ } -+ for (i = 0; i < post_len; i++) { -+ int inc = 1, chars_new; -+ -+ if (post[i] == '\t') -+ inc = 8; -+ if (post[i] == '\n') { -+ inc = 0; -+ chars_new = 0; -+ } else -+ chars_new = chars + inc; -+ -+ if (chars_new > MAXWIDTH) { -+ fputc('\n', fpout); -+ chars_new = inc; -+ } -+ fputc(post[i], fpout); -+ chars = chars_new; -+ } -+ } -+ } -+ else -+ fputs(buf, fpout); -+ fflush(fpout); -+ if (fpout != stderr) -+ fclose(fpout); -+ -+ return; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/error.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/error.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,84 @@ -+#ifndef __ERROR_H__ -+#define __ERROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+ -+void error_initlog(const char *logfile); -+int read_procfile(FILE *fp_out, const char *procfile); -+ -+void __err_ret(const char *fmt, ...); -+void __err_sys(const char *fmt, ...); -+void __err_msg(const char *fmt, ...); -+void __err_quit(const char *fmt, ...); -+void __err_dump(const char *fmt, ...); -+ -+void info_msg(const char *fmt, ...); -+ -+#ifdef DEBUG -+#define __loc_msg(str) do { \ -+ __err_msg("[%s. FILE: %s FUNC: %s LINE: %d]\n", \ -+ str, __FILE__, __FUNCTION__, __LINE__); \ -+} while (0) -+#else -+#define __loc_msg(str) -+#endif -+ -+ -+#define err_dump(fmt, ...) do { \ -+ __loc_msg("ErrDump"); \ -+ __err_dump(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_quit(fmt, ...) do { \ -+ __loc_msg("ErrQuit"); \ -+ __err_quit(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+ -+#define err_ret(fmt, ...) do { \ -+ __loc_msg("ErrRet"); \ -+ __err_ret(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_sys(fmt, ...) do { \ -+ __loc_msg("ErrSys"); \ -+ __err_sys(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define err_msg(fmt, ...) do { \ -+ __loc_msg("ErrMsg"); \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define log_msg(fmt, ...) do { \ -+ /* __loc_msg("LogMsg"); */ \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#ifdef DEBUG -+#define dbg_msg(fmt, ...) do { \ -+ __loc_msg("DbgMsg"); \ -+ __err_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+#else -+#define dbg_msg(fmt, ...) do {} while (0) -+#endif -+ -+#endif /* __ERROR_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/example_ubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+#ifndef __EXAMPLE_UBI_H__ -+#define __EXAMPLE_UBI_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * Defaults for our cards. -+ */ -+#define EXAMPLE_UBI_DEVICE 0 -+#define EXAMPLE_BOOTENV_VOL_ID_1 4 -+#define EXAMPLE_BOOTENV_VOL_ID_2 5 -+ -+#endif /* __EXAMPLE_UBI_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,412 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+#include -+#include "error.h" -+#include "hashmap.h" -+#define DEFAULT_BUCKETS 4096 -+ -+#if 0 -+#define INFO_MSG(fmt...) do { \ -+ info_msg(fmt); \ -+} while (0) -+#else -+#define INFO_MSG(fmt...) -+#endif -+ -+struct hashentry { -+ char* key; /* key '0' term. str */ -+ char* value; /* payload '0' term. str */ -+ -+ hashentry_t next; -+}; -+ -+struct hashmap { -+ size_t entries; /* current #entries */ -+ size_t maxsize; /* no. of hash buckets */ -+ hashentry_t* data; /* array of buckets */ -+}; -+ -+static int -+is_empty(hashentry_t l) -+{ -+ return l == NULL ? 1 : 0; -+} -+ -+hashmap_t -+hashmap_new(void) -+{ -+ hashmap_t res; -+ res = (hashmap_t) calloc(1, sizeof(struct hashmap)); -+ -+ if (res == NULL) -+ return NULL; -+ -+ res->maxsize = DEFAULT_BUCKETS; -+ res->entries = 0; -+ -+ res->data = (hashentry_t*) -+ calloc(1, res->maxsize * sizeof(struct hashentry)); -+ -+ if (res->data == NULL) -+ return NULL; -+ -+ return res; -+} -+ -+static hashentry_t -+new_entry(const char* key, const char* value) -+{ -+ hashentry_t res; -+ -+ res = (hashentry_t) calloc(1, sizeof(struct hashentry)); -+ -+ if (res == NULL) -+ return NULL; -+ -+ /* allocate key and value and copy them */ -+ res->key = strdup(key); -+ if (res->key == NULL) { -+ free(res); -+ return NULL; -+ } -+ -+ res->value = strdup(value); -+ if (res->value == NULL) { -+ free(res->key); -+ free(res); -+ return NULL; -+ } -+ -+ res->next = NULL; -+ -+ return res; -+} -+ -+static hashentry_t -+free_entry(hashentry_t e) -+{ -+ if (!is_empty(e)) { -+ if(e->key != NULL) { -+ free(e->key); -+ } -+ if(e->value != NULL) -+ free(e->value); -+ free(e); -+ } -+ -+ return NULL; -+} -+ -+static hashentry_t -+remove_entry(hashentry_t l, const char* key, size_t* entries) -+{ -+ hashentry_t lnext; -+ if (is_empty(l)) -+ return NULL; -+ -+ if(strcmp(l->key,key) == 0) { -+ lnext = l->next; -+ l = free_entry(l); -+ (*entries)--; -+ return lnext; -+ } -+ -+ l->next = remove_entry(l->next, key, entries); -+ -+ return l; -+} -+ -+static hashentry_t -+insert_entry(hashentry_t l, hashentry_t e, size_t* entries) -+{ -+ if (is_empty(l)) { -+ (*entries)++; -+ return e; -+ } -+ -+ /* check for update */ -+ if (strcmp(l->key, e->key) == 0) { -+ e->next = l->next; -+ l = free_entry(l); -+ return e; -+ } -+ -+ l->next = insert_entry(l->next, e, entries); -+ return l; -+} -+ -+static hashentry_t -+remove_all(hashentry_t l, size_t* entries) -+{ -+ hashentry_t lnext; -+ if (is_empty(l)) -+ return NULL; -+ -+ lnext = l->next; -+ free_entry(l); -+ (*entries)--; -+ -+ return remove_all(lnext, entries); -+} -+ -+static const char* -+value_lookup(hashentry_t l, const char* key) -+{ -+ if (is_empty(l)) -+ return NULL; -+ -+ if (strcmp(l->key, key) == 0) -+ return l->value; -+ -+ return value_lookup(l->next, key); -+} -+ -+static void -+print_all(hashentry_t l) -+{ -+ if (is_empty(l)) { -+ printf("\n"); -+ return; -+ } -+ -+ printf("%s=%s", l->key, l->value); -+ if (!is_empty(l->next)) { -+ printf(","); -+ } -+ -+ print_all(l->next); -+} -+ -+static void -+keys_to_array(hashentry_t l, const char** a, size_t* i) -+{ -+ if (is_empty(l)) -+ return; -+ -+ a[*i] = l->key; -+ (*i)++; -+ -+ keys_to_array(l->next, a, i); -+} -+ -+uint32_t -+hash_str(const char* str, uint32_t mapsize) -+{ -+ uint32_t hash = 0; -+ uint32_t x = 0; -+ uint32_t i = 0; -+ size_t len = strlen(str); -+ -+ for(i = 0; i < len; str++, i++) { -+ hash = (hash << 4) + (*str); -+ if((x = hash & 0xF0000000L) != 0) { -+ hash ^= (x >> 24); -+ hash &= ~x; -+ } -+ } -+ -+ return (hash & 0x7FFFFFFF) % mapsize; -+} -+ -+ -+int -+hashmap_is_empty(hashmap_t map) -+{ -+ if (map == NULL) -+ return -EINVAL; -+ -+ return map->entries > 0 ? 1 : 0; -+} -+ -+const char* -+hashmap_lookup(hashmap_t map, const char* key) -+{ -+ uint32_t i; -+ -+ if ((map == NULL) || (key == NULL)) -+ return NULL; -+ -+ i = hash_str(key, map->maxsize); -+ -+ return value_lookup(map->data[i], key); -+} -+ -+int -+hashmap_add(hashmap_t map, const char* key, const char* value) -+{ -+ uint32_t i; -+ hashentry_t entry; -+ -+ if ((map == NULL) || (key == NULL) || (value == NULL)) -+ return -EINVAL; -+ -+ i = hash_str(key, map->maxsize); -+ entry = new_entry(key, value); -+ if (entry == NULL) -+ return -ENOMEM; -+ -+ map->data[i] = insert_entry(map->data[i], -+ entry, &map->entries); -+ -+ INFO_MSG("HASH_ADD: chain[%d] key:%s val:%s",i, key, value); -+ return 0; -+} -+ -+int -+hashmap_remove(hashmap_t map, const char* key) -+{ -+ uint32_t i; -+ -+ if ((map == NULL) || (key == NULL)) -+ return -EINVAL; -+ -+ i = hash_str(key, map->maxsize); -+ map->data[i] = remove_entry(map->data[i], key, &map->entries); -+ -+ return 0; -+} -+ -+size_t -+hashmap_size(hashmap_t map) -+{ -+ if (map != NULL) -+ return map->entries; -+ else -+ return 0; -+} -+ -+int -+hashmap_free(hashmap_t map) -+{ -+ size_t i; -+ -+ if (map == NULL) -+ return -EINVAL; -+ -+ /* "children" first */ -+ for(i = 0; i < map->maxsize; i++) { -+ map->data[i] = remove_all(map->data[i], &map->entries); -+ } -+ free(map->data); -+ free(map); -+ -+ return 0; -+} -+ -+int -+hashmap_dump(hashmap_t map) -+{ -+ size_t i; -+ if (map == NULL) -+ return -EINVAL; -+ -+ for(i = 0; i < map->maxsize; i++) { -+ if (map->data[i] != NULL) { -+ printf("[%zd]: ", i); -+ print_all(map->data[i]); -+ } -+ } -+ -+ return 0; -+} -+ -+static const char** -+sort_key_vector(const char** a, size_t size) -+{ -+ /* uses bubblesort */ -+ size_t i, j; -+ const char* tmp; -+ -+ if (size <= 0) -+ return a; -+ -+ for (i = size - 1; i > 0; i--) { -+ for (j = 0; j < i; j++) { -+ if (strcmp(a[j], a[j+1]) > 0) { -+ tmp = a[j]; -+ a[j] = a[j+1]; -+ a[j+1] = tmp; -+ } -+ } -+ } -+ return a; -+} -+ -+const char** -+hashmap_get_key_vector(hashmap_t map, size_t* size, int sort) -+{ -+ const char** res; -+ size_t i, j; -+ *size = map->entries; -+ -+ res = (const char**) malloc(*size * sizeof(char*)); -+ if (res == NULL) -+ return NULL; -+ -+ j = 0; -+ for(i=0; i < map->maxsize; i++) { -+ keys_to_array(map->data[i], res, &j); -+ } -+ -+ if (sort) -+ res = sort_key_vector(res, *size); -+ -+ return res; -+} -+ -+int -+hashmap_key_is_in_vector(const char** vec, size_t size, const char* key) -+{ -+ size_t i; -+ for (i = 0; i < size; i++) { -+ if (strcmp(vec[i], key) == 0) /* found */ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+const char** -+hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, -+ const char** vec2, size_t vec2_size, size_t* res_size) -+{ -+ const char** res; -+ size_t i, j; -+ -+ *res_size = vec2_size; -+ -+ res = (const char**) malloc(*res_size * sizeof(char*)); -+ if (res == NULL) -+ return NULL; -+ -+ /* get all keys from vec2 which are not set in vec1 */ -+ j = 0; -+ for (i = 0; i < vec2_size; i++) { -+ if (!hashmap_key_is_in_vector(vec1, vec1_size, vec2[i])) -+ res[j++] = vec2[i]; -+ } -+ -+ *res_size = j; -+ return res; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/hashmap.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,49 @@ -+#ifndef __HASHMAP_H__ -+#define __HASHMAP_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+ -+typedef struct hashentry *hashentry_t; -+typedef struct hashmap *hashmap_t; -+ -+hashmap_t hashmap_new(void); -+int hashmap_free(hashmap_t map); -+ -+int hashmap_add(hashmap_t map, const char* key, const char* value); -+int hashmap_update(hashmap_t map, const char* key, const char* value); -+int hashmap_remove(hashmap_t map, const char* key); -+const char* hashmap_lookup(hashmap_t map, const char* key); -+ -+const char** hashmap_get_key_vector(hashmap_t map, size_t* size, int sort); -+int hashmap_key_is_in_vector(const char** vec, size_t size, const char* key); -+const char** hashmap_get_update_key_vector(const char** vec1, size_t vec1_size, -+ const char** vec2, size_t vec2_size, size_t* res_size); -+ -+int hashmap_dump(hashmap_t map); -+ -+int hashmap_is_empty(hashmap_t map); -+size_t hashmap_size(hashmap_t map); -+ -+uint32_t hash_str(const char* str, uint32_t mapsize); -+ -+#endif /* __HASHMAP_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libpfiflash.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1325 @@ -+/* -+ * Copyright International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Oliver Lohmann -+ * Drake Dowsett -+ * Contact: Andreas Arnez -+ */ -+ -+/* TODO Compare data before writing it. This implies that the volume -+ * parameters are compared first: size, alignment, name, type, ..., -+ * this is the same, compare the data. Volume deletion is deffered -+ * until the difference has been found out. -+ */ -+ -+#include -+#include -+#include -+#include -+#define __USE_GNU -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include /* FIXME Is this ok here? */ -+#include -+ -+#include "pfiflash_error.h" -+#include "ubimirror.h" -+#include "error.h" -+#include "reader.h" -+#include "example_ubi.h" -+#include "bootenv.h" -+ -+/* ubi-header.h and crc32.h needed for CRC checking */ -+#include /* FIXME Is this ok here? */ -+#include "crc32.h" -+ -+#define ubi_unused __attribute__((unused)) -+ -+#define COMPARE_BUFFER_SIZE 2048 -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+static const char copyright [] ubi_unused = -+ "Copyright International Business Machines Corp., 2006, 2007"; -+ -+/* simply clear buffer, then write into front of it */ -+#define EBUF(fmt...) \ -+ snprintf(err_buf, err_buf_size, fmt); -+ -+/* make a history of buffer and then prepend something in front */ -+#define EBUF_PREPEND(fmt) \ -+ do { \ -+ int EBUF_HISTORY_LENGTH = strlen(err_buf); \ -+ char EBUF_HISTORY[EBUF_HISTORY_LENGTH + 1]; \ -+ strncpy(EBUF_HISTORY, err_buf, EBUF_HISTORY_LENGTH + 1);\ -+ EBUF(fmt ": %s", EBUF_HISTORY); \ -+ } while (0) -+ -+/* An array of PDD function pointers indexed by the algorithm. */ -+static pdd_func_t pdd_funcs[PDD_HANDLING_NUM] = -+ { -+ &bootenv_pdd_keep, -+ &bootenv_pdd_merge, -+ &bootenv_pdd_overwrite -+ }; -+ -+typedef enum ubi_update_process_t { -+ UBI_REMOVE = 0, -+ UBI_WRITE, -+ UBI_COMPARE, -+} ubi_update_process_t; -+ -+ -+/** -+ * skip_raw_volumes - reads data from pfi to advance fp past raw block -+ * @pfi: fp to pfi data -+ * @pfi_raws: header information -+ * -+ * Error handling): -+ * when early EOF in pfi data -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ **/ -+static int -+skip_raw_volumes(FILE* pfi, list_t pfi_raws, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc; -+ void *i; -+ list_t ptr; -+ -+ if (is_empty(pfi_raws)) -+ return 0; -+ -+ rc = 0; -+ foreach(i, ptr, pfi_raws) { -+ size_t j; -+ pfi_raw_t raw; -+ -+ raw = (pfi_raw_t)i; -+ for(j = 0; j < raw->data_size; j++) { -+ int c; -+ -+ c = fgetc(pfi); -+ if (c == EOF) -+ rc = -PFIFLASH_ERR_EOF; -+ else if (ferror(pfi)) -+ rc = -PFIFLASH_ERR_FIO; -+ -+ if (rc != 0) -+ goto err; -+ } -+ } -+ -+ err: -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ return rc; -+} -+ -+ -+/** -+ * my_ubi_mkvol - wraps the ubi_mkvol functions and impl. bootenv update hook -+ * @devno: UBI device number. -+ * @s: Current seqnum. -+ * @u: Information about the UBI volume from the PFI. -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't create a volume -+ * - returns -PFIFLASH_ERR_UBI_MKVOL, err_buf matches text to err -+ **/ -+static int -+my_ubi_mkvol(int devno, int s, pfi_ubi_t u, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, type; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ struct ubi_mkvol_request req; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ ubimkvol id=%d, size=%d, data_size=%d, type=%d, " -+ "alig=%d, nlen=%d, name=%s", -+ u->ids[s], u->size, u->data_size, u->type, u->alignment, -+ strnlen(u->names[s], PFI_UBI_VOL_NAME_LEN), u->names[s]); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ switch (u->type) { -+ case pfi_ubi_static: -+ type = UBI_STATIC_VOLUME; break; -+ case pfi_ubi_dynamic: -+ default: -+ type = UBI_DYNAMIC_VOLUME; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); -+ -+ req.vol_id = u->ids[s]; -+ req.alignment = u->alignment; -+ req.bytes = u->size; -+ req.vol_type = type; -+ req.name = u->names[s]; -+ -+ rc = ubi_mkvol(ulib, path, &req); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_UBI_MKVOL; -+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[s]); -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * my_ubi_rmvol - a wrapper around the UBI library function ubi_rmvol -+ * @devno UBI device number -+ * @id UBI volume id to remove -+ * -+ * If the volume does not exist, the function will return success. -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't update (truncate) a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_UPDATE, err_buf matches text to err -+ * when UBI system couldn't remove a volume -+ * - returns -PFIFLASH_ERR_UBI_RMVOL, err_buf matches text to err -+ **/ -+static int -+my_ubi_rmvol(int devno, uint32_t id, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, fd; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ ubirmvol id=%d", id); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ /* truncate whether it exist or not */ -+ fd = open(path, O_RDWR); -+ if (fd < 0) { -+ libubi_close(ulib); -+ return 0; /* not existent, return 0 */ -+ } -+ -+ rc = ubi_update_start(ulib, fd, 0); -+ close(fd); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; /* if EBUSY than empty device, continue */ -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_DEV_PATTERN, devno); -+ -+ rc = ubi_rmvol(ulib, path, id); -+ if (rc != 0) { -+#ifdef DEBUG -+ int rc_old = rc; -+ dbg_msg("Remove UBI volume %d returned with error: %d " -+ "errno=%d", id, rc_old, errno); -+#endif -+ -+ rc = -PFIFLASH_ERR_UBI_RMVOL; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ -+ /* TODO Define a ubi_rmvol return value which says -+ * sth like EUBI_NOSUCHDEV. In this case, a failed -+ * operation is acceptable. Everything else has to be -+ * classified as real error. But talk to Andreas Arnez -+ * before defining something odd... -+ */ -+ /* if ((errno == EINVAL) || (errno == ENODEV)) -+ return 0; */ /* currently it is EINVAL or ENODEV */ -+ -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * read_bootenv_volume - reads the current bootenv data from id into be_old -+ * @devno UBI device number -+ * @id UBI volume id to remove -+ * @bootenv_old to hold old boot_env data -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't open a volume to read -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when couldn't read bootenv data -+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err -+ **/ -+static int -+read_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ FILE* fp_in; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ -+ rc = 0; -+ fp_in = NULL; -+ ulib = NULL; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_in = fopen(path, "r"); -+ if (!fp_in) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ log_msg("[ reading old bootenvs ..."); -+ -+ /* Save old bootenvs for reference */ -+ rc = bootenv_read(fp_in, bootenv_old, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ err: -+ if (fp_in) -+ fclose(fp_in); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * write_bootenv_volume - writes data from PFI file int to bootenv UBI volume -+ * @devno UBI device number -+ * @id UBI volume id -+ * @bootend_old old PDD data from machine -+ * @pdd_f function to handle PDD with -+ * @fp_in new pdd data contained in PFI -+ * @fp_in_size data size of new pdd data in PFI -+ * @pfi_crc crc value from PFI header -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when bootenv can't be created -+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err -+ * when bootenv can't be read -+ * - returns -PFIFLASH_ERR_BOOTENV_READ, err_buf matches text to err -+ * when PDD handling function returns and error -+ * - passes rc and err_buf data -+ * when CRC check fails -+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ * when bootenv can't be resized -+ * - returns -PFIFLASH_ERR_BOOTENV_SIZE, err_buf matches text to err -+ * when UBI system couldn't open a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when couldn't write bootenv data -+ * - returns -PFIFLASH_ERR_BOOTENV_WRITE, err_buf matches text to err -+ **/ -+static int -+write_bootenv_volume(int devno, uint32_t id, bootenv_t bootenv_old, -+ pdd_func_t pdd_f, FILE* fp_in, size_t fp_in_size, -+ uint32_t pfi_crc, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, warnings, fd_out; -+ uint32_t crc; -+ char path[PATH_MAX]; -+ size_t update_size; -+ FILE *fp_out; -+ bootenv_t bootenv_new, bootenv_res; -+ libubi_t ulib; -+ -+ rc = 0; -+ warnings = 0; -+ crc = 0; -+ update_size = 0; -+ fp_out = NULL; -+ bootenv_new = NULL; -+ bootenv_res = NULL; -+ ulib = NULL; -+ -+ log_msg("[ ubiupdatevol bootenv id=%d, fp_in=%p", id, fp_in); -+ -+ /* Workflow: -+ * 1. Apply PDD operation and get the size of the returning -+ * bootenv_res section. Without the correct size it wouldn't -+ * be possible to call UBI update vol. -+ * 2. Call UBI update vol -+ * 3. Get FILE* to vol dev -+ * 4. Write to FILE* -+ */ -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_new); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], " 'new'"); -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], " 'res'"); -+ goto err; -+ } -+ -+ rc = bootenv_read_crc(fp_in, bootenv_new, fp_in_size, &crc); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } else if (crc != pfi_crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); -+ goto err; -+ } -+ -+ rc = pdd_f(bootenv_old, bootenv_new, &bootenv_res, &warnings, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("handling PDD"); -+ goto err; -+ } -+ else if (warnings) -+ /* TODO do something with warnings */ -+ dbg_msg("A warning in the PDD operation occured: %d", -+ warnings); -+ -+ rc = bootenv_size(bootenv_res, &update_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_SIZE; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ fp_out = fdopen(fd_out, "r+"); -+ if (!fp_out) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ rc = ubi_update_start(ulib, fd_out, update_size); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ rc = bootenv_write(fp_out, bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_WRITE; -+ EBUF(PFIFLASH_ERRSTR[-rc], devno, id); -+ goto err; -+ } -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ if (bootenv_new != NULL) -+ bootenv_destroy(&bootenv_new); -+ if (bootenv_res != NULL) -+ bootenv_destroy(&bootenv_res); -+ if (fp_out) -+ fclose(fp_out); -+ -+ return rc; -+} -+ -+ -+/** -+ * write_normal_volume - writes data from PFI file int to regular UBI volume -+ * @devno UBI device number -+ * @id UBI volume id -+ * @update_size size of data stream -+ * @fp_in PFI data file pointer -+ * @pfi_crc CRC data from PFI header -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ * when UBI system couldn't open a volume -+ * - returns -PFIFLASH_ERR_UBI_VOL_FOPEN, err_buf matches text to err -+ * when unexpected EOF is encountered -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ * when CRC check fails -+ * - retruns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ **/ -+static int -+write_normal_volume(int devno, uint32_t id, size_t update_size, FILE* fp_in, -+ uint32_t pfi_crc, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc, fd_out; -+ uint32_t crc, crc32_table[256]; -+ char path[PATH_MAX]; -+ size_t bytes_left; -+ FILE* fp_out; -+ libubi_t ulib; -+ -+ rc = 0; -+ crc = UBI_CRC32_INIT; -+ bytes_left = update_size; -+ fp_out = NULL; -+ ulib = NULL; -+ -+ log_msg("[ ubiupdatevol id=%d, update_size=%d fp_in=%p", -+ id, update_size, fp_in); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ fp_out = fdopen(fd_out, "r+"); -+ if (!fp_out) { -+ rc = -PFIFLASH_ERR_UBI_VOL_FOPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ rc = ubi_update_start(ulib, fd_out, update_size); -+ if (rc < 0) { -+ rc = -PFIFLASH_ERR_UBI_VOL_UPDATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], id); -+ goto err; -+ } -+ -+ init_crc32_table(crc32_table); -+ while (bytes_left) { -+ char buf[1024]; -+ size_t to_rw = sizeof buf > bytes_left ? -+ bytes_left : sizeof buf; -+ if (fread(buf, 1, to_rw, fp_in) != to_rw) { -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ crc = clc_crc32(crc32_table, crc, buf, to_rw); -+ if (fwrite(buf, 1, to_rw, fp_out) != to_rw) { -+ rc = -PFIFLASH_ERR_FIO; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ bytes_left -= to_rw; -+ } -+ -+ if (crc != pfi_crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], pfi_crc, crc); -+ goto err; -+ } -+ -+ err: -+ if (fp_out) -+ fclose(fp_out); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+static int compare_bootenv(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, -+ uint32_t data_size, pdd_func_t pdd_f, char *err_buf, -+ size_t err_buf_size) -+{ -+ int rc, warnings = 0; -+ unsigned int i; -+ bootenv_t bootenv_pfi, bootenv_res = NULL, bootenv_flash = NULL; -+ -+ rc = bootenv_create(&bootenv_pfi); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_create(&bootenv_res); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_pfi, bootenv_pfi, data_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ rc = bootenv_create(&bootenv_flash); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_flash[i], bootenv_flash, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_READ; -+ goto err; -+ } -+ -+ rc = pdd_f(bootenv_flash, bootenv_pfi, &bootenv_res, -+ &warnings, err_buf, err_buf_size); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_PDD_UNKNOWN; -+ goto err; -+ } -+ -+ rc = bootenv_compare(bootenv_flash, bootenv_res); -+ if (rc > 0) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } else if (rc < 0) { -+ rc = -PFIFLASH_ERR_COMPARE; -+ goto err; -+ } -+ -+ bootenv_destroy(&bootenv_flash); -+ bootenv_flash = NULL; -+ } -+ -+err: -+ if (bootenv_pfi) -+ bootenv_destroy(&bootenv_pfi); -+ if (bootenv_res) -+ bootenv_destroy(&bootenv_res); -+ if (bootenv_flash) -+ bootenv_destroy(&bootenv_flash); -+ -+ return rc; -+} -+ -+static int compare_data(FILE *fp_pfi, FILE **fp_flash, uint32_t ids_size, -+ uint32_t bytes_left) -+{ -+ unsigned int i; -+ size_t read_bytes, rc = 0; -+ char buf_pfi[COMPARE_BUFFER_SIZE]; -+ char *buf_flash[ids_size]; -+ -+ for (i = 0; i < ids_size; i++) { -+ buf_flash[i] = malloc(COMPARE_BUFFER_SIZE); -+ if (!buf_flash[i]) -+ return -PFIFLASH_ERR_COMPARE; -+ } -+ -+ while (bytes_left) { -+ if (bytes_left > COMPARE_BUFFER_SIZE) -+ read_bytes = COMPARE_BUFFER_SIZE; -+ else -+ read_bytes = bytes_left; -+ -+ rc = fread(buf_pfi, 1, read_bytes, fp_pfi); -+ if (rc != read_bytes) { -+ rc = -PFIFLASH_ERR_COMPARE; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ rc = fread(buf_flash[i], 1, read_bytes, fp_flash[i]); -+ if (rc != read_bytes) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } -+ -+ rc = memcmp(buf_pfi, buf_flash[i], read_bytes); -+ if (rc != 0) { -+ rc = -PFIFLASH_CMP_DIFF; -+ goto err; -+ } -+ } -+ -+ bytes_left -= read_bytes; -+ } -+ -+err: -+ for (i = 0; i < ids_size; i++) -+ free(buf_flash[i]); -+ -+ return rc; -+} -+ -+static int compare_volumes(int devno, pfi_ubi_t u, FILE *fp_pfi, -+ pdd_func_t pdd_f, char *err_buf, size_t err_buf_size) -+{ -+ int rc, is_bootenv = 0; -+ unsigned int i; -+ char path[PATH_MAX]; -+ libubi_t ulib = NULL; -+ FILE *fp_flash[u->ids_size]; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ goto err; -+ } -+ -+ for (i = 0; i < u->ids_size; i++) { -+ if (u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_1 || -+ u->ids[i] == EXAMPLE_BOOTENV_VOL_ID_2) -+ is_bootenv = 1; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, u->ids[i]); -+ -+ fp_flash[i] = fopen(path, "r"); -+ if (fp_flash[i] == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ goto err; -+ } -+ } -+ -+ if (is_bootenv) -+ rc = compare_bootenv(fp_pfi, fp_flash, u->ids_size, -+ u->data_size, pdd_f, err_buf, err_buf_size); -+ else -+ rc = compare_data(fp_pfi, fp_flash, u->ids_size, u->data_size); -+ -+err: -+ if (rc < 0) -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ -+ for (i = 0; i < u->ids_size; i++) -+ fclose(fp_flash[i]); -+ if (ulib) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+static int -+erase_mtd_region(FILE* file_p, int start, int length) -+{ -+ int rc, fd; -+ erase_info_t erase; -+ mtd_info_t mtdinfo; -+ loff_t offset = start; -+ loff_t end = offset + length; -+ -+ fd = fileno(file_p); -+ if (fd < 0) -+ return -PFIFLASH_ERR_MTD_ERASE; -+ -+ rc = ioctl(fd, MEMGETINFO, &mtdinfo); -+ if (rc) -+ return -PFIFLASH_ERR_MTD_ERASE; -+ -+ /* check for bad blocks in case of NAND flash */ -+ if (mtdinfo.type == MTD_NANDFLASH) { -+ while (offset < end) { -+ rc = ioctl(fd, MEMGETBADBLOCK, &offset); -+ if (rc > 0) { -+ return -PFIFLASH_ERR_MTD_ERASE; -+ } -+ -+ offset += mtdinfo.erasesize; -+ } -+ } -+ -+ erase.start = start; -+ erase.length = length; -+ -+ rc = ioctl(fd, MEMERASE, &erase); -+ if (rc) { -+ return -PFIFLASH_ERR_MTD_ERASE; -+ } -+ -+ return rc; -+} -+ -+/** -+ * process_raw_volumes - writes the raw sections of the PFI data -+ * @pfi PFI data file pointer -+ * @pfi_raws list of PFI raw headers -+ * @rawdev device to use to write raw data -+ * -+ * Error handling: -+ * when early EOF in PFI data -+ * - returns -PFIFLASH_ERR_EOF, err_buf matches text to err -+ * when file I/O error -+ * - returns -PFIFLASH_ERR_FIO, err_buf matches text to err -+ * when CRC check fails -+ * - returns -PFIFLASH_ERR_CRC_CHECK, err_buf matches text to err -+ * when opening MTD device fails -+ * - reutrns -PFIFLASH_ERR_MTD_OPEN, err_buf matches text to err -+ * when closing MTD device fails -+ * - returns -PFIFLASH_ERR_MTD_CLOSE, err_buf matches text to err -+ **/ -+static int -+process_raw_volumes(FILE* pfi, list_t pfi_raws, const char* rawdev, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc; -+ char *pfi_data; -+ void *i; -+ uint32_t crc, crc32_table[256]; -+ size_t j, k; -+ FILE* mtd = NULL; -+ list_t ptr; -+ -+ if (is_empty(pfi_raws)) -+ return 0; -+ -+ if (rawdev == NULL) -+ return 0; -+ -+ rc = 0; -+ -+ pfi_data = NULL; -+ -+ log_msg("[ rawupdate dev=%s", rawdev); -+ -+ crc = UBI_CRC32_INIT; -+ init_crc32_table(crc32_table); -+ -+ /* most likely only one element in list, but just in case */ -+ foreach(i, ptr, pfi_raws) { -+ pfi_raw_t r = (pfi_raw_t)i; -+ -+ /* read in pfi data */ -+ if (pfi_data != NULL) -+ free(pfi_data); -+ pfi_data = malloc(r->data_size * sizeof(char)); -+ for (j = 0; j < r->data_size; j++) { -+ int c = fgetc(pfi); -+ if (c == EOF) { -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } else if (ferror(pfi)) { -+ rc = -PFIFLASH_ERR_FIO; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ pfi_data[j] = (char)c; -+ } -+ crc = clc_crc32(crc32_table, crc, pfi_data, r->data_size); -+ -+ /* check crc */ -+ if (crc != r->crc) { -+ rc = -PFIFLASH_ERR_CRC_CHECK; -+ EBUF(PFIFLASH_ERRSTR[-rc], r->crc, crc); -+ goto err; -+ } -+ -+ /* open device */ -+ mtd = fopen(rawdev, "r+"); -+ if (mtd == NULL) { -+ rc = -PFIFLASH_ERR_MTD_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev); -+ goto err; -+ } -+ -+ for (j = 0; j < r->starts_size; j++) { -+ rc = erase_mtd_region(mtd, r->starts[j], r->data_size); -+ if (rc) { -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ fseek(mtd, r->starts[j], SEEK_SET); -+ for (k = 0; k < r->data_size; k++) { -+ int c = fputc((int)pfi_data[k], mtd); -+ if (c == EOF) { -+ fclose(mtd); -+ rc = -PFIFLASH_ERR_EOF; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ if ((char)c != pfi_data[k]) { -+ fclose(mtd); -+ rc = -1; -+ goto err; -+ } -+ } -+ } -+ rc = fclose(mtd); -+ mtd = NULL; -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_MTD_CLOSE; -+ EBUF(PFIFLASH_ERRSTR[-rc], rawdev); -+ goto err; -+ } -+ } -+ -+ err: -+ if (mtd != NULL) -+ fclose(mtd); -+ if (pfi_data != NULL) -+ free(pfi_data); -+ return rc; -+} -+ -+ -+/** -+ * erase_unmapped_ubi_volumes - skip volumes provided by PFI file, clear rest -+ * @devno UBI device number -+ * @pfi_ubis list of UBI header data -+ * -+ * Error handling: -+ * when UBI id is out of bounds -+ * - returns -PFIFLASH_ERR_UBI_VID_OOB, err_buf matches text to err -+ * when UBI volume can't be removed -+ * - passes rc, prepends err_buf with contextual aid -+ **/ -+static int -+erase_unmapped_ubi_volumes(int devno, list_t pfi_ubis, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ uint8_t ubi_volumes[PFI_UBI_MAX_VOLUMES]; -+ size_t i; -+ list_t ptr; -+ pfi_ubi_t u; -+ -+ rc = 0; -+ -+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) -+ ubi_volumes[i] = 1; -+ -+ foreach(u, ptr, pfi_ubis) { -+ /* iterate over each vol_id */ -+ for(i = 0; i < u->ids_size; i++) { -+ if (u->ids[i] >= PFI_UBI_MAX_VOLUMES) { -+ rc = -PFIFLASH_ERR_UBI_VID_OOB; -+ EBUF(PFIFLASH_ERRSTR[-rc], u->ids[i]); -+ goto err; -+ } -+ /* remove from removal list */ -+ ubi_volumes[u->ids[i]] = 0; -+ } -+ } -+ -+ for (i = 0; i < PFI_UBI_MAX_VOLUMES; i++) { -+ if (ubi_volumes[i]) { -+ rc = my_ubi_rmvol(devno, i, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("remove volume failed"); -+ goto err; -+ } -+ } -+ } -+ -+ err: -+ return rc; -+} -+ -+ -+/** -+ * process_ubi_volumes - delegate tasks regarding UBI volumes -+ * @pfi PFI data file pointer -+ * @seqnum sequence number -+ * @pfi_ubis list of UBI header data -+ * @bootenv_old storage for current system PDD -+ * @pdd_f function to handle PDD -+ * @ubi_update_process whether reading or writing -+ * -+ * Error handling: -+ * when and unknown ubi_update_process is given -+ * - returns -PFIFLASH_ERR_UBI_UNKNOWN, err_buf matches text to err -+ * otherwise -+ * - passes rc and err_buf -+ **/ -+static int -+process_ubi_volumes(FILE* pfi, int seqnum, list_t pfi_ubis, -+ bootenv_t bootenv_old, pdd_func_t pdd_f, -+ ubi_update_process_t ubi_update_process, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ pfi_ubi_t u; -+ list_t ptr; -+ -+ rc = 0; -+ -+ foreach(u, ptr, pfi_ubis) { -+ int s = seqnum; -+ -+ if (s > ((int)u->ids_size - 1)) -+ s = 0; /* per default use the first */ -+ u->curr_seqnum = s; -+ -+ switch (ubi_update_process) { -+ case UBI_REMOVE: -+ /* TODO are all these "EXAMPLE" vars okay? */ -+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || -+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { -+ rc = read_bootenv_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], bootenv_old, -+ err_buf, err_buf_size); -+ /* it's okay if there is no bootenv -+ * we're going to write one */ -+ if ((rc == -PFIFLASH_ERR_UBI_VOL_FOPEN) || -+ (rc == -PFIFLASH_ERR_BOOTENV_READ)) -+ rc = 0; -+ if (rc != 0) -+ goto err; -+ } -+ -+ rc = my_ubi_rmvol(EXAMPLE_UBI_DEVICE, u->ids[s], -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ -+ break; -+ case UBI_WRITE: -+ rc = my_ubi_mkvol(EXAMPLE_UBI_DEVICE, s, u, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("creating volume"); -+ goto err; -+ } -+ -+ if ((u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_1) || -+ (u->ids[s] == EXAMPLE_BOOTENV_VOL_ID_2)) { -+ rc = write_bootenv_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], -+ bootenv_old, pdd_f, -+ pfi, -+ u->data_size, -+ u->crc, -+ err_buf, -+ err_buf_size); -+ if (rc != 0) -+ EBUF_PREPEND("bootenv volume"); -+ } else { -+ rc = write_normal_volume(EXAMPLE_UBI_DEVICE, -+ u->ids[s], -+ u->data_size, pfi, -+ u->crc, -+ err_buf, -+ err_buf_size); -+ if (rc != 0) -+ EBUF_PREPEND("normal volume"); -+ } -+ if (rc != 0) -+ goto err; -+ -+ break; -+ case UBI_COMPARE: -+ rc = compare_volumes(EXAMPLE_UBI_DEVICE, u, pfi, pdd_f, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("compare volume"); -+ goto err; -+ } -+ -+ break; -+ default: -+ rc = -PFIFLASH_ERR_UBI_UNKNOWN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ } -+ -+ err: -+ return rc; -+} -+ -+ -+/** -+ * mirror_ubi_volumes - mirror redundant pairs of volumes -+ * @devno UBI device number -+ * @pfi_ubis list of PFI header data -+ * -+ * Error handling: -+ * when UBI system couldn't be opened -+ * - returns -PFIFLASH_ERR_UBI_OPEN, err_buf matches text to err -+ **/ -+static int -+mirror_ubi_volumes(uint32_t devno, list_t pfi_ubis, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ uint32_t j; -+ list_t ptr; -+ pfi_ubi_t i; -+ libubi_t ulib; -+ -+ rc = 0; -+ ulib = NULL; -+ -+ log_msg("[ mirror ..."); -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ rc = -PFIFLASH_ERR_UBI_OPEN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ /** -+ * Execute all mirror operations on redundant groups. -+ * Create a volume within a redundant group if it does -+ * not exist already (this is a precondition of -+ * ubimirror). -+ */ -+ foreach(i, ptr, pfi_ubis) { -+ for (j = 0; j < i->ids_size; j++) { -+ /* skip self-match */ -+ if (i->ids[j] == i->ids[i->curr_seqnum]) -+ continue; -+ -+ rc = my_ubi_rmvol(devno, i->ids[j], -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ -+ rc = my_ubi_mkvol(devno, j, i, -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ } -+ } -+ -+ foreach(i, ptr, pfi_ubis) { -+ rc = ubimirror(devno, i->curr_seqnum, i->ids, i->ids_size, -+ err_buf, err_buf_size); -+ if (rc != 0) -+ goto err; -+ } -+ -+ -+ err: -+ if (ulib != NULL) -+ libubi_close(ulib); -+ -+ return rc; -+} -+ -+ -+/** -+ * pfiflash_with_options - exposed func to flash memory with a PFI file -+ * @pfi PFI data file pointer -+ * @complete flag to erase unmapped volumes -+ * @seqnum sequence number -+ * @compare flag to compare -+ * @pdd_handling method to handle pdd (keep, merge, overwrite...) -+ * -+ * Error handling: -+ * when bootenv can't be created -+ * - returns -PFIFLASH_ERR_BOOTENV_CREATE, err_buf matches text to err -+ * when PFI headers can't be read, or -+ * when fail to skip raw sections, or -+ * when error occurs while processing raw volumes, or -+ * when fail to erase unmapped UBI vols, or -+ * when error occurs while processing UBI volumes, or -+ * when error occurs while mirroring UBI volumes -+ * - passes rc, prepends err_buf with contextual aid -+ **/ -+int -+pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, -+ pdd_handling_t pdd_handling, const char* rawdev, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc; -+ bootenv_t bootenv; -+ pdd_func_t pdd_f; -+ -+ if (pfi == NULL) -+ return -EINVAL; -+ -+ rc = 0; -+ pdd_f = NULL; -+ -+ /* If the user didnt specify a seqnum we start per default -+ * with the index 0 */ -+ int curr_seqnum = seqnum < 0 ? 0 : seqnum; -+ -+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ -+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ -+ -+ rc = bootenv_create(&bootenv); -+ if (rc != 0) { -+ rc = -PFIFLASH_ERR_BOOTENV_CREATE; -+ EBUF(PFIFLASH_ERRSTR[-rc], ""); -+ goto err; -+ } -+ -+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, pfi, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("reading PFI header"); -+ goto err; -+ } -+ -+ if (rawdev == NULL || compare) -+ rc = skip_raw_volumes(pfi, pfi_raws, err_buf, err_buf_size); -+ else -+ rc = process_raw_volumes(pfi, pfi_raws, rawdev, err_buf, -+ err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("handling raw section"); -+ goto err; -+ } -+ -+ if (complete && !compare) { -+ rc = erase_unmapped_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("deleting unmapped UBI volumes"); -+ goto err; -+ } -+ } -+ -+ if (((int)pdd_handling >= 0) && -+ (pdd_handling < PDD_HANDLING_NUM)) -+ pdd_f = pdd_funcs[pdd_handling]; -+ else { -+ rc = -PFIFLASH_ERR_PDD_UNKNOWN; -+ EBUF(PFIFLASH_ERRSTR[-rc]); -+ goto err; -+ } -+ -+ if (!compare) { -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_REMOVE, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("removing UBI volumes"); -+ goto err; -+ } -+ -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_WRITE, err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("writing UBI volumes"); -+ goto err; -+ } -+ -+ if (seqnum < 0) { /* mirror redundant pairs */ -+ rc = mirror_ubi_volumes(EXAMPLE_UBI_DEVICE, pfi_ubis, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ EBUF_PREPEND("mirroring UBI volumes"); -+ goto err; -+ } -+ } -+ } else { -+ /* only compare volumes, don't alter the content */ -+ rc = process_ubi_volumes(pfi, curr_seqnum, pfi_ubis, bootenv, -+ pdd_f, UBI_COMPARE, err_buf, err_buf_size); -+ -+ if (rc == -PFIFLASH_CMP_DIFF) -+ /* update is necessary, return positive value */ -+ rc = 1; -+ -+ if (rc < 0) { -+ EBUF_PREPEND("comparing UBI volumes"); -+ goto err; -+ } -+ } -+ -+ err: -+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); -+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); -+ bootenv_destroy(&bootenv); -+ return rc; -+} -+ -+ -+/** -+ * pfiflash - passes to pfiflash_with_options -+ * @pfi PFI data file pointer -+ * @complete flag to erase unmapped volumes -+ * @seqnum sequence number -+ * @pdd_handling method to handle pdd (keep, merge, overwrite...) -+ **/ -+int -+pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, -+ char *err_buf, size_t err_buf_size) -+{ -+ return pfiflash_with_options(pfi, complete, seqnum, 0, pdd_handling, -+ NULL, err_buf, err_buf_size); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,915 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "libubi.h" -+#include "libubi_int.h" -+ -+libubi_t libubi_open(void) -+{ -+ int fd, version; -+ struct libubi *lib; -+ -+ lib = calloc(1, sizeof(struct libubi)); -+ if (!lib) -+ return NULL; -+ -+ /* TODO: this must be discovered instead */ -+ lib->sysfs = strdup("/sys"); -+ if (!lib->sysfs) -+ goto error; -+ -+ lib->sysfs_ubi = mkpath(lib->sysfs, SYSFS_UBI); -+ if (!lib->sysfs_ubi) -+ goto error; -+ -+ /* Make sure UBI is present */ -+ fd = open(lib->sysfs_ubi, O_RDONLY); -+ if (fd == -1) -+ goto error; -+ close(fd); -+ -+ lib->ubi_dev = mkpath(lib->sysfs_ubi, UBI_DEV_NAME_PATT); -+ if (!lib->ubi_dev) -+ goto error; -+ -+ lib->ubi_version = mkpath(lib->sysfs_ubi, UBI_VER); -+ if (!lib->ubi_version) -+ goto error; -+ -+ lib->dev_dev = mkpath(lib->ubi_dev, DEV_DEV); -+ if (!lib->dev_dev) -+ goto error; -+ -+ lib->dev_avail_ebs = mkpath(lib->ubi_dev, DEV_AVAIL_EBS); -+ if (!lib->dev_avail_ebs) -+ goto error; -+ -+ lib->dev_total_ebs = mkpath(lib->ubi_dev, DEV_TOTAL_EBS); -+ if (!lib->dev_total_ebs) -+ goto error; -+ -+ lib->dev_bad_count = mkpath(lib->ubi_dev, DEV_BAD_COUNT); -+ if (!lib->dev_bad_count) -+ goto error; -+ -+ lib->dev_eb_size = mkpath(lib->ubi_dev, DEV_EB_SIZE); -+ if (!lib->dev_eb_size) -+ goto error; -+ -+ lib->dev_max_ec = mkpath(lib->ubi_dev, DEV_MAX_EC); -+ if (!lib->dev_max_ec) -+ goto error; -+ -+ lib->dev_bad_rsvd = mkpath(lib->ubi_dev, DEV_MAX_RSVD); -+ if (!lib->dev_bad_rsvd) -+ goto error; -+ -+ lib->dev_max_vols = mkpath(lib->ubi_dev, DEV_MAX_VOLS); -+ if (!lib->dev_max_vols) -+ goto error; -+ -+ lib->dev_min_io_size = mkpath(lib->ubi_dev, DEV_MIN_IO_SIZE); -+ if (!lib->dev_min_io_size) -+ goto error; -+ -+ lib->ubi_vol = mkpath(lib->sysfs_ubi, UBI_VOL_NAME_PATT); -+ if (!lib->ubi_vol) -+ goto error; -+ -+ lib->vol_type = mkpath(lib->ubi_vol, VOL_TYPE); -+ if (!lib->vol_type) -+ goto error; -+ -+ lib->vol_dev = mkpath(lib->ubi_vol, VOL_DEV); -+ if (!lib->vol_dev) -+ goto error; -+ -+ lib->vol_alignment = mkpath(lib->ubi_vol, VOL_ALIGNMENT); -+ if (!lib->vol_alignment) -+ goto error; -+ -+ lib->vol_data_bytes = mkpath(lib->ubi_vol, VOL_DATA_BYTES); -+ if (!lib->vol_data_bytes) -+ goto error; -+ -+ lib->vol_rsvd_ebs = mkpath(lib->ubi_vol, VOL_RSVD_EBS); -+ if (!lib->vol_rsvd_ebs) -+ goto error; -+ -+ lib->vol_eb_size = mkpath(lib->ubi_vol, VOL_EB_SIZE); -+ if (!lib->vol_eb_size) -+ goto error; -+ -+ lib->vol_corrupted = mkpath(lib->ubi_vol, VOL_CORRUPTED); -+ if (!lib->vol_corrupted) -+ goto error; -+ -+ lib->vol_name = mkpath(lib->ubi_vol, VOL_NAME); -+ if (!lib->vol_name) -+ goto error; -+ -+ if (read_int(lib->ubi_version, &version)) -+ goto error; -+ if (version != LIBUBI_UBI_VERSION) { -+ fprintf(stderr, "LIBUBI: this library was made for UBI version " -+ "%d, but UBI version %d is detected\n", -+ LIBUBI_UBI_VERSION, version); -+ goto error; -+ } -+ -+ return lib; -+ -+error: -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->sysfs); -+ free(lib); -+ return NULL; -+} -+ -+void libubi_close(libubi_t desc) -+{ -+ struct libubi *lib = (struct libubi *)desc; -+ -+ free(lib->vol_name); -+ free(lib->vol_corrupted); -+ free(lib->vol_eb_size); -+ free(lib->vol_rsvd_ebs); -+ free(lib->vol_data_bytes); -+ free(lib->vol_alignment); -+ free(lib->vol_dev); -+ free(lib->vol_type); -+ free(lib->ubi_vol); -+ free(lib->dev_min_io_size); -+ free(lib->dev_max_vols); -+ free(lib->dev_bad_rsvd); -+ free(lib->dev_max_ec); -+ free(lib->dev_eb_size); -+ free(lib->dev_bad_count); -+ free(lib->dev_total_ebs); -+ free(lib->dev_avail_ebs); -+ free(lib->dev_dev); -+ free(lib->ubi_version); -+ free(lib->ubi_dev); -+ free(lib->sysfs_ubi); -+ free(lib->sysfs); -+ free(lib); -+} -+ -+int ubi_get_info(libubi_t desc, struct ubi_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_info)); -+ -+ /* -+ * We have to scan the UBI sysfs directory to identify how many UBI -+ * devices are present. -+ */ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_dev_num = INT_MAX; -+ while ((dirent = readdir(sysfs_ubi))) { -+ char *name = &dirent->d_name[0]; -+ int dev_num, ret; -+ -+ ret = sscanf(name, UBI_DEV_NAME_PATT, &dev_num); -+ if (ret == 1) { -+ info->dev_count += 1; -+ if (dev_num > info->highest_dev_num) -+ info->highest_dev_num = dev_num; -+ if (dev_num < info->lowest_dev_num) -+ info->lowest_dev_num = dev_num; -+ } -+ } -+ -+ if (info->lowest_dev_num == INT_MAX) -+ info->lowest_dev_num = 0; -+ -+ if (read_int(lib->ubi_version, &info->version)) -+ goto close; -+ -+ return closedir(sysfs_ubi); -+ -+close: -+ closedir(sysfs_ubi); -+ return -1; -+} -+ -+int ubi_mkvol(libubi_t desc, const char *node, struct ubi_mkvol_request *req) -+{ -+ int fd, ret; -+ struct ubi_mkvol_req r; -+ size_t n; -+ -+ desc = desc; -+ r.vol_id = req->vol_id; -+ r.alignment = req->alignment; -+ r.bytes = req->bytes; -+ r.vol_type = req->vol_type; -+ -+ n = strlen(req->name); -+ if (n > UBI_MAX_VOLUME_NAME) -+ return -1; -+ -+ strncpy(r.name, req->name, UBI_MAX_VOLUME_NAME + 1); -+ r.name_len = n; -+ -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCMKVOL, &r); -+ if (!ret) -+ req->vol_id = r.vol_id; -+ -+ close(fd); -+ return ret; -+} -+ -+int ubi_rmvol(libubi_t desc, const char *node, int vol_id) -+{ -+ int fd, ret; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ ret = ioctl(fd, UBI_IOCRMVOL, &vol_id); -+ close(fd); -+ return ret; -+} -+ -+int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) -+{ -+ int fd, ret; -+ struct ubi_rsvol_req req; -+ -+ desc = desc; -+ fd = open(node, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ req.bytes = bytes; -+ req.vol_id = vol_id; -+ -+ ret = ioctl(fd, UBI_IOCRSVOL, &req); -+ close(fd); -+ return ret; -+} -+ -+int ubi_update_start(libubi_t desc, int fd, long long bytes) -+{ -+ desc = desc; -+ if (ioctl(fd, UBI_IOCVOLUP, &bytes)) -+ return -1; -+ return 0; -+} -+ -+int ubi_get_dev_info(libubi_t desc, const char *node, struct ubi_dev_info *info) -+{ -+ int dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ dev_num = find_dev_num(lib, node); -+ if (dev_num == -1) -+ return -1; -+ -+ return ubi_get_dev_info1(desc, dev_num, info); -+} -+ -+int ubi_get_dev_info1(libubi_t desc, int dev_num, struct ubi_dev_info *info) -+{ -+ DIR *sysfs_ubi; -+ struct dirent *dirent; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ memset(info, '\0', sizeof(struct ubi_dev_info)); -+ info->dev_num = dev_num; -+ -+ sysfs_ubi = opendir(lib->sysfs_ubi); -+ if (!sysfs_ubi) -+ return -1; -+ -+ info->lowest_vol_num = INT_MAX; -+ while ((dirent = readdir(sysfs_ubi))) { -+ char *name = &dirent->d_name[0]; -+ int vol_id, ret, devno; -+ -+ ret = sscanf(name, UBI_VOL_NAME_PATT, &devno, &vol_id); -+ if (ret == 2 && devno == dev_num) { -+ info->vol_count += 1; -+ if (vol_id > info->highest_vol_num) -+ info->highest_vol_num = vol_id; -+ if (vol_id < info->lowest_vol_num) -+ info->lowest_vol_num = vol_id; -+ } -+ } -+ -+ closedir(sysfs_ubi); -+ -+ if (info->lowest_vol_num == INT_MAX) -+ info->lowest_vol_num = 0; -+ -+ if (dev_read_int(lib->dev_avail_ebs, dev_num, &info->avail_ebs)) -+ return -1; -+ if (dev_read_int(lib->dev_total_ebs, dev_num, &info->total_ebs)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_count, dev_num, &info->bad_count)) -+ return -1; -+ if (dev_read_int(lib->dev_eb_size, dev_num, &info->eb_size)) -+ return -1; -+ if (dev_read_int(lib->dev_bad_rsvd, dev_num, &info->bad_rsvd)) -+ return -1; -+ if (dev_read_ll(lib->dev_max_ec, dev_num, &info->max_ec)) -+ return -1; -+ if (dev_read_int(lib->dev_max_vols, dev_num, &info->max_vol_count)) -+ return -1; -+ if (dev_read_int(lib->dev_min_io_size, dev_num, &info->min_io_size)) -+ return -1; -+ -+ info->avail_bytes = info->avail_ebs * info->eb_size; -+ info->total_bytes = info->total_ebs * info->eb_size; -+ -+ return 0; -+} -+ -+int ubi_get_vol_info(libubi_t desc, const char *node, struct ubi_vol_info *info) -+{ -+ int vol_id, dev_num; -+ struct libubi *lib = (struct libubi *)desc; -+ -+ dev_num = find_dev_num_vol(lib, node); -+ if (dev_num == -1) -+ return -1; -+ -+ vol_id = find_vol_num(lib, dev_num, node); -+ if (vol_id == -1) -+ return -1; -+ -+ return ubi_get_vol_info1(desc, dev_num, vol_id, info); -+} -+ -+int ubi_get_vol_info1(libubi_t desc, int dev_num, int vol_id, -+ struct ubi_vol_info *info) -+{ -+ int ret; -+ struct libubi *lib = (struct libubi *)desc; -+ char buf[50]; -+ -+ memset(info, '\0', sizeof(struct ubi_vol_info)); -+ info->dev_num = dev_num; -+ info->vol_id = vol_id; -+ -+ ret = vol_read_data(lib->vol_type, dev_num, vol_id, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ if (strncmp(&buf[0], "static\n", ret) == 0) -+ info->type = UBI_STATIC_VOLUME; -+ else if (strncmp(&buf[0], "dynamic\n", ret) == 0) -+ info->type = UBI_DYNAMIC_VOLUME; -+ else { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ ret = vol_read_int(lib->vol_alignment, dev_num, vol_id, -+ &info->alignment); -+ if (ret) -+ return -1; -+ ret = vol_read_ll(lib->vol_data_bytes, dev_num, vol_id, -+ &info->data_bytes); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_rsvd_ebs, dev_num, vol_id, &info->rsvd_ebs); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_eb_size, dev_num, vol_id, &info->eb_size); -+ if (ret) -+ return -1; -+ ret = vol_read_int(lib->vol_corrupted, dev_num, vol_id, -+ &info->corrupted); -+ if (ret) -+ return -1; -+ info->rsvd_bytes = info->eb_size * info->rsvd_ebs; -+ -+ ret = vol_read_data(lib->vol_name, dev_num, vol_id, &info->name, -+ UBI_VOL_NAME_MAX + 2); -+ if (ret < 0) -+ return -1; -+ -+ info->name[ret - 1] = '\0'; -+ return 0; -+} -+ -+/** -+ * read_int - read an 'int' value from a file. -+ * -+ * @file the file to read from -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int read_int(const char *file, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ -+ fd = open(file, O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_int - read an 'int' value from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_int(const char *patt, int dev_num, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_ll - read a 'long long' value from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int dev_read_ll(const char *patt, int dev_num, long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * dev_read_data - read data from an UBI device's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @buf buffer to read data to -+ * @buf_len buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len) -+{ -+ int fd, rd; -+ char file[strlen(patt) + 50]; -+ -+ sprintf(&file[0], patt, dev_num); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return rd; -+} -+ -+/** -+ * vol_read_int - read an 'int' value from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%d\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * vol_read_ll - read a 'long long' value from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @value the result is stored here -+ * -+ * This function returns %0 in case of success and %-1 in case of failure. -+ */ -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value) -+{ -+ int fd, rd; -+ char buf[50]; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, &buf[0], 50); -+ if (rd == -1) -+ goto error; -+ -+ if (sscanf(&buf[0], "%lld\n", value) != 1) { -+ /* This must be a UBI bug */ -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ goto error; -+ } -+ -+ close(fd); -+ return 0; -+ -+error: -+ close(fd); -+ return -1; -+} -+ -+/** -+ * vol_read_data - read data from an UBI volume's sysfs file. -+ * -+ * @patt the file pattern to read from -+ * @dev_num UBI device number -+ * @vol_id volume identifier -+ * @buf buffer to read to -+ * @buf_len buffer length -+ * -+ * This function returns number of read bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len) -+{ -+ int fd, rd; -+ char file[strlen(patt) + 100]; -+ -+ sprintf(&file[0], patt, dev_num, vol_id); -+ fd = open(&file[0], O_RDONLY); -+ if (fd == -1) -+ return -1; -+ -+ rd = read(fd, buf, buf_len); -+ if (rd == -1) { -+ close(fd); -+ return -1; -+ } -+ -+ close(fd); -+ return rd; -+} -+ -+/** -+ * mkpath - compose full path from 2 given components. -+ * -+ * @path first component -+ * @name second component -+ * -+ * This function returns the resulting path in case of success and %NULL in -+ * case of failure. -+ */ -+static char *mkpath(const char *path, const char *name) -+{ -+ char *n; -+ int len1 = strlen(path); -+ int len2 = strlen(name); -+ -+ n = malloc(len1 + len2 + 2); -+ if (!n) -+ return NULL; -+ -+ memcpy(n, path, len1); -+ if (n[len1 - 1] != '/') -+ n[len1++] = '/'; -+ -+ memcpy(n + len1, name, len2 + 1); -+ return n; -+} -+ -+/** -+ * find_dev_num - find UBI device number by its character device node. -+ * -+ * @lib UBI library descriptor -+ * @node UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_dev_num(struct libubi *lib, const char *node) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor != 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (minor1 == minor && major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} -+ -+/** -+ * find_dev_num_vol - find UBI device number by volume character device node. -+ * -+ * @lib UBI library descriptor -+ * @node UBI character device node name -+ * -+ * This function returns positive UBI device number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_dev_num_vol(struct libubi *lib, const char *node) -+{ -+ struct stat stat; -+ struct ubi_info info; -+ int i, major; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ -+ if (minor(stat.st_rdev) == 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_info((libubi_t *)lib, &info)) -+ return -1; -+ -+ for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = dev_read_data(lib->dev_dev, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} -+ -+/** -+ * find_vol_num - find UBI volume number by its character device node. -+ * -+ * @lib UBI library descriptor -+ * @dev_num UBI device number -+ * @node UBI volume character device node name -+ * -+ * This function returns positive UBI volume number in case of success and %-1 -+ * in case of failure. -+ */ -+static int find_vol_num(struct libubi *lib, int dev_num, const char *node) -+{ -+ struct stat stat; -+ struct ubi_dev_info info; -+ int i, major, minor; -+ -+ if (lstat(node, &stat)) -+ return -1; -+ -+ if (!S_ISCHR(stat.st_mode)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ major = major(stat.st_rdev); -+ minor = minor(stat.st_rdev); -+ -+ if (minor == 0) { -+ errno = -EINVAL; -+ return -1; -+ } -+ -+ if (ubi_get_dev_info1((libubi_t *)lib, dev_num, &info)) -+ return -1; -+ -+ for (i = info.lowest_vol_num; i <= info.highest_vol_num; i++) { -+ int major1, minor1, ret; -+ char buf[50]; -+ -+ ret = vol_read_data(lib->vol_dev, dev_num, i, &buf[0], 50); -+ if (ret < 0) -+ return -1; -+ -+ ret = sscanf(&buf[0], "%d:%d\n", &major1, &minor1); -+ if (ret != 2) { -+ fprintf(stderr, "LIBUBI: bad value at sysfs file\n"); -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (minor1 == minor && major1 == major) -+ return i; -+ } -+ -+ errno = ENOENT; -+ return -1; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubi_int.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,129 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Artem B. Bityutskiy -+ * -+ * UBI (Unsorted Block Images) library. -+ */ -+ -+#ifndef __LIBUBI_INT_H__ -+#define __LIBUBI_INT_H__ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * UBI heavily makes use of the sysfs file system to interact with users-pace. -+ * The below are pre-define UBI file and directory names. -+ */ -+ -+#define SYSFS_UBI "class/ubi" -+#define UBI_DEV_NAME_PATT "ubi%d" -+#define UBI_VER "version" -+#define DEV_DEV "dev" -+#define UBI_VOL_NAME_PATT "ubi%d_%d" -+#define DEV_AVAIL_EBS "avail_eraseblocks" -+#define DEV_TOTAL_EBS "total_eraseblocks" -+#define DEV_BAD_COUNT "bad_peb_count" -+#define DEV_EB_SIZE "eraseblock_size" -+#define DEV_MAX_EC "max_ec" -+#define DEV_MAX_RSVD "reserved_for_bad" -+#define DEV_MAX_VOLS "max_vol_count" -+#define DEV_MIN_IO_SIZE "min_io_size" -+#define VOL_TYPE "type" -+#define VOL_DEV "dev" -+#define VOL_ALIGNMENT "alignment" -+#define VOL_DATA_BYTES "data_bytes" -+#define VOL_RSVD_EBS "reserved_ebs" -+#define VOL_EB_SIZE "usable_eb_size" -+#define VOL_CORRUPTED "corrupted" -+#define VOL_NAME "name" -+ -+/** -+ * libubi - UBI library description data structure. -+ * -+ * @sysfs sysfs file system path -+ * @sysfs_ubi UBI directory in sysfs -+ * @ubi_dev UBI device sysfs directory pattern -+ * @ubi_version UBI version file sysfs path -+ * @dev_dev UBI device's major/minor numbers file pattern -+ * @dev_avail_ebs count of available eraseblocks sysfs path pattern -+ * @dev_total_ebs total eraseblocks count sysfs path pattern -+ * @dev_bad_count count of bad eraseblocks sysfs path pattern -+ * @dev_eb_size size of UBI device's eraseblocks sysfs path pattern -+ * @dev_max_ec maximum erase counter sysfs path pattern -+ * @dev_bad_rsvd count of physical eraseblock reserved for bad eraseblocks -+ * handling -+ * @dev_max_vols maximum volumes number count sysfs path pattern -+ * @dev_min_io_size minimum I/O unit size sysfs path pattern -+ * @ubi_vol UBI volume sysfs directory pattern -+ * @vol_type volume type sysfs path pattern -+ * @vol_dev volume's major/minor numbers file pattern -+ * @vol_alignment volume alignment sysfs path pattern -+ * @vol_data_bytes volume data size sysfs path pattern -+ * @vol_rsvd_ebs volume reserved size sysfs path pattern -+ * @vol_eb_size volume eraseblock size sysfs path pattern -+ * @vol_corrupted volume corruption flag sysfs path pattern -+ * @vol_name volume name sysfs path pattern -+ */ -+struct libubi -+{ -+ char *sysfs; -+ char *sysfs_ubi; -+ char *ubi_dev; -+ char *ubi_version; -+ char *dev_dev; -+ char *dev_avail_ebs; -+ char *dev_total_ebs; -+ char *dev_bad_count; -+ char *dev_eb_size; -+ char *dev_max_ec; -+ char *dev_bad_rsvd; -+ char *dev_max_vols; -+ char *dev_min_io_size; -+ char *ubi_vol; -+ char *vol_type; -+ char *vol_dev; -+ char *vol_alignment; -+ char *vol_data_bytes; -+ char *vol_rsvd_ebs; -+ char *vol_eb_size; -+ char *vol_corrupted; -+ char *vol_name; -+ char *vol_max_count; -+}; -+ -+static int read_int(const char *file, int *value); -+static int dev_read_int(const char *patt, int dev_num, int *value); -+static int dev_read_ll(const char *patt, int dev_num, long long *value); -+static int dev_read_data(const char *patt, int dev_num, void *buf, int buf_len); -+static int vol_read_int(const char *patt, int dev_num, int vol_id, int *value); -+static int vol_read_ll(const char *patt, int dev_num, int vol_id, -+ long long *value); -+static int vol_read_data(const char *patt, int dev_num, int vol_id, void *buf, -+ int buf_len); -+static char *mkpath(const char *path, const char *name); -+static int find_dev_num(struct libubi *lib, const char *node); -+static int find_dev_num_vol(struct libubi *lib, const char *node); -+static int find_vol_num(struct libubi *lib, int dev_num, const char *node); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* !__LIBUBI_INT_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,487 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Add UBI headers to binary data. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "ubigen.h" -+#include "crc32.h" -+ -+#define UBI_NAME_SIZE 256 -+#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE)) -+#define MIN(a,b) ((a) < (b) ? (a) : (b)) -+ -+static uint32_t crc32_table[256]; -+ -+struct ubi_info { -+ struct ubi_vid_hdr* v; /* Volume ID header */ -+ struct ubi_ec_hdr* ec; /* Erase count header */ -+ -+ FILE* fp_in; /* Input Stream */ -+ FILE* fp_out; /* Output stream */ -+ -+ size_t eb_size; /* Physical EB size in bytes */ -+ size_t leb_size; /* Size of a logical EB in a physical EB */ -+ size_t leb_total; /* Total input size in logical EB */ -+ size_t alignment; /* Block alignment */ -+ size_t data_pad; /* Size of padding in each physical EB */ -+ -+ size_t bytes_total; /* Total input size in bytes */ -+ size_t bytes_read; /* Nymber of read bytes (total) */ -+ -+ uint32_t blks_written; /* Number of written logical EB */ -+ -+ uint8_t* buf; /* Allocated buffer */ -+ uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */ -+ uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */ -+ uint8_t* ptr_data; /* Pointer to data region in buf */ -+}; -+ -+ -+static uint32_t -+byte_to_blk(uint64_t byte, uint32_t eb_size) -+{ -+ return (byte % eb_size) == 0 -+ ? (byte / eb_size) -+ : (byte / eb_size) + 1; -+} -+ -+static int -+validate_ubi_info(ubi_info_t u) -+{ -+ if ((u->v->vol_type != UBI_VID_DYNAMIC) && -+ (u->v->vol_type != UBI_VID_STATIC)) { -+ return EUBIGEN_INVALID_TYPE; -+ } -+ -+ if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) { -+ return EUBIGEN_INVALID_HDR_OFFSET; -+ } -+ -+ return 0; -+} -+ -+static int -+skip_blks(ubi_info_t u, uint32_t blks) -+{ -+ uint32_t i; -+ size_t read = 0, to_read = 0; -+ -+ /* Step to a maximum of leb_total - 1 to keep the -+ restrictions. */ -+ for (i = 0; i < MIN(blks, u->leb_total-1); i++) { -+ /* Read in data */ -+ to_read = MIN(u->leb_size, -+ (u->bytes_total - u->bytes_read)); -+ read = fread(u->ptr_data, 1, to_read, u->fp_in); -+ if (read != to_read) { -+ return -EIO; -+ } -+ u->bytes_read += read; -+ u->blks_written++; -+ } -+ -+ return 0; -+} -+ -+static void -+clear_buf(ubi_info_t u) -+{ -+ memset(u->buf, 0xff, u->eb_size); -+} -+ -+static void -+write_ec_hdr(ubi_info_t u) -+{ -+ memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE); -+} -+ -+static int -+fill_data_buffer_from_file(ubi_info_t u, size_t* read) -+{ -+ size_t to_read = 0; -+ -+ if (u-> fp_in == NULL) -+ return -EIO; -+ -+ to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read)); -+ *read = fread(u->ptr_data, 1, to_read, u->fp_in); -+ if (*read != to_read) { -+ return -EIO; -+ } -+ return 0; -+} -+ -+static void -+add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action) -+{ -+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ u->ptr_data, data_size); -+ -+ u->v->data_size = cpu_to_be32(data_size); -+ u->v->data_crc = cpu_to_be32(crc); -+ -+ if (action & BROKEN_DATA_CRC) { -+ u->v->data_crc = -+ cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1); -+ } -+ if (action & BROKEN_DATA_SIZE) { -+ u->v->data_size = -+ cpu_to_be32(be32_to_cpu(u->v->data_size) + 1); -+ } -+} -+ -+static void -+write_vid_hdr(ubi_info_t u, ubigen_action_t action) -+{ -+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ u->v, UBI_VID_HDR_SIZE_CRC); -+ /* Write VID header */ -+ u->v->hdr_crc = cpu_to_be32(crc); -+ if (action & BROKEN_HDR_CRC) { -+ u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1); -+ } -+ memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE); -+} -+ -+static int -+write_to_output_stream(ubi_info_t u) -+{ -+ size_t written; -+ -+ written = fwrite(u->buf, 1, u->eb_size, u->fp_out); -+ if (written != u->eb_size) { -+ return -EIO; -+ } -+ return 0; -+} -+ -+int -+ubigen_write_leb(ubi_info_t u, ubigen_action_t action) -+{ -+ int rc = 0; -+ size_t read = 0; -+ -+ clear_buf(u); -+ write_ec_hdr(u); -+ -+ rc = fill_data_buffer_from_file(u, &read); -+ if (rc != 0) -+ return rc; -+ -+ if (u->v->vol_type == UBI_VID_STATIC) { -+ add_static_info(u, read, action); -+ } -+ -+ u->v->lnum = cpu_to_be32(u->blks_written); -+ -+ if (action & MARK_AS_UPDATE) { -+ u->v->copy_flag = (u->v->copy_flag)++; -+ } -+ -+ write_vid_hdr(u, action); -+ rc = write_to_output_stream(u); -+ if (rc != 0) -+ return rc; -+ -+ /* Update current handle */ -+ u->bytes_read += read; -+ u->blks_written++; -+ return 0; -+} -+ -+int -+ubigen_write_complete(ubi_info_t u) -+{ -+ size_t i; -+ int rc = 0; -+ -+ for (i = 0; i < u->leb_total; i++) { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ if (rc != 0) -+ return rc; -+ } -+ -+ return 0; -+} -+ -+int -+ubigen_write_broken_update(ubi_info_t u, uint32_t blk) -+{ -+ int rc = 0; -+ -+ rc = skip_blks(u, blk); -+ if (rc != 0) -+ return rc; -+ -+ rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC); -+ if (rc != 0) -+ return rc; -+ -+ -+ return 0; -+} -+ -+void -+dump_info(ubi_info_t u ubi_unused) -+{ -+#ifdef DEBUG -+ int err = 0; -+ if (!u) { -+ fprintf(stderr, ""); -+ return; -+ } -+ if (!u->ec) { -+ fprintf(stderr, ""); -+ err = 1; -+ } -+ if (!u->v) { -+ fprintf(stderr, ""); -+ err = 1; -+ } -+ if (err) return; -+ -+ fprintf(stderr, "ubi volume\n"); -+ fprintf(stderr, "version : %8d\n", u->v->version); -+ fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id)); -+ fprintf(stderr, "vol_type : %8s\n", -+ u->v->vol_type == UBI_VID_STATIC ? -+ "static" : "dynamic"); -+ fprintf(stderr, "used_ebs : %8d\n", -+ be32_to_cpu(u->v->used_ebs)); -+ fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size); -+ fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size); -+ fprintf(stderr, "data_pad : 0x%08x\n", -+ be32_to_cpu(u->v->data_pad)); -+ fprintf(stderr, "leb_total : %8d\n", u->leb_total); -+ fprintf(stderr, "header offs : 0x%08x\n", -+ be32_to_cpu(u->ec->vid_hdr_offset)); -+ fprintf(stderr, "bytes_total : %8d\n", u->bytes_total); -+ fprintf(stderr, " + in MiB : %8.2f M\n", -+ ((float)(u->bytes_total)) / 1024 / 1024); -+ fprintf(stderr, "-------------------------------\n\n"); -+#else -+ return; -+#endif -+} -+ -+int -+ubigen_destroy(ubi_info_t *u) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ ubi_info_t tmp = *u; -+ -+ if (tmp) { -+ if (tmp->v) -+ free(tmp->v); -+ if (tmp->ec) -+ free(tmp->ec); -+ if (tmp->buf) -+ free(tmp->buf); -+ free(tmp); -+ } -+ *u = NULL; -+ return 0; -+} -+ -+void -+ubigen_init(void) -+{ -+ init_crc32_table(crc32_table); -+} -+ -+int -+ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type, -+ uint32_t eb_size, uint64_t ec, uint32_t alignment, -+ uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag, -+ size_t data_size, FILE* fp_in, FILE* fp_out) -+{ -+ int rc = 0; -+ ubi_info_t res = NULL; -+ uint32_t crc; -+ uint32_t data_offset; -+ -+ if (alignment == 0) { -+ rc = EUBIGEN_INVALID_ALIGNMENT; -+ goto ubigen_create_err; -+ } -+ if ((fp_in == NULL) || (fp_out == NULL)) { -+ rc = -EINVAL; -+ goto ubigen_create_err; -+ } -+ -+ res = (ubi_info_t) calloc(1, sizeof(struct ubi_info)); -+ if (res == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr)); -+ if (res->v == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr)); -+ if (res->ec == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ /* data which is needed in the general process */ -+ vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET; -+ data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE; -+ res->bytes_total = data_size; -+ res->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE; -+ res->data_pad = (res->eb_size - data_offset) % alignment; -+ res->leb_size = res->eb_size - data_offset - res->data_pad; -+ res->leb_total = byte_to_blk(data_size, res->leb_size); -+ res->alignment = alignment; -+ -+ if ((res->eb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) { -+ rc = EUBIGEN_TOO_SMALL_EB; -+ goto ubigen_create_err; -+ } -+ res->fp_in = fp_in; -+ res->fp_out = fp_out; -+ -+ /* vid hdr data which doesn't change */ -+ res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); -+ res->v->version = version ? version : UBI_VERSION; -+ res->v->vol_type = vol_type; -+ res->v->vol_id = cpu_to_be32(vol_id); -+ res->v->compat = compat_flag; -+ res->v->data_pad = cpu_to_be32(res->data_pad); -+ -+ /* static only: used_ebs */ -+ if (res->v->vol_type == UBI_VID_STATIC) { -+ res->v->used_ebs = cpu_to_be32(byte_to_blk -+ (res->bytes_total, -+ res->leb_size)); -+ } -+ -+ /* ec hdr (fixed, doesn't change) */ -+ res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); -+ res->ec->version = version ? version : UBI_VERSION; -+ res->ec->ec = cpu_to_be64(ec); -+ res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset); -+ -+ res->ec->data_offset = cpu_to_be32(data_offset); -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec, -+ UBI_EC_HDR_SIZE_CRC); -+ res->ec->hdr_crc = cpu_to_be32(crc); -+ -+ /* prepare a read buffer */ -+ res->buf = (uint8_t*) malloc (res->eb_size * sizeof(uint8_t)); -+ if (res->buf == NULL) { -+ rc = -ENOMEM; -+ goto ubigen_create_err; -+ } -+ -+ /* point to distinct regions within the buffer */ -+ res->ptr_ec_hdr = res->buf; -+ res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset); -+ res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset) -+ + UBI_VID_HDR_SIZE; -+ -+ rc = validate_ubi_info(res); -+ if (rc != 0) { -+ fprintf(stderr, "Volume validation failed: %d\n", rc); -+ goto ubigen_create_err; -+ } -+ -+ dump_info(res); -+ *u = res; -+ return rc; -+ -+ ubigen_create_err: -+ if (res) { -+ if (res->v) -+ free(res->v); -+ if (res->ec) -+ free(res->ec); -+ if (res->buf) -+ free(res->buf); -+ free(res); -+ } -+ *u = NULL; -+ return rc; -+} -+ -+int -+ubigen_get_leb_size(ubi_info_t u, size_t* size) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ *size = u->leb_size; -+ return 0; -+} -+ -+ -+int -+ubigen_get_leb_total(ubi_info_t u, size_t* total) -+{ -+ if (u == NULL) -+ return -EINVAL; -+ -+ *total = u->leb_total; -+ return 0; -+} -+ -+int -+ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, -+ const char* vol_name, struct ubi_vtbl_record *lvol_rec) -+{ -+ uint32_t crc; -+ -+ if ((u == NULL) || (vol_name == NULL)) -+ return -EINVAL; -+ -+ memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE); -+ -+ lvol_rec->reserved_pebs = -+ cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size)); -+ lvol_rec->alignment = cpu_to_be32(u->alignment); -+ lvol_rec->data_pad = u->v->data_pad; -+ lvol_rec->vol_type = u->v->vol_type; -+ -+ lvol_rec->name_len = -+ cpu_to_be16((uint16_t)strlen((const char*)vol_name)); -+ -+ memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1); -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ lvol_rec, UBI_VTBL_RECORD_SIZE_CRC); -+ lvol_rec->crc = cpu_to_be32(crc); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/libubimirror.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,237 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "ubimirror.h" -+ -+#define COMPARE_BUF_SIZE (128 * 1024) -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+#define EBUF(fmt...) do { \ -+ snprintf(err_buf, err_buf_size, fmt); \ -+} while (0) -+ -+enum { -+ compare_error = -1, -+ seek_error = -2, -+ write_error = -3, -+ read_error = -4, -+ update_error = -5, -+ ubi_error = -6, -+ open_error = -7, -+ close_error = -8, -+ compare_equal = 0, -+ compare_different = 1 -+}; -+ -+/* -+ * Read len number of bytes from fd. -+ * Return 0 on EOF, -1 on error. -+ */ -+static ssize_t fill_buffer(int fd, unsigned char *buf, ssize_t len) -+{ -+ ssize_t got, have = 0; -+ -+ do { -+ got = read(fd, buf + have, len - have); -+ if (got == -1 && errno != EINTR) -+ return -1; -+ have += got; -+ } while (got > 0 && have < len); -+ return have; -+} -+ -+/* -+ * Write len number of bytes to fd. -+ * Return bytes written (>= 0), -1 on error. -+ */ -+static ssize_t flush_buffer(int fd, unsigned char *buf, ssize_t len) -+{ -+ ssize_t done, have = 0; -+ -+ do { -+ done = write(fd, buf + have, len - have); -+ if (done == -1 && errno != EINTR) -+ return -1; -+ have += done; -+ } while (done > 0 && have < len); -+ return have; -+} -+ -+/* -+ * Compare two files. Return 0, 1, or -1, depending on whether the -+ * files are equal, different, or an error occured. -+ * Return compare-different when target volume can not be read. Might be -+ * an interrupted volume update and then the target device returns -EIO but -+ * can be updated. -+ * -+ * fd_a is source -+ * fd_b is destination -+ */ -+static int compare_files(int fd_a, int fd_b) -+{ -+ unsigned char buf_a[COMPARE_BUF_SIZE], buf_b[COMPARE_BUF_SIZE]; -+ ssize_t len_a, len_b; -+ int rc; -+ -+ for (;;) { -+ len_a = fill_buffer(fd_a, buf_a, sizeof(buf_a)); -+ if (len_a == -1) { -+ rc = compare_error; -+ break; -+ } -+ len_b = fill_buffer(fd_b, buf_b, sizeof(buf_b)); -+ if (len_b == -1) { -+ rc = compare_different; -+ break; -+ } -+ if (len_a != len_b) { -+ rc = compare_different; -+ break; -+ } -+ if (len_a == 0) { /* Size on both files equal and EOF */ -+ rc = compare_equal; -+ break; -+ } -+ if (memcmp(buf_a, buf_b, len_a) != 0 ) { -+ rc = compare_different; -+ break; -+ } -+ } -+ /* Position both files at the beginning */ -+ if (lseek(fd_a, 0, SEEK_SET) == -1 || -+ lseek(fd_b, 0, SEEK_SET) == -1) -+ rc = seek_error; -+ return rc; -+} -+ -+int vol_get_used_bytes(int vol_fd, unsigned long long *bytes) -+{ -+ off_t res; -+ -+ res = lseek(vol_fd, 0, SEEK_END); -+ if (res == (off_t)-1) -+ return -1; -+ *bytes = (unsigned long long) res; -+ res = lseek(vol_fd, 0, SEEK_SET); -+ return res == (off_t)-1 ? -1 : 0; -+} -+ -+static int copy_files(libubi_t ulib, int fd_in, int fd_out) -+{ -+ unsigned char buf_a[COMPARE_BUF_SIZE]; -+ ssize_t len_a, len_b; -+ unsigned long long update_size, copied; -+ -+ if (vol_get_used_bytes(fd_in, &update_size) == -1 || -+ ubi_update_start(ulib, fd_out, update_size) == -1) -+ return update_error; -+ for (copied = 0; copied < update_size; copied += len_b ) { -+ len_a = fill_buffer(fd_in, buf_a, sizeof(buf_a)); -+ if (len_a == -1) -+ return read_error; -+ if (len_a == 0) /* Reach EOF */ -+ return 0; -+ len_b = flush_buffer(fd_out, buf_a, len_a); -+ if (len_b != len_a) -+ return write_error; -+ } -+ return 0; -+} -+ -+int ubimirror(uint32_t devno, int seqnum, uint32_t *ids, ssize_t ids_size, -+ char *err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ uint32_t src_id; -+ char path[PATH_MAX]; -+ libubi_t ulib; -+ int fd_in = -1, i = 0, fd_out = -1; -+ -+ if (ids_size == 0) -+ return 0; -+ else { -+ if ((seqnum < 0) || (seqnum > (ids_size - 1))) { -+ EBUF("volume id %d out of range", seqnum); -+ return EUBIMIRROR_NO_SRC; -+ } -+ src_id = ids[seqnum]; -+ } -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) -+ return ubi_error; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, src_id); -+ -+ fd_in = open(path, O_RDONLY); -+ if (fd_in == -1) { -+ EBUF("open error source volume %d", ids[i]); -+ rc = open_error; -+ goto err; -+ } -+ -+ for (i = 0; i < ids_size; i++) { -+ if (ids[i] == src_id) /* skip self-mirror */ -+ continue; -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, ids[i]); -+ -+ fd_out = open(path, O_RDWR); -+ if (fd_out < 0){ -+ EBUF("open error destination volume %d", ids[i]); -+ rc = open_error; -+ goto err; -+ } -+ rc = compare_files(fd_in, fd_out); -+ if (rc < 0) { -+ EBUF("compare error volume %d and %d", src_id, ids[i]); -+ goto err; -+ } else if (rc == compare_different) { -+ rc = copy_files(ulib, fd_in, fd_out); -+ if (rc != 0) { -+ EBUF("mirror error volume %d to %d", src_id, -+ ids[i]); -+ goto err; -+ } -+ } -+ if ((rc = close(fd_out)) == -1) { -+ EBUF("close error volume %d", ids[i]); -+ rc = close_error; -+ goto err; -+ } else -+ fd_out = -1; -+ } -+err: -+ if (fd_out != -1) -+ close(fd_out); -+ if (fd_in != -1) -+ close(fd_in); -+ if (ulib != NULL) -+ libubi_close(ulib); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,149 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+#include -+ -+#include "list.h" -+ -+list_t -+mk_empty(void) -+{ -+ return (list_t) NULL; -+} -+ -+int -+is_empty(list_t l) -+{ -+ return l == NULL; -+} -+ -+info_t -+head(list_t l) -+{ -+ assert(!is_empty(l)); -+ return l->info; -+} -+ -+list_t -+tail(list_t l) -+{ -+ assert(!is_empty(l)); -+ return l->next; -+} -+ -+list_t -+remove_head(list_t l) -+{ -+ list_t res; -+ assert(!is_empty(l)); -+ -+ res = l->next; -+ free(l); -+ return res; -+} -+ -+list_t -+cons(info_t e, list_t l) -+{ -+ list_t res = malloc(sizeof(*l)); -+ if (!res) -+ return NULL; -+ res->info = e; -+ res->next = l; -+ -+ return res; -+} -+ -+list_t -+prepend_elem(info_t e, list_t l) -+{ -+ return cons(e,l); -+} -+ -+list_t -+append_elem(info_t e, list_t l) -+{ -+ if (is_empty(l)) { -+ return cons(e,l); -+ } -+ l->next = append_elem(e, l->next); -+ -+ return l; -+} -+ -+list_t -+insert_sorted(cmp_func_t cmp, info_t e, list_t l) -+{ -+ if (is_empty(l)) -+ return cons(e, l); -+ -+ switch (cmp(e, l->info)) { -+ case -1: -+ case 0: -+ return l; -+ break; -+ case 1: -+ l->next = insert_sorted(cmp, e, l); -+ break; -+ default: -+ break; -+ } -+ -+ /* never reached */ -+ return NULL; -+} -+ -+list_t -+remove_all(free_func_t free_func, list_t l) -+{ -+ if (is_empty(l)) -+ return l; -+ list_t lnext = l->next; -+ -+ if (free_func && l->info) { -+ free_func(&(l->info)); -+ } -+ free(l); -+ -+ return remove_all(free_func, lnext); -+} -+ -+ -+info_t -+is_in(cmp_func_t cmp, info_t e, list_t l) -+{ -+ return -+ (is_empty(l)) -+ ? NULL -+ : (cmp(e, l->info)) == 0 ? l->info : is_in(cmp, e, l->next); -+} -+ -+ -+void -+apply(process_func_t process_func, list_t l) -+{ -+ list_t ptr; -+ void *i; -+ foreach(i, ptr, l) { -+ process_func(i); -+ } -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/list.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/list.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+#ifndef __LIST_H__ -+#define __LIST_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+ -+#define foreach(elem, ptr, list) \ -+ for (elem = list != NULL ? (typeof(elem)) head(list) \ -+ : NULL, ptr = list; \ -+ ptr != NULL; \ -+ ptr = tail(ptr), \ -+ elem = (typeof(elem)) ptr ? head(ptr) : NULL) -+ -+typedef struct node* list_t; -+typedef void* info_t; -+typedef int (*free_func_t)(info_t*); -+typedef int (*cmp_func_t)(info_t, info_t); -+typedef void (*process_func_t)(info_t); -+ -+struct node { -+ list_t next; -+ info_t info; -+}; -+ -+list_t mk_empty(void); -+int is_empty(list_t l); -+info_t is_in(cmp_func_t cmp, info_t e, list_t l); -+info_t head(list_t l); -+list_t tail(list_t l); -+list_t remove_head(list_t l); -+list_t cons(info_t e, list_t l); -+list_t prepend_elem(info_t e, list_t); -+list_t append_elem(info_t e, list_t); -+list_t remove_all(free_func_t free_func, list_t l); -+list_t insert_sorted(cmp_func_t cmp_func, info_t e, list_t l); -+void apply(process_func_t process_func, list_t l); -+ -+#endif /* __LIST_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/mkbootenv.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Create boot-parameter/pdd data from an ASCII-text input file. -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanup -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "bootenv.h" -+#include "error.h" -+ -+#define PROGRAM_VERSION "1.3" -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "mkbootenv - processes bootenv text files and convertes " -+ "them into a binary format.\n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright (c) International Business Machines Corp., 2006"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright informatoin.\n" -+" -o, --output= Write the output data to instead of\n" -+" stdout.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: mkbootenv [-c?V] [-o ] [--copyright] [--output=]\n" -+" [--help] [--usage] [--version] [bootenv-txt-file]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ FILE* fp_in; -+ FILE* fp_out; -+ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "co:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ case 'o': -+ args->fp_out = fopen(optarg, "wb"); -+ if ((args->fp_out) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for output\n", optarg); -+ exit(1); -+ } -+ break; -+ case '?': /* help */ -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s for input\n", -+ argv[optind]); -+ exit(1); -+ } -+ } -+ -+ return 0; -+} -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ bootenv_t env; -+ -+ myargs args = { -+ .fp_in = stdin, -+ .fp_out = stdout, -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ -+ rc = bootenv_create(&env); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle."); -+ goto err; -+ } -+ rc = bootenv_read_txt(args.fp_in, env); -+ if (rc != 0) { -+ err_msg("Cannot read bootenv from input file."); -+ goto err; -+ } -+ rc = bootenv_write(args.fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to output file."); -+ goto err; -+ } -+ -+ if (args.fp_in != stdin) { -+ fclose(args.fp_in); -+ } -+ if (args.fp_out != stdout) { -+ fclose(args.fp_out); -+ } -+ -+err: -+ bootenv_destroy(&env); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nand2bin.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,493 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ * -+ * An utility to decompose NAND images and strip OOB off. Not yet finished ... -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanup -+ * 1.4 Fixed OOB output file -+ * 1.5 Added verbose output and option to set blocksize. -+ * Added split block mode for more convenient analysis. -+ * 1.6 Fixed ECC error detection and correction. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "nandecc.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define MAXPATH 1024 -+#define MIN(x,y) ((x)<(y)?(x):(y)) -+ -+struct args { -+ const char *oob_file; -+ const char *output_file; -+ size_t pagesize; -+ size_t blocksize; -+ int split_blocks; -+ size_t in_len; /* size of input file */ -+ int correct_ecc; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+}; -+ -+static struct args myargs = { -+ .output_file = "data.bin", -+ .oob_file = "oob.bin", -+ .pagesize = 2048, -+ .blocksize = 128 * 1024, -+ .in_len = 0, -+ .split_blocks = 0, -+ .correct_ecc = 0, -+ .arg1 = NULL, -+ .options = NULL, -+}; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "nand2bin - split data and OOB.\n"; -+ -+static const char *optionsstr = -+" -o, --output= Data output file\n" -+" -O, --oob= OOB output file\n" -+" -p, --pagesize= NAND pagesize\n" -+" -b, --blocksize= NAND blocksize\n" -+" -s, --split-blocks generate binaries for each block\n" -+" -e, --correct-ecc Correct data according to ECC info\n" -+" -v, --verbose verbose output\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n"; -+ -+static const char *usage = -+"Usage: nand2bin [-?] [-o ] [-O ] [-p ]\n" -+" [--output=] [--oob=] [--pagesize=] [--help]\n" -+" [--usage] input.mif\n"; -+ -+static int verbose = 0; -+ -+static struct option long_options[] = { -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "oob", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "pagesize", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, -+ { .name = "split-blocks", .has_arg = 0, .flag = NULL, .val = 's' }, -+ { .name = "correct-ecc", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { NULL, 0, NULL, 0} -+}; -+ -+/* -+ * str_to_num - Convert string into number and cope with endings like -+ * k, K, kib, KiB for kilobyte -+ * m, M, mib, MiB for megabyte -+ */ -+static uint32_t str_to_num(char *str) -+{ -+ char *s = str; -+ ulong num = strtoul(s, &s, 0); -+ -+ if (*s != '\0') { -+ if (strcmp(s, "KiB") == 0) -+ num *= 1024; -+ else if (strcmp(s, "MiB") == 0) -+ num *= 1024*1024; -+ else { -+ fprintf(stderr, "WARNING: Wrong number format " -+ "\"%s\", check your paramters!\n", str); -+ } -+ } -+ return num; -+} -+ -+/* -+ * @brief Parse the arguments passed into the test case. -+ * -+ * @param argc The number of arguments -+ * @param argv The argument list -+ * @param args Pointer to program args structure -+ * -+ * @return error -+ * -+ */ -+static int parse_opt(int argc, char **argv, struct args *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "b:eo:O:p:sv?", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'p': /* --pagesize */ -+ args->pagesize = str_to_num(optarg); -+ break; -+ -+ case 'b': /* --blocksize */ -+ args->blocksize = str_to_num(optarg); -+ break; -+ -+ case 'v': /* --verbose */ -+ verbose++; -+ break; -+ -+ case 's': /* --split-blocks */ -+ args->split_blocks = 1; -+ break; -+ -+ case 'e': /* --correct-ecc */ -+ args->correct_ecc = 1; -+ break; -+ -+ case 'o': /* --output= */ -+ args->output_file = optarg; -+ break; -+ -+ case 'O': /* --oob= */ -+ args->oob_file = optarg; -+ break; -+ -+ case '?': /* help */ -+ printf("Usage: nand2bin [OPTION...] input.mif\n"); -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) -+ args->arg1 = argv[optind++]; -+ -+ return 0; -+} -+ -+static int calc_oobsize(size_t pagesize) -+{ -+ switch (pagesize) { -+ case 512: return 16; -+ case 2048: return 64; -+ default: -+ exit(EXIT_FAILURE); -+ } -+ return 0; -+} -+ -+static inline void hexdump(FILE *fp, const uint8_t *buf, ssize_t size) -+{ -+ int k; -+ -+ for (k = 0; k < size; k++) { -+ fprintf(fp, "%02x ", buf[k]); -+ if ((k & 15) == 15) -+ fprintf(fp, "\n"); -+ } -+} -+ -+static int process_page(uint8_t* buf, uint8_t *oobbuf, size_t pagesize) -+{ -+ int eccpoi, oobsize; -+ size_t i; -+ -+ switch (pagesize) { -+ case 2048: oobsize = 64; eccpoi = 64 / 2; break; -+ case 512: oobsize = 16; eccpoi = 16 / 2; break; -+ default: -+ fprintf(stderr, "Unsupported page size: %zd\n", pagesize); -+ return -EINVAL; -+ } -+ memset(oobbuf, 0xff, oobsize); -+ -+ for (i = 0; i < pagesize; i += 256, eccpoi += 3) { -+ oobbuf[eccpoi++] = 0x0; -+ /* Calculate ECC */ -+ nand_calculate_ecc(&buf[i], &oobbuf[eccpoi]); -+ } -+ return 0; -+} -+ -+static int bad_marker_offs_in_oob(int pagesize) -+{ -+ switch (pagesize) { -+ case 2048: return 0; -+ case 512: return 5; -+ } -+ return -EINVAL; -+} -+ -+static int decompose_image(struct args *args, FILE *in_fp, -+ FILE *bin_fp, FILE *oob_fp) -+{ -+ int read, rc, page = 0; -+ size_t oobsize = calc_oobsize(args->pagesize); -+ uint8_t *buf = malloc(args->pagesize); -+ uint8_t *oob = malloc(oobsize); -+ uint8_t *calc_oob = malloc(oobsize); -+ uint8_t *calc_buf = malloc(args->pagesize); -+ uint8_t *page_buf; -+ int pages_per_block = args->blocksize / args->pagesize; -+ int eccpoi = 0, eccpoi_start; -+ unsigned int i; -+ int badpos = bad_marker_offs_in_oob(args->pagesize); -+ -+ switch (args->pagesize) { -+ case 2048: eccpoi_start = 64 / 2; break; -+ case 512: eccpoi_start = 16 / 2; break; -+ default: exit(EXIT_FAILURE); -+ } -+ -+ if (!buf) -+ exit(EXIT_FAILURE); -+ if (!oob) -+ exit(EXIT_FAILURE); -+ if (!calc_oob) -+ exit(EXIT_FAILURE); -+ if (!calc_buf) -+ exit(EXIT_FAILURE); -+ -+ while (!feof(in_fp)) { -+ /* read page by page */ -+ read = fread(buf, 1, args->pagesize, in_fp); -+ if (ferror(in_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ if (read != (ssize_t)args->pagesize) -+ break; -+ -+ read = fread(oob, 1, oobsize, in_fp); -+ if (ferror(in_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ -+ page_buf = buf; /* default is unmodified data */ -+ -+ if ((page == 0 || page == 1) && (oob[badpos] != 0xff)) { -+ if (verbose) -+ printf("Block %d is bad\n", -+ page / pages_per_block); -+ goto write_data; -+ } -+ if (args->correct_ecc) -+ page_buf = calc_buf; -+ -+ process_page(buf, calc_oob, args->pagesize); -+ memcpy(calc_buf, buf, args->pagesize); -+ -+ /* -+ * Our oob format uses only the last 3 bytes out of 4. -+ * The first byte is 0x00 when the ECC is generated by -+ * our toolset and 0xff when generated by Linux. This -+ * is to be fixed when we want nand2bin work for other -+ * ECC layouts too. -+ */ -+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize; -+ i += 256, eccpoi += 4) -+ oob[eccpoi] = calc_oob[eccpoi] = 0xff; -+ -+ if (verbose && memcmp(oob, calc_oob, oobsize) != 0) { -+ printf("\nECC compare mismatch found at block %d page %d!\n", -+ page / pages_per_block, page % pages_per_block); -+ -+ printf("Read out OOB Data:\n"); -+ hexdump(stdout, oob, oobsize); -+ -+ printf("Calculated OOB Data:\n"); -+ hexdump(stdout, calc_oob, oobsize); -+ } -+ -+ /* Do correction on subpage base */ -+ for (i = 0, eccpoi = eccpoi_start; i < args->pagesize; -+ i += 256, eccpoi += 4) { -+ rc = nand_correct_data(calc_buf + i, &oob[eccpoi + 1], -+ &calc_oob[eccpoi + 1]); -+ -+ if (rc == -1) -+ fprintf(stdout, "Uncorrectable ECC error at " -+ "block %d page %d/%d\n", -+ page / pages_per_block, -+ page % pages_per_block, i / 256); -+ else if (rc > 0) -+ fprintf(stdout, "Correctable ECC error at " -+ "block %d page %d/%d\n", -+ page / pages_per_block, -+ page % pages_per_block, i / 256); -+ } -+ -+ write_data: -+ rc = fwrite(page_buf, 1, args->pagesize, bin_fp); -+ if (ferror(bin_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ rc = fwrite(oob, 1, oobsize, oob_fp); -+ if (ferror(bin_fp)) { -+ fprintf(stderr, "I/O Error."); -+ exit(EXIT_FAILURE); -+ } -+ -+ page++; -+ } -+ free(calc_buf); -+ free(calc_oob); -+ free(oob); -+ free(buf); -+ return 0; -+} -+ -+static int split_blocks(struct args *args, FILE *in_fp) -+{ -+ uint8_t *buf; -+ size_t oobsize = calc_oobsize(args->pagesize); -+ int pages_per_block = args->blocksize / args->pagesize; -+ int block_len = pages_per_block * (args->pagesize + oobsize); -+ int blocks = args->in_len / block_len; -+ char bname[256] = { 0, }; -+ int badpos = bad_marker_offs_in_oob(args->pagesize); -+ int bad_blocks = 0, i, bad_block = 0; -+ ssize_t rc; -+ FILE *b; -+ -+ buf = malloc(block_len); -+ if (!buf) { -+ perror("Not enough memory"); -+ exit(EXIT_FAILURE); -+ } -+ -+ for (i = 0; i < blocks; i++) { -+ rc = fread(buf, 1, block_len, in_fp); -+ if (rc != block_len) { -+ fprintf(stderr, "cannot read enough data!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ /* do block analysis */ -+ bad_block = 0; -+ if ((buf[args->pagesize + badpos] != 0xff) || -+ (buf[2 * args->pagesize + oobsize + badpos] != 0xff)) { -+ bad_blocks++; -+ bad_block = 1; -+ } -+ if ((verbose && bad_block) || (verbose > 1)) { -+ printf("-- (block %d oob of page 0 and 1)\n", i); -+ hexdump(stdout, buf + args->pagesize, oobsize); -+ printf("--\n"); -+ hexdump(stdout, buf + 2 * args->pagesize + -+ oobsize, oobsize); -+ } -+ -+ /* write complete block out */ -+ snprintf(bname, sizeof(bname) - 1, "%s.%d", args->arg1, i); -+ b = fopen(bname, "w+"); -+ if (!b) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ rc = fwrite(buf, 1, block_len, b); -+ if (rc != block_len) { -+ fprintf(stderr, "could not write all data!\n"); -+ exit(EXIT_FAILURE); -+ } -+ fclose(b); -+ } -+ -+ free(buf); -+ if (bad_blocks || verbose) -+ fprintf(stderr, "%d blocks, %d bad blocks\n", -+ blocks, bad_blocks); -+ return 0; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ FILE *in, *bin = NULL, *oob = NULL; -+ struct stat file_info; -+ -+ parse_opt(argc, argv, &myargs); -+ -+ if (!myargs.arg1) { -+ fprintf(stderr, "Please specify input file!\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (lstat(myargs.arg1, &file_info) != 0) { -+ perror("Cannot fetch file size from input file.\n"); -+ exit(EXIT_FAILURE); -+ } -+ myargs.in_len = file_info.st_size; -+ -+ in = fopen(myargs.arg1, "r"); -+ if (!in) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (myargs.split_blocks) { -+ split_blocks(&myargs, in); -+ goto out; -+ } -+ -+ bin = fopen(myargs.output_file, "w+"); -+ if (!bin) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ oob = fopen(myargs.oob_file, "w+"); -+ if (!oob) { -+ perror("Cannot open file"); -+ exit(EXIT_FAILURE); -+ } -+ decompose_image(&myargs, in, bin, oob); -+ -+ out: -+ if (in) fclose(in); -+ if (bin) fclose(bin); -+ if (oob) fclose(oob); -+ exit(EXIT_SUCCESS); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandcorr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * ECC algorithm for NAND FLASH. Detects and corrects 1 bit errors in -+ * a 256 bytes of data. -+ * -+ * Reimplement by Thomas Gleixner after staring long enough at the -+ * mess in drivers/mtd/nand/nandecc.c -+ * -+ */ -+ -+#include "nandecc.h" -+ -+static int countbits(uint32_t byte) -+{ -+ int res = 0; -+ -+ for (;byte; byte >>= 1) -+ res += byte & 0x01; -+ return res; -+} -+ -+/** -+ * @dat: data which should be corrected -+ * @read_ecc: ecc information read from flash -+ * @calc_ecc: calculated ecc information from the data -+ * @return: number of corrected bytes -+ * or -1 when no correction is possible -+ */ -+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, -+ const uint8_t *calc_ecc) -+{ -+ uint8_t s0, s1, s2; -+ -+ /* -+ * Do error detection -+ * -+ * Be careful, the index magic is due to a pointer to a -+ * uint32_t. -+ */ -+ s0 = calc_ecc[0] ^ read_ecc[0]; -+ s1 = calc_ecc[1] ^ read_ecc[1]; -+ s2 = calc_ecc[2] ^ read_ecc[2]; -+ -+ if ((s0 | s1 | s2) == 0) -+ return 0; -+ -+ /* Check for a single bit error */ -+ if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && -+ ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && -+ ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { -+ -+ uint32_t byteoffs, bitnum; -+ -+ byteoffs = (s1 << 0) & 0x80; -+ byteoffs |= (s1 << 1) & 0x40; -+ byteoffs |= (s1 << 2) & 0x20; -+ byteoffs |= (s1 << 3) & 0x10; -+ -+ byteoffs |= (s0 >> 4) & 0x08; -+ byteoffs |= (s0 >> 3) & 0x04; -+ byteoffs |= (s0 >> 2) & 0x02; -+ byteoffs |= (s0 >> 1) & 0x01; -+ -+ bitnum = (s2 >> 5) & 0x04; -+ bitnum |= (s2 >> 4) & 0x02; -+ bitnum |= (s2 >> 3) & 0x01; -+ -+ dat[byteoffs] ^= (1 << bitnum); -+ -+ return 1; -+ } -+ -+ if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) -+ return 1; -+ -+ return -1; -+} -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * This file contains an ECC algorithm from Toshiba that detects and -+ * corrects 1 bit errors in a 256 byte block of data. -+ * -+ * drivers/mtd/nand/nand_ecc.c -+ * -+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) -+ * Toshiba America Electronics Components, Inc. -+ * -+ * This file is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 or (at your option) any -+ * later version. -+ * -+ * This file is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -+ * for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this file; if not, write to the Free Software Foundation, Inc., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * As a special exception, if other files instantiate templates or use -+ * macros or inline functions from these files, or you compile these -+ * files and link them with other works to produce a work based on these -+ * files, these files do not by themselves cause the resulting work to be -+ * covered by the GNU General Public License. However the source code for -+ * these files must still be made available in accordance with section (3) -+ * of the GNU General Public License. -+ * -+ * This exception does not invalidate any other reasons why a work based on -+ * this file might be covered by the GNU General Public License. -+ */ -+ -+#include "nandecc.h" -+ -+/* -+ * Pre-calculated 256-way 1 byte column parity -+ */ -+static const uint8_t nand_ecc_precalc_table[] = { -+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, -+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, -+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, -+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, -+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, -+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, -+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, -+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, -+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, -+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, -+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, -+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, -+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, -+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, -+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, -+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, -+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, -+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, -+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, -+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, -+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, -+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, -+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, -+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, -+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, -+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, -+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, -+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, -+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, -+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, -+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, -+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -+}; -+ -+/** -+ * nand_trans_result - [GENERIC] create non-inverted ECC -+ * @reg2: line parity reg 2 -+ * @reg3: line parity reg 3 -+ * @ecc_code: ecc -+ * -+ * Creates non-inverted ECC code from line parity -+ */ -+static void nand_trans_result(uint8_t reg2, uint8_t reg3, -+ uint8_t *ecc_code) -+{ -+ uint8_t a, b, i, tmp1, tmp2; -+ -+ /* Initialize variables */ -+ a = b = 0x80; -+ tmp1 = tmp2 = 0; -+ -+ /* Calculate first ECC byte */ -+ for (i = 0; i < 4; i++) { -+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ -+ tmp1 |= b; -+ b >>= 1; -+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ -+ tmp1 |= b; -+ b >>= 1; -+ a >>= 1; -+ } -+ -+ /* Calculate second ECC byte */ -+ b = 0x80; -+ for (i = 0; i < 4; i++) { -+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ -+ tmp2 |= b; -+ b >>= 1; -+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ -+ tmp2 |= b; -+ b >>= 1; -+ a >>= 1; -+ } -+ -+ /* Store two of the ECC bytes */ -+ ecc_code[1] = tmp1; -+ ecc_code[0] = tmp2; -+} -+ -+/** -+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for -+ * 256 byte block -+ * -+ * @dat: raw data -+ * @ecc_code: buffer for ECC -+ */ -+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code) -+{ -+ uint8_t idx, reg1, reg2, reg3; -+ int j; -+ -+ /* Initialize variables */ -+ reg1 = reg2 = reg3 = 0; -+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; -+ -+ /* Build up column parity */ -+ for(j = 0; j < 256; j++) { -+ -+ /* Get CP0 - CP5 from table */ -+ idx = nand_ecc_precalc_table[dat[j]]; -+ reg1 ^= (idx & 0x3f); -+ -+ /* All bit XOR = 1 ? */ -+ if (idx & 0x40) { -+ reg3 ^= (uint8_t) j; -+ reg2 ^= ~((uint8_t) j); -+ } -+ } -+ -+ /* Create non-inverted ECC code from line parity */ -+ nand_trans_result(reg2, reg3, ecc_code); -+ -+ /* Calculate final ECC code */ -+ ecc_code[0] = ~ecc_code[0]; -+ ecc_code[1] = ~ecc_code[1]; -+ ecc_code[2] = ((~reg1) << 2) | 0x03; -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/nandecc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,29 @@ -+#ifndef _NAND_ECC_H -+#define _NAND_ECC_H -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * NAND ecc functions -+ */ -+ -+#include -+ -+int nand_calculate_ecc(const uint8_t *dat, uint8_t *ecc_code); -+int nand_correct_data(uint8_t *dat, const uint8_t *read_ecc, -+ const uint8_t *calc_ecc); -+ -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pddcustomize.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,516 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2008 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * PDD (platform description data) contains a set of system specific -+ * boot-parameters. Some of those parameters need to be handled -+ * special on updates, e.g. the MAC addresses. They must also be kept -+ * if the system is updated and one must be able to modify them when -+ * the system has booted the first time. This tool is intended to do -+ * PDD modification. -+ * -+ * 1.3 Removed argp because we want to use uClibc. -+ * 1.4 Minor cleanups -+ * 1.5 Migrated to new libubi -+ * 1.6 Fixed broken volume update -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "bootenv.h" -+#include "error.h" -+#include "example_ubi.h" -+#include "libubi.h" -+#include "ubimirror.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+#define DEFAULT_DEV_PATTERN "/dev/ubi%d" -+#define DEFAULT_VOL_PATTERN "/dev/ubi%d_%d" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0, -+ ACT_LIST, -+ ACT_ARGP_ABORT, -+ ACT_ARGP_ERR, -+} action_t; -+ -+#define ABORT_ARGP do { \ -+ args->action = ACT_ARGP_ABORT; \ -+} while (0) -+ -+#define ERR_ARGP do { \ -+ args->action = ACT_ARGP_ERR; \ -+} while (0) -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pddcustomize - customize bootenv and pdd values.\n"; -+ -+static const char *optionsstr = -+" -b, --both Mirror updated PDD to redundand copy.\n" -+" -c, --copyright Print copyright information.\n" -+" -i, --input= Binary input file. For debug purposes.\n" -+" -l, --list List card bootenv/pdd values.\n" -+" -o, --output= Binary output file. For debug purposes.\n" -+" -s, --side= The side/seqnum to update.\n" -+" -x, --host use x86 platform for debugging.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pddcustomize [-bclx?V] [-i ] [-o ] [-s ]\n" -+" [--both] [--copyright] [--input=] [--list]\n" -+" [--output=] [--side=] [--host] [--help] [--usage]\n" -+" [--version] [key=value] [...]\n"; -+ -+struct option long_options[] = { -+ { .name = "both", .has_arg = 0, .flag = NULL, .val = 'b' }, -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "input", .has_arg = 1, .flag = NULL, .val = 'i' }, -+ { .name = "list", .has_arg = 0, .flag = NULL, .val = 'l' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "host", .has_arg = 0, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+typedef struct myargs { -+ action_t action; -+ const char* file_in; -+ const char* file_out; -+ int both; -+ int side; -+ int x86; /* X86 host, use files for testing */ -+ bootenv_t env_in; -+ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+get_update_side(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ -+ return i; -+} -+ -+static int -+extract_pair(bootenv_t env, const char* str) -+{ -+ int rc = 0; -+ char* key; -+ char* val; -+ -+ key = strdup(str); -+ if (key == NULL) -+ return -ENOMEM; -+ -+ val = strstr(key, "="); -+ if (val == NULL) { -+ err_msg("Wrong argument: %s\n" -+ "Expecting key=value pair.\n", str); -+ rc = -1; -+ goto err; -+ } -+ -+ *val = '\0'; /* split strings */ -+ val++; -+ rc = bootenv_set(env, key, val); -+ -+err: -+ free(key); -+ return rc; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ int rc = 0; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "clbxs:i:o:?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ err_msg("%s\n", copyright); -+ ABORT_ARGP; -+ break; -+ case 'l': -+ args->action = ACT_LIST; -+ break; -+ case 'b': -+ args->both = 1; -+ break; -+ case 'x': -+ args->x86 = 1; -+ break; -+ case 's': -+ args->side = get_update_side(optarg); -+ if (args->side < 0) { -+ err_msg("Unsupported seqnum: %d.\n" -+ "Supported seqnums are " -+ "'0' and '1'\n", -+ args->side, optarg); -+ ERR_ARGP; -+ } -+ break; -+ case 'i': -+ args->file_in = optarg; -+ break; -+ case 'o': -+ args->file_out = optarg; -+ break; -+ case '?': /* help */ -+ err_msg("Usage: pddcustomize [OPTION...] " -+ "[key=value] [...]"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ rc = extract_pair(args->env_in, argv[optind++]); -+ if (rc != 0) -+ ERR_ARGP; -+ } -+ -+ return 0; -+} -+ -+static int -+list_bootenv(bootenv_t env) -+{ -+ int rc = 0; -+ rc = bootenv_write_txt(stdout, env); -+ if (rc != 0) { -+ err_msg("Cannot list bootenv/pdd. rc: %d\n", rc); -+ goto err; -+ } -+err: -+ return rc; -+} -+ -+static int -+process_key_value(bootenv_t env_in, bootenv_t env) -+{ -+ int rc = 0; -+ size_t size, i; -+ const char* tmp; -+ const char** key_vec = NULL; -+ -+ rc = bootenv_get_key_vector(env_in, &size, 0, &key_vec); -+ if (rc != 0) -+ goto err; -+ -+ for (i = 0; i < size; i++) { -+ rc = bootenv_get(env_in, key_vec[i], &tmp); -+ if (rc != 0) { -+ err_msg("Cannot read value to input key: %s. rc: %d\n", -+ key_vec[i], rc); -+ goto err; -+ } -+ rc = bootenv_set(env, key_vec[i], tmp); -+ if (rc != 0) { -+ err_msg("Cannot set value key: %s. rc: %d\n", -+ key_vec[i], rc); -+ goto err; -+ } -+ } -+ -+err: -+ if (key_vec != NULL) -+ free(key_vec); -+ return rc; -+} -+ -+static int -+read_bootenv(const char* file, bootenv_t env) -+{ -+ int rc = 0; -+ FILE* fp_in = NULL; -+ -+ fp_in = fopen(file, "rb"); -+ if (fp_in == NULL) { -+ err_msg("Cannot open file: %s\n", file); -+ return -EIO; -+ } -+ -+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ err_msg("Cannot read bootenv from file %s. rc: %d\n", -+ file, rc); -+ goto err; -+ } -+ -+err: -+ fclose(fp_in); -+ return rc; -+} -+ -+/* -+ * Read bootenv from ubi volume -+ */ -+static int -+ubi_read_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -+{ -+ libubi_t ulib; -+ int rc = 0; -+ char path[PATH_MAX]; -+ FILE* fp_in = NULL; -+ -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ err_msg("Cannot allocate ubi structure\n"); -+ return -1; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_in = fopen(path, "r"); -+ if (fp_in == NULL) { -+ err_msg("Cannot open volume:%d number:%d\n", devno, id); -+ goto err; -+ } -+ -+ rc = bootenv_read(fp_in, env, BOOTENV_MAXSIZE); -+ if (rc != 0) { -+ err_msg("Cannot read volume:%d number:%d\n", devno, id); -+ goto err; -+ } -+ -+err: -+ if (fp_in) -+ fclose(fp_in); -+ libubi_close(ulib); -+ return rc; -+} -+ -+static int -+write_bootenv(const char* file, bootenv_t env) -+{ -+ int rc = 0; -+ FILE* fp_out; -+ -+ fp_out = fopen(file, "wb"); -+ if (fp_out == NULL) { -+ err_msg("Cannot open file: %s\n", file); -+ return -EIO; -+ } -+ -+ rc = bootenv_write(fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to file %s. rc: %d\n", file, rc); -+ goto err; -+ } -+ -+err: -+ fclose(fp_out); -+ return rc; -+} -+ -+/* -+ * Read bootenv from ubi volume -+ */ -+static int -+ubi_write_bootenv(uint32_t devno, uint32_t id, bootenv_t env) -+{ -+ libubi_t ulib; -+ int rc = 0; -+ char path[PATH_MAX]; -+ FILE* fp_out = NULL; -+ size_t nbytes; -+ -+ rc = bootenv_size(env, &nbytes); -+ if (rc) { -+ err_msg("Cannot determine size of bootenv structure\n"); -+ return rc; -+ } -+ ulib = libubi_open(); -+ if (ulib == NULL) { -+ err_msg("Cannot allocate ubi structure\n"); -+ return rc; -+ } -+ -+ snprintf(path, PATH_MAX, DEFAULT_VOL_PATTERN, devno, id); -+ -+ fp_out = fopen(path, "r+"); -+ if (fp_out == NULL) { -+ err_msg("Cannot fopen volume:%d number:%d\n", devno, id); -+ rc = -EBADF; -+ goto err; -+ } -+ -+ rc = ubi_update_start(ulib, fileno(fp_out), nbytes); -+ if (rc != 0) { -+ err_msg("Cannot start update for %s\n", path); -+ goto err; -+ } -+ -+ rc = bootenv_write(fp_out, env); -+ if (rc != 0) { -+ err_msg("Cannot write bootenv to volume %d number:%d\n", -+ devno, id); -+ goto err; -+ } -+err: -+ if( fp_out ) -+ fclose(fp_out); -+ libubi_close(ulib); -+ return rc; -+} -+ -+static int -+do_mirror(int volno) -+{ -+ char errbuf[1024]; -+ uint32_t ids[2]; -+ int rc; -+ int src_volno_idx = 0; -+ -+ ids[0] = EXAMPLE_BOOTENV_VOL_ID_1; -+ ids[1] = EXAMPLE_BOOTENV_VOL_ID_2; -+ -+ if (volno == EXAMPLE_BOOTENV_VOL_ID_2) -+ src_volno_idx = 1; -+ -+ rc = ubimirror(EXAMPLE_UBI_DEVICE, src_volno_idx, ids, 2, errbuf, -+ sizeof errbuf); -+ if( rc ) -+ err_msg(errbuf); -+ return rc; -+} -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ bootenv_t env = NULL; -+ uint32_t boot_volno; -+ myargs args = { -+ .action = ACT_NORMAL, -+ .file_in = NULL, -+ .file_out = NULL, -+ .side = -1, -+ .x86 = 0, -+ .both = 0, -+ .env_in = NULL, -+ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ rc = bootenv_create(&env); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle. rc: %d", rc); -+ goto err; -+ } -+ -+ rc = bootenv_create(&(args.env_in)); -+ if (rc != 0) { -+ err_msg("Cannot create bootenv handle. rc: %d", rc); -+ goto err; -+ } -+ -+ parse_opt(argc, argv, &args); -+ if (args.action == ACT_ARGP_ERR) { -+ rc = -1; -+ goto err; -+ } -+ if (args.action == ACT_ARGP_ABORT) { -+ rc = 0; -+ goto out; -+ } -+ -+ if ((args.side == 0) || (args.side == -1)) -+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_1; -+ else -+ boot_volno = EXAMPLE_BOOTENV_VOL_ID_2; -+ -+ if( args.x86 ) -+ rc = read_bootenv(args.file_in, env); -+ else -+ rc = ubi_read_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if (args.action == ACT_LIST) { -+ rc = list_bootenv(env); -+ if (rc != 0) { -+ goto err; -+ } -+ goto out; -+ } -+ -+ rc = process_key_value(args.env_in, env); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if( args.x86 ) -+ rc = write_bootenv(args.file_in, env); -+ else -+ rc = ubi_write_bootenv(EXAMPLE_UBI_DEVICE, boot_volno, env); -+ if (rc != 0) -+ goto err; -+ -+ if( args.both ) /* No side specified, update both */ -+ rc = do_mirror(boot_volno); -+ -+ out: -+ err: -+ bootenv_destroy(&env); -+ bootenv_destroy(&(args.env_in)); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,116 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "peb.h" -+ -+int -+peb_cmp(peb_t eb_1, peb_t eb_2) -+{ -+ assert(eb_1); -+ assert(eb_2); -+ -+ return eb_1->num == eb_2->num ? 0 -+ : eb_1->num > eb_2->num ? 1 : -1; -+} -+ -+int -+peb_new(uint32_t eb_num, uint32_t eb_size, peb_t *peb) -+{ -+ int rc = 0; -+ -+ peb_t res = (peb_t) malloc(sizeof(struct peb)); -+ if (!res) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ -+ res->num = eb_num; -+ res->size = eb_size; -+ res->data = (uint8_t*) malloc(res->size * sizeof(uint8_t)); -+ if (!res->data) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(res->data, 0xff, res->size); -+ -+ *peb = res; -+ return 0; -+err: -+ if (res) { -+ if (res->data) -+ free(res->data); -+ free(res); -+ } -+ *peb = NULL; -+ return rc; -+} -+ -+int -+peb_fill(peb_t peb, uint8_t* buf, size_t buf_size) -+{ -+ if (!peb) -+ return -EINVAL; -+ -+ if (buf_size > peb->size) -+ return -EINVAL; -+ -+ memcpy(peb->data, buf, buf_size); -+ return 0; -+} -+ -+int -+peb_write(FILE* fp_out, peb_t peb) -+{ -+ size_t written = 0; -+ -+ if (peb == NULL) -+ return -EINVAL; -+ -+ written = fwrite(peb->data, 1, peb->size, fp_out); -+ -+ if (written != peb->size) -+ return -EIO; -+ -+ return 0; -+} -+ -+int -+peb_free(peb_t* peb) -+{ -+ peb_t tmp = *peb; -+ if (tmp) { -+ if (tmp->data) -+ free(tmp->data); -+ free(tmp); -+ } -+ *peb = NULL; -+ -+ return 0; -+} -+ -+void peb_dump(FILE* fp_out, peb_t peb) -+{ -+ fprintf(fp_out, "num: %08d\tsize: 0x%08x\n", peb->num, peb->size); -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/peb.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/peb.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,41 @@ -+#ifndef __RAW_BLOCK_H__ -+#define __RAW_BLOCK_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ */ -+ -+#include -+#include -+ -+typedef struct peb *peb_t; -+struct peb { -+ uint32_t num; /* Physical eraseblock number -+ * in the RAW file. */ -+ uint32_t size; /* Data Size (equals physical -+ * erase block size) */ -+ uint8_t* data; /* Data buffer */ -+}; -+ -+int peb_new(uint32_t peb_num, uint32_t peb_size, peb_t* peb); -+int peb_free(peb_t* peb); -+int peb_cmp(peb_t peb_1, peb_t peb_2); -+int peb_write(FILE* fp_out, peb_t peb); -+void peb_dump(FILE* fp_out, peb_t peb); -+ -+#endif /* __RAW_BLOCK_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,458 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * @file pfi.c -+ * -+ * @author Oliver Lohmann -+ * Andreas Arnez -+ * Joern Engel -+ * Frank Haverkamp -+ * -+ * @brief libpfi holds all code to create and process pfi files. -+ * -+ * Wed Feb 8 11:38:22 CET 2006: Initial creation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "pfi.h" -+ -+#define PFI_MAGIC "PFI!\n" -+#define PFI_DATA "DATA\n" /* The same size as PFI_MAGIC */ -+#define PFI_MAGIC_LEN 5 -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright (c) International Business Machines Corp., 2006"; -+ -+enum key_id { -+ /* version 1 */ -+ key_version, /* must be index position 0! */ -+ key_mode, -+ key_size, -+ key_crc, -+ key_label, -+ key_flags, -+ key_ubi_ids, -+ key_ubi_size, -+ key_ubi_type, -+ key_ubi_names, -+ key_ubi_alignment, -+ key_raw_starts, -+ key_raw_total_size, -+ num_keys, -+}; -+ -+struct pfi_header { -+ char defined[num_keys]; /* reserve all possible keys even if -+ version does not require this. */ -+ int mode_no; /* current mode no. -> can only increase */ -+ union { -+ char *str; -+ uint32_t num; -+ } value[num_keys]; -+}; -+ -+ -+#define PFI_MANDATORY 0x0001 -+#define PFI_STRING 0x0002 -+#define PFI_LISTVALUE 0x0004 /* comma seperated list of nums */ -+#define PFI_MANDATORY_UBI 0x0008 -+#define PFI_MANDATORY_RAW 0x0010 -+ -+struct key_descriptor { -+ enum key_id id; -+ const char *name; -+ uint32_t flags; -+}; -+ -+static const struct key_descriptor key_desc_v1[] = { -+ { key_version, "version", PFI_MANDATORY }, -+ { key_mode, "mode", PFI_MANDATORY | PFI_STRING }, -+ { key_size, "size", PFI_MANDATORY }, -+ { key_crc, "crc", PFI_MANDATORY }, -+ { key_label, "label", PFI_MANDATORY | PFI_STRING }, -+ { key_flags, "flags", PFI_MANDATORY }, -+ { key_ubi_ids, "ubi_ids", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_size, "ubi_size", PFI_MANDATORY_UBI }, -+ { key_ubi_type, "ubi_type", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_names, "ubi_names", PFI_MANDATORY_UBI | PFI_STRING }, -+ { key_ubi_alignment, "ubi_alignment", PFI_MANDATORY_UBI }, -+ { key_raw_starts, "raw_starts", PFI_MANDATORY_RAW | PFI_STRING }, -+ { key_raw_total_size, "raw_total_size", PFI_MANDATORY_RAW }, -+}; -+ -+static const struct key_descriptor *key_descriptors[] = { -+ NULL, -+ key_desc_v1, /* version 1 */ -+}; -+ -+static const int key_descriptors_max[] = { -+ 0, /* version 0 */ -+ sizeof(key_desc_v1)/sizeof(struct key_descriptor), /* version 1 */ -+}; -+ -+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -+ -+static const char* modes[] = {"raw", "ubi"}; /* order isn't arbitrary! */ -+ -+/* latest version contains all possible keys */ -+static const struct key_descriptor *key_desc = key_desc_v1; -+ -+#define PFI_IS_UBI(mode) \ -+ (((mode) != NULL) && (strcmp("ubi", (mode)) == 0)) -+ -+#define PFI_IS_RAW(mode) \ -+ (((mode) != NULL) && (strcmp("raw", (mode)) == 0)) -+ -+/** -+ * @return <0 On Error. -+ * >=0 Mode no. -+ */ -+static int -+get_mode_no(const char* mode) -+{ -+ int i; -+ -+ for (i = 0; i < (int)ARRAY_SIZE(modes); i++) -+ if (strcmp(mode, modes[i]) == 0) -+ return i; -+ return -1; -+} -+ -+static int -+find_key_by_name (const char *name) -+{ -+ int i; -+ -+ for (i = 0; i < num_keys; i++) { -+ if (strcmp(name, key_desc[i].name) == 0) -+ return i; -+ } -+ return -1; -+} -+ -+static int -+check_valid (pfi_header head) -+{ -+ int i; -+ int max_keys; -+ uint32_t version; -+ const char *mode; -+ const struct key_descriptor *desc; -+ uint32_t to_check = PFI_MANDATORY; -+ -+ /* -+ * For the validity check the list of possible keys depends on -+ * the version of the PFI file used. -+ */ -+ version = head->value[key_version].num; -+ if (version > PFI_HDRVERSION) -+ return PFI_ENOHEADER; -+ -+ max_keys = key_descriptors_max[version]; -+ desc = key_descriptors[version]; -+ -+ if (!desc) -+ return PFI_ENOVERSION; -+ -+ mode = head->value[key_mode].str; -+ if (PFI_IS_UBI(mode)) { -+ to_check |= PFI_MANDATORY_UBI; -+ } -+ else if (PFI_IS_RAW(mode)) { -+ to_check |= PFI_MANDATORY_RAW; -+ } -+ else { /* neither UBI nor RAW == ERR */ -+ return PFI_EINSUFF; -+ } -+ -+ for (i = 0; i < max_keys; i++) { -+ if ((desc[i].flags & to_check) && !head->defined[i]) { -+ fprintf(stderr, "libpfi: %s missing\n", desc[i].name); -+ return PFI_EINSUFF; -+ } -+ } -+ -+ return 0; -+} -+ -+int pfi_header_init (pfi_header *head) -+{ -+ int i; -+ pfi_header self = (pfi_header) malloc(sizeof(*self)); -+ -+ *head = self; -+ if (self == NULL) -+ return PFI_ENOMEM; -+ -+ /* initialize maximum number of possible keys */ -+ for (i = 0; i < num_keys; i++) { -+ memset(self, 0, sizeof(*self)); -+ self->defined[i] = 0; -+ } -+ -+ return 0; -+} -+ -+int pfi_header_destroy (pfi_header *head) -+{ -+ int i; -+ pfi_header self = *head; -+ -+ for (i = 0; i < num_keys; i++) { -+ if (self->defined[i] && (key_desc[i].flags & PFI_STRING) && -+ self->value[i].str) { -+ free(self->value[i].str); -+ } -+ } -+ free(*head); -+ *head = NULL; -+ return 0; -+} -+ -+int pfi_header_setnumber (pfi_header head, -+ const char *key, uint32_t value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) -+ return PFI_EBADTYPE; -+ -+ head->value[key_id].num = value; -+ head->defined[key_id] = 1; -+ return 0; -+} -+ -+int pfi_header_setvalue (pfi_header head, -+ const char *key, const char *value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (value == NULL) -+ return PFI_EINSUFF; -+ -+ if ((key_id < 0) || (key_id >= num_keys)) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) { -+ /* -+ * The value is a string. Copy to a newly allocated -+ * buffer. Delete the old value, if already set. -+ */ -+ size_t len = strlen(value) + 1; -+ char *old_str = NULL; -+ char *str; -+ -+ old_str = head->value[key_id].str; -+ if (old_str != NULL) -+ free(old_str); -+ -+ str = head->value[key_id].str = (char *) malloc(len); -+ if (str == NULL) -+ return PFI_ENOMEM; -+ -+ strcpy(str, value); -+ } else { -+ int len; -+ int ret; -+ /* FIXME: here we assume that the value is always -+ given in hex and starts with '0x'. */ -+ ret = sscanf(value, "0x%x%n", &head->value[key_id].num, &len); -+ if (ret < 1 || value[len] != '\0') -+ return PFI_EBADTYPE; -+ } -+ head->defined[key_id] = 1; -+ return 0; -+} -+ -+int pfi_header_getnumber (pfi_header head, -+ const char *key, uint32_t *value) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (key_desc[key_id].flags & PFI_STRING) -+ return PFI_EBADTYPE; -+ -+ if (!head->defined[key_id]) -+ return PFI_EUNDEF; -+ -+ *value = head->value[key_id].num; -+ return 0; -+} -+ -+int pfi_header_getstring (pfi_header head, -+ const char *key, char *value, size_t size) -+{ -+ int key_id = find_key_by_name(key); -+ -+ if (key_id < 0) -+ return PFI_EUNDEF; -+ -+ if (!(key_desc[key_id].flags & PFI_STRING)) -+ return PFI_EBADTYPE; -+ -+ if (!head->defined[key_id]) -+ return PFI_EUNDEF; -+ -+ strncpy(value, head->value[key_id].str, size-1); -+ value[size-1] = '\0'; -+ return 0; -+} -+ -+int pfi_header_write (FILE *out, pfi_header head) -+{ -+ int i; -+ int ret; -+ -+ pfi_header_setnumber(head, "version", PFI_HDRVERSION); -+ -+ if ((ret = check_valid(head)) != 0) -+ return ret; -+ -+ /* OK. Now write the header. */ -+ -+ ret = fwrite(PFI_MAGIC, 1, PFI_MAGIC_LEN, out); -+ if (ret < PFI_MAGIC_LEN) -+ return ret; -+ -+ -+ for (i = 0; i < num_keys; i++) { -+ if (!head->defined[i]) -+ continue; -+ -+ ret = fprintf(out, "%s=", key_desc[i].name); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ if (key_desc[i].flags & PFI_STRING) { -+ ret = fprintf(out, "%s", head->value[i].str); -+ if (ret < 0) -+ return PFI_EFILE; -+ } else { -+ ret = fprintf(out, "0x%8x", head->value[i].num); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ } -+ ret = fprintf(out, "\n"); -+ if (ret < 0) -+ return PFI_EFILE; -+ } -+ ret = fprintf(out, "\n"); -+ if (ret < 0) -+ return PFI_EFILE; -+ -+ ret = fflush(out); -+ if (ret != 0) -+ return PFI_EFILE; -+ -+ return 0; -+} -+ -+int pfi_header_read (FILE *in, pfi_header head) -+{ -+ char magic[PFI_MAGIC_LEN]; -+ char mode[PFI_KEYWORD_LEN]; -+ char buf[256]; -+ -+ if (PFI_MAGIC_LEN != fread(magic, 1, PFI_MAGIC_LEN, in)) -+ return PFI_EFILE; -+ if (memcmp(magic, PFI_MAGIC, PFI_MAGIC_LEN) != 0) { -+ if (memcmp(magic, PFI_DATA, PFI_MAGIC_LEN) == 0) { -+ return PFI_DATA_START; -+ } -+ return PFI_ENOHEADER; -+ } -+ -+ while (fgets(buf, sizeof(buf), in) != NULL && buf[0] != '\n') { -+ char *value; -+ char *end; -+ value = strchr(buf, '='); -+ if (value == NULL) -+ return PFI_ENOHEADER; -+ -+ *value = '\0'; -+ value++; -+ end = strchr(value, '\n'); -+ if (end) -+ *end = '\0'; -+ -+ if (pfi_header_setvalue(head, buf, value)) -+ return PFI_ENOHEADER; -+ } -+ -+ if (check_valid(head) != 0) -+ return PFI_ENOHEADER; -+ -+ /* set current mode no. in head */ -+ pfi_header_getstring(head, "mode", mode, PFI_KEYWORD_LEN); -+ if (head->mode_no > get_mode_no(mode)) { -+ return PFI_EMODE; -+ } -+ head->mode_no = get_mode_no(mode); -+ return 0; -+} -+ -+int pfi_header_dump (FILE *out, pfi_header head __attribute__((__unused__))) -+{ -+ fprintf(out, "Sorry not implemented yet. Write mail to " -+ "Andreas Arnez and complain!\n"); -+ return 0; -+} -+ -+int pfi_read (FILE *in, pfi_read_func func, void *priv_data) -+{ -+ int rc; -+ pfi_header header; -+ -+ rc = pfi_header_init (&header); -+ if (0 != rc) -+ return rc; -+ if (!func) -+ return PFI_EINVAL; -+ -+ while ((0 == rc) && !feof(in)) { -+ /* -+ * Read header and check consistency of the fields. -+ */ -+ rc = pfi_header_read( in, header ); -+ if (0 != rc) -+ break; -+ if (func) { -+ rc = func(in, header, priv_data); -+ if (rc != 0) -+ break; -+ } -+ } -+ -+ pfi_header_destroy(&header); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,244 @@ -+#ifndef __pfi_h -+#define __pfi_h -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * @file pfi.h -+ * -+ * @author Oliver Lohmann -+ * Andreas Arnez -+ * Joern Engel -+ * Frank Haverkamp -+ * -+ * @brief libpfi will hold all code to create and process pfi -+ * images. Definitions made in this file are equaly usable for the -+ * development host and the target system. -+ * -+ * @note This header additionally holds the official definitions for -+ * the pfi headers. -+ */ -+ -+#include /* FILE */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Definitions. */ -+ -+#define PFI_HDRVERSION 1 /* current header version */ -+ -+#define PFI_ENOVERSION 1 /* unknown version */ -+#define PFI_ENOHEADER 2 /* not a pfi header */ -+#define PFI_EINSUFF 3 /* insufficient information */ -+#define PFI_EUNDEF 4 /* key not defined */ -+#define PFI_ENOMEM 5 /* out of memory */ -+#define PFI_EBADTYPE 6 /* bad data type */ -+#define PFI_EFILE 7 /* file I/O error: see errno */ -+#define PFI_EFILEINVAL 8 /* file format not valid */ -+#define PFI_EINVAL 9 /* invalid parameter */ -+#define PFI_ERANGE 10 /* invalid range */ -+#define PFI_EMODE 11 /* expecting other mode in this header */ -+#define PFI_DATA_START 12 /* data section starts */ -+#define PFI_EMAX 13 /* should be always larger as the largest -+ error code */ -+ -+#define PFI_LABEL_LEN 64 /* This is the maximum length for a -+ PFI header label */ -+#define PFI_KEYWORD_LEN 32 /* This is the maximum length for an -+ entry in the mode and type fields */ -+ -+#define PFI_UBI_MAX_VOLUMES 128 -+#define PFI_UBI_VOL_NAME_LEN 127 -+ -+/** -+ * @brief The pfi header allows to set flags which influence the flashing -+ * behaviour. -+ */ -+#define PFI_FLAG_PROTECTED 0x00000001 -+ -+ -+/** -+ * @brief Handle to pfi header. Used in most of the functions associated -+ * with pfi file handling. -+ */ -+typedef struct pfi_header *pfi_header; -+ -+ -+/** -+ * @brief Initialize a pfi header object. -+ * -+ * @param head Pointer to handle. This function allocates memory -+ * for this data structure. -+ * @return 0 on success, otherwise: -+ * PFI_ENOMEM : no memory available for the handle. -+ */ -+int pfi_header_init (pfi_header *head); -+ -+ -+/** -+ * @brief Destroy a pfi header object. -+ * -+ * @param head handle. head is invalid after calling this function. -+ * @return 0 always. -+ */ -+int pfi_header_destroy (pfi_header *head); -+ -+ -+/** -+ * @brief Add a key/value pair to a pfi header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value string. Must be 0 terminated. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_ENOMEM : no memory available for the handle. -+ * PFI_EBADTYPE : value is not an hex string. This happens -+ * when the key stores an integer and the -+ * new value is not convertable e.g. not in -+ * 0xXXXXXXXX format. -+ */ -+int pfi_header_setvalue (pfi_header head, -+ const char *key, const char *value); -+ -+ -+/** -+ * @brief Add a key/value pair to a pfi header object. Provide the -+ * value as a number. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value value to set. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : value is not a string. This happens -+ * when the key stores a string. -+ */ -+int pfi_header_setnumber (pfi_header head, -+ const char *key, uint32_t value); -+ -+ -+/** -+ * @brief For a given key, return the numerical value stored in a -+ * pfi header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : stored value is not an integer but a string. -+ */ -+int pfi_header_getnumber (pfi_header head, -+ const char *key, uint32_t *value); -+ -+ -+static inline uint32_t -+pfi_getnumber(pfi_header head, const char *key) -+{ -+ uint32_t value; -+ pfi_header_getnumber(head, key, &value); -+ return value; -+} -+ -+/** -+ * @brief For a given key, return the string value stored in a pfi -+ * header object. -+ * -+ * @param head handle. -+ * @param key pointer to key string. Must be 0 terminated. -+ * @param value pointer to value string. Memory must be allocated by the user. -+ * @return 0 on success, otherwise: -+ * PFI_EUNDEF : key was not found. -+ * PFI_EBADTYPE : stored value is not a string but an integer. -+ */ -+int pfi_header_getstring (pfi_header head, -+ const char *key, char *value, size_t size); -+ -+ -+/** -+ * @brief Write a pfi header object into a given file. -+ * -+ * @param out output stream. -+ * @param head handle. -+ * @return 0 on success, error values otherwise: -+ * PFI_EINSUFF : not all mandatory fields are filled. -+ * PFI_ENOHEADER : wrong header version or magic number. -+ * -E* : see . -+ */ -+int pfi_header_write (FILE *out, pfi_header head); -+ -+ -+/** -+ * @brief Read a pfi header object from a given file. -+ * -+ * @param in input stream. -+ * @param head handle. -+ * @return 0 on success, error values otherwise: -+ * PFI_ENOVERSION: unknown header version. -+ * PFI_EFILE : cannot read enough data. -+ * PFI_ENOHEADER : wrong header version or magic number. -+ * -E* : see . -+ * -+ * If the header verification returned success the user can assume that -+ * all mandatory fields for a particular version are accessible. Checking -+ * the return code when calling the get-function for those keys is not -+ * required in those cases. For optional fields the checking must still be -+ * done. -+ */ -+int pfi_header_read (FILE *in, pfi_header head); -+ -+ -+/** -+ * @brief Display a pfi header in human-readable form. -+ * -+ * @param out output stream. -+ * @param head handle. -+ * @return always 0. -+ * -+ * @note Prints out that it is not implemented and whom you should -+ * contact if you need it urgently!. -+ */ -+int pfi_header_dump (FILE *out, pfi_header head); -+ -+ -+/* -+ * @brief Iterates over a stream of pfi files. The iterator function -+ * must advance the file pointer in FILE *in to the next pfi -+ * header. Function exists on feof(in). -+ * -+ * @param in input file descriptor, must be open and valid. -+ * @param func iterator function called when pfi header could be -+ * read and was validated. The function must return 0 on -+ * success. -+ * @return See pfi_header_init and pfi_header_read. -+ * PFI_EINVAL : func is not valid -+ * 0 ok. -+ */ -+typedef int (* pfi_read_func)(FILE *in, pfi_header hdr, void *priv_data); -+ -+int pfi_read (FILE *in, pfi_read_func func, void *priv_data); -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __pfi_h */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfi2bin.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,682 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Convert a PFI file (partial flash image) into a plain binary file. -+ * This tool can be used to prepare the data to be burned into flash -+ * chips in a manufacturing step where the flashes are written before -+ * being soldered onto the hardware. For NAND images another step is -+ * required to add the right OOB data to the binary image. -+ * -+ * 1.3 Removed argp because we want to use uClibc. -+ * 1.4 Minor cleanups -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "config.h" -+#include "list.h" -+#include "error.h" -+#include "reader.h" -+#include "peb.h" -+#include "crc32.h" -+ -+#define PROGRAM_VERSION "1.4" -+ -+#define MAX_FNAME 255 -+#define DEFAULT_ERASE_COUNT 0 /* Hmmm.... Perhaps */ -+#define ERR_BUF_SIZE 1024 -+ -+#define MIN(a,b) ((a) < (b) ? (a) : (b)) -+ -+static uint32_t crc32_table[256]; -+static char err_buf[ERR_BUF_SIZE]; -+ -+/* -+ * Data used to buffer raw blocks which have to be -+ * located at a specific point inside the generated RAW file -+ */ -+ -+typedef enum action_t { -+ ACT_NOTHING = 0x00000000, -+ ACT_RAW = 0x00000001, -+} action_t; -+ -+static const char copyright [] __attribute__((unused)) = -+ "(c) Copyright IBM Corp 2006\n"; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pfi2bin - a tool to convert PFI files into binary images.\n"; -+ -+static const char *optionsstr = -+" Common settings:\n" -+" -c, --copyright\n" -+" -v, --verbose Print more information.\n" -+"\n" -+" Input:\n" -+" -j, --platform=pdd-file PDD information which contains the card settings.\n" -+"\n" -+" Output:\n" -+" -o, --output=filename Outputfile, default: stdout.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pfi2bin [-cv?V] [-j pdd-file] [-o filename] [--copyright]\n" -+" [--verbose] [--platform=pdd-file] [--output=filename] [--help]\n" -+" [--usage] [--version] pfifile\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "platform", .has_arg = 1, .flag = NULL, .val = 'j' }, -+ { .name = "output", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct io { -+ FILE* fp_pdd; /* a FilePointer to the PDD data */ -+ FILE* fp_pfi; /* a FilePointer to the PFI input stream */ -+ FILE* fp_out; /* a FilePointer to the output stream */ -+} *io_t; -+ -+typedef struct myargs { -+ /* common settings */ -+ action_t action; -+ int verbose; -+ const char *f_in_pfi; -+ const char *f_in_pdd; -+ const char *f_out; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cvj:o:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ /* common settings */ -+ case 'v': /* --verbose= */ -+ args->verbose = 1; -+ break; -+ -+ case 'c': /* --copyright */ -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ -+ case 'j': /* --platform */ -+ args->f_in_pdd = optarg; -+ break; -+ -+ case 'o': /* --output */ -+ args->f_out = optarg; -+ break; -+ -+ case '?': /* help */ -+ printf("pfi2bin [OPTION...] pfifile\n"); -+ printf("%s", doc); -+ printf("%s", optionsstr); -+ printf("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ printf("%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ printf("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) -+ args->f_in_pfi = argv[optind++]; -+ -+ return 0; -+} -+ -+ -+static size_t -+byte_to_blk(size_t byte, size_t blk_size) -+{ -+ return (byte % blk_size) == 0 -+ ? byte / blk_size -+ : byte / blk_size + 1; -+} -+ -+ -+ -+ -+/** -+ * @precondition IO: File stream points to first byte of RAW data. -+ * @postcondition IO: File stream points to first byte of next -+ * or EOF. -+ */ -+static int -+memorize_raw_eb(pfi_raw_t pfi_raw, pdd_data_t pdd, list_t *raw_pebs, -+ io_t io) -+{ -+ int rc = 0; -+ uint32_t i; -+ -+ size_t read, to_read, eb_num; -+ size_t bytes_left; -+ list_t pebs = *raw_pebs; -+ peb_t peb = NULL; -+ -+ long old_file_pos = ftell(io->fp_pfi); -+ for (i = 0; i < pfi_raw->starts_size; i++) { -+ bytes_left = pfi_raw->data_size; -+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ -+ eb_num = byte_to_blk(pfi_raw->starts[i], pdd->eb_size); -+ while (bytes_left) { -+ to_read = MIN(bytes_left, pdd->eb_size); -+ rc = peb_new(eb_num++, pdd->eb_size, &peb); -+ if (rc != 0) -+ goto err; -+ read = fread(peb->data, 1, to_read, io->fp_pfi); -+ if (read != to_read) { -+ rc = -EIO; -+ goto err; -+ } -+ pebs = append_elem(peb, pebs); -+ bytes_left -= read; -+ } -+ -+ } -+ *raw_pebs = pebs; -+ return 0; -+err: -+ pebs = remove_all((free_func_t)&peb_free, pebs); -+ return rc; -+} -+ -+static int -+convert_ubi_volume(pfi_ubi_t ubi, pdd_data_t pdd, list_t raw_pebs, -+ struct ubi_vtbl_record *vol_tab, -+ size_t *ebs_written, io_t io) -+{ -+ int rc = 0; -+ uint32_t i, j; -+ peb_t raw_peb; -+ peb_t cmp_peb; -+ ubi_info_t u; -+ size_t leb_total = 0; -+ uint8_t vol_type; -+ -+ switch (ubi->type) { -+ case pfi_ubi_static: -+ vol_type = UBI_VID_STATIC; break; -+ case pfi_ubi_dynamic: -+ vol_type = UBI_VID_DYNAMIC; break; -+ default: -+ vol_type = UBI_VID_DYNAMIC; -+ } -+ -+ rc = peb_new(0, 0, &cmp_peb); -+ if (rc != 0) -+ goto err; -+ -+ long old_file_pos = ftell(io->fp_pfi); -+ for (i = 0; i < ubi->ids_size; i++) { -+ rc = fseek(io->fp_pfi, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ rc = ubigen_create(&u, ubi->ids[i], vol_type, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ ubi->alignment, UBI_VERSION, -+ pdd->vid_hdr_offset, 0, ubi->data_size, -+ io->fp_pfi, io->fp_out); -+ if (rc != 0) -+ goto err; -+ -+ rc = ubigen_get_leb_total(u, &leb_total); -+ if (rc != 0) -+ goto err; -+ -+ j = 0; -+ while(j < leb_total) { -+ cmp_peb->num = *ebs_written; -+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, -+ raw_pebs); -+ if (raw_peb) { -+ rc = peb_write(io->fp_out, raw_peb); -+ } -+ else { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ j++; -+ } -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ /* memorize volume table entry */ -+ rc = ubigen_set_lvol_rec(u, ubi->size, -+ ubi->names[i], -+ (void*) &vol_tab[ubi->ids[i]]); -+ if (rc != 0) -+ goto err; -+ ubigen_destroy(&u); -+ } -+ -+ peb_free(&cmp_peb); -+ return 0; -+ -+err: -+ peb_free(&cmp_peb); -+ ubigen_destroy(&u); -+ return rc; -+} -+ -+ -+static FILE* -+my_fmemopen (void *buf, size_t size, const char *opentype) -+{ -+ FILE* f; -+ size_t ret; -+ -+ assert(strcmp(opentype, "r") == 0); -+ -+ f = tmpfile(); -+ ret = fwrite(buf, 1, size, f); -+ rewind(f); -+ -+ return f; -+} -+ -+/** -+ * @brief Builds a UBI volume table from a volume entry list. -+ * @return 0 On success. -+ * else Error. -+ */ -+static int -+write_ubi_volume_table(pdd_data_t pdd, list_t raw_pebs, -+ struct ubi_vtbl_record *vol_tab, size_t vol_tab_size, -+ size_t *ebs_written, io_t io) -+{ -+ int rc = 0; -+ ubi_info_t u; -+ peb_t raw_peb; -+ peb_t cmp_peb; -+ size_t leb_size, leb_total, j = 0; -+ uint8_t *ptr = NULL; -+ FILE* fp_leb = NULL; -+ int vt_slots; -+ size_t vol_tab_size_limit; -+ -+ rc = peb_new(0, 0, &cmp_peb); -+ if (rc != 0) -+ goto err; -+ -+ /* @FIXME: Artem creates one volume with 2 LEBs. -+ * IMO 2 volumes would be more convenient. In order -+ * to get 2 reserved LEBs from ubigen, I have to -+ * introduce this stupid mechanism. Until no final -+ * decision of the VTAB structure is made... Good enough. -+ */ -+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ 1, UBI_VERSION, -+ pdd->vid_hdr_offset, UBI_COMPAT_REJECT, -+ vol_tab_size, stdin, io->fp_out); -+ /* @FIXME stdin for fp_in is a hack */ -+ if (rc != 0) -+ goto err; -+ rc = ubigen_get_leb_size(u, &leb_size); -+ if (rc != 0) -+ goto err; -+ ubigen_destroy(&u); -+ -+ /* -+ * The number of supported volumes is restricted by the eraseblock size -+ * and by the UBI_MAX_VOLUMES constant. -+ */ -+ vt_slots = leb_size / UBI_VTBL_RECORD_SIZE; -+ if (vt_slots > UBI_MAX_VOLUMES) -+ vt_slots = UBI_MAX_VOLUMES; -+ vol_tab_size_limit = vt_slots * UBI_VTBL_RECORD_SIZE; -+ -+ ptr = (uint8_t*) malloc(leb_size * sizeof(uint8_t)); -+ if (ptr == NULL) -+ goto err; -+ -+ memset(ptr, 0xff, leb_size); -+ memcpy(ptr, vol_tab, vol_tab_size_limit); -+ fp_leb = my_fmemopen(ptr, leb_size, "r"); -+ -+ rc = ubigen_create(&u, UBI_LAYOUT_VOLUME_ID, UBI_VID_DYNAMIC, -+ pdd->eb_size, DEFAULT_ERASE_COUNT, -+ 1, UBI_VERSION, pdd->vid_hdr_offset, -+ UBI_COMPAT_REJECT, leb_size * UBI_LAYOUT_VOLUME_EBS, -+ fp_leb, io->fp_out); -+ if (rc != 0) -+ goto err; -+ rc = ubigen_get_leb_total(u, &leb_total); -+ if (rc != 0) -+ goto err; -+ -+ long old_file_pos = ftell(fp_leb); -+ while(j < leb_total) { -+ rc = fseek(fp_leb, old_file_pos, SEEK_SET); -+ if (rc != 0) -+ goto err; -+ -+ cmp_peb->num = *ebs_written; -+ raw_peb = is_in((cmp_func_t)peb_cmp, cmp_peb, -+ raw_pebs); -+ if (raw_peb) { -+ rc = peb_write(io->fp_out, raw_peb); -+ } -+ else { -+ rc = ubigen_write_leb(u, NO_ERROR); -+ j++; -+ } -+ -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ -+err: -+ free(ptr); -+ peb_free(&cmp_peb); -+ ubigen_destroy(&u); -+ fclose(fp_leb); -+ return rc; -+} -+ -+static int -+write_remaining_raw_ebs(pdd_data_t pdd, list_t raw_blocks, size_t *ebs_written, -+ FILE* fp_out) -+{ -+ int rc = 0; -+ uint32_t j, delta; -+ list_t ptr; -+ peb_t empty_eb, peb; -+ -+ /* create an empty 0xff EB (for padding) */ -+ rc = peb_new(0, pdd->eb_size, &empty_eb); -+ -+ foreach(peb, ptr, raw_blocks) { -+ if (peb->num < *ebs_written) { -+ continue; /* omit blocks which -+ are already passed */ -+ } -+ -+ if (peb->num < *ebs_written) { -+ err_msg("eb_num: %d\n", peb->num); -+ err_msg("Bug: This should never happen. %d %s", -+ __LINE__, __FILE__); -+ goto err; -+ } -+ -+ delta = peb->num - *ebs_written; -+ if (((delta + *ebs_written) * pdd->eb_size) > pdd->flash_size) { -+ err_msg("RAW block outside of flash_size."); -+ goto err; -+ } -+ for (j = 0; j < delta; j++) { -+ rc = peb_write(fp_out, empty_eb); -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ rc = peb_write(fp_out, peb); -+ if (rc != 0) -+ goto err; -+ (*ebs_written)++; -+ } -+ -+err: -+ peb_free(&empty_eb); -+ return rc; -+} -+ -+static int -+init_vol_tab(struct ubi_vtbl_record **vol_tab, size_t *vol_tab_size) -+{ -+ uint32_t crc; -+ size_t i; -+ struct ubi_vtbl_record* res = NULL; -+ -+ *vol_tab_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE; -+ -+ res = (struct ubi_vtbl_record*) calloc(1, *vol_tab_size); -+ if (vol_tab == NULL) { -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < UBI_MAX_VOLUMES; i++) { -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, -+ &(res[i]), UBI_VTBL_RECORD_SIZE_CRC); -+ res[i].crc = cpu_to_be32(crc); -+ } -+ -+ *vol_tab = res; -+ return 0; -+} -+ -+static int -+create_raw(io_t io) -+{ -+ int rc = 0; -+ size_t ebs_written = 0; /* eraseblocks written already... */ -+ size_t vol_tab_size; -+ list_t ptr; -+ -+ list_t pfi_raws = mk_empty(); /* list of raw sections from a pfi */ -+ list_t pfi_ubis = mk_empty(); /* list of ubi sections from a pfi */ -+ list_t raw_pebs = mk_empty(); /* list of raw eraseblocks */ -+ -+ struct ubi_vtbl_record *vol_tab = NULL; -+ pdd_data_t pdd = NULL; -+ -+ rc = init_vol_tab (&vol_tab, &vol_tab_size); -+ if (rc != 0) { -+ err_msg("Cannot initialize volume table."); -+ goto err; -+ } -+ -+ rc = read_pdd_data(io->fp_pdd, &pdd, -+ err_buf, ERR_BUF_SIZE); -+ if (rc != 0) { -+ err_msg("Cannot read necessary pdd_data: %s rc: %d", -+ err_buf, rc); -+ goto err; -+ } -+ -+ rc = read_pfi_headers(&pfi_raws, &pfi_ubis, io->fp_pfi, -+ err_buf, ERR_BUF_SIZE); -+ if (rc != 0) { -+ err_msg("Cannot read pfi header: %s rc: %d", -+ err_buf, rc); -+ goto err; -+ } -+ -+ pfi_raw_t pfi_raw; -+ foreach(pfi_raw, ptr, pfi_raws) { -+ rc = memorize_raw_eb(pfi_raw, pdd, &raw_pebs, -+ io); -+ if (rc != 0) { -+ err_msg("Cannot create raw_block in mem. rc: %d\n", -+ rc); -+ goto err; -+ } -+ } -+ -+ pfi_ubi_t pfi_ubi; -+ foreach(pfi_ubi, ptr, pfi_ubis) { -+ rc = convert_ubi_volume(pfi_ubi, pdd, raw_pebs, -+ vol_tab, &ebs_written, io); -+ if (rc != 0) { -+ err_msg("Cannot convert UBI volume. rc: %d\n", rc); -+ goto err; -+ } -+ } -+ -+ rc = write_ubi_volume_table(pdd, raw_pebs, vol_tab, vol_tab_size, -+ &ebs_written, io); -+ if (rc != 0) { -+ err_msg("Cannot write UBI volume table. rc: %d\n", rc); -+ goto err; -+ } -+ -+ rc = write_remaining_raw_ebs(pdd, raw_pebs, &ebs_written, io->fp_out); -+ if (rc != 0) -+ goto err; -+ -+ if (io->fp_out != stdout) -+ info_msg("Physical eraseblocks written: %8d\n", ebs_written); -+err: -+ free(vol_tab); -+ pfi_raws = remove_all((free_func_t)&free_pfi_raw, pfi_raws); -+ pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, pfi_ubis); -+ raw_pebs = remove_all((free_func_t)&peb_free, raw_pebs); -+ free_pdd_data(&pdd); -+ return rc; -+} -+ -+ -+/* ------------------------------------------------------------------------- */ -+static void -+open_io_handle(myargs *args, io_t io) -+{ -+ /* set PDD input */ -+ io->fp_pdd = fopen(args->f_in_pdd, "r"); -+ if (io->fp_pdd == NULL) { -+ err_sys("Cannot open: %s", args->f_in_pdd); -+ } -+ -+ /* set PFI input */ -+ io->fp_pfi = fopen(args->f_in_pfi, "r"); -+ if (io->fp_pfi == NULL) { -+ err_sys("Cannot open PFI input file: %s", args->f_in_pfi); -+ } -+ -+ /* set output prefix */ -+ if (strcmp(args->f_out,"") == 0) -+ io->fp_out = stdout; -+ else { -+ io->fp_out = fopen(args->f_out, "wb"); -+ if (io->fp_out == NULL) { -+ err_sys("Cannot open output file: %s", args->f_out); -+ } -+ } -+} -+ -+static void -+close_io_handle(io_t io) -+{ -+ if (fclose(io->fp_pdd) != 0) { -+ err_sys("Cannot close PDD file."); -+ } -+ if (fclose(io->fp_pfi) != 0) { -+ err_sys("Cannot close PFI file."); -+ } -+ if (io->fp_out != stdout) { -+ if (fclose(io->fp_out) != 0) { -+ err_sys("Cannot close output file."); -+ } -+ } -+ -+ io->fp_pdd = NULL; -+ io->fp_pfi = NULL; -+ io->fp_out = NULL; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ int rc = 0; -+ -+ ubigen_init(); -+ init_crc32_table(crc32_table); -+ -+ struct io io = {NULL, NULL, NULL}; -+ myargs args = { -+ .action = ACT_RAW, -+ .verbose = 0, -+ -+ .f_in_pfi = "", -+ .f_in_pdd = "", -+ .f_out = "", -+ -+ /* arguments */ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ /* parse arguments */ -+ parse_opt(argc, argv, &args); -+ -+ if (strcmp(args.f_in_pfi, "") == 0) { -+ err_quit("No PFI input file specified!"); -+ } -+ -+ if (strcmp(args.f_in_pdd, "") == 0) { -+ err_quit("No PDD input file specified!"); -+ } -+ -+ open_io_handle(&args, &io); -+ -+ info_msg("[ Creating RAW..."); -+ rc = create_raw(&io); -+ if (rc != 0) { -+ err_msg("Creating RAW failed."); -+ goto err; -+ } -+ -+err: -+ close_io_handle(&io); -+ if (rc != 0) { -+ remove(args.f_out); -+ } -+ -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * Frank Haverkamp -+ * -+ * Process a PFI (partial flash image) and write the data to the -+ * specified UBI volumes. This tool is intended to be used for system -+ * update using PFI files. -+ * -+ * 1.1 fixed output to stderr and stdout in logfile mode. -+ * 1.2 updated. -+ * 1.3 removed argp parsing to be able to use uClib. -+ * 1.4 Minor cleanups. -+ * 1.5 Forgot to delete raw block before updating it. -+ * 1.6 Migrated to new libubi. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#undef DEBUG -+#include "error.h" -+#include "config.h" -+ -+#define PROGRAM_VERSION "1.6" -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "pfiflash - a tool for updating a controller with PFI files.\n"; -+ -+static const char *optionsstr = -+" Standard options:\n" -+" -c, --copyright Print copyright information.\n" -+" -l, --logfile= Write a logfile to .\n" -+" -v, --verbose Be verbose during program execution.\n" -+"\n" -+" Process options:\n" -+" -C, --complete Execute a complete system update. Updates both\n" -+" sides.\n" -+" -p, --pdd-update= Specify the pdd-update algorithm. is either\n" -+" 'keep', 'merge' or 'overwrite'.\n" -+" -r, --raw-flash= Flash the raw data. Use the specified mtd device.\n" -+" -s, --side= Select the side which shall be updated.\n" -+" -x, --compare Only compare on-flash and pfi data, print info if\n" -+" an update is neccessary and return appropriate\n" -+" error code.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: pfiflash [-cvC?V] [-l ] [-p ] [-r ] [-s ]\n" -+" [--copyright] [--logfile=] [--verbose] [--complete]\n" -+" [--pdd-update=] [--raw-flash=] [--side=]\n" -+" [--compare] [--help] [--usage] [--version] [pfifile]\n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "logfile", .has_arg = 1, .flag = NULL, .val = 'l' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "complete", .has_arg = 0, .flag = NULL, .val = 'C' }, -+ { .name = "pdd-update", .has_arg = 1, .flag = NULL, .val = 'p' }, -+ { .name = "raw-flash", .has_arg = 1, .flag = NULL, .val = 'r' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "compare", .has_arg = 0, .flag = NULL, .val = 'x' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ int verbose; -+ const char *logfile; -+ const char *raw_dev; -+ -+ pdd_handling_t pdd_handling; -+ int seqnum; -+ int compare; -+ int complete; -+ -+ FILE* fp_in; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static pdd_handling_t -+get_pdd_handling(const char* str) -+{ -+ if (strcmp(str, "keep") == 0) { -+ return PDD_KEEP; -+ } -+ if (strcmp(str, "merge") == 0) { -+ return PDD_MERGE; -+ } -+ if (strcmp(str, "overwrite") == 0) { -+ return PDD_OVERWRITE; -+ } -+ -+ return -1; -+} -+ -+static int -+get_update_seqnum(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ -+ return i; -+} -+ -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cl:vCp:r:s:x?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ /* standard options */ -+ case 'c': -+ err_msg("%s\n", copyright); -+ exit(0); -+ break; -+ case 'v': -+ args->verbose = 1; -+ break; -+ case 'l': -+ args->logfile = optarg; -+ break; -+ /* process options */ -+ case 'C': -+ args->complete = 1; -+ break; -+ case 'p': -+ args->pdd_handling = get_pdd_handling(optarg); -+ if ((int)args->pdd_handling < 0) { -+ err_quit("Unknown PDD handling: %s.\n" -+ "Please use either " -+ "'keep', 'merge' or" -+ "'overwrite'.\n'"); -+ } -+ break; -+ case 's': -+ args->seqnum = get_update_seqnum(optarg); -+ if (args->seqnum < 0) { -+ err_quit("Unsupported side: %s.\n" -+ "Supported sides are '0' " -+ "and '1'\n", optarg); -+ } -+ break; -+ case 'x': -+ args->compare = 1; -+ break; -+ case 'r': -+ args->raw_dev = optarg; -+ break; -+ case '?': /* help */ -+ err_msg("Usage: pfiflash [OPTION...] [pfifile]"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ -+ } -+ } -+ -+ if (optind < argc) { -+ args->fp_in = fopen(argv[optind++], "r"); -+ if ((args->fp_in) == NULL) { -+ err_sys("Cannot open PFI file %s for input", -+ argv[optind]); -+ } -+ } -+ -+ return 0; -+} -+ -+int main (int argc, char** argv) -+{ -+ int rc = 0; -+ char err_buf[PFIFLASH_MAX_ERR_BUF_SIZE]; -+ memset(err_buf, '\0', PFIFLASH_MAX_ERR_BUF_SIZE); -+ -+ myargs args = { -+ .verbose = 0, -+ .seqnum = -1, -+ .compare = 0, -+ .complete = 0, -+ .logfile = NULL, /* "/tmp/pfiflash.log", */ -+ .pdd_handling = PDD_KEEP, -+ .fp_in = stdin, -+ .raw_dev = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ error_initlog(args.logfile); -+ -+ if (!args.fp_in) { -+ rc = -1; -+ snprintf(err_buf, PFIFLASH_MAX_ERR_BUF_SIZE, -+ "No PFI input file specified!\n"); -+ goto err; -+ } -+ -+ rc = pfiflash_with_options(args.fp_in, args.complete, args.seqnum, -+ args.compare, args.pdd_handling, args.raw_dev, err_buf, -+ PFIFLASH_MAX_ERR_BUF_SIZE); -+ if (rc < 0) { -+ goto err_fp; -+ } -+ -+ err_fp: -+ if (args.fp_in != stdin) -+ fclose(args.fp_in); -+ err: -+ if (rc != 0) -+ err_msg("pfiflash: %s\nrc: %d\n", err_buf, rc); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,76 @@ -+#ifndef __PFIFLASH_H__ -+#define __PFIFLASH_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/** -+ * -+ * @file pfi.h -+ * -+ * @author Oliver Lohmann -+ * -+ * @brief The pfiflash library offers an interface for using the -+ * pfiflash * utility. -+ */ -+ -+#include /* FILE */ -+ -+#define PFIFLASH_MAX_ERR_BUF_SIZE 1024 -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef enum pdd_handling_t -+{ -+ PDD_KEEP = 0, -+ PDD_MERGE, -+ PDD_OVERWRITE, -+ PDD_HANDLING_NUM, /* always the last item */ -+} pdd_handling_t; /**< Possible PDD handle algorithms. */ -+ -+/** -+ * @brief Flashes a PFI file to UBI Device 0. -+ * @param complete [0|1] Do a complete system update. -+ * @param seqnum Index in a redundant group. -+ * @param compare [0|1] Compare contents. -+ * @param pdd_handling The PDD handling algorithm. -+ * @param rawdev Device to use for raw flashing -+ * @param err_buf An error buffer. -+ * @param err_buf_size Size of the error buffer. -+ */ -+int pfiflash_with_options(FILE* pfi, int complete, int seqnum, int compare, -+ pdd_handling_t pdd_handling, const char* rawdev, -+ char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Flashes a PFI file to UBI Device 0. -+ * @param complete [0|1] Do a complete system update. -+ * @param seqnum Index in a redundant group. -+ * @param pdd_handling The PDD handling algorithm. -+ * @param err_buf An error buffer. -+ * @param err_buf_size Size of the error buffer. -+ */ -+int pfiflash(FILE* pfi, int complete, int seqnum, pdd_handling_t pdd_handling, -+ char *err_buf, size_t err_buf_size); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __PFIFLASH_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/pfiflash_error.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,75 @@ -+#ifndef __PFIFLASH_ERROR_H__ -+#define __PFIFLASH_ERROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Author: Drake Dowsett -+ * Contact: Andreas Arnez -+ */ -+ -+enum pfiflash_err { -+ PFIFLASH_ERR_EOF = 1, -+ PFIFLASH_ERR_FIO, -+ PFIFLASH_ERR_UBI_OPEN, -+ PFIFLASH_ERR_UBI_CLOSE, -+ PFIFLASH_ERR_UBI_MKVOL, -+ PFIFLASH_ERR_UBI_RMVOL, -+ PFIFLASH_ERR_UBI_VOL_UPDATE, -+ PFIFLASH_ERR_UBI_VOL_FOPEN, -+ PFIFLASH_ERR_UBI_UNKNOWN, -+ PFIFLASH_ERR_UBI_VID_OOB, -+ PFIFLASH_ERR_BOOTENV_CREATE, -+ PFIFLASH_ERR_BOOTENV_READ, -+ PFIFLASH_ERR_BOOTENV_SIZE, -+ PFIFLASH_ERR_BOOTENV_WRITE, -+ PFIFLASH_ERR_PDD_UNKNOWN, -+ PFIFLASH_ERR_MTD_OPEN, -+ PFIFLASH_ERR_MTD_CLOSE, -+ PFIFLASH_ERR_CRC_CHECK, -+ PFIFLASH_ERR_MTD_ERASE, -+ PFIFLASH_ERR_COMPARE, -+ PFIFLASH_CMP_DIFF -+}; -+ -+const char *const PFIFLASH_ERRSTR[] = { -+ "", -+ "unexpected EOF", -+ "file I/O error", -+ "couldn't open UBI", -+ "couldn't close UBI", -+ "couldn't make UBI volume %d", -+ "couldn't remove UBI volume %d", -+ "couldn't update UBI volume %d", -+ "couldn't open UBI volume %d", -+ "unknown UBI operation", -+ "PFI data contains out of bounds UBI id %d", -+ "couldn't create bootenv%s", -+ "couldn't read bootenv", -+ "couldn't resize bootenv", -+ "couldn't write bootenv on ubi%d_%d", -+ "unknown PDD handling algorithm", -+ "couldn't open MTD device %s", -+ "couldn't close MTD device %s", -+ "CRC check failed: given=0x%08x, calculated=0x%08x", -+ "couldn't erase raw mtd region", -+ "couldn't compare volumes", -+ "on-flash data differ from pfi data, update is neccessary" -+}; -+ -+#endif /* __PFIFLASH_ERROR_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,482 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Read in PFI (partial flash image) data and store it into internal -+ * data structures for further processing. Take also care about -+ * special handling if the data contains PDD (platform description -+ * data/boot-parameters). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "bootenv.h" -+#include "reader.h" -+ -+#define __unused __attribute__((unused)) -+ -+/* @FIXME hard coded offsets right now - get them from Artem? */ -+#define NAND2048_DEFAULT_VID_HDR_OFF 1984 -+#define NAND512_DEFAULT_VID_HDR_OFF 448 -+#define NOR_DEFAULT_VID_HDR_OFF 64 -+ -+#define EBUF_PFI(fmt...) \ -+ do { int i = snprintf(err_buf, err_buf_size, "%s\n", label); \ -+ snprintf(err_buf + i, err_buf_size - i, fmt); \ -+ } while (0) -+ -+#define EBUF(fmt...) \ -+ do { snprintf(err_buf, err_buf_size, fmt); } while (0) -+ -+ -+int -+read_pdd_data(FILE* fp_pdd, pdd_data_t* pdd_data, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ bootenv_t pdd = NULL; -+ pdd_data_t res = NULL; -+ const char* value; -+ -+ res = (pdd_data_t) malloc(sizeof(struct pdd_data)); -+ if (!res) { -+ rc = -ENOMEM; -+ goto err; -+ } -+ rc = bootenv_create(&pdd); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_read_txt(fp_pdd, pdd); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_get(pdd, "flash_type", &value); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ if (strcmp(value, "NAND") == 0) { -+ -+ rc = bootenv_get_num(pdd, "flash_page_size", -+ &(res->flash_page_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_page_size' from pdd."); -+ goto err; -+ } -+ res->flash_type = NAND_FLASH; -+ -+ switch (res->flash_page_size) { -+ case 512: -+ res->vid_hdr_offset = NAND512_DEFAULT_VID_HDR_OFF; -+ break; -+ case 2048: -+ res->vid_hdr_offset = NAND2048_DEFAULT_VID_HDR_OFF; -+ break; -+ default: -+ EBUF("Unsupported 'flash_page_size' %d.", -+ res->flash_page_size); -+ goto err; -+ } -+ } -+ else if (strcmp(value, "NOR") == 0){ -+ res->flash_type = NOR_FLASH; -+ res->vid_hdr_offset = NOR_DEFAULT_VID_HDR_OFF; -+ } -+ else { -+ snprintf(err_buf, err_buf_size, -+ "Unkown flash type: %s", value); -+ goto err; -+ } -+ -+ rc = bootenv_get_num(pdd, "flash_eraseblock_size", -+ &(res->eb_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_eraseblock_size' from pdd."); -+ goto err; -+ } -+ -+ rc = bootenv_get_num(pdd, "flash_size", -+ &(res->flash_size)); -+ if (rc != 0) { -+ EBUF("Cannot read 'flash_size' from pdd."); -+ goto err; -+ } -+ -+ goto out; -+ err: -+ if (res) { -+ free(res); -+ res = NULL; -+ } -+ out: -+ bootenv_destroy(&pdd); -+ *pdd_data = res; -+ return rc; -+} -+ -+int -+read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_raw_t* pfi_raw, -+ const char* label, char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ char tmp_str[PFI_KEYWORD_LEN]; -+ bootenv_list_t raw_start_list = NULL; -+ pfi_raw_t res; -+ size_t size; -+ -+ res = (pfi_raw_t) malloc(sizeof(struct pfi_raw)); -+ if (!res) -+ return -ENOMEM; -+ -+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'crc' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "raw_starts", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'raw_starts' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_create(&raw_start_list); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ rc = bootenv_list_import(raw_start_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ -+ rc = bootenv_list_to_num_vector(raw_start_list, -+ &size, &(res->starts)); -+ res->starts_size = size; -+ -+ if (rc != 0) { -+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str); -+ goto err; -+ } -+ -+ goto out; -+ -+ err: -+ if (res) { -+ free(res); -+ res = NULL; -+ } -+ out: -+ bootenv_list_destroy(&raw_start_list); -+ *pfi_raw = res; -+ return rc; -+} -+ -+int -+read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi __unused, pfi_ubi_t* pfi_ubi, -+ const char *label, char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ const char** tmp_names = NULL; -+ char tmp_str[PFI_KEYWORD_LEN]; -+ bootenv_list_t ubi_id_list = NULL; -+ bootenv_list_t ubi_name_list = NULL; -+ pfi_ubi_t res; -+ uint32_t i; -+ size_t size; -+ -+ res = (pfi_ubi_t) calloc(1, sizeof(struct pfi_ubi)); -+ if (!res) -+ return -ENOMEM; -+ -+ rc = pfi_header_getnumber(pfi_hd, "size", &(res->data_size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "crc", &(res->crc)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'crc' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_ids", tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_ids' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_create(&ubi_id_list); -+ if (rc != 0) { -+ goto err; -+ } -+ rc = bootenv_list_create(&ubi_name_list); -+ if (rc != 0) { -+ goto err; -+ } -+ -+ rc = bootenv_list_import(ubi_id_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ -+ rc = bootenv_list_to_num_vector(ubi_id_list, &size, -+ &(res->ids)); -+ res->ids_size = size; -+ if (rc != 0) { -+ EBUF_PFI("Cannot create numeric value array: %s", tmp_str); -+ goto err; -+ } -+ -+ if (res->ids_size == 0) { -+ rc = -1; -+ EBUF_PFI("Sanity check failed: No ubi_ids specified."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_type", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_type' from PFI."); -+ goto err; -+ } -+ if (strcmp(tmp_str, "static") == 0) -+ res->type = pfi_ubi_static; -+ else if (strcmp(tmp_str, "dynamic") == 0) -+ res->type = pfi_ubi_dynamic; -+ else { -+ EBUF_PFI("Unknown ubi_type in PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "ubi_alignment", &(res->alignment)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_alignment' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getnumber(pfi_hd, "ubi_size", &(res->size)); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_size' from PFI."); -+ goto err; -+ } -+ -+ rc = pfi_header_getstring(pfi_hd, "ubi_names", -+ tmp_str, PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF_PFI("Cannot read 'ubi_names' from PFI."); -+ goto err; -+ } -+ -+ rc = bootenv_list_import(ubi_name_list, tmp_str); -+ if (rc != 0) { -+ EBUF_PFI("Cannot translate PFI value: %s", tmp_str); -+ goto err; -+ } -+ rc = bootenv_list_to_vector(ubi_name_list, &size, -+ &(tmp_names)); -+ res->names_size = size; -+ if (rc != 0) { -+ EBUF_PFI("Cannot create string array: %s", tmp_str); -+ goto err; -+ } -+ -+ if (res->names_size != res->ids_size) { -+ EBUF_PFI("Sanity check failed: ubi_ids list does not match " -+ "sizeof ubi_names list."); -+ rc = -1; -+ } -+ -+ /* copy tmp_names to own structure */ -+ res->names = (char**) calloc(1, res->names_size * sizeof (char*)); -+ if (res->names == NULL) -+ goto err; -+ -+ for (i = 0; i < res->names_size; i++) { -+ res->names[i] = calloc(PFI_UBI_VOL_NAME_LEN + 1, sizeof(char)); -+ if (res->names[i] == NULL) -+ goto err; -+ strncpy(res->names[i], tmp_names[i], PFI_UBI_VOL_NAME_LEN + 1); -+ } -+ -+ goto out; -+ -+ err: -+ if (res) { -+ if (res->names) { -+ for (i = 0; i < res->names_size; i++) { -+ if (res->names[i]) { -+ free(res->names[i]); -+ } -+ } -+ free(res->names); -+ } -+ if (res->ids) { -+ free(res->ids); -+ } -+ free(res); -+ res = NULL; -+ } -+ -+ out: -+ bootenv_list_destroy(&ubi_id_list); -+ bootenv_list_destroy(&ubi_name_list); -+ if (tmp_names != NULL) -+ free(tmp_names); -+ *pfi_ubi = res; -+ return rc; -+} -+ -+ -+int -+free_pdd_data(pdd_data_t* pdd_data) -+{ -+ if (*pdd_data) { -+ free(*pdd_data); -+ } -+ *pdd_data = NULL; -+ -+ return 0; -+} -+ -+int -+free_pfi_raw(pfi_raw_t* pfi_raw) -+{ -+ pfi_raw_t tmp = *pfi_raw; -+ if (tmp) { -+ if (tmp->starts) -+ free(tmp->starts); -+ free(tmp); -+ } -+ *pfi_raw = NULL; -+ -+ return 0; -+} -+ -+int -+free_pfi_ubi(pfi_ubi_t* pfi_ubi) -+{ -+ size_t i; -+ pfi_ubi_t tmp = *pfi_ubi; -+ if (tmp) { -+ if (tmp->ids) -+ free(tmp->ids); -+ if (tmp->names) { -+ for (i = 0; i < tmp->names_size; i++) { -+ if (tmp->names[i]) { -+ free(tmp->names[i]); -+ } -+ } -+ free(tmp->names); -+ } -+ free(tmp); -+ } -+ *pfi_ubi = NULL; -+ -+ return 0; -+} -+ -+ -+int -+read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, -+ char* err_buf, size_t err_buf_size) -+{ -+ int rc = 0; -+ char mode[PFI_KEYWORD_LEN]; -+ char label[PFI_LABEL_LEN]; -+ -+ *pfi_raws = mk_empty(); pfi_raw_t raw = NULL; -+ *pfi_ubis = mk_empty(); pfi_ubi_t ubi = NULL; -+ pfi_header pfi_header = NULL; -+ -+ /* read all headers from PFI and store them in lists */ -+ rc = pfi_header_init(&pfi_header); -+ if (rc != 0) { -+ EBUF("Cannot initialize pfi header."); -+ goto err; -+ } -+ while ((rc == 0) && !feof(fp_pfi)) { -+ rc = pfi_header_read(fp_pfi, pfi_header); -+ if (rc != 0) { -+ if (rc == PFI_DATA_START) { -+ rc = 0; -+ break; /* data section starts, -+ all headers read */ -+ } -+ else { -+ goto err; -+ } -+ } -+ rc = pfi_header_getstring(pfi_header, "label", label, -+ PFI_LABEL_LEN); -+ if (rc != 0) { -+ EBUF("Cannot read 'label' from PFI."); -+ goto err; -+ } -+ rc = pfi_header_getstring(pfi_header, "mode", mode, -+ PFI_KEYWORD_LEN); -+ if (rc != 0) { -+ EBUF("Cannot read 'mode' from PFI."); -+ goto err; -+ } -+ if (strcmp(mode, "ubi") == 0) { -+ rc = read_pfi_ubi(pfi_header, fp_pfi, &ubi, label, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ goto err; -+ } -+ *pfi_ubis = append_elem(ubi, *pfi_ubis); -+ } -+ else if (strcmp(mode, "raw") == 0) { -+ rc = read_pfi_raw(pfi_header, fp_pfi, &raw, label, -+ err_buf, err_buf_size); -+ if (rc != 0) { -+ goto err; -+ } -+ *pfi_raws = append_elem(raw, *pfi_raws); -+ } -+ else { -+ EBUF("Recvieved unknown mode from PFI: %s", mode); -+ goto err; -+ } -+ } -+ goto out; -+ -+ err: -+ *pfi_raws = remove_all((free_func_t)&free_pfi_raw, *pfi_raws); -+ *pfi_ubis = remove_all((free_func_t)&free_pfi_ubi, *pfi_ubis); -+ out: -+ pfi_header_destroy(&pfi_header); -+ return rc; -+ -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/reader.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/reader.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,87 @@ -+#ifndef __READER_H__ -+#define __READER_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Read Platform Description Data (PDD). -+ */ -+ -+#include -+#include -+ -+#include "pfi.h" -+#include "bootenv.h" -+#include "list.h" -+ -+typedef enum flash_type_t { -+ NAND_FLASH = 0, -+ NOR_FLASH, -+} flash_type_t; -+ -+typedef struct pdd_data *pdd_data_t; -+typedef struct pfi_raw *pfi_raw_t; -+typedef struct pfi_ubi *pfi_ubi_t; -+ -+struct pdd_data { -+ uint32_t flash_size; -+ uint32_t flash_page_size; -+ uint32_t eb_size; -+ uint32_t vid_hdr_offset; -+ flash_type_t flash_type; -+}; -+ -+struct pfi_raw { -+ uint32_t data_size; -+ uint32_t *starts; -+ uint32_t starts_size; -+ uint32_t crc; -+}; -+ -+struct pfi_ubi { -+ uint32_t data_size; -+ uint32_t alignment; -+ uint32_t *ids; -+ uint32_t ids_size; -+ char **names; -+ uint32_t names_size; -+ uint32_t size; -+ enum { pfi_ubi_dynamic, pfi_ubi_static } type; -+ int curr_seqnum; /* specifies the seqnum taken in an update, -+ default: 0 (used by pfiflash, ubimirror) */ -+ uint32_t crc; -+}; -+ -+int read_pdd_data(FILE* fp_pdd, pdd_data_t *pdd_data, -+ char *err_buf, size_t err_buf_size); -+int read_pfi_raw(pfi_header pfi_hd, FILE* fp_pfi, pfi_raw_t *pfi_raw, -+ const char *label, char *err_buf, size_t err_buf_size); -+int read_pfi_ubi(pfi_header pfi_hd, FILE* fp_pfi, pfi_ubi_t *pfi_ubi, -+ const char *label, char *err_buf, size_t err_buf_size); -+ -+/** -+ * @brief Reads all pfi headers into list structures, separated by -+ * RAW and UBI sections. -+ */ -+int read_pfi_headers(list_t *pfi_raws, list_t *pfi_ubis, FILE* fp_pfi, -+ char* err_buf, size_t err_buf_size); -+int free_pdd_data(pdd_data_t *pdd_data); -+int free_pfi_raw(pfi_raw_t *raw_pfi); -+int free_pfi_ubi(pfi_ubi_t *pfi_ubi); -+ -+#endif /* __READER_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * Tool to add UBI headers to binary images. -+ * -+ * 1.0 Initial version -+ * 1.1 Different CRC32 start value -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ubigen.h" -+#include "config.h" -+ -+#define PROGRAM_VERSION "1.3" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0x00000001, -+ ACT_BROKEN_UPDATE = 0x00000002, -+} action_t; -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "ubigen - a tool for adding UBI information to a binary input file.\n"; -+ -+static const char *optionsstr = -+" Common settings:\n" -+" -c, --copyright Print copyright information.\n" -+" -d, --debug\n" -+" -v, --verbose Print more progress information.\n" -+"\n" -+" UBI Settings:\n" -+" -A, --alignment= Set the alignment size to (default 1).\n" -+" Values can be specified as bytes, 'ki' or 'Mi'.\n" -+" -B, --blocksize= Set the eraseblock size to (default 128\n" -+" KiB).\n" -+" Values can be specified as bytes, 'ki' or 'Mi'.\n" -+" -E, --erasecount= Set the erase count to (default 0)\n" -+" -I, --id= The UBI volume id.\n" -+" -O, --offset= Offset from start of an erase block to the UBI\n" -+" volume header.\n" -+" -T, --type= The UBI volume type:\n" -+" 1 = dynamic, 2 = static\n" -+" -X, --setver= Set UBI version number to (default 1)\n" -+"\n" -+" Input/Output:\n" -+" -i, --infile= Read input from file.\n" -+" -o, --outfile= Write output to file (default is stdout).\n" -+"\n" -+" Special options:\n" -+" -U, --broken-update= Create an ubi image which simulates a broken\n" -+" update.\n" -+" specifies the logical eraseblock number to\n" -+" update.\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: ubigen [-cdv?V] [-A ] [-B ] [-E ] [-I ]\n" -+" [-O ] [-T ] [-X ] [-i ] [-o ]\n" -+" [-U ] [--copyright] [--debug] [--verbose] [--alignment=]\n" -+" [--blocksize=] [--erasecount=] [--id=]\n" -+" [--offset=] [--type=] [--setver=]\n" -+" [--infile=] [--outfile=]\n" -+" [--broken-update=] [--help] [--usage] [--version]\n"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "debug", .has_arg = 0, .flag = NULL, .val = 'd' }, -+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "alignment", .has_arg = 1, .flag = NULL, .val = 'A' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'B' }, -+ { .name = "erasecount", .has_arg = 1, .flag = NULL, .val = 'E' }, -+ { .name = "id", .has_arg = 1, .flag = NULL, .val = 'I' }, -+ { .name = "offset", .has_arg = 1, .flag = NULL, .val = 'O' }, -+ { .name = "type", .has_arg = 1, .flag = NULL, .val = 'T' }, -+ { .name = "setver", .has_arg = 1, .flag = NULL, .val = 'X' }, -+ { .name = "infile", .has_arg = 1, .flag = NULL, .val = 'i' }, -+ { .name = "outfile", .has_arg = 1, .flag = NULL, .val = 'o' }, -+ { .name = "broken-update", .has_arg = 1, .flag = NULL, .val = 'U' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+static const char copyright [] __attribute__((unused)) = -+ "Copyright IBM Corp 2006"; -+ -+#define CHECK_ENDP(option, endp) do { \ -+ if (*endp) { \ -+ fprintf(stderr, \ -+ "Parse error option \'%s\'. " \ -+ "No correct numeric value.\n" \ -+ , option); \ -+ exit(EXIT_FAILURE); \ -+ } \ -+} while(0) -+ -+typedef struct myargs { -+ /* common settings */ -+ action_t action; -+ int verbose; -+ -+ int32_t id; -+ uint8_t type; -+ uint32_t eb_size; -+ uint64_t ec; -+ uint8_t version; -+ uint32_t hdr_offset; -+ uint32_t update_block; -+ uint32_t alignment; -+ -+ FILE* fp_in; -+ FILE* fp_out; -+ -+ /* special stuff needed to get additional arguments */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+ -+static int ustrtoul(const char *cp, char **endp, unsigned int base) -+{ -+ unsigned long result = strtoul(cp, endp, base); -+ -+ switch (**endp) { -+ case 'G': -+ result *= 1024; -+ case 'M': -+ result *= 1024; -+ case 'k': -+ case 'K': -+ result *= 1024; -+ /* "Ki", "ki", "Mi" or "Gi" are to be used. */ -+ if ((*endp)[1] == 'i') -+ (*endp) += 2; -+ } -+ return result; -+} -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ int err = 0; -+ char* endp; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cdvA:B:E:I:O:T:X:i:o:U:?V", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ fprintf(stderr, "%s\n", copyright); -+ exit(0); -+ break; -+ case 'o': /* output */ -+ args->fp_out = fopen(optarg, "wb"); -+ if ((args->fp_out) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for output\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'i': /* input */ -+ args->fp_in = fopen(optarg, "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s " -+ "for input\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'v': /* verbose */ -+ args->verbose = 1; -+ break; -+ -+ case 'B': /* eb_size */ -+ args->eb_size = -+ (uint32_t)ustrtoul(optarg, &endp, 0); -+ CHECK_ENDP("B", endp); -+ break; -+ case 'E': /* erasecount */ -+ args->ec = (uint64_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("E", endp); -+ break; -+ case 'I': /* id */ -+ args->id = (uint16_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("I", endp); -+ break; -+ case 'T': /* type */ -+ args->type = -+ (uint16_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("T", endp); -+ break; -+ case 'X': /* versionnr */ -+ args->version = -+ (uint8_t)strtoul(optarg, &endp, 0); -+ CHECK_ENDP("X", endp); -+ break; -+ case 'O': /* offset for volume hdr */ -+ args->hdr_offset = -+ (uint32_t) strtoul(optarg, &endp, 0); -+ CHECK_ENDP("O", endp); -+ break; -+ -+ case 'U': /* broken update */ -+ args->action = ACT_BROKEN_UPDATE; -+ args->update_block = -+ (uint32_t) strtoul(optarg, &endp, 0); -+ CHECK_ENDP("U", endp); -+ break; -+ -+ case '?': /* help */ -+ fprintf(stderr, "Usage: ubigen [OPTION...]\n"); -+ fprintf(stderr, "%s", doc); -+ fprintf(stderr, "%s", optionsstr); -+ fprintf(stderr, "\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ -+ case 'V': -+ fprintf(stderr, "%s\n", PROGRAM_VERSION); -+ exit(0); -+ break; -+ -+ default: -+ fprintf(stderr, "%s", usage); -+ exit(-1); -+ } -+ } -+ -+ if (optind < argc) { -+ if (!args->fp_in) { -+ args->fp_in = fopen(argv[optind++], "rb"); -+ if ((args->fp_in) == NULL) { -+ fprintf(stderr, "Cannot open file %s for " -+ "input\n", argv[optind]); -+ exit(1); -+ } -+ } -+ } -+ if (args->id < 0) { -+ err = 1; -+ fprintf(stderr, -+ "Please specify an UBI Volume ID.\n"); -+ } -+ if (args->type == 0) { -+ err = 1; -+ fprintf(stderr, -+ "Please specify an UBI Volume type.\n"); -+ } -+ if (err) { -+ fprintf(stderr, "%s", usage); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -+ -+int -+main(int argc, char **argv) -+{ -+ int rc = 0; -+ ubi_info_t u; -+ struct stat file_info; -+ off_t input_len = 0; /* only used in static volumes */ -+ -+ myargs args = { -+ .action = ACT_NORMAL, -+ .verbose = 0, -+ -+ .id = -1, -+ .type = 0, -+ .eb_size = 0, -+ .update_block = 0, -+ .ec = 0, -+ .version = 0, -+ .hdr_offset = (DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE), -+ .alignment = 1, -+ -+ .fp_in = NULL, -+ .fp_out = stdout, -+ /* arguments */ -+ .arg1 = NULL, -+ .options = NULL, -+ }; -+ -+ ubigen_init(); /* Init CRC32 table in ubigen */ -+ -+ /* parse arguments */ -+ parse_opt(argc, argv, &args); -+ -+ if (fstat(fileno(args.fp_in), &file_info) != 0) { -+ fprintf(stderr, "Cannot fetch file size " -+ "from input file.\n"); -+ } -+ input_len = file_info.st_size; -+ -+ rc = ubigen_create(&u, (uint32_t)args.id, args.type, -+ args.eb_size, args.ec, args.alignment, -+ args.version, args.hdr_offset, 0 ,input_len, -+ args.fp_in, args.fp_out); -+ -+ if (rc != 0) { -+ fprintf(stderr, "Cannot create UBI info handler rc: %d\n", rc); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (!args.fp_in || !args.fp_out) { -+ fprintf(stderr, "Input/Output error.\n"); -+ exit(EXIT_FAILURE); -+ -+ } -+ -+ if (args.action & ACT_NORMAL) { -+ rc = ubigen_write_complete(u); -+ } -+ else if (args.action & ACT_BROKEN_UPDATE) { -+ rc = ubigen_write_broken_update(u, args.update_block); -+ } -+ if (rc != 0) { -+ fprintf(stderr, "Error converting input data.\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ rc = ubigen_destroy(&u); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubigen.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,149 @@ -+#ifndef __UBIGEN_H__ -+#define __UBIGEN_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Frank Haverkamp -+ * -+ * An utility to update UBI volumes. -+ */ -+ -+#include /* FILE */ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define DEFAULT_BLOCKSIZE (128 * 1024) -+#define DEFAULT_PAGESIZE (2*1024) -+ -+#define EUBIGEN_INVALID_TYPE 1 -+#define EUBIGEN_INVALID_HDR_OFFSET 2 -+#define EUBIGEN_INVALID_ALIGNMENT 3 -+#define EUBIGEN_TOO_SMALL_EB 4 -+#define EUBIGEN_MAX_ERROR 5 -+ -+ -+typedef enum action { -+ NO_ERROR = 0x00000000, -+ BROKEN_HDR_CRC = 0x00000001, -+ BROKEN_DATA_CRC = 0x00000002, -+ BROKEN_DATA_SIZE = 0x00000004, -+ BROKEN_OMIT_BLK = 0x00000008, -+ MARK_AS_UPDATE = 0x00000010, -+} ubigen_action_t; -+ -+typedef struct ubi_info *ubi_info_t; -+ -+/** -+ * @brief Initialize the internal CRC32 table. -+ * @note Necessary because of the used crc32 function in UBI. -+ * A usage of CRC32, from e.g. zlib will fail. -+ */ -+void ubigen_init(void); -+ -+/** -+ * @brief Create an ubigen handle. -+ * @param ... -+ * @return 0 On sucess. -+ * else Error. -+ * @note This parameterlist is ugly. But we have to use -+ * two big structs and meta information internally, -+ * filling them would be even uglier. -+ */ -+int ubigen_create(ubi_info_t *u, uint32_t vol_id, uint8_t vol_type, -+ uint32_t eb_size, uint64_t ec, uint32_t alignment, -+ uint8_t version, uint32_t vid_hdr_offset, -+ uint8_t compat_flag, size_t data_size, -+ FILE* fp_in, FILE* fp_out); -+ -+/** -+ * @brief Destroy an ubigen handle. -+ * @param u Handle to free. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_destroy(ubi_info_t *u); -+ -+/** -+ * @brief Get number of total logical EBs, necessary for the -+ * complete storage of data in the handle. -+ * @param u The handle. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_get_leb_total(ubi_info_t u, size_t* total); -+ -+/** -+ * @brief Get the size in bytes of one logical EB in the handle. -+ * @param u The handle. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_get_leb_size(ubi_info_t u, size_t* size); -+ -+ -+/** -+ * @brief Write a logical EB (fits exactly into 1 physical EB). -+ * @param u Handle which holds all necessary data. -+ * @param action Additional operations which shall be applied on this -+ * logical eraseblock. Mostly injecting artifical errors. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_leb(ubi_info_t u, ubigen_action_t action); -+ -+/** -+ * @brief Write a complete array of logical eraseblocks at once. -+ * @param u Handle which holds all necessary data. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_complete(ubi_info_t u); -+ -+/** -+ * @brief Write a single block which is extracted from the -+ * binary input data. -+ * @param u Handle which holds all necessary data. -+ * @param blk Logical eraseblock which shall hold a inc. copy entry -+ * and a bad data crc. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_write_broken_update(ubi_info_t u, uint32_t blk); -+ -+/** -+ * @brief Use the current ubi_info data and some additional data -+ * to set an UBI volume table entry from it. -+ * @param u Handle which holds some of the necessary data. -+ * @param res_bytes Number of reserved bytes which is stored in the volume -+ * table entry. -+ * @param name A string which shall be used as a volume label. -+ * @param lvol_r A pointer to a volume table entry. -+ * @return 0 On success. -+ * else Error. -+ */ -+int ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes, -+ const char* name, struct ubi_vtbl_record *lvol_rec); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* __UBIGEN_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,213 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups -+ * 1.4 Migrated to new libubi -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "error.h" -+#include "example_ubi.h" -+#include "ubimirror.h" -+ -+#define PROGRAM_VERSION "1.4" -+ -+typedef enum action_t { -+ ACT_NORMAL = 0, -+ ACT_ARGP_ABORT, -+ ACT_ARGP_ERR, -+} action_t; -+ -+#define ABORT_ARGP do { \ -+ args->action = ACT_ARGP_ABORT; \ -+} while (0) -+ -+#define ERR_ARGP do { \ -+ args->action = ACT_ARGP_ERR; \ -+} while (0) -+ -+#define VOL_ARGS_MAX 2 -+ -+static char doc[] = "\nVersion: " PROGRAM_VERSION "\n" -+ "ubimirror - mirrors ubi volumes.\n"; -+ -+static const char *optionsstr = -+" -c, --copyright Print copyright information.\n" -+" -s, --side= Use the side as source.\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" -V, --version Print program version\n"; -+ -+static const char *usage = -+"Usage: ubimirror [-c?V] [-s ] [--copyright] [--side=]\n" -+" [--help] [--usage] [--version] \n"; -+ -+static const char copyright [] __attribute__((unused)) = -+ "(C) IBM Coorporation 2007"; -+ -+struct option long_options[] = { -+ { .name = "copyright", .has_arg = 0, .flag = NULL, .val = 'c' }, -+ { .name = "side", .has_arg = 1, .flag = NULL, .val = 's' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+typedef struct myargs { -+ action_t action; -+ int side; -+ int vol_no; /* index of current volume */ -+ /* @FIXME replace by bootenv_list, makes live easier */ -+ /* @FIXME remove the constraint of two entries in the array */ -+ const char* vol[VOL_ARGS_MAX]; /* comma separated list of src/dst -+ volumes */ -+ char *arg1; -+ char **options; /* [STRING...] */ -+} myargs; -+ -+static int -+get_update_side(const char* str) -+{ -+ uint32_t i = strtoul(str, NULL, 0); -+ -+ if ((i != 0) && (i != 1)) { -+ return -1; -+ } -+ return i; -+} -+ -+ -+static int -+parse_opt(int argc, char **argv, myargs *args) -+{ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "cs:?V", long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'c': -+ err_msg("%s", copyright); -+ ABORT_ARGP; -+ break; -+ case 's': -+ args->side = get_update_side(optarg); -+ if (args->side < 0) { -+ err_msg("Unsupported seqnum: %s.\n" -+ "Supported seqnums are '0' " -+ "and '1'\n", optarg); -+ ERR_ARGP; -+ } -+ break; -+ case '?': /* help */ -+ err_msg("Usage: ubimirror [OPTION...] " -+ " \n"); -+ err_msg("%s", doc); -+ err_msg("%s", optionsstr); -+ err_msg("\nReport bugs to %s\n", -+ PACKAGE_BUGREPORT); -+ exit(0); -+ break; -+ case 'V': -+ err_msg("%s", PROGRAM_VERSION); -+ exit(0); -+ break; -+ default: -+ err_msg("%s", usage); -+ exit(-1); -+ } -+ } -+ -+ while (optind < argc) { -+ /* only two entries allowed */ -+ if (args->vol_no >= VOL_ARGS_MAX) { -+ err_msg("%s", usage); -+ ERR_ARGP; -+ } -+ args->vol[(args->vol_no)++] = argv[optind++]; -+ } -+ -+ return 0; -+} -+ -+ -+int -+main(int argc, char **argv) { -+ int rc = 0; -+ unsigned int ids[VOL_ARGS_MAX]; -+ char err_buf[1024]; -+ -+ myargs args = { -+ .action = ACT_NORMAL, -+ .side = -1, -+ .vol_no = 0, -+ .vol = {"", ""}, -+ .options = NULL, -+ }; -+ -+ parse_opt(argc, argv, &args); -+ if (args.action == ACT_ARGP_ERR) { -+ rc = 127; -+ goto err; -+ } -+ if (args.action == ACT_ARGP_ABORT) { -+ rc = 126; -+ goto out; -+ } -+ if (args.vol_no < VOL_ARGS_MAX) { -+ fprintf(stderr, "missing volume number for %s\n", -+ args.vol_no == 0 ? "source and target" : "target"); -+ rc = 125; -+ goto out; -+ } -+ for( rc = 0; rc < args.vol_no; ++rc){ -+ char *endp; -+ ids[rc] = strtoul(args.vol[rc], &endp, 0); -+ if( *endp != '\0' ){ -+ fprintf(stderr, "invalid volume number %s\n", -+ args.vol[rc]); -+ rc = 125; -+ goto out; -+ } -+ } -+ rc = ubimirror(EXAMPLE_UBI_DEVICE, args.side, ids, args.vol_no, -+ err_buf, sizeof(err_buf)); -+ if( rc ){ -+ err_buf[sizeof err_buf - 1] = '\0'; -+ fprintf(stderr, err_buf); -+ if( rc < 0 ) -+ rc = -rc; -+ } -+ out: -+ err: -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/ubimirror.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,66 @@ -+#ifndef __UBIMIRROR_H__ -+#define __UBIMIRROR_H__ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * Author: Oliver Lohmann -+ * -+ * An utility to mirror UBI volumes. -+ */ -+ -+#include -+ -+/** -+ * @def EUBIMIRROR_SRC_EQ_DST -+ * @brief Given source volume is also in the set of destination volumes. -+ */ -+#define EUBIMIRROR_SRC_EQ_DST 20 -+ -+/** -+ * @def EUBIMIRROR_NO_SRC -+ * @brief The given source volume does not exist. -+ */ -+#define EUBIMIRROR_NO_SRC 21 -+ -+/** -+ * @def EUBIMIRROR_NO_DST -+ * @brief One of the given destination volumes does not exist. -+ */ -+#define EUBIMIRROR_NO_DST 22 -+ -+/** -+ * @brief Mirrors UBI devices from a source device (specified by seqnum) -+ * to n target devices. -+ * @param devno Device number used by the UBI operations. -+ * @param seqnum An index into ids (defines the src_id). -+ * @param ids An array of ids. -+ * @param ids_size The number of entries in the ids array. -+ * @param err_buf A buffer to store verbose error messages. -+ * @param err_buf_size The size of the error buffer. -+ * -+ * @note A seqnum of value < 0 defaults to a seqnum of 0. -+ * @note A seqnum exceeding the range of ids_size defaults to 0. -+ * @note An empty ids list results in a empty stmt. -+ * @pre The UBI volume which shall be used as source volume exists. -+ * @pre The UBI volumes which are defined as destination volumes exist. -+ * @post The content of the UBI volume which was defined as source volume -+ * equals the content of the volumes which were defined as destination. -+ */ -+int ubimirror(uint32_t devno, int seqnum, uint32_t* ids, ssize_t ids_size, -+ char *err_buf, size_t err_buf_size); -+ -+#endif /* __UBIMIRROR_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1024 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Drake Dowsett, dowsett@de.ibm.com -+ * Frank Haverkamp, haver@vnet.ibm.com -+ * -+ * 1.2 Removed argp because we want to use uClibc. -+ * 1.3 Minor cleanups. -+ * 1.4 Meanwhile Drake had done a lot of changes, syncing those. -+ * 1.5 Bugfixes, simplifications -+ */ -+ -+/* -+ * unubi reads an image file containing blocks of UBI headers and data -+ * (such as produced from nand2bin) and rebuilds the volumes within. The -+ * default operation (when no flags are given) is to rebuild all valid -+ * volumes found in the image. unubi can also read straight from the -+ * onboard MTD device (ex. /dev/mtdblock/NAND). -+ */ -+ -+/* TODO: consideration for dynamic vs. static volumes */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "crc32.h" -+#include "unubi_analyze.h" -+ -+#define EXEC "unubi" -+#define CONTACT "haver@vnet.ibm.com" -+#define VERSION "1.5" -+ -+static char doc[] = "\nVersion: " VERSION "\n"; -+static int debug = 0; -+ -+static const char *optionsstr = -+"Extract volumes and/or analysis information from an UBI data file.\n" -+"When no parameters are flagged or given, the default operation is\n" -+"to rebuild all valid complete UBI volumes found within the image.\n" -+"\n" -+" OPERATIONS\n" -+" -a, --analyze Analyze image and create gnuplot graphs\n" -+" -i, --info-table Extract volume information tables\n" -+" -r, --rebuild= Extract and rebuild volume\n" -+"\n" -+" OPTIONS\n" -+" -b, --blocksize= Specify size of eraseblocks in image in bytes\n" -+" (default 128KiB)\n" -+" -d, --dir= Specify output directory\n" -+" -D, --debug Enable debug output\n" -+" -s, --headersize= Specify size reserved for metadata in eraseblock\n" -+ " in bytes (default 2048 Byte)\n" -+ /* the -s option might be insufficient when using different vid -+ offset than what we used when writing this tool ... Better would -+ probably be --vid-hdr-offset or alike */ -+"\n" -+" ADVANCED\n" -+" -e, --eb-split Generate individual eraseblock images (all\n" -+" eraseblocks)\n" -+" -v, --vol-split Generate individual eraseblock images (valid\n" -+" eraseblocks only)\n" -+" -V, --vol-split! Raw split by eraseblock (valid eraseblocks only)\n" -+"\n" -+" -?, --help Give this help list\n" -+" --usage Give a short usage message\n" -+" --version Print program version\n" -+"\n"; -+ -+static const char *usage = -+"Usage: unubi [-aievV?] [-r ] [-b ] [-d ]\n" -+" [-s ] [--analyze] [--info-table]\n" -+" [--rebuild=] [--blocksize=]\n" -+" [--dir=] [--headersize=] [--eb-split]\n" -+" [--vol-split] [--vol-split!] [--help] [--usage] [--version]\n" -+" image-file\n"; -+ -+#define ERR_MSG(fmt...) \ -+ fprintf(stderr, EXEC ": " fmt) -+ -+#define SPLIT_DATA 1 -+#define SPLIT_RAW 2 -+ -+#define DIR_FMT "unubi_%s" -+#define KIB 1024 -+#define MIB (KIB * KIB) -+#define MAXPATH KIB -+ -+/* filenames */ -+#define FN_INVAL "%s/eb%04u%s" /* invalid eraseblock */ -+#define FN_NSURE "%s/eb%04u_%03u_%03u_%03x%s" /* unsure eraseblock */ -+#define FN_VALID "%s/eb%04u_%03u_%03u_%03x%s" /* valid eraseblock */ -+#define FN_VOLSP "%s/vol%03u_%03u_%03u_%04zu" /* split volume */ -+#define FN_VOLWH "%s/volume%03u" /* whole volume */ -+#define FN_VITBL "%s/vol_info_table%zu" /* vol info table */ -+ -+static uint32_t crc32_table[256]; -+ -+/* struct args: -+ * bsize int, blocksize of image blocks -+ * hsize int, eraseblock header size -+ * analyze flag, when non-zero produce analysis -+ * eb_split flag, when non-zero output eb#### -+ * note: SPLIT_DATA vs. SPLIT_RAW -+ * vol_split flag, when non-zero output vol###_#### -+ * note: SPLIT_DATA vs. SPLIT_RAW -+ * odir_path string, directory to place volumes in -+ * img_path string, file to read as ubi image -+ * vols int array of size UBI_MAX_VOLUMES, where a 1 can be -+ * written for each --rebuild flag in the index specified -+ * then the array can be counted and collapsed using -+ * count_set() and collapse() -+ */ -+struct args { -+ int analyze; -+ int itable; -+ uint32_t *vols; -+ -+ size_t vid_hdr_offset; -+ size_t data_offset; -+ size_t bsize; /* FIXME replace by vid_hdr/data offs? */ -+ size_t hsize; -+ -+ char *odir_path; -+ int eb_split; -+ int vol_split; -+ char *img_path; -+ -+ char **options; -+}; -+ -+struct option long_options[] = { -+ { .name = "rebuild", .has_arg = 1, .flag = NULL, .val = 'r' }, -+ { .name = "dir", .has_arg = 1, .flag = NULL, .val = 'd' }, -+ { .name = "analyze", .has_arg = 0, .flag = NULL, .val = 'a' }, -+ { .name = "blocksize", .has_arg = 1, .flag = NULL, .val = 'b' }, -+ { .name = "eb-split", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "vol-split", .has_arg = 0, .flag = NULL, .val = 'v' }, -+ { .name = "vol-split!", .has_arg = 0, .flag = NULL, .val = 'e' }, -+ { .name = "help", .has_arg = 0, .flag = NULL, .val = '?' }, -+ { .name = "usage", .has_arg = 0, .flag = NULL, .val = 0 }, -+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'J' }, -+ { NULL, 0, NULL, 0} -+}; -+ -+/** -+ * parses out a numerical value from a string of numbers followed by: -+ * k, K, kib, KiB for kibibyte -+ * m, M, mib, MiB for mebibyte -+ **/ -+static uint32_t -+str_to_num(char *str) -+{ -+ char *s; -+ ulong num; -+ -+ s = str; -+ num = strtoul(s, &s, 0); -+ -+ if (*s != '\0') { -+ if ((strcmp(s, "KiB") == 0) || (strcmp(s, "K") == 0) || -+ (strcmp(s, "kib") == 0) || (strcmp(s, "k") == 0)) -+ num *= KIB; -+ else if ((strcmp(s, "MiB") == 0) || (strcmp(s, "M") == 0) || -+ (strcmp(s, "mib") == 0) || (strcmp(s, "m") == 0)) -+ num *= MIB; -+ else -+ ERR_MSG("couldn't parse '%s', assuming %lu\n", -+ s, num); -+ } -+ return num; -+} -+ -+static int -+parse_opt(int argc, char **argv, struct args *args) -+{ -+ uint32_t i; -+ -+ while (1) { -+ int key; -+ -+ key = getopt_long(argc, argv, "ab:s:d:Deir:vV?J", -+ long_options, NULL); -+ if (key == -1) -+ break; -+ -+ switch (key) { -+ case 'a': /* --analyze */ -+ args->analyze = 1; -+ break; -+ case 'b': /* --block-size= */ -+ args->bsize = str_to_num(optarg); -+ break; -+ case 's': /* --header-size= */ -+ args->hsize = str_to_num(optarg); -+ break; -+ case 'd': /* --dir= */ -+ args->odir_path = optarg; -+ break; -+ case 'D': /* --debug */ -+ /* I wanted to use -v but that was already -+ used ... */ -+ debug = 1; -+ break; -+ case 'e': /* --eb-split */ -+ args->eb_split = SPLIT_RAW; -+ break; -+ case 'i': /* --info-table */ -+ args->itable = 1; -+ break; -+ case 'r': /* --rebuild= */ -+ i = str_to_num(optarg); -+ if (i < UBI_MAX_VOLUMES) -+ args->vols[str_to_num(optarg)] = 1; -+ else { -+ ERR_MSG("volume-id out of bounds\n"); -+ return -1; -+ } -+ break; -+ case 'v': /* --vol-split */ -+ if (args->vol_split != SPLIT_RAW) -+ args->vol_split = SPLIT_DATA; -+ break; -+ case 'V': /* --vol-split! */ -+ args->vol_split = SPLIT_RAW; -+ break; -+ case '?': /* help */ -+ fprintf(stderr, "Usage: unubi [OPTION...] " -+ "image-file\n%s%s\nReport bugs to %s\n", -+ doc, optionsstr, CONTACT); -+ exit(0); -+ break; -+ case 'J': -+ fprintf(stderr, "%s\n", VERSION); -+ exit(0); -+ break; -+ default: -+ fprintf(stderr, "%s", usage); -+ exit(-1); -+ } -+ } -+ -+ /* FIXME I suppose hsize should be replaced! */ -+ args->vid_hdr_offset = args->hsize - UBI_VID_HDR_SIZE; -+ args->data_offset = args->hsize; -+ -+ if (optind < argc) -+ args->img_path = argv[optind++]; -+ return 0; -+} -+ -+ -+/** -+ * counts the number of indicies which are flagged in full_array; -+ * full_array is an array of flags (1/0); -+ **/ -+static size_t -+count_set(uint32_t *full_array, size_t full_len) -+{ -+ size_t count, i; -+ -+ if (full_array == NULL) -+ return 0; -+ -+ for (i = 0, count = 0; i < full_len; i++) -+ if (full_array[i] != 0) -+ count++; -+ -+ return count; -+} -+ -+ -+/** -+ * generates coll_array from full_array; -+ * full_array is an array of flags (1/0); -+ * coll_array is an array of the indicies in full_array which are flagged (1); -+ **/ -+static size_t -+collapse(uint32_t *full_array, size_t full_len, -+ uint32_t *coll_array, size_t coll_len) -+{ -+ size_t i, j; -+ -+ if ((full_array == NULL) || (coll_array == NULL)) -+ return 0; -+ -+ for (i = 0, j = 0; (i < full_len) && (j < coll_len); i++) -+ if (full_array[i] != 0) { -+ coll_array[j] = i; -+ j++; -+ } -+ -+ return j; -+} -+ -+/** -+ * data_crc: save the FILE* position, calculate the crc over a span, -+ * reset the position -+ * returns non-zero when EOF encountered -+ **/ -+static int -+data_crc(FILE* fpin, size_t length, uint32_t *ret_crc) -+{ -+ int rc; -+ size_t i; -+ char buf[length]; -+ uint32_t crc; -+ fpos_t start; -+ -+ rc = fgetpos(fpin, &start); -+ if (rc < 0) -+ return -1; -+ -+ for (i = 0; i < length; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF\n"); -+ return -1; -+ } -+ buf[i] = (char)c; -+ } -+ -+ rc = fsetpos(fpin, &start); -+ if (rc < 0) -+ return -1; -+ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, buf, length); -+ *ret_crc = crc; -+ return 0; -+} -+ -+ -+/** -+ * reads data of size len from fpin and writes it to path -+ **/ -+static int -+extract_data(FILE* fpin, size_t len, const char *path) -+{ -+ int rc; -+ size_t i; -+ FILE* fpout; -+ -+ rc = 0; -+ fpout = NULL; -+ -+ fpout = fopen(path, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", path); -+ rc = -1; -+ goto err; -+ } -+ -+ for (i = 0; i < len; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF while writing: %s\n", path); -+ rc = -2; -+ goto err; -+ } -+ c = fputc(c, fpout); -+ if (c == EOF) { -+ ERR_MSG("couldn't write: %s\n", path); -+ rc = -3; -+ goto err; -+ } -+ } -+ -+ err: -+ if (fpout != NULL) -+ fclose(fpout); -+ return rc; -+} -+ -+ -+/** -+ * extract volume information table from block. saves and reloads fpin -+ * position -+ * returns -1 when a fpos set or get fails, otherwise <= -2 on other -+ * failure and 0 on success -+ **/ -+static int -+extract_itable(FILE *fpin, struct eb_info *cur, size_t bsize, size_t num, -+ const char *path) -+{ -+ char filename[MAXPATH + 1]; -+ int rc; -+ size_t i, max; -+ fpos_t temp; -+ FILE* fpout = NULL; -+ struct ubi_vtbl_record rec; -+ -+ if (fpin == NULL || cur == NULL || path == NULL) -+ return -2; -+ -+ /* remember position */ -+ rc = fgetpos(fpin, &temp); -+ if (rc < 0) -+ return -1; -+ -+ /* jump to top of eraseblock, skip to data section */ -+ fsetpos(fpin, &cur->eb_top); -+ if (rc < 0) -+ return -1; -+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR); -+ -+ /* prepare output file */ -+ if (be32_to_cpu(cur->vid.vol_id) != UBI_LAYOUT_VOLUME_ID) -+ return -2; -+ memset(filename, 0, MAXPATH + 1); -+ snprintf(filename, MAXPATH, FN_VITBL, path, num); -+ fpout = fopen(filename, "w"); -+ if (fpout == NULL) -+ return -2; -+ -+ /* loop through entries */ -+ fprintf(fpout, -+ "index\trpebs\talign\ttype\tcrc\t\tname\n"); -+ max = bsize - be32_to_cpu(cur->ec.data_offset); -+ for (i = 0; i < (max / sizeof(rec)); i++) { -+ int blank = 1; -+ char *ptr, *base; -+ char name[UBI_VOL_NAME_MAX + 1]; -+ const char *type = "unknown\0"; -+ uint32_t crc; -+ -+ /* read record */ -+ rc = fread(&rec, 1, sizeof(rec), fpin); -+ if (rc == 0) -+ break; -+ if (rc != sizeof(rec)) { -+ ERR_MSG("reading volume information " -+ "table record failed\n"); -+ rc = -3; -+ goto exit; -+ } -+ -+ /* check crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &rec, -+ UBI_VTBL_RECORD_SIZE_CRC); -+ if (crc != be32_to_cpu(rec.crc)) -+ continue; -+ -+ /* check for empty */ -+ base = (char *)&rec; -+ ptr = base; -+ while (blank && -+ ((unsigned)(ptr - base) < UBI_VTBL_RECORD_SIZE_CRC)) { -+ if (*ptr != 0) -+ blank = 0; -+ ptr++; -+ } -+ -+ if (blank) -+ continue; -+ -+ /* prep type string */ -+ if (rec.vol_type == UBI_VID_DYNAMIC) -+ type = "dynamic\0"; -+ else if (rec.vol_type == UBI_VID_STATIC) -+ type = "static\0"; -+ -+ /* prep name string */ -+ rec.name[be16_to_cpu(rec.name_len)] = '\0'; -+ sprintf(name, "%s", rec.name); -+ -+ /* print record line to fpout */ -+ fprintf(fpout, "%zu\t%u\t%u\t%s\t0x%08x\t%s\n", -+ i, -+ be32_to_cpu(rec.reserved_pebs), -+ be32_to_cpu(rec.alignment), -+ type, -+ be32_to_cpu(rec.crc), -+ name); -+ } -+ -+ exit: -+ /* reset position */ -+ if (fsetpos(fpin, &temp) < 0) -+ rc = -1; -+ -+ if (fpout != NULL) -+ fclose(fpout); -+ -+ return rc; -+} -+ -+ -+/** -+ * using eb chain, tries to rebuild the data of volume at vol_id, or for all -+ * the known volumes, if vol_id is NULL; -+ **/ -+static int -+rebuild_volume(FILE * fpin, uint32_t *vol_id, struct eb_info **head, -+ const char *path, size_t block_size, size_t header_size) -+{ -+ char filename[MAXPATH]; -+ int rc; -+ uint32_t vol, num, data_size; -+ FILE* fpout; -+ struct eb_info *cur; -+ -+ rc = 0; -+ -+ if ((fpin == NULL) || (head == NULL) || (*head == NULL)) -+ return 0; -+ -+ /* when vol_id is null, then do all */ -+ if (vol_id == NULL) { -+ cur = *head; -+ vol = be32_to_cpu(cur->vid.vol_id); -+ } else { -+ vol = *vol_id; -+ eb_chain_position(head, vol, NULL, &cur); -+ if (cur == NULL) { -+ if (debug) -+ ERR_MSG("no valid volume %d was found\n", vol); -+ return -1; -+ } -+ } -+ -+ num = 0; -+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol); -+ fpout = fopen(filename, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", filename); -+ return -1; -+ } -+ -+ while (cur != NULL) { -+ size_t i; -+ -+ if (be32_to_cpu(cur->vid.vol_id) != vol) { -+ /* close out file */ -+ fclose(fpout); -+ -+ /* only stay around if that was the only volume */ -+ if (vol_id != NULL) -+ goto out; -+ -+ /* begin with next */ -+ vol = be32_to_cpu(cur->vid.vol_id); -+ num = 0; -+ snprintf(filename, MAXPATH, FN_VOLWH, path, vol); -+ fpout = fopen(filename, "wb"); -+ if (fpout == NULL) { -+ ERR_MSG("couldn't open file for writing: %s\n", -+ filename); -+ return -1; -+ } -+ } -+ -+ while (num < be32_to_cpu(cur->vid.lnum)) { -+ /* FIXME haver: I hope an empty block is -+ written out so that the binary has no holes -+ ... */ -+ if (debug) -+ ERR_MSG("missing valid block %d for volume %d\n", -+ num, vol); -+ num++; -+ } -+ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc < 0) -+ goto out; -+ fseek(fpin, be32_to_cpu(cur->ec.data_offset), SEEK_CUR); -+ -+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) -+ /* FIXME It might be that alignment has influence */ -+ data_size = block_size - header_size; -+ else -+ data_size = be32_to_cpu(cur->vid.data_size); -+ -+ for (i = 0; i < data_size; i++) { -+ int c = fgetc(fpin); -+ if (c == EOF) { -+ ERR_MSG("unexpected EOF while writing: %s\n", -+ filename); -+ rc = -2; -+ goto out; -+ } -+ c = fputc(c, fpout); -+ if (c == EOF) { -+ ERR_MSG("couldn't write: %s\n", filename); -+ rc = -3; -+ goto out; -+ } -+ } -+ -+ cur = cur->next; -+ num++; -+ } -+ -+ out: -+ if (vol_id == NULL) -+ fclose(fpout); -+ return rc; -+} -+ -+ -+/** -+ * traverses FILE* trying to load complete, valid and accurate header data -+ * into the eb chain; -+ **/ -+static int -+unubi_volumes(FILE* fpin, uint32_t *vols, size_t vc, struct args *a) -+{ -+ char filename[MAXPATH + 1]; -+ char reason[MAXPATH + 1]; -+ int rc; -+ size_t i, count, itable_num; -+ /* relations: -+ * cur ~ head -+ * next ~ first */ -+ struct eb_info *head, *cur, *first, *next; -+ struct eb_info **next_ptr; -+ -+ rc = 0; -+ count = 0; -+ itable_num = 0; -+ head = NULL; -+ first = NULL; -+ next = NULL; -+ cur = malloc(sizeof(*cur)); -+ if (cur == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(cur, 0, sizeof(*cur)); -+ -+ fgetpos(fpin, &(cur->eb_top)); -+ while (1) { -+ const char *raw_path; -+ uint32_t crc; -+ -+ cur->phys_addr = ftell(fpin); -+ cur->phys_block = cur->phys_addr / a->bsize; -+ cur->data_crc_ok = 0; -+ cur->ec_crc_ok = 0; -+ cur->vid_crc_ok = 0; -+ -+ memset(filename, 0, MAXPATH + 1); -+ memset(reason, 0, MAXPATH + 1); -+ -+ /* in case of an incomplete ec header */ -+ raw_path = FN_INVAL; -+ -+ /* read erasecounter header */ -+ rc = fread(&cur->ec, 1, sizeof(cur->ec), fpin); -+ if (rc == 0) -+ goto out; /* EOF */ -+ if (rc != sizeof(cur->ec)) { -+ ERR_MSG("reading ec-hdr failed\n"); -+ rc = -1; -+ goto err; -+ } -+ -+ /* check erasecounter header magic */ -+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) { -+ snprintf(reason, MAXPATH, ".invalid.ec_magic"); -+ goto invalid; -+ } -+ -+ /* check erasecounter header crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->ec), -+ UBI_EC_HDR_SIZE_CRC); -+ if (be32_to_cpu(cur->ec.hdr_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.ec_hdr_crc"); -+ goto invalid; -+ } -+ -+ /* read volume id header */ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ fseek(fpin, be32_to_cpu(cur->ec.vid_hdr_offset), SEEK_CUR); -+ rc = fread(&cur->vid, 1, sizeof(cur->vid), fpin); -+ if (rc == 0) -+ goto out; /* EOF */ -+ if (rc != sizeof(cur->vid)) { -+ ERR_MSG("reading vid-hdr failed\n"); -+ rc = -1; -+ goto err; -+ } -+ -+ /* if the magic number is 0xFFFFFFFF, then it's very likely -+ * that the volume is empty */ -+ if (be32_to_cpu(cur->vid.magic) == 0xffffffff) { -+ snprintf(reason, MAXPATH, ".empty"); -+ goto invalid; -+ } -+ -+ /* vol_id should be in bounds */ -+ if ((be32_to_cpu(cur->vid.vol_id) >= UBI_MAX_VOLUMES) && -+ (be32_to_cpu(cur->vid.vol_id) < -+ UBI_INTERNAL_VOL_START)) { -+ snprintf(reason, MAXPATH, ".invalid"); -+ goto invalid; -+ } else -+ raw_path = FN_NSURE; -+ -+ /* check volume id header magic */ -+ if (be32_to_cpu(cur->vid.magic) != UBI_VID_HDR_MAGIC) { -+ snprintf(reason, MAXPATH, ".invalid.vid_magic"); -+ goto invalid; -+ } -+ cur->ec_crc_ok = 1; -+ -+ /* check volume id header crc */ -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &(cur->vid), -+ UBI_VID_HDR_SIZE_CRC); -+ if (be32_to_cpu(cur->vid.hdr_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.vid_hdr_crc"); -+ goto invalid; -+ } -+ cur->vid_crc_ok = 1; -+ -+ /* check data crc, but only for a static volume */ -+ if (cur->vid.vol_type == UBI_VID_STATIC) { -+ rc = data_crc(fpin, be32_to_cpu(cur->vid.data_size), -+ &crc); -+ if (rc < 0) -+ goto err; -+ if (be32_to_cpu(cur->vid.data_crc) != crc) { -+ snprintf(reason, MAXPATH, ".invalid.data_crc"); -+ goto invalid; -+ } -+ cur->data_crc_ok = 1; -+ } -+ -+ /* enlist this vol, it's valid */ -+ raw_path = FN_VALID; -+ cur->linear = count; -+ rc = eb_chain_insert(&head, cur); -+ if (rc < 0) { -+ if (rc == -ENOMEM) { -+ ERR_MSG("out of memory\n"); -+ goto err; -+ } -+ ERR_MSG("unknown and unexpected error, please contact " -+ CONTACT "\n"); -+ goto err; -+ } -+ -+ /* extract info-table */ -+ if (a->itable && -+ (be32_to_cpu(cur->vid.vol_id) == UBI_LAYOUT_VOLUME_ID)) { -+ extract_itable(fpin, cur, a->bsize, -+ itable_num, a->odir_path); -+ itable_num++; -+ } -+ -+ /* split volumes */ -+ if (a->vol_split) { -+ size_t size = 0; -+ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ -+ /* -+ * FIXME For dynamic UBI volumes we must write -+ * the maximum available data. The -+ * vid.data_size field is not used in this -+ * case. The dynamic volume user is -+ * responsible for the content. -+ */ -+ if (a->vol_split == SPLIT_DATA) { -+ /* Write only data section */ -+ if (cur->vid.vol_type == UBI_VID_DYNAMIC) { -+ /* FIXME Formular is not -+ always right ... */ -+ size = a->bsize - a->hsize; -+ } else -+ size = be32_to_cpu(cur->vid.data_size); -+ -+ fseek(fpin, -+ be32_to_cpu(cur->ec.data_offset), -+ SEEK_CUR); -+ } -+ else if (a->vol_split == SPLIT_RAW) -+ /* write entire eraseblock */ -+ size = a->bsize; -+ -+ snprintf(filename, MAXPATH, FN_VOLSP, -+ a->odir_path, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), count); -+ rc = extract_data(fpin, size, filename); -+ if (rc < 0) -+ goto err; -+ } -+ -+ invalid: -+ /* split eraseblocks */ -+ if (a->eb_split) { -+ /* jump to top of block */ -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ -+ if (strcmp(raw_path, FN_INVAL) == 0) -+ snprintf(filename, MAXPATH, raw_path, -+ a->odir_path, count, reason); -+ else -+ snprintf(filename, MAXPATH, raw_path, -+ a->odir_path, -+ count, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ be32_to_cpu(cur->vid.leb_ver), -+ reason); -+ -+ rc = extract_data(fpin, a->bsize, filename); -+ if (rc < 0) -+ goto err; -+ } -+ -+ /* append to simple linked list */ -+ if (first == NULL) -+ next_ptr = &first; -+ else -+ next_ptr = &next->next; -+ -+ *next_ptr = malloc(sizeof(**next_ptr)); -+ if (*next_ptr == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = -ENOMEM; -+ goto err; -+ } -+ memset(*next_ptr, 0, sizeof(**next_ptr)); -+ -+ next = *next_ptr; -+ memcpy(next, cur, sizeof(*next)); -+ next->next = NULL; -+ -+ count++; -+ rc = fsetpos(fpin, &(cur->eb_top)); -+ if (rc != 0) -+ goto err; -+ fseek(fpin, a->bsize, SEEK_CUR); -+ memset(cur, 0, sizeof(*cur)); -+ -+ fgetpos(fpin, &(cur->eb_top)); -+ } -+ -+ out: -+ for (i = 0; i < vc; i++) { -+ rc = rebuild_volume(fpin, &vols[i], &head, a->odir_path, -+ a->bsize, a->hsize); -+ if (rc < 0) -+ goto err; -+ } -+ -+ /* if there were no volumes specified, rebuild them all, -+ * UNLESS eb_ or vol_ split or analyze was specified */ -+ if ((vc == 0) && (!a->eb_split) && (!a->vol_split) && -+ (!a->analyze) && (!a->itable)) { -+ rc = rebuild_volume(fpin, NULL, &head, a->odir_path, a->bsize, -+ a->hsize); -+ if (rc < 0) -+ goto err; -+ } -+ -+ err: -+ free(cur); -+ -+ if (a->analyze) { -+ char fname[PATH_MAX]; -+ FILE *fp; -+ -+ unubi_analyze(&head, first, a->odir_path); -+ -+ /* prepare output files */ -+ memset(fname, 0, PATH_MAX + 1); -+ snprintf(fname, PATH_MAX, "%s/%s", a->odir_path, FN_EH_STAT); -+ fp = fopen(fname, "w"); -+ if (fp != NULL) { -+ eb_chain_print(fp, head); -+ fclose(fp); -+ } -+ } -+ eb_chain_destroy(&head); -+ eb_chain_destroy(&first); -+ -+ return rc; -+} -+ -+ -+/** -+ * handles command line arguments, then calls unubi_volumes -+ **/ -+int -+main(int argc, char *argv[]) -+{ -+ int rc, free_a_odir; -+ size_t vols_len; -+ uint32_t *vols; -+ FILE* fpin; -+ struct args a; -+ -+ rc = 0; -+ free_a_odir = 0; -+ vols_len = 0; -+ vols = NULL; -+ fpin = NULL; -+ init_crc32_table(crc32_table); -+ -+ /* setup struct args a */ -+ memset(&a, 0, sizeof(a)); -+ a.bsize = 128 * KIB; -+ a.hsize = 2 * KIB; -+ a.vols = malloc(sizeof(*a.vols) * UBI_MAX_VOLUMES); -+ if (a.vols == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ memset(a.vols, 0, sizeof(*a.vols) * UBI_MAX_VOLUMES); -+ -+ /* parse args and check for validity */ -+ parse_opt(argc, argv, &a); -+ if (a.img_path == NULL) { -+ ERR_MSG("no image file specified\n"); -+ rc = EINVAL; -+ goto err; -+ } -+ else if (a.odir_path == NULL) { -+ char *ptr; -+ int len; -+ -+ ptr = strrchr(a.img_path, '/'); -+ if (ptr == NULL) -+ ptr = a.img_path; -+ else -+ ptr++; -+ -+ len = strlen(DIR_FMT) + strlen(ptr); -+ free_a_odir = 1; -+ a.odir_path = malloc(sizeof(*a.odir_path) * len); -+ if (a.odir_path == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ snprintf(a.odir_path, len, DIR_FMT, ptr); -+ } -+ -+ fpin = fopen(a.img_path, "rb"); -+ if (fpin == NULL) { -+ ERR_MSG("couldn't open file for reading: " -+ "%s\n", a.img_path); -+ rc = EINVAL; -+ goto err; -+ } -+ -+ rc = mkdir(a.odir_path, 0777); -+ if ((rc < 0) && (errno != EEXIST)) { -+ ERR_MSG("couldn't create ouput directory: " -+ "%s\n", a.odir_path); -+ rc = -rc; -+ goto err; -+ } -+ -+ /* fill in vols array */ -+ vols_len = count_set(a.vols, UBI_MAX_VOLUMES); -+ if (vols_len > 0) { -+ vols = malloc(sizeof(*vols) * vols_len); -+ if (vols == NULL) { -+ ERR_MSG("out of memory\n"); -+ rc = ENOMEM; -+ goto err; -+ } -+ collapse(a.vols, UBI_MAX_VOLUMES, vols, vols_len); -+ } -+ -+ /* unubi volumes */ -+ rc = unubi_volumes(fpin, vols, vols_len, &a); -+ if (rc < 0) { -+ /* ERR_MSG("error encountered while working on image file: " -+ "%s\n", a.img_path); */ -+ rc = -rc; -+ goto err; -+ } -+ -+ err: -+ free(a.vols); -+ if (free_a_odir != 0) -+ free(a.odir_path); -+ if (fpin != NULL) -+ fclose(fpin); -+ if (vols_len > 0) -+ free(vols); -+ return rc; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,463 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+/* -+ * Authors: Drake Dowsett, dowsett@de.ibm.com -+ * Contact: Andreas Arnez, arnez@de.ibm.com -+ * -+ * unubi uses the following functions to generate analysis output based on -+ * the header information in a raw-UBI image -+ */ -+ -+/* -+ * TODO: use OOB data to check for eraseblock validity in NAND images -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "unubi_analyze.h" -+#include "crc32.h" -+ -+#define EC_X_INT 50 -+ -+/** -+ * intcmp - function needed by qsort to order integers -+ **/ -+int intcmp(const void *a, const void *b) -+{ -+ int A = *(int *)a; -+ int B = *(int *)b; -+ return A - B; -+} -+ -+int longcmp(const void *a, const void *b) -+{ -+ long long A = *(long long *)a; -+ long long B = *(long long *)b; -+ return A - B; -+} -+ -+ -+/** -+ * unubi_analyze_group_index - finds the normalized index in an array -+ * item: look for this item in the array -+ * array: array to search through -+ * size: length of the array -+ * array should be sorted for this algorithm to perform properly; -+ * if the item is not found returns -1, otherwise return value is the -+ * index in the array (note this contricts the array size to 2^32-1); -+ **/ -+int -+norm_index(uint32_t item, uint32_t *array, size_t length) -+{ -+ size_t i, index; -+ -+ for (index = 0, i = 0; i < length; i++) { -+ if ((i != 0) && (array[i] != array[i - 1])) -+ index++; -+ -+ if (item == array[i]) -+ return index; -+ } -+ -+ return -1; -+} -+ -+ -+/** -+ * unubi_analyze_ec_hdr - generate data table and plot script -+ * first: head of simple linked list -+ * path: folder to write into -+ * generates a data file containing the eraseblock index in the image -+ * and the erase counter found in its ec header; -+ * if the crc check fails, the line is commented out in the data file; -+ * also generates a simple gnuplot sript for quickly viewing one -+ * display of the data file; -+ **/ -+int -+unubi_analyze_ec_hdr(struct eb_info *first, const char *path) -+{ -+ char filename[PATH_MAX + 1]; -+ size_t count, eraseblocks; -+ uint32_t crc, crc32_table[256]; -+ uint64_t *erase_counts; -+ FILE* fpdata; -+ FILE* fpplot; -+ struct eb_info *cur; -+ -+ if (first == NULL) -+ return -1; -+ -+ /* crc check still needed for `first' linked list */ -+ init_crc32_table(crc32_table); -+ -+ /* prepare output files */ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_DATA); -+ fpdata = fopen(filename, "w"); -+ if (fpdata == NULL) -+ return -1; -+ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_EH_PLOT); -+ fpplot = fopen(filename, "w"); -+ if (fpplot == NULL) { -+ fclose(fpdata); -+ return -1; -+ } -+ -+ /* make executable */ -+ chmod(filename, 0755); -+ -+ /* first run: count elements */ -+ count = 0; -+ cur = first; -+ while (cur != NULL) { -+ cur = cur->next; -+ count++; -+ } -+ eraseblocks = count; -+ -+ erase_counts = malloc(eraseblocks * sizeof(*erase_counts)); -+ if (!erase_counts) { -+ perror("out of memory"); -+ exit(EXIT_FAILURE); -+ } -+ -+ memset(erase_counts, 0, eraseblocks * sizeof(*erase_counts)); -+ -+ /* second run: populate array to sort */ -+ count = 0; -+ cur = first; -+ while (cur != NULL) { -+ erase_counts[count] = be64_to_cpu(cur->ec.ec); -+ cur = cur->next; -+ count++; -+ } -+ qsort(erase_counts, eraseblocks, sizeof(*erase_counts), -+ (void *)longcmp); -+ -+ /* third run: generate data file */ -+ count = 0; -+ cur = first; -+ fprintf(fpdata, "# eraseblock_no actual_erase_count " -+ "sorted_erase_count\n"); -+ while (cur != NULL) { -+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, &cur->ec, -+ UBI_EC_HDR_SIZE_CRC); -+ -+ if ((be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) || -+ (crc != be32_to_cpu(cur->ec.hdr_crc))) -+ fprintf(fpdata, "# "); -+ -+ fprintf(fpdata, "%zu %llu %llu", count, -+ (unsigned long long)be64_to_cpu(cur->ec.ec), -+ (unsigned long long)erase_counts[count]); -+ -+ if (be32_to_cpu(cur->ec.magic) != UBI_EC_HDR_MAGIC) -+ fprintf(fpdata, " ## bad magic: %08x", -+ be32_to_cpu(cur->ec.magic)); -+ -+ if (crc != be32_to_cpu(cur->ec.hdr_crc)) -+ fprintf(fpdata, " ## CRC mismatch: given=%08x, " -+ "calc=%08x", be32_to_cpu(cur->ec.hdr_crc), -+ crc); -+ -+ fprintf(fpdata, "\n"); -+ -+ cur = cur->next; -+ count++; -+ } -+ fclose(fpdata); -+ -+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); -+ fprintf(fpplot, "set xlabel \"eraseblock\"\n"); -+ -+ /* fourth run: generate plot file xtics */ -+ count = 0; -+ cur = first; -+ fprintf(fpplot, "set xtics ("); -+ while (cur != NULL) { -+ if ((count % EC_X_INT) == 0) { -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ fprintf(fpplot, "%zd", count); -+ } -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ fprintf(fpplot, "set ylabel \"erase count\"\n"); -+ fprintf(fpplot, "set xrange [-1:%zu]\n", eraseblocks + 1); -+ fprintf(fpplot, "# set yrange [-1:%llu]\n", -+ (unsigned long long)erase_counts[eraseblocks - 1] + 1); -+ fprintf(fpplot, "plot \"%s\" u 1:2 t \"unsorted: %s\" with boxes\n", -+ FN_EH_DATA, FN_EH_DATA); -+ fprintf(fpplot, "# replot \"%s\" u 1:3 t \"sorted: %s\" with lines\n", -+ FN_EH_DATA, FN_EH_DATA); -+ fprintf(fpplot, "pause -1 \"press ENTER\"\n"); -+ -+ fclose(fpplot); -+ -+ return 0; -+} -+ -+ -+/** -+ * unubi_analyze_vid_hdr - generate data table and plot script -+ * head: head of complex linked list (eb_chain) -+ * path: folder to write into -+ * generates a data file containing the volume id, logical number, leb version, -+ * and data size from the vid header; -+ * all eraseblocks listed in the eb_chain are valid (checked in unubi); -+ * also generates a simple gnuplot sript for quickly viewing one -+ * display of the data file; -+ **/ -+int -+unubi_analyze_vid_hdr(struct eb_info **head, const char *path) -+{ -+ char filename[PATH_MAX + 1]; -+ int rc, y1, y2; -+ size_t count, step, breadth; -+ uint32_t *leb_versions, *data_sizes; -+ FILE* fpdata; -+ FILE* fpplot; -+ struct eb_info *cur; -+ -+ if (head == NULL || *head == NULL) -+ return -1; -+ -+ rc = 0; -+ fpdata = NULL; -+ fpplot = NULL; -+ data_sizes = NULL; -+ leb_versions = NULL; -+ -+ /* prepare output files */ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_DATA); -+ fpdata = fopen(filename, "w"); -+ if (fpdata == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ -+ memset(filename, 0, PATH_MAX + 1); -+ snprintf(filename, PATH_MAX, "%s/%s", path, FN_VH_PLOT); -+ fpplot = fopen(filename, "w"); -+ if (fpplot == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ -+ /* make executable */ -+ chmod(filename, 0755); -+ -+ /* first run: count elements */ -+ count = 0; -+ cur = *head; -+ while (cur != NULL) { -+ cur = cur->next; -+ count++; -+ } -+ breadth = count; -+ -+ leb_versions = malloc(breadth * sizeof(uint32_t)); -+ if (leb_versions == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ memset(leb_versions, 0, breadth * sizeof(uint32_t)); -+ -+ data_sizes = malloc(breadth * sizeof(uint32_t)); -+ if (data_sizes == NULL) { -+ rc = -1; -+ goto exit; -+ } -+ memset(data_sizes, 0, breadth * sizeof(*data_sizes)); -+ -+ /* second run: populate arrays to sort */ -+ count = 0; -+ cur = *head; -+ while (cur != NULL) { -+ leb_versions[count] = be32_to_cpu(cur->vid.leb_ver); -+ data_sizes[count] = be32_to_cpu(cur->vid.data_size); -+ cur = cur->next; -+ count++; -+ } -+ qsort(leb_versions, breadth, sizeof(*leb_versions), (void *)intcmp); -+ qsort(data_sizes, breadth, sizeof(*data_sizes), (void *)intcmp); -+ -+ /* third run: generate data file */ -+ count = 0; -+ cur = *head; -+ fprintf(fpdata, "# x_axis vol_id lnum y1_axis leb_ver " -+ "y2_axis data_size\n"); -+ while (cur != NULL) { -+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions, -+ breadth); -+ y2 = norm_index(be32_to_cpu(cur->vid.data_size), data_sizes, -+ breadth); -+ -+ if ((y1 == -1) || (y2 == -1)) { -+ rc = -1; -+ goto exit; -+ } -+ -+ fprintf(fpdata, "%zu %u %u %u %u %u %u\n", -+ count, -+ be32_to_cpu(cur->vid.vol_id), -+ be32_to_cpu(cur->vid.lnum), -+ y1, -+ be32_to_cpu(cur->vid.leb_ver), -+ y2, -+ be32_to_cpu(cur->vid.data_size)); -+ cur = cur->next; -+ count++; -+ } -+ -+ fprintf(fpplot, "#!/usr/bin/gnuplot -persist\n"); -+ fprintf(fpplot, "set xlabel \"volume\"\n"); -+ -+ /* fourth run: generate plot file xtics */ -+ count = 0; -+ step = 0; -+ cur = *head; -+ fprintf(fpplot, "set xtics ("); -+ while (cur != NULL) { -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ if (step != be32_to_cpu(cur->vid.vol_id)) { -+ step = be32_to_cpu(cur->vid.vol_id); -+ fprintf(fpplot, "\"%zd\" %zd 0", step, count); -+ } -+ else -+ fprintf(fpplot, "\"%d\" %zd 1", -+ be32_to_cpu(cur->vid.lnum), count); -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ fprintf(fpplot, "set nox2tics\n"); -+ -+ /* fifth run: generate plot file ytics */ -+ count = 0; -+ cur = *head; -+ fprintf(fpplot, "set ylabel \"leb version\"\n"); -+ fprintf(fpplot, "set ytics ("); -+ while (cur->next != NULL) { -+ y1 = norm_index(be32_to_cpu(cur->vid.leb_ver), leb_versions, -+ breadth); -+ -+ if (y1 == -1) { -+ rc = -1; -+ goto exit; -+ } -+ -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ -+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.leb_ver), -+ y1); -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ /* sixth run: generate plot file y2tics */ -+ count = 0; -+ cur = *head; -+ fprintf(fpplot, "set y2label \"data size\"\n"); -+ fprintf(fpplot, "set y2tics ("); -+ while (cur != NULL) { -+ y2 = norm_index(be32_to_cpu(cur->vid.data_size), -+ data_sizes, breadth); -+ -+ if (y2 == -1) { -+ rc = -1; -+ goto exit; -+ } -+ -+ if (count > 0) -+ fprintf(fpplot, ", "); -+ -+ fprintf(fpplot, "\"%u\" %u", be32_to_cpu(cur->vid.data_size), -+ y2); -+ -+ cur = cur->next; -+ count++; -+ } -+ fprintf(fpplot, ")\n"); -+ -+ y1 = norm_index(leb_versions[breadth - 1], leb_versions, breadth); -+ y2 = norm_index(data_sizes[breadth - 1], data_sizes, breadth); -+ fprintf(fpplot, "set xrange [-1:%zu]\n", count + 1); -+ fprintf(fpplot, "set yrange [-1:%u]\n", y1 + 1); -+ fprintf(fpplot, "set y2range [-1:%u]\n", y2 + 1); -+ fprintf(fpplot, "plot \"%s\" u 1:4 t \"leb version: %s\" " -+ "axes x1y1 with lp\n", FN_VH_DATA, FN_VH_DATA); -+ fprintf(fpplot, "replot \"%s\" u 1:6 t \"data size: %s\" " -+ "axes x1y2 with lp\n", FN_VH_DATA, FN_VH_DATA); -+ fprintf(fpplot, "pause -1 \"press ENTER\"\n"); -+ -+ exit: -+ if (fpdata != NULL) -+ fclose(fpdata); -+ if (fpplot != NULL) -+ fclose(fpplot); -+ if (data_sizes != NULL) -+ free(data_sizes); -+ if (leb_versions != NULL) -+ free(leb_versions); -+ -+ return rc; -+} -+ -+ -+/** -+ * unubi_analyze - run all analyses -+ * head: eb_chain head -+ * first: simple linked list of eraseblock headers (use .next) -+ * path: directory (without trailing slash) to output to -+ * returns 0 upon successful completion, or -1 otherwise -+ **/ -+int -+unubi_analyze(struct eb_info **head, struct eb_info *first, const char *path) -+{ -+ int ec_rc, vid_rc; -+ -+ if (path == NULL) -+ return -1; -+ -+ ec_rc = unubi_analyze_ec_hdr(first, path); -+ vid_rc = unubi_analyze_vid_hdr(head, path); -+ if (ec_rc < 0 || vid_rc < 0) -+ return -1; -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/src/unubi_analyze.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,87 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006, 2007 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#ifndef __UNUBI_ANALYZE_H__ -+#define __UNUBI_ANALYZE_H__ -+ -+/* -+ * Author: Drake Dowsett -+ * Contact: Andreas Arnez (arnez@de.ibm.com) -+ * -+ * Eraseblock Chain -+ * -+ * A linked list structure to order eraseblocks by volume and logical number -+ * and to update by version number. Doesn't contain actual eraseblock data -+ * but rather the erasecounter and volume id headers as well as a position -+ * indicator. -+ * -+ * Diagram Example: -+ * -+ * [V1.0v0]->[V1.1v2]->[V1.2v1]->[V2.0v2]->[V2.1v0]->[V2.2v1]->NULL -+ * | | | | | | -+ * NULL [V1.1v1] [V1.2v0] [V2.0v1] NULL [V2.2v0] -+ * | | | | -+ * [V1.1v0] NULL [V2.0v0] NULL -+ * | | -+ * NULL NULL -+ * -+ * [VA.BvC] represents the eb_info for the eraseblock with the vol_id A, -+ * lnum B and leb_ver C -+ * -> represents the `next' pointer -+ * | represents the `older' pointer -+ */ -+ -+#include -+#include -+#include -+ -+#define FN_EH_STAT "analysis_blocks.txt" -+#define FN_EH_DATA "analysis_ec_hdr.data" -+#define FN_EH_PLOT "analysis_ec_hdr.plot" -+#define FN_VH_DATA "analysis_vid_hdr.data" -+#define FN_VH_PLOT "analysis_vid_hdr.plot" -+ -+struct eb_info { -+ struct ubi_ec_hdr ec; -+ struct ubi_vid_hdr vid; -+ -+ fpos_t eb_top; -+ uint32_t linear; -+ int ec_crc_ok; -+ int vid_crc_ok; -+ int data_crc_ok; -+ uint32_t phys_addr; -+ int phys_block; -+ -+ struct eb_info *next; -+ struct eb_info *older; -+}; -+ -+int eb_chain_insert(struct eb_info **head, struct eb_info *item); -+ -+int eb_chain_position(struct eb_info **head, uint32_t vol_id, uint32_t *lnum, -+ struct eb_info **pos); -+ -+int eb_chain_print(FILE *stream, struct eb_info *head); -+ -+int eb_chain_destroy(struct eb_info **head); -+ -+int unubi_analyze(struct eb_info **head, struct eb_info *first, -+ const char *path); -+ -+#endif /* __UNUBI_ANALYZE_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/testcases.txt linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/testcases.txt ---- linux-2.6.24.7.old/drivers/mtd/mtd-utils/ubi-utils/testcases.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtd-utils/ubi-utils/testcases.txt 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,9 @@ -+1. Start some large update, but write there byte-by-byte -+ -+2. start update for N bytes, write N-x bytes, then write y bytes, y>x. -+ You have to see that at the last write only x bytes were written, -+ but y-x bytes were not. we may vary x a bit. good number would be -+ 1, 128, 128Ki-128... -+ -+3. Try to start update for x bytes, write x bytes, then try to write more. -+ Check that it is impossible to write more. -diff -urN linux-2.6.24.7.old/drivers/mtd/mtd_blkdevs.c linux-2.6.24.7/drivers/mtd/mtd_blkdevs.c ---- linux-2.6.24.7.old/drivers/mtd/mtd_blkdevs.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/mtd_blkdevs.c 2009-04-12 18:13:57.000000000 +0200 -@@ -278,7 +278,7 @@ - - /* 2.5 has capacity in units of 512 bytes while still - having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ -- set_capacity(gd, (new->size * tr->blksize) >> 9); -+ set_capacity(gd, ((u_int64_t)new->size * tr->blksize) >> 9); - - gd->private_data = new; - new->blkcore_priv = gd; -diff -urN linux-2.6.24.7.old/drivers/mtd/mtdblock-jz.uu linux-2.6.24.7/drivers/mtd/mtdblock-jz.uu ---- linux-2.6.24.7.old/drivers/mtd/mtdblock-jz.uu 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtdblock-jz.uu 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,535 @@ -+begin 644 mtdblock-jz.o -+M?T5,1@$!`0````````````$`"``!```````````````T-0```1``4#0````` -+M`"@`(P`@`````````````````#P`@XR`*`4`'`!BC.K_!"0A**(```"CC/]_ -+M`CS__T(T`P!A!"008@```,*L(2````@`X`,A$(````"#C```HHP``(*L"`#@ -+M`P``HZS8_[TG(3B@`"``M*\AH(``)`"(CAP`LZ\AF,``0#`'`,`0!P"`(`<` -+M*AAF`B0`OZ\8`+*O%`"QKQ``L*\@`(F.`0#*)"$02`!$`&`4(2"(````@XP` -+M`$*,`"D#```A`@"`&`,`@!`"`",@@@`C**,`(2")`"$HJ0```(*,``"CC"L0 -+M8@`U`$`0(8C``(`0!P"`(`H`(9`"`8`8$0`J$&H"(2"(``\`0!0A&&@```"" -+MC```8XP`(0(``"D#`(`0`@"`&`,`(R""`",HHP`A((D`(2BI````@HP``*., -+M*Q!B``N(0@$?`"<2@(`1`"&`$`$``$*.```#C@`A`@``*0,`@!`"`(`8`P`C -+M(((`(RBC`"$H)0$A("0!"`"$)`X```P(`*4D(2!``@X```PA*``"(3@@`D`P -+M!P`D`(B.P!`'`(`@!P`J&&8"(`")C@$`RB0A$$@`OO]@$"$@B``V```((8C@ -+M`"0`OX\@`+2/'`"SCQ@`LH\4`+&/$`"PCP@`X`,H`+TGR/^])RP`MZ\T`+^O -+M,`"^KR@`MJ\D`+6O(`"TKQP`LZ\8`+*O%`"QKQ``L*\\`)6,`!$%`"``M(Z` -+M*`4`(Q!%`"$05``(`%*,``"GCB0`OHXJ$$<"*0!`$"&X0`(`$1(`@"@2`",P -+M10`A&(8"#`!DC```8HPK$((`(`!`$`P`TR2=```(([#R`"``HHXA$&("#`!$ -+MC```0XPK&(,`%P!@$`P`/*`"VCR0`M8\@`+2/'`"SCQ@` -+MLH\4`+&/$`"PCP@`X`,X`+TG```#/`@`X`/8`&*,```#/`@`X`/<`&*,Z/^] -+M)Q``L*\4`+^O````#"&`@``A(``"%`"_CQ``L(\````(&`"])^#_O2<0`+"O -+M(8"@`!0`L:\A*```(8B```@`!B08`+^O````#"$@``($``,D$``")`$``J(` -+M``.B(``CCB$0``""&0,``@`#IA@`OX\4`+&/$`"PCP@`X`,@`+TGX/^])QP` -+MOZ\4`+&O&`"RKQ``L*\``(*,(8B``*@`0XP4`%*,4`!DC%0`<(P!``@D(X`$ -+M`@2`"`+__Q`R)``DCD*2$@`(`":N!``EKB$P``(,`">N+``HKO__4C(````, -+M(2@```(P$G(H`"2.'`"_CQ@`LH\4`+&/$`"PCR$H```````((`"])XC_O2=P -+M`+^O;`"WKV@`MJ]D`+6O8`"TKUP`LZ]8`+*O5`"QKU``L*\\`(.,``"3C``` -+M:(RH`'*.`0`")0(`0B@@`&>,5`!&CE``1(X9`$`4)`!CC",0Q``!`!0D!!!4 -+M`/__0C`A,&``__]5)"$@```8`+8G```7/`0`T(P!`(0D@!`0```9$``C&&(` -+M(8CC``0`(I(!`$,P`@!",`,`0!0$`,8D$`!@%`````#R_X@4`````/3_`R1P -+M`+^/;`"WCV@`MH]D`+6/8`"TCUP`LX]8`+*/5`"QCU``L(\A$&``"`#@`W@` -+MO2<``+"L(2#``B$H```````,.``&),P`Y28,``(D(1@```(`!"0P`**O-`"C -+MKT@`I:\8`+2O0`"DKU0`2([#'Q``)S`(`$(X$`!0`$2.!CC'``08`P$@``8Q -+M!!`0`248XP`+&$8`!""5``L0!@`A,$0`PR\$`!``MJ\K0,(`(3AE`$@`8HXA -+M.`O>`"VKW0`M:]P`+2O;`"SKV@`LJ]D`+&O8`"PKP```CP,`)&,)`!"C!P` -+MD(Q7`$`0J``SCAT``A(```(\*`!")(8"``@!``0D&``#$@```````$.,`0"$ -+M)/O_8!0$`$(D```#/```8HP?`$`0```2/```8B0$`$*,#`!`$``````7``(2 -+M```"/`@`0B29`@`(`0`$)!0``Q(``!(\``!#C`$`A"3[_V`4!`!")"$0``"$ -+M`+^/@`"^CWP`MX]X`+:/=`"UCW``M(]L`+./:`"RCV0`L8]@`+"/"`#@`X@` -+MO2.)R`&`$`8"0`$&(,`!B#'`"4@9``@`,@P!BC)``L@J``A$(("```$K@`` -+M0XPC$(,`"``#K@\`0!P$``*N```$/`````P``(0D```%C@@`!HX```0\```` -+M#```A"0```0\````#```A"0```2.__^")`0``JX$``*.#``$KM"`!32`(`(` -+M````#!```JX```2.'``"K@`1!`"`(`0`(R!$``````S0``4D```$CB```JZ` -+M(`0`!`"$)`````S0``4D(1A``!P``HY;_T`0)``#KB```HX5_T`0]/\")!/_ -+M8!`AD```4`"@KR&8```\`+"N```1CB&P0`(J$%$"5`!`$%@`LJ]"*!(`(8@` -+M`%P`I:]4`**/7`"ECU0`1(P8`*,G$`"CKR<8!``&&&4`!#B3`"``A3`E.&<` -+M!#"2`$@`XHX+.,4`(2#@`@GX0``+,`4````"/,P`1"3,`$.,!`""C`8`8A`! -+M`#$F````#``````J$"("Y_]`%%0`HH\@``*.4`"ECP$``R0A$*(`!`!#H``` -+M`CS,`$(D"`!#C/__`B1F`&(04`"DCR```HXA$((```!#K"0``XZ`$!(`(1!# -+M``0`5JQ0`*6/(``#C@$`PB8A&*,`"`!BK%0`HH]<`*6/5`!$C(``XHXG&`0` -+M!AAE``0XDP`@`(4P!#"2`"4X9P`+.,4````#/`LP!0`A(.`""?A``,P`<8Q# -+M`$`06`"FCU@`I8\K`@`,(2"@`@$`0B8K(%(`(1B3`%``I(\AD$``#`"$)"&8 -+M8`"/`P`(4`"DK\(7$0`\`+*.(1!1`$.``@`@`%:."```&B0`4XXA*``"(2!` -+M`O__$"83```,(3`@`OO_`!8A*``"`@`B*AL`0!2`$!$`(8!3``$`%R0$`',F -+M```#C@``8HX`*0,``"$"`(`8`P"`$`(`(R""`",HHP`A(,0"(2C%`@@`A"0. -+M```,"`"E)/__,28A*``"#@``#"$@8`(A($`"`0`%)!,```PA,"`"ZO\W%OS_ -+M$";__P,D3`#")P0`HZXA$(("```#/```5:S8`'6L``"DC@```CR=`@`(W`!$ -+MK"$H(`+N`0`,(2"@`M\#``@!`$(F(``"CB$0H@#``P`(``!`K'C_O2=\`+.O -+M>`"RKW``L*\<`*"O(`"@KX``OZ]T`+&O&`"@KR0`H*\H`*"O``"#CP```CP0 -+M`+,G``!")"&`@``<`*.O(`"BKR$@8`(AD*``````#*@`$8X```(\*!9")&`` -+MHJ\P`+"O5``GCL,?$@`G*`<`0B`2``8@I``$,.,`)3#$`#P`IJ]4`"2.$``% -+MC@00D@`@`.`"RCW0`L8]P`+"/"`#@`X@`O2<````,```` -+M`"$@8`(````,(2@@`B$0``*``+^/?`"SCW@`LH]T`+&/<`"PCP@`X`.(`+TG -+MX/^])QP`OZ\8`+*O%`"QKQ``L*\D`*6O``"0C`0`A8PAD(``OP$`#*@`$8XD -+M`*6/*P(`#"$@0`(D`*6/)@0`#"$@``(```4\```$/```I20F`$`4``"$)%0` -+M)(XD`**/(`"%,"$P0`##/P(`0A@"`"<0!``&&$,`!#B'`"4X9P`$,(8`A``" -+MC@LXQ0`A(``""?A```LP!0`A($`""`$`#"0`I2<```0\```%/```A"0#`$`0 -+M``"E)`````P`````!`!%CB0`IH_N`0`,(2!``B0`HH\<`+^/&`"RCQ0`L8\0 -+M`+"/"`#@`R``O2<````,)`"FCYD$``A4`"2.@/^])W``MJ]\`+^O>`"^KW0` -+MMZ]L`+6O:`"TKV0`LZ]@`+*O7`"QKU@`L*^``*2O``"3C#P`@HRH`'6.$`!D -+MCH0`I:\@`$*,T``%)%``HJ]4`+&.````#%``L(ZD`$`0(;!``!@`I"/<`"VCVP`M8]H`+2/9`"SCV``LH]<`+&/6`"PCP@` -+MX`.``+TG9`4`"```A"1\`+^/>`"^CW0`MX]P`+:/;`"UCV@`M(]D`+./8`"R -+MCUP`L8]8`+"/]/\")`@`X`.``+TG-`"$C`,`!20!``8D````""$X```@_[TG -+MT`"VK[P`L:_<`+^OV`"^K]0`MZ_,`+6OR`"TK\0`LZ_``+*ON`"PKP``@HP! -+M`!$DK`"BKZ@`0XP\`(6,J`"CKU0`8HQ0`&.,(`"EC",00P`$$%$`__]","&P -+M@``L`(2,I`"EKZ``HJ\X`,6.#@"`%)P`I:_<`+^/V`"^C]0`MX_0`+:/S`"U -+MC\@`M(_$`+./P`"RC[P`L8^X`+"/(1````@`X`/@`+TG&`"D)R$H```````, -+M.``&)*P`J(\8`+&O%``$C0P``B0``-6.,`"BKP```CP@`*2O(1@```(`!"3, -+M`$(D-`"CKT``I*\D`*"O2`"BKZ@`HXX4`**.E`"CKS@`Q(Z4`*6/F`"DKT(2 -+M`@#__UC@(0T'/__Q`FC`"BK[``L*^(`*"O -+MB`"CCR0`PH[__W,P(1!3````0Y"B`&`0E`"DCQ$`X!("$'=RD`"BKY``HX\H -+M`,*.(2!#````@Y`,`6`0E`"EC_\%``@AD`````!"D`@!0!"4`*6/`0!")O__ -+M4C#Z__(6(1"2`+``HX^(`*2/__]B,`$`A"0!`$(DX?]$%(@`I*\(`->.(8@` -+M`(`@%P``&1<`I`"ECR.09``A@+(`!``"D@0`0C!D`$`0`````/G_(`:D`*6/ -+M``#4CCP`QXZH`)..`0`1)%``8XY4`&*.4`"D)R,00P`$$%$`(2@``#@`!B0@ -+M`/",````#/__7C!0`+&O```(/!0`AXX```@E#``")```!(UH`**O```"/"$8 -+M``#_``4D6`"GK\P`0B0"``O7`"@KP````R``**O!`## -+MC@``!#S,`(.L!`#"CLP`A20A@%`"!`"BK````XZ9`,`;"`"CK"&`X`+#CQ<` -+M(9```$D&``A"J!<`D@#2$P````!4`&>.4`!HCB_T`4__\1)*P`I(\F!``,(2C@`B&(0``` -+M``*.(2#``@$`0B0```*N=```#"$HX`*4_R$&(2C@`H($``PA(,`"```$/``` -+M!3PA,.`"``"$)`@`PJX``*4D````#"$X0``(`->.@"`7``X&``@`&1<`C`"E -+MCU``AXPA$+,`(1@``$(H`@`G(`<`!BB%``2(XP`@`.8P!(#B`"6(L0`+B`8" -+MIP8`"`N`!@!(`$*.`0!")`4`0R@F`&`02`!"KI0`J(]0``>-(`#"C@08\P`A -+M$$,`?`"BKU``HB<0`**O2`"BCB$P``(A."`""?A``"$@H`(``!0\```$/``` -+MA"0``(4F(3#``Q<`0!`A.&`"```#/$@`8HPAD&``````#!``HJ\,`,.."`#" -+MC@``!#S>_V(4``"$)`````P`````2`!"C@$`0B0%`$,HW/]@%$@`0JX```0\ -+M``"$)```A28````,(3#``P``!#RP`*./2`"`K(@`I(___V(P`0"$)`$`0B03 -+M_T04B`"DKPL&``@(`->.````#`````"!`$`0H`"BCW\`0!@"$%=P(8!``*`` -+MHH_F!@`((9`"`GD`$A(`````J`"CCYP`I8]0`&2,&`"H)Q``J*\G$`0`K`"H -+MCT(8$``A.```1`"EKP880P`$.(<`(`"%,`0PD``E.&<`2``"C0LXQ0`A(``! -+M"?A```LP!0`!`!`FZ/]`$"&(0``A*.`"@@0`#"$@P`(AN$``@"`"```9`@`. -+M!@`("`#"KB&0``",`*B/4`"FC"$0:`(A&```0B@"`"<@!@`&*(4`!(C#`"`` -+MQS`$@,(`)8BQ``N(!P(9!P`("X`'`$0`@HX!`$(D!0!#*"(`8!!$`(*NF`"B -+MCU``HR=\`**O$`"CKT@`HHXA,``"(3@@`@GX0``A(*`"```%/```"#P``*0D -+M(3#``P``!248`$`0(3A@`@```SQ$`&*,(:!@``````P0`**O#`##C@@`PHX` -+M``4\XO]B%```I"0````,`````$0`@HX!`$(D!0!#*.#_8!1$`(*N```$/``` -+M"#P``(0D```%)0````PA,,`#```#/"L05P((`$`41`!@K`0&``BP`*./`0!" -+M)O__4C`K&%<"NOY@$+``HX\H`,*.D`"DCY@`J(\A$((`(1!2````0Y!`.A(` -+M(2@'`?+_8!0``@8DE`"BCU``1(P@`,*.!""3`"$@AP`````,(2""`$<'``@! -+M`$(F#`#0C@@`PHX8``(24`"D)P``T8X\`,*.(2@``#@`!B0@`%*,````#*@` -+M,XX,``(D`0`&)&@`HJ\```(\4`"FKR$8```"``8DS`!")"$@(`(A*``";`"C -+MKW@`IJ\F!``,@`"BKR(`0!````,\``#"C@$`$"2H`$.,%`!1C%``9(Q4`&*, -+M0HH1`",01``$@%``__\0,B0`Q(XA,``"__\Q,BP`P*X````,(2@```(P$7(H -+M`,2.````#"$H``#<`+^/V`"^C]0`MX_0`+:/S`"UC\@`M(_$`+./P`"RC[P` -+ML8^X`+"/(1````@`X`/@`+TG``!C)```9(S_``4D````#`P`!B2`&!```!$0 -+M`",00P`A$$("``!#C```!#P!`&,DS`"$)```0ZP(`(.L5`!DCE``I2O -+M=`"UKW``M*]L`+.O:`"RKV``L*^$`+^O@`"^KW@`MJ]D`+&O``"1C"&@@``4 -+M`"*.J``VCD(2`@#__T0P&P"D`/0!@``!`!OD`"FKQ*H``!)`*,2$(`` -+M`!@`OB>Q"``((`"W)P````P`````&P!R`O0!0`(!``(D(`"BKQ0`(XX8`**/ -+M,`"'CC0`A8XH`*.O(2`@`BP`H*\0,````AA"/>`"VCW0`M8]P`+2/;`"SCV@`LH]D -+M`+&/8`"PCR$0```(`.`#B`"])P(8D'`H`(*.6`"DCR$08@`A$$0```!#D"H` -+M8!`@`+,G0!($`"``@XX$*+``(2BB`"$HHP`````,(2#@`(0`OX^``+Z/?`"W -+MCW@`MH]T`+6/<`"TCVP`LX]H`+*/9`"QCV``L(\A$```"`#@`X@`O2. -+M-`"0KE@`I(^0`*:/0"H$`)0`I(\````,(2BG`(0`OX^``+Z/?`"WCW@`MH]T -+M`+6/<`"TCVP`LX]H`+*/9`"QCV``L(\A$```"`#@`X@`O2"5X("T^ -+M($Y53$P*`&1R:79EF]N95]P -+M='(@:7,@;G5L;`H```!Z;VYE7W!T"`*`````"5S.B!W"`*`````"5S.B!F:6QL -+M7V)L;V-K,2!P:'ES7V)L;V-K.B5D+'!A9V4Z)60L7-?8FQO -+M8VL*````)7,Z(')E861I;F<@97)R;W(@=VAE;B!M;V1I9GEI;F<@<&AY"5X(&5R87-I -+M;F<@9F%I;&5D+"!M87)K960@8F%D+"!A;F0@9FEN9"!N97<@8FQO8VL@,'@E -+M>`H`````)7,Z('!H>7-?8FQO8VL@,'@E>"!P````!T````?````]`4`````#X#X____```````` -+M```H````'0```!\```#\!@``````@/C___\``````````!@````=````'P`` -+M`+@'``````>`_/___P``````````(````!T````?````K`@``````X#X____ -+M```````````@````'0```!\```"X"0````#_P/S___\``````````(@````= -+M````'P```)@0``````^`^/___P``````````B````!T````?````"!(````` -+M!X#\____```````````@````'0```!\````$$P````#_P/S___\````````` -+M`(`````=````'P```"@6`````````````````````````````!T````?```` -+M````````````````````````````````'0```!\```````````#_P/S___\` -+M`````````.`````=````'P```/@>``````.`^/___P``````````(````!T` -+M```?````;!\`````#X#X____```````````H````'0```!\````````````# -+M@/C___\``````````"`````=````'P```'@A`````/_`_/___P`````````` -+MB````!T````?`````````````8#\____```````````8````'0```!\```!4 -+M)0`````````````````````````````=````'P```'@E`````/^`^/___P`` -+M````````0````!T````?`````````````(#X____```````````8````'0`` -+M`!\```"D)P`````````````````````````````=````'P````!'0T,Z("A' -+M3E4I(#0N,2XR```N6UT86)?9W!L -+M`"YR96Q?7VMC"\``"0```````````````0````````` -+MVP````D```````````````Q)```P````(0```!<````$````"````.L````! -+M`````P````````"<+P``&P```````````````0````````#V````"`````,` -+M````````P"\``/```````````````!``````````^P````@````#```0```` -+M`,`O```````````````````$``````````4!```!``````````````#`+P`` -+M0`0`````````````!``````````!`0``"0``````````````/$D``!`!```A -+M````'`````0````(````"@$```$````````````````T```````````````` -+M```!`````````!@!```!````````````````-```$@```````````````0`` -+M```````1`````P``````````````$C0``"$!``````````````$````````` -+M`0````(``````````````$Q*``"0"@``(@```(8````$````$`````D````# -+M``````````````#<5```@`@``````````````0````````!H`0``!`$``'0! -+M```$`0``J`$```0!``!0`@``!`$``*@"```$`0``M`(```0!``#\`@``!1H` -+M``0#```&&@``"`,```4:```0`P``!AH``"`#```$J```-`,```2+``!<`P`` -+M!)D``/0#```$F0``&`0```29```4!0``!)D``!P%```&&@``F`4```8:``#L -+M!0``!`$```P&```%HP``%`8```:C``````0!0```9X``!$%```!)<``+`2```%:```2!0```9H``!P%``` -+M!`$``(`4```%>0``A!0```9Y```\%```!6@``(P4```&:```D!0```27``"H -+M%```!`$``+@4```$`0``Z!0```0!```H%0``!`$``(@5```%>@``C!4```9Z -+M``"4%0``!)<``'P4```%:```F!4```9H``"@%0``!`$``*@5```$`0``L!4` -+M``2+``#L%0``!`$``/04```%>P``\!4```9[```T%@``!(X``/`6```$F0`` -+M$!<```4:```@%P``!AH``'07```$F0``Z!<```0!``",&```!)D``)@8```% -+M?```H!@```9\``"P&```!1H``,`8```&&@``V!@```29``#D&```!1H``.@8 -+M```&&@``E`0```4:``#P&```!AH``!09```$`0``D!D```0!``"8&0``!7T` -+M`*09```&?0``K!0```5H``"H&0``!F@``+`9```$EP``Y!D```0!````&@`` -+M!`$``!`:```$`0``&!H```5^```D&@``!GX``)P9```%:```+!H```9H```P -+M&@``!)<``$`:```$`0``>!H```0!``"`&@``!AH``)`:```&&@``S!H```5_ -+M``#0&@``!G\``!P:```%:```U!H```9H``#D&@``!1H``.@:```&&@``\!H` -+M``27````&P``!8````@;```&@```#!L```27```4&P``!AH``"0;```&&@`` -+M*!L```6!```L&P``!H$``,@:```%:```,!L```9H```T&P``!)<``#P;```% -+M&@``1!L```8:``!@&P``!`$``&@;```$E0``B!L```0!``#X&P``!`$```P< -+M```$`0``2!P```0!``!0'```!AH``&`<```&&@``B!P```6"``"0'```!H(` -+M`(P<```%:```F!P```9H``"D'```!1H``*@<```&&@``L!P```27``#`'``` -+M!8```,@<```&@```S!P```27``#4'```!AH``.0<```&&@``Z!P```6!``#P -+M'```!H$``.P<```%:```]!P```9H``#X'```!)<````=```%&@``#!T```8: -+M```0'0``!`$``&@=```$B@`````$F0``+!X```29``#@'0``!7P``&@>```&?``` -+M=!X```29``"0'@``!1H``)@>```&&@``Z!X```0!``#P'@``!`$```P?```% -+M&@``$!\```8:```D'P``!)8``"P?```$G@``-!\```2=``"$'P``!1H``(@? -+M```&&@``G!\```0!``"8'P``!1H``*`?```&&@``N!\```4:``"\'P``!AH` -+M`,0?```&&@``W!\```0!``#8'P``!1H``.`?```&&@``&"````4:```@(``` -+M!AH``#0@```$E@``/"````2>``!$(```!)T``'0@```$BP``?"````2+``"$ -+M(```!(L``(P@```$BP``E"````2+``"<(```!(L``*0@```$BP``K"````2+ -+M``"T(```!(L``+P@```$BP``Z"````4:``#L(```!AH``/@@```%@P``_"`` -+M``:#````(0``!)<``/0@```%#P``!"$```8/```((0``!`$``"@A```$E@`` -+M,"$```2>```X(0``!)T```PB```$`0``%"(```29``"4(@``!6@``*`B```& -+M:```F"(```6$``"D(@``!H0``)PB```%#P``K"(```8/``"P(@``!)<``+PB -+M```$`0``S"(```0!``#L(@``!)D``%PC```$B@``L",```2*``#T(P``!)D` -+M`(@D```$B@``S"0```0!``#4)```!`$``-PD```$E@``Y"0```2>``#L)``` -+M!)T``/0D```%:````"4```9H``#X)```!80```0E```&A```""4```27``#\ -+M)```!0\```PE```&#P``%"4```0!```<)0``!`$``#@E```$`0``6"4```4: -+M``!@)0``!AH``'`E```$`0``^"4```0!```4)@``!`$``"`F```$`0``/"8` -+M``0!``!,)@``!`$``)0F```$B@``V"8```26``#@)@``!)X``.@F```$G0`` -+M]"8```0!````)P``!`$```PG```%A0``+"8```6%```4)P``!H4``!@G```$ -+MEP``$"<```5H```<)P``!F@``"`G```$`0``+"<```26```T)P``!)X``#PG -+M```$G0``2"<```0!``!@)P``!`$``&@G```%A0``;"<```:%``!P)P``!)<` -+M`%0G```%:```="<```9H``!X)P``!`$``(PG```$`0``J"<```4:``"P)P`` -+M!AH``,`G```$`0``$`````4:```4````!AH``"`````%&@``*`````8:```P -+M````!*```%@````%&@``8`````8:``!H````!*```)0````$FP``D`````41 -+M``"8````!A$```0````$D0````````41```(````!A$````````"&@`````` -+M``*4```$`````A````@````"H0``#`````(0```0`````HD``!0````"$``` -+M&`````*0```<`````A```"`````"B```)`````(0`````````J4```0````" -+MI@``"`````*?```,`````HT``!`````"AP````````((```4`````@$``!@` -+M```"`0``'`````(!```@`````@$``"0````"`0``*`````(!```L`````@$` -+M`#`````"`0````````(%`````````@,````````"&0``!`````(#```,```` -+M`AD``!`````"`P``&`````(9```<`````@,````````"`0``(`````(!``!` -+M`````@$``&`````"`0``@`````*)``"@`````J$``,`````"`P``X`````(# -+M`````0```@,``"`!```"`P``0`$```(!``!@`0```@$``(`!```"`0``H`$` -+M``(!``#``0```@$``.`!```"`0````(```(!```@`@```@$``$`"```"`0`` -+M8`(```(!``"``@```@$``*`"```"`0``P`(```(!``#@`@```@4````#```" -+MG@``(`,```(!``!``P```@$``&`#```"E```@`,```(!``"@`P```H@``,`# -+M```"`0``X`,```(!````!````I```"`$```"`0`````````````````````` -+M``````````````````,``0`````````````````#``(````````````````` -+M`P`#``````````````````,`!``````````````````#``4````````````` -+M`````P`&``````````````````,`!P`````````````````#``@````````` -+M`````````P`)``````````````````,`"@`````````````````#``L````` -+M`````````````P`,``````````````````,`#0`````````````````#``X` -+M`````````````````P`/``````````````````,`$``````````````````# -+M`!$``````````````````P`2``````````````````,`$P`````````````` -+M```#`!0``````````````````P`5``````````````````,`%@`````````` -+M```````#`!<``````````````````P`8``````````````````,`&0`````` -+M```````````#`!H``````````````````P`;``````````````````,`'``` -+M```````````````#`!T``````````````````P`>``````````````````,` -+M'P`````````````````#`"```````````````````P`A```````````````` -+M``,`(@`!```````````````$`/'_#P`````````X`````@`!`"H````X```` -+M%`````(``0`X````3````(0!```"``$`3````-`!```L`0```@`!`&4```#8 -+M````!`````$`&@!R````W`````0````!`!H`?``````````@`````@`#`(P` -+M``!`````!`````$`&@"6````(````#@````"``,`I````"`````@`````0`: -+M`*T```!8````.`````(``P"Z`````````"`````!`!H`P@```)`````,```` -+M`@`#`-``````````3`````$`$0#<````%`,``"@````"``$`\````#P#``!< -+M`````@`!```!``"8`P``B`````(``0`;`0``(`0``-0!```"``$`-`$``,P` -+M```,`````0`:`#T!``#T!0``"`$```(``0!.`0``_`8``+P````"``$`<`$` -+M`+@'``#T`````@`!`)`!```D````(`````$`#P"?`0``K`@```P!```"``$` -+MP0$``+@)``#@!@```@`!`,\!``#@````!`````$`&@#:`0``3````(`````! -+M`!H`X@$``!0````.`````0`/`/$!``````````````$`&P#]`0``F!```'`! -+M```"``$`"0(``"@6```4`````@`!`!@"```($@``_`````(``0`X`@``!!,` -+M`"0#```"``$`5P(````````,`````@`%`&@"``!(````!`````$`&@!Z`@`` -+M1`````0````!`!H`C`(``/@>``!T`````@`!`)L"``!L'P``I`$```(``0"L -+M`@```````!$````!``\`NP(``'@A``"L`P```@`!`,H"``!$````#P````$` -+M#P#9`@``5"4``"0````"``$`ZP(``'@E```(`@```@`!`/L"``"D)P``)``` -+M``(``0`.`P````````0````!`!,`*@,````````$`````0`5`$0#```````` -+M#`````$`%P!<`P````````H````!`!D`>`,```P````,`````0`7`(X#```* -+M````"0````$`&0"H`P``&`````P````!`!<`O0,``!,````(`````0`9`-8# -+M````````"`````$`"P#P`P```````!`````!`!``"@0````````$`````0`- -+M`"0$```(````"`````$`"P`Z!```$`````P````!`!``4`0```0````$```` -+M`0`-`&8$```0````"`````$`"P!_!```'`````\````!`!``F`0```@````$ -+M`````0`-`+$$```8````"`````$`"P#2!```+````!<````!`!``\P0```P` -+M```$`````0`-`!0%```@````"`````$`"P`T!0``1````!8````!`!``5`4` -+M`!`````$`````0`-`'0%````````````````"`!Y!0``+`````````````@` -+M?@4``$@````````````(`(,%``!@````````````"`"(!0``=``````````` -+M``@`C04``)0````````````(`)(%``#4````````````"`"7!0``,`$````` -+M``````@`G`4```P!```````````(`*$%``!(`0``````````"`"F!0``8`$` -+M``````````@`K`4``'@!```````````(`+(%``"D`0``````````"`"X!0`` -+M[`$```````````@`O@4``#`"```````````(`,0%``!,`@``````````"`#* -+M!0``>`(```````````@`T`4``)P"```````````(`-8%``#,`@`````````` -+M"`#BYC`&UT9&)L;V-K7V%D9')E0!M=&1B;&]C:U]L:69E=&EM95]R97-O0!?7V9U;F-?7RXQ-3,T.0!M -+M=&1B;&]C:U]B;&]C:U]I;F9O7VUA<%]B861?8FQO8VL`;71D8FQO8VM?;W!E -+M;@!M=&1B;&M?:61X`&UT9&)L:W,`7U]F=6YC7U\N,38Q.#,`7U]K97DN,38P -+M-3,`97)A&ET8V%L;%]C;&5A;G5P7VUT9&)L;V-K`%]?:6YI=&-A;&Q? -+M:6YI=%]M=&1B;&]C:S8`7U]S971U<%]M=&1B;&ML;V=?6UT86)?=61C7V9L=7-H -+M7V-A8VAE`%]?:W-T6UT86)?=61C7V=E=%]M=&0`7U]K6UT86)? -+M=61C7V=E=%]M=&1B;&L`7U]K6UT86)?=61C7VUT9&)L;V-K7W=R -+M:71E6UT86)?=61C7VUT -+M9&)L;V-K7W)E861S96-T`%]?:W-T%]L;V-K`'!R:6YT:P!?7VUU=&5X7VEN:70` -+M;65M - * (C) 1999-2003 David Woodhouse -@@ -15,7 +15,7 @@ - #include - #include - #include -- -+#include - #include - #include - #include -@@ -361,12 +361,27 @@ - kfree(dev); - } - -+ -+static int mtdblock_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) -+{ -+ struct gendisk *gd = dev->blkcore_priv; -+ memset(geo, 0, sizeof(*geo)); -+ geo->heads = 4; -+ geo->sectors = 16; -+ geo->cylinders = dev->size/(4*16); -+ -+ printk("cylinders: %x \n", geo->cylinders); -+ printk("sects: %x\n", dev->size); -+ return 0; -+} -+ - static struct mtd_blktrans_ops mtdblock_tr = { - .name = "mtdblock", - .major = 31, - .part_bits = 0, - .blksize = 512, - .open = mtdblock_open, -+ .getgeo = mtdblock_getgeo, - .flush = mtdblock_flush, - .release = mtdblock_release, - .readsect = mtdblock_readsect, -diff -urN linux-2.6.24.7.old/drivers/mtd/mtdchar.c linux-2.6.24.7/drivers/mtd/mtdchar.c ---- linux-2.6.24.7.old/drivers/mtd/mtdchar.c 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/mtdchar.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ -+ * $Id: mtdchar.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ - * - * Character-device access to raw MTD devices. - * -@@ -7,7 +7,6 @@ - - #include - #include --#include - #include - #include - #include -@@ -83,8 +82,6 @@ - return -EINVAL; - } - -- -- - static int mtd_open(struct inode *inode, struct file *file) - { - int minor = iminor(inode); -@@ -137,8 +134,7 @@ - - DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - -- /* Only sync if opened RW */ -- if ((file->f_mode & 2) && mtd->sync) -+ if (mtd->sync) - mtd->sync(mtd); - - put_mtd_device(mtd); -@@ -157,7 +153,7 @@ - { - struct mtd_file_info *mfi = file->private_data; - struct mtd_info *mtd = mfi->mtd; -- size_t retlen=0; -+ size_mtd_t retlen=0; - size_t total_retlen=0; - int ret=0; - int len; -@@ -251,7 +247,7 @@ - struct mtd_file_info *mfi = file->private_data; - struct mtd_info *mtd = mfi->mtd; - char *kbuf; -- size_t retlen; -+ size_mtd_t retlen; - size_t total_retlen=0; - int ret=0; - int len; -@@ -536,7 +532,7 @@ - { - struct mtd_oob_buf buf; - struct mtd_oob_ops ops; -- -+ - if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) - return -EFAULT; - -@@ -576,6 +572,73 @@ - break; - } - -+ case MEMWRITEPAGE: -+ { -+ struct mtd_page_buf buf; -+ struct mtd_oob_ops ops; -+ -+ memset(&ops, 0, sizeof(ops)); -+#if 1 -+ if(!(file->f_mode & 2)) -+ return -EPERM; -+#endif -+ -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_page_buf))) -+ return -EFAULT; -+ -+ if (buf.ooblength > mtd->oobsize) -+ return -EINVAL; -+ -+ if (!mtd->write_oob) -+ ret = -EOPNOTSUPP; -+ else -+ ret = access_ok(VERIFY_READ, buf.oobptr, -+ buf.ooblength) ? 0 : EFAULT; -+ -+ if (ret) -+ return ret; -+ -+ ops.len = mtd->writesize; -+ ops.ooblen = buf.ooblength; -+ ops.ooboffs = buf.start & (mtd->oobsize - 1); -+ ops.mode = MTD_OOB_PLACE; -+ -+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) -+ return -EINVAL; -+ -+ /* alloc memory and copy oob data from user mode to kernel mode */ -+ ops.oobbuf = kmalloc(buf.ooblength, GFP_KERNEL); -+ if (!ops.oobbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(ops.oobbuf, buf.oobptr, buf.ooblength)) { -+ kfree(ops.oobbuf); -+ return -EFAULT; -+ } -+ -+ /* alloc memory and copy page data from user mode to kernel mode */ -+ ops.datbuf = kmalloc(mtd->writesize, GFP_KERNEL); -+ if (!ops.datbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(ops.datbuf, buf.datptr, mtd->writesize)) { -+ kfree(ops.datbuf); -+ return -EFAULT; -+ } -+ -+ buf.start &= ~(mtd->oobsize - 1); -+ ret = mtd->write_oob(mtd, buf.start, &ops); -+ -+ if (copy_to_user(argp + 2*sizeof(uint32_t), &ops.retlen, -+ sizeof(uint32_t))) -+ ret = -EFAULT; -+ -+ kfree(ops.oobbuf); -+ kfree(ops.datbuf); -+ break; -+ } -+ -+ - case MEMLOCK: - { - struct erase_info_user info; -@@ -627,9 +690,9 @@ - - case MEMGETBADBLOCK: - { -- loff_t offs; -+ loff_mtd_t offs; - -- if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ if (copy_from_user(&offs, argp, sizeof(loff_mtd_t))) - return -EFAULT; - if (!mtd->block_isbad) - ret = -EOPNOTSUPP; -@@ -640,9 +703,9 @@ - - case MEMSETBADBLOCK: - { -- loff_t offs; -+ loff_mtd_t offs; - -- if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ if (copy_from_user(&offs, argp, sizeof(loff_mtd_t))) - return -EFAULT; - if (!mtd->block_markbad) - ret = -EOPNOTSUPP; -@@ -764,9 +827,9 @@ - #endif - - default: -+ printk("line : %d\n", __LINE__); - ret = -ENOTTY; - } -- - return ret; - } /* memory_ioctl */ - -diff -urN linux-2.6.24.7.old/drivers/mtd/mtdchar.c.orig linux-2.6.24.7/drivers/mtd/mtdchar.c.orig ---- linux-2.6.24.7.old/drivers/mtd/mtdchar.c.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/mtdchar.c.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,816 @@ -+/* -+ * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ -+ * -+ * Character-device access to raw MTD devices. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+static struct class *mtd_class; -+ -+static void mtd_notify_add(struct mtd_info* mtd) -+{ -+ if (!mtd) -+ return; -+ -+ class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), -+ NULL, "mtd%d", mtd->index); -+ -+ class_device_create(mtd_class, NULL, -+ MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), -+ NULL, "mtd%dro", mtd->index); -+} -+ -+static void mtd_notify_remove(struct mtd_info* mtd) -+{ -+ if (!mtd) -+ return; -+ -+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); -+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); -+} -+ -+static struct mtd_notifier notifier = { -+ .add = mtd_notify_add, -+ .remove = mtd_notify_remove, -+}; -+ -+/* -+ * Data structure to hold the pointer to the mtd device as well -+ * as mode information ofr various use cases. -+ */ -+struct mtd_file_info { -+ struct mtd_info *mtd; -+ enum mtd_file_modes mode; -+}; -+ -+static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ -+ switch (orig) { -+ case SEEK_SET: -+ break; -+ case SEEK_CUR: -+ offset += file->f_pos; -+ break; -+ case SEEK_END: -+ offset += mtd->size; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (offset >= 0 && offset <= mtd->size) -+ return file->f_pos = offset; -+ -+ return -EINVAL; -+} -+ -+ -+ -+static int mtd_open(struct inode *inode, struct file *file) -+{ -+ int minor = iminor(inode); -+ int devnum = minor >> 1; -+ struct mtd_info *mtd; -+ struct mtd_file_info *mfi; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); -+ -+ if (devnum >= MAX_MTD_DEVICES) -+ return -ENODEV; -+ -+ /* You can't open the RO devices RW */ -+ if ((file->f_mode & 2) && (minor & 1)) -+ return -EACCES; -+ -+ mtd = get_mtd_device(NULL, devnum); -+ -+ if (IS_ERR(mtd)) -+ return PTR_ERR(mtd); -+ -+ if (MTD_ABSENT == mtd->type) { -+ put_mtd_device(mtd); -+ return -ENODEV; -+ } -+ -+ /* You can't open it RW if it's not a writeable device */ -+ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { -+ put_mtd_device(mtd); -+ return -EACCES; -+ } -+ -+ mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); -+ if (!mfi) { -+ put_mtd_device(mtd); -+ return -ENOMEM; -+ } -+ mfi->mtd = mtd; -+ file->private_data = mfi; -+ -+ return 0; -+} /* mtd_open */ -+ -+/*====================================================================*/ -+ -+static int mtd_close(struct inode *inode, struct file *file) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); -+ -+ /* Only sync if opened RW */ -+ if ((file->f_mode & 2) && mtd->sync) -+ mtd->sync(mtd); -+ -+ put_mtd_device(mtd); -+ file->private_data = NULL; -+ kfree(mfi); -+ -+ return 0; -+} /* mtd_close */ -+ -+/* FIXME: This _really_ needs to die. In 2.5, we should lock the -+ userspace buffer down and use it directly with readv/writev. -+*/ -+#define MAX_KMALLOC_SIZE 0x20000 -+ -+static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ size_t retlen=0; -+ size_t total_retlen=0; -+ int ret=0; -+ int len; -+ char *kbuf; -+ -+ DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); -+ -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; -+ -+ if (!count) -+ return 0; -+ -+ /* FIXME: Use kiovec in 2.5 to lock down the user's buffers -+ and pass them directly to the MTD functions */ -+ -+ if (count > MAX_KMALLOC_SIZE) -+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); -+ else -+ kbuf=kmalloc(count, GFP_KERNEL); -+ -+ if (!kbuf) -+ return -ENOMEM; -+ -+ while (count) { -+ -+ if (count > MAX_KMALLOC_SIZE) -+ len = MAX_KMALLOC_SIZE; -+ else -+ len = count; -+ -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ case MTD_MODE_OTP_USER: -+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ case MTD_MODE_RAW: -+ { -+ struct mtd_oob_ops ops; -+ -+ ops.mode = MTD_OOB_RAW; -+ ops.datbuf = kbuf; -+ ops.oobbuf = NULL; -+ ops.len = len; -+ -+ ret = mtd->read_oob(mtd, *ppos, &ops); -+ retlen = ops.retlen; -+ break; -+ } -+ default: -+ ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); -+ } -+ /* Nand returns -EBADMSG on ecc errors, but it returns -+ * the data. For our userspace tools it is important -+ * to dump areas with ecc errors ! -+ * For kernel internal usage it also might return -EUCLEAN -+ * to signal the caller that a bitflip has occured and has -+ * been corrected by the ECC algorithm. -+ * Userspace software which accesses NAND this way -+ * must be aware of the fact that it deals with NAND -+ */ -+ if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { -+ *ppos += retlen; -+ if (copy_to_user(buf, kbuf, retlen)) { -+ kfree(kbuf); -+ return -EFAULT; -+ } -+ else -+ total_retlen += retlen; -+ -+ count -= retlen; -+ buf += retlen; -+ if (retlen == 0) -+ count = 0; -+ } -+ else { -+ kfree(kbuf); -+ return ret; -+ } -+ -+ } -+ -+ kfree(kbuf); -+ return total_retlen; -+} /* mtd_read */ -+ -+static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ char *kbuf; -+ size_t retlen; -+ size_t total_retlen=0; -+ int ret=0; -+ int len; -+ -+ DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); -+ -+ if (*ppos == mtd->size) -+ return -ENOSPC; -+ -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; -+ -+ if (!count) -+ return 0; -+ -+ if (count > MAX_KMALLOC_SIZE) -+ kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); -+ else -+ kbuf=kmalloc(count, GFP_KERNEL); -+ -+ if (!kbuf) -+ return -ENOMEM; -+ -+ while (count) { -+ -+ if (count > MAX_KMALLOC_SIZE) -+ len = MAX_KMALLOC_SIZE; -+ else -+ len = count; -+ -+ if (copy_from_user(kbuf, buf, len)) { -+ kfree(kbuf); -+ return -EFAULT; -+ } -+ -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ ret = -EROFS; -+ break; -+ case MTD_MODE_OTP_USER: -+ if (!mtd->write_user_prot_reg) { -+ ret = -EOPNOTSUPP; -+ break; -+ } -+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); -+ break; -+ -+ case MTD_MODE_RAW: -+ { -+ struct mtd_oob_ops ops; -+ -+ ops.mode = MTD_OOB_RAW; -+ ops.datbuf = kbuf; -+ ops.oobbuf = NULL; -+ ops.len = len; -+ -+ ret = mtd->write_oob(mtd, *ppos, &ops); -+ retlen = ops.retlen; -+ break; -+ } -+ -+ default: -+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); -+ } -+ if (!ret) { -+ *ppos += retlen; -+ total_retlen += retlen; -+ count -= retlen; -+ buf += retlen; -+ } -+ else { -+ kfree(kbuf); -+ return ret; -+ } -+ } -+ -+ kfree(kbuf); -+ return total_retlen; -+} /* mtd_write */ -+ -+/*====================================================================== -+ -+ IOCTL calls for getting device parameters. -+ -+======================================================================*/ -+static void mtdchar_erase_callback (struct erase_info *instr) -+{ -+ wake_up((wait_queue_head_t *)instr->priv); -+} -+ -+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) -+static int otp_select_filemode(struct mtd_file_info *mfi, int mode) -+{ -+ struct mtd_info *mtd = mfi->mtd; -+ int ret = 0; -+ -+ switch (mode) { -+ case MTD_OTP_FACTORY: -+ if (!mtd->read_fact_prot_reg) -+ ret = -EOPNOTSUPP; -+ else -+ mfi->mode = MTD_MODE_OTP_FACTORY; -+ break; -+ case MTD_OTP_USER: -+ if (!mtd->read_fact_prot_reg) -+ ret = -EOPNOTSUPP; -+ else -+ mfi->mode = MTD_MODE_OTP_USER; -+ break; -+ default: -+ ret = -EINVAL; -+ case MTD_OTP_OFF: -+ break; -+ } -+ return ret; -+} -+#else -+# define otp_select_filemode(f,m) -EOPNOTSUPP -+#endif -+ -+static int mtd_ioctl(struct inode *inode, struct file *file, -+ u_int cmd, u_long arg) -+{ -+ struct mtd_file_info *mfi = file->private_data; -+ struct mtd_info *mtd = mfi->mtd; -+ void __user *argp = (void __user *)arg; -+ int ret = 0; -+ u_long size; -+ struct mtd_info_user info; -+ -+ DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); -+ -+ size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; -+ if (cmd & IOC_IN) { -+ if (!access_ok(VERIFY_READ, argp, size)) -+ return -EFAULT; -+ } -+ if (cmd & IOC_OUT) { -+ if (!access_ok(VERIFY_WRITE, argp, size)) -+ return -EFAULT; -+ } -+ -+ switch (cmd) { -+ case MEMGETREGIONCOUNT: -+ if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) -+ return -EFAULT; -+ break; -+ -+ case MEMGETREGIONINFO: -+ { -+ struct region_info_user ur; -+ -+ if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) -+ return -EFAULT; -+ -+ if (ur.regionindex >= mtd->numeraseregions) -+ return -EINVAL; -+ if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), -+ sizeof(struct mtd_erase_region_info))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MEMGETINFO: -+ info.type = mtd->type; -+ info.flags = mtd->flags; -+ info.size = mtd->size; -+ info.erasesize = mtd->erasesize; -+ info.writesize = mtd->writesize; -+ info.oobsize = mtd->oobsize; -+ /* The below fields are obsolete */ -+ info.ecctype = -1; -+ info.eccsize = 0; -+ if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) -+ return -EFAULT; -+ break; -+ -+ case MEMERASE: -+ { -+ struct erase_info *erase; -+ -+ if(!(file->f_mode & 2)) -+ return -EPERM; -+ -+ erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); -+ if (!erase) -+ ret = -ENOMEM; -+ else { -+ wait_queue_head_t waitq; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ init_waitqueue_head(&waitq); -+ -+ if (copy_from_user(&erase->addr, argp, -+ sizeof(struct erase_info_user))) { -+ kfree(erase); -+ return -EFAULT; -+ } -+ erase->mtd = mtd; -+ erase->callback = mtdchar_erase_callback; -+ erase->priv = (unsigned long)&waitq; -+ -+ /* -+ FIXME: Allow INTERRUPTIBLE. Which means -+ not having the wait_queue head on the stack. -+ -+ If the wq_head is on the stack, and we -+ leave because we got interrupted, then the -+ wq_head is no longer there when the -+ callback routine tries to wake us up. -+ */ -+ ret = mtd->erase(mtd, erase); -+ if (!ret) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&waitq, &wait); -+ if (erase->state != MTD_ERASE_DONE && -+ erase->state != MTD_ERASE_FAILED) -+ schedule(); -+ remove_wait_queue(&waitq, &wait); -+ set_current_state(TASK_RUNNING); -+ -+ ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0; -+ } -+ kfree(erase); -+ } -+ break; -+ } -+ -+ case MEMWRITEOOB: -+ { -+ struct mtd_oob_buf buf; -+ struct mtd_oob_ops ops; -+ -+ if(!(file->f_mode & 2)) -+ return -EPERM; -+ -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ return -EFAULT; -+ -+ if (buf.length > 4096) -+ return -EINVAL; -+ -+ if (!mtd->write_oob) -+ ret = -EOPNOTSUPP; -+ else -+ ret = access_ok(VERIFY_READ, buf.ptr, -+ buf.length) ? 0 : EFAULT; -+ -+ if (ret) -+ return ret; -+ -+ ops.ooblen = buf.length; -+ ops.ooboffs = buf.start & (mtd->oobsize - 1); -+ ops.datbuf = NULL; -+ ops.mode = MTD_OOB_PLACE; -+ -+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) -+ return -EINVAL; -+ -+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); -+ if (!ops.oobbuf) -+ return -ENOMEM; -+ -+ if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) { -+ kfree(ops.oobbuf); -+ return -EFAULT; -+ } -+ -+ buf.start &= ~(mtd->oobsize - 1); -+ ret = mtd->write_oob(mtd, buf.start, &ops); -+ -+ if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen, -+ sizeof(uint32_t))) -+ ret = -EFAULT; -+ -+ kfree(ops.oobbuf); -+ break; -+ -+ } -+ -+ case MEMREADOOB: -+ { -+ struct mtd_oob_buf buf; -+ struct mtd_oob_ops ops; -+ -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ return -EFAULT; -+ -+ if (buf.length > 4096) -+ return -EINVAL; -+ -+ if (!mtd->read_oob) -+ ret = -EOPNOTSUPP; -+ else -+ ret = access_ok(VERIFY_WRITE, buf.ptr, -+ buf.length) ? 0 : -EFAULT; -+ if (ret) -+ return ret; -+ -+ ops.ooblen = buf.length; -+ ops.ooboffs = buf.start & (mtd->oobsize - 1); -+ ops.datbuf = NULL; -+ ops.mode = MTD_OOB_PLACE; -+ -+ if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) -+ return -EINVAL; -+ -+ ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); -+ if (!ops.oobbuf) -+ return -ENOMEM; -+ -+ buf.start &= ~(mtd->oobsize - 1); -+ ret = mtd->read_oob(mtd, buf.start, &ops); -+ -+ if (put_user(ops.oobretlen, (uint32_t __user *)argp)) -+ ret = -EFAULT; -+ else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf, -+ ops.oobretlen)) -+ ret = -EFAULT; -+ -+ kfree(ops.oobbuf); -+ break; -+ } -+ -+ case MEMLOCK: -+ { -+ struct erase_info_user info; -+ -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ -+ if (!mtd->lock) -+ ret = -EOPNOTSUPP; -+ else -+ ret = mtd->lock(mtd, info.start, info.length); -+ break; -+ } -+ -+ case MEMUNLOCK: -+ { -+ struct erase_info_user info; -+ -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ -+ if (!mtd->unlock) -+ ret = -EOPNOTSUPP; -+ else -+ ret = mtd->unlock(mtd, info.start, info.length); -+ break; -+ } -+ -+ /* Legacy interface */ -+ case MEMGETOOBSEL: -+ { -+ struct nand_oobinfo oi; -+ -+ if (!mtd->ecclayout) -+ return -EOPNOTSUPP; -+ if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos)) -+ return -EINVAL; -+ -+ oi.useecc = MTD_NANDECC_AUTOPLACE; -+ memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos)); -+ memcpy(&oi.oobfree, mtd->ecclayout->oobfree, -+ sizeof(oi.oobfree)); -+ oi.eccbytes = mtd->ecclayout->eccbytes; -+ -+ if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MEMGETBADBLOCK: -+ { -+ loff_t offs; -+ -+ if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ return -EFAULT; -+ if (!mtd->block_isbad) -+ ret = -EOPNOTSUPP; -+ else -+ return mtd->block_isbad(mtd, offs); -+ break; -+ } -+ -+ case MEMSETBADBLOCK: -+ { -+ loff_t offs; -+ -+ if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ return -EFAULT; -+ if (!mtd->block_markbad) -+ ret = -EOPNOTSUPP; -+ else -+ return mtd->block_markbad(mtd, offs); -+ break; -+ } -+ -+#if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) -+ case OTPSELECT: -+ { -+ int mode; -+ if (copy_from_user(&mode, argp, sizeof(int))) -+ return -EFAULT; -+ -+ mfi->mode = MTD_MODE_NORMAL; -+ -+ ret = otp_select_filemode(mfi, mode); -+ -+ file->f_pos = 0; -+ break; -+ } -+ -+ case OTPGETREGIONCOUNT: -+ case OTPGETREGIONINFO: -+ { -+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ ret = -EOPNOTSUPP; -+ switch (mfi->mode) { -+ case MTD_MODE_OTP_FACTORY: -+ if (mtd->get_fact_prot_info) -+ ret = mtd->get_fact_prot_info(mtd, buf, 4096); -+ break; -+ case MTD_MODE_OTP_USER: -+ if (mtd->get_user_prot_info) -+ ret = mtd->get_user_prot_info(mtd, buf, 4096); -+ break; -+ default: -+ break; -+ } -+ if (ret >= 0) { -+ if (cmd == OTPGETREGIONCOUNT) { -+ int nbr = ret / sizeof(struct otp_info); -+ ret = copy_to_user(argp, &nbr, sizeof(int)); -+ } else -+ ret = copy_to_user(argp, buf, ret); -+ if (ret) -+ ret = -EFAULT; -+ } -+ kfree(buf); -+ break; -+ } -+ -+ case OTPLOCK: -+ { -+ struct otp_info info; -+ -+ if (mfi->mode != MTD_MODE_OTP_USER) -+ return -EINVAL; -+ if (copy_from_user(&info, argp, sizeof(info))) -+ return -EFAULT; -+ if (!mtd->lock_user_prot_reg) -+ return -EOPNOTSUPP; -+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); -+ break; -+ } -+#endif -+ -+ case ECCGETLAYOUT: -+ { -+ if (!mtd->ecclayout) -+ return -EOPNOTSUPP; -+ -+ if (copy_to_user(argp, mtd->ecclayout, -+ sizeof(struct nand_ecclayout))) -+ return -EFAULT; -+ break; -+ } -+ -+ case ECCGETSTATS: -+ { -+ if (copy_to_user(argp, &mtd->ecc_stats, -+ sizeof(struct mtd_ecc_stats))) -+ return -EFAULT; -+ break; -+ } -+ -+ case MTDFILEMODE: -+ { -+ mfi->mode = 0; -+ -+ switch(arg) { -+ case MTD_MODE_OTP_FACTORY: -+ case MTD_MODE_OTP_USER: -+ ret = otp_select_filemode(mfi, arg); -+ break; -+ -+ case MTD_MODE_RAW: -+ if (!mtd->read_oob || !mtd->write_oob) -+ return -EOPNOTSUPP; -+ mfi->mode = arg; -+ -+ case MTD_MODE_NORMAL: -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ file->f_pos = 0; -+ break; -+ } -+#ifdef CONFIG_MTD_PARTITIONS -+ case MTDREFRESH: -+ { -+ ret = refresh_mtd_partitions(mtd); -+ break; -+ } -+#endif -+ -+ default: -+ ret = -ENOTTY; -+ } -+ -+ return ret; -+} /* memory_ioctl */ -+ -+static const struct file_operations mtd_fops = { -+ .owner = THIS_MODULE, -+ .llseek = mtd_lseek, -+ .read = mtd_read, -+ .write = mtd_write, -+ .ioctl = mtd_ioctl, -+ .open = mtd_open, -+ .release = mtd_close, -+}; -+ -+static int __init init_mtdchar(void) -+{ -+ if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { -+ printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -+ MTD_CHAR_MAJOR); -+ return -EAGAIN; -+ } -+ -+ mtd_class = class_create(THIS_MODULE, "mtd"); -+ -+ if (IS_ERR(mtd_class)) { -+ printk(KERN_ERR "Error creating mtd class.\n"); -+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); -+ return PTR_ERR(mtd_class); -+ } -+ -+ register_mtd_user(¬ifier); -+ return 0; -+} -+ -+static void __exit cleanup_mtdchar(void) -+{ -+ unregister_mtd_user(¬ifier); -+ class_destroy(mtd_class); -+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); -+} -+ -+module_init(init_mtdchar); -+module_exit(cleanup_mtdchar); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Woodhouse "); -+MODULE_DESCRIPTION("Direct character-device access to MTD devices"); -diff -urN linux-2.6.24.7.old/drivers/mtd/mtdcore.c linux-2.6.24.7/drivers/mtd/mtdcore.c ---- linux-2.6.24.7.old/drivers/mtd/mtdcore.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/mtdcore.c 2009-04-12 18:13:57.000000000 +0200 -@@ -303,10 +303,10 @@ - */ - - int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, -- unsigned long count, loff_t to, size_t *retlen) -+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen) - { - unsigned long i; -- size_t totlen = 0, thislen; -+ size_mtd_t totlen = 0, thislen; - int ret = 0; - - if(!mtd->write) { -@@ -350,7 +350,7 @@ - if (!this) - return 0; - -- return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, -+ return sprintf(buf, "mtd%d: %09llx %8.8x \"%s\"\n", i, this->size, - this->erasesize, this->name); - } - -diff -urN linux-2.6.24.7.old/drivers/mtd/mtdpart.c linux-2.6.24.7/drivers/mtd/mtdpart.c ---- linux-2.6.24.7.old/drivers/mtd/mtdpart.c 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/mtdpart.c 2009-04-12 18:38:31.000000000 +0200 -@@ -30,7 +30,7 @@ - struct mtd_part { - struct mtd_info mtd; - struct mtd_info *master; -- u_int32_t offset; -+ u_int64_t offset; - int index; - struct list_head list; - int registered; -@@ -48,8 +48,8 @@ - * to the _real_ device. - */ - --static int part_read (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) - { - struct mtd_part *part = PART(mtd); - int res; -@@ -69,8 +69,8 @@ - return res; - } - --static int part_point (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char **buf) -+static int part_point (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char **buf) - { - struct mtd_part *part = PART(mtd); - if (from >= mtd->size) -@@ -81,14 +81,14 @@ - len, retlen, buf); - } - --static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) -+static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_mtd_t from, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - - part->master->unpoint (part->master, addr, from + part->offset, len); - } - --static int part_read_oob(struct mtd_info *mtd, loff_t from, -+static int part_read_oob(struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops) - { - struct mtd_part *part = PART(mtd); -@@ -109,8 +109,8 @@ - return res; - } - --static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) - { - struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, -@@ -118,14 +118,14 @@ - } - - static int part_get_user_prot_info (struct mtd_info *mtd, -- struct otp_info *buf, size_t len) -+ struct otp_info *buf, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - return part->master->get_user_prot_info (part->master, buf, len); - } - --static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) - { - struct mtd_part *part = PART(mtd); - return part->master->read_fact_prot_reg (part->master, from, -@@ -133,14 +133,14 @@ - } - - static int part_get_fact_prot_info (struct mtd_info *mtd, -- struct otp_info *buf, size_t len) -+ struct otp_info *buf, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - return part->master->get_fact_prot_info (part->master, buf, len); - } - --static int part_write (struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const u_char *buf) -+static int part_write (struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, -+ size_mtd_t *retlen, const u_char *buf) - { - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) -@@ -153,7 +153,7 @@ - len, retlen, buf); - } - --static int part_write_oob(struct mtd_info *mtd, loff_t to, -+static int part_write_oob(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops) - { - struct mtd_part *part = PART(mtd); -@@ -168,22 +168,22 @@ - return part->master->write_oob(part->master, to + part->offset, ops); - } - --static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, u_char *buf) - { - struct mtd_part *part = PART(mtd); - return part->master->write_user_prot_reg (part->master, from, - len, retlen, buf); - } - --static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) -+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - return part->master->lock_user_prot_reg (part->master, from, len); - } - - static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, -- unsigned long count, loff_t to, size_t *retlen) -+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen) - { - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) -@@ -224,7 +224,7 @@ - } - EXPORT_SYMBOL_GPL(mtd_erase_callback); - --static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int part_lock (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) -@@ -232,7 +232,7 @@ - return part->master->lock(part->master, ofs + part->offset, len); - } - --static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int part_unlock (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len) - { - struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) -@@ -258,7 +258,7 @@ - part->master->resume(part->master); - } - --static int part_block_isbad (struct mtd_info *mtd, loff_t ofs) -+static int part_block_isbad (struct mtd_info *mtd, loff_mtd_t ofs) - { - struct mtd_part *part = PART(mtd); - if (ofs >= mtd->size) -@@ -267,7 +267,7 @@ - return part->master->block_isbad(part->master, ofs); - } - --static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) -+static int part_block_markbad (struct mtd_info *mtd, loff_mtd_t ofs) - { - struct mtd_part *part = PART(mtd); - int res; -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/Kconfig linux-2.6.24.7/drivers/mtd/nand/Kconfig ---- linux-2.6.24.7.old/drivers/mtd/nand/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/nand/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -1,5 +1,5 @@ - # drivers/mtd/nand/Kconfig --# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ -+# $Id: Kconfig,v 1.3 2008-07-04 08:05:48 lhhuang Exp $ - - menuconfig MTD_NAND - tristate "NAND Device Support" -@@ -306,4 +306,127 @@ - These two (and possibly other) Alauda-based cardreaders for - SmartMedia and xD allow raw flash access. - -+config MTD_NAND_JZ4730 -+ tristate "Support NAND Flash device on Jz4730 board" -+ depends on SOC_JZ4730 -+ help -+ Support NAND Flash device on Jz4730 board -+ -+config MTD_NAND_JZ4740 -+ tristate "Support NAND Flash device on Jz4740 board" -+ depends on SOC_JZ4740 -+ help -+ Support NAND Flash device on Jz4740 board -+ -+config MTD_NAND_JZ4750 -+ tristate "Support NAND Flash device on Jz4750 board" -+ depends on SOC_JZ4750 || SOC_JZ4750D -+ help -+ Support NAND Flash device on Jz4750 board -+ -+config MTD_NAND_CS2 -+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 -+ bool 'Use NAND on CS2_N of JZSOC' -+ default n -+ -+config MTD_NAND_CS3 -+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 -+ bool 'Use NAND on CS3_N of JZSOC' -+ default n -+ -+config MTD_NAND_CS4 -+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4750 -+ bool 'Use NAND on CS4_N of JZSOC' -+ default n -+ -+config MTD_NAND_MULTI_PLANE -+ depends on MTD_NAND_JZ4730 || MTD_NAND_JZ4740 || MTD_NAND_JZ4750 -+ bool 'Use multiple planes if the NAND supports' -+ default y -+ help -+ It is just supported on jz4740 now. -+ -+if MTD_NAND_JZ4740 || MTD_NAND_JZ4730 || MTD_NAND_JZ4750 -+choice -+ prompt "ECC type" -+ default CONFIG_MTD_SW_HM_ECC -+ -+config MTD_HW_HM_ECC -+ depends on MTD_NAND_JZ4740 || MTD_NAND_JZ4730 -+ bool 'Select hardware HM ECC' -+ -+config MTD_SW_HM_ECC -+ bool 'Select software HM ECC' -+ -+config MTD_HW_RS_ECC -+ depends on MTD_NAND_JZ4740 -+ bool 'Select hardware RS ECC' -+ -+config MTD_HW_BCH_ECC -+ depends on MTD_NAND_JZ4750 -+ bool 'Select hardware BCH ECC' -+endchoice -+ -+choice -+ prompt "4 bit or 8 bit BCH ecc" -+ depends on MTD_HW_BCH_ECC -+ default CONFIG_MTD_HW_BCH_4BIT -+ -+config MTD_HW_BCH_4BIT -+ bool '4 bit' -+ -+config MTD_HW_BCH_8BIT -+ bool '8 bit' -+ -+endchoice -+ -+config MTD_NAND_DMA -+ depends on MTD_HW_BCH_ECC -+ bool 'Use DMA mode' -+ help -+ This enables using DMA for reading and writing NAND flash, if not selected, -+ then CPU mode is used. -+ -+config MTD_NAND_DMABUF -+ depends on MTD_NAND_DMA -+ bool 'use DMA buffer in NAND driver' -+ help -+ It's better to say NO. If saying yes, DMA buffers will be allocated for -+ NAND reading and writing in NAND driver instead of upper layer. It's -+ slower. Just usable on CS1_N now. By saying NO, upper buffers will be -+ used as DMA buffer. It's faster, but kmalloc instead of vmalloc is required. -+endif -+ -+config MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ bool "MTDBLOCK write verify enable" -+ default n -+ help -+ This will enable the write verification, which will read back data to check -+ after doing a write opetaion. -+ -+ It will be used by the JZ mtdblock driver (mtdblock-jz.c). -+ -+config MTD_OOB_COPIES -+ int "how many copies of the fs info in the oob area" -+ default 3 -+ range 0 128 -+ depends on MTD -+ help -+ This defines the copies of the fs info in the oob area inside a block. -+ Value ranges from 0 to (pages_per_block - 1). -+ -+ It will be used by the JZ mtdblock driver (mtdblock-jz.c). -+ -+config MTD_BADBLOCK_FLAG_PAGE -+ int "which page inside a block will store the badblock mark" -+ default 0 -+ range 0 127 -+ depends on MTD -+ help -+ This defines which page of a block will store the badblock mark. -+ Value ranges from 0 to (pages_per_block - 1). -+ -+ Old SLC NANDs store the badblock mark in the first page of a block, but -+ most modern MLC NANDs store it in the last page of a block. -+ - endif # MTD_NAND -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/Makefile linux-2.6.24.7/drivers/mtd/nand/Makefile ---- linux-2.6.24.7.old/drivers/mtd/nand/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/nand/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -1,7 +1,7 @@ - # - # linux/drivers/nand/Makefile - # --# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ -+# $Id: Makefile,v 1.2 2008-07-04 08:07:45 lhhuang Exp $ - - obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o - obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o -@@ -29,5 +29,8 @@ - obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o - obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o - obj-$(CONFIG_MTD_ALAUDA) += alauda.o -+obj-$(CONFIG_MTD_NAND_JZ4730) += jz4730_nand.o -+obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o -+obj-$(CONFIG_MTD_NAND_JZ4750) += jz4750_nand.o - - nand-objs := nand_base.o nand_bbt.o -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/jz4730_nand.c linux-2.6.24.7/drivers/mtd/nand/jz4730_nand.c ---- linux-2.6.24.7.old/drivers/mtd/nand/jz4730_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/nand/jz4730_nand.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,367 @@ -+/* -+ * linux/drivers/mtd/nand/jz4730_nand.c -+ * -+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Ingenic JZ4730 NAND driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define NAND_DATA_PORT 0xB4000000 /* read-write area */ -+#define __nand_ecc() (REG_EMC_NFECC & 0x00ffffff) -+#define __nand_ecc_enable() (REG_EMC_NFCSR |= EMC_NFCSR_ECCE | EMC_NFCSR_ERST) -+#define __nand_ecc_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_ECCE) -+ -+/* -+ * MTD structure for JzSOC board -+ */ -+static struct mtd_info *jz_mtd = NULL; -+ -+/* -+ * Define partitions for flash devices -+ */ -+#ifdef CONFIG_JZ4730_PMP -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 56 * 0x100000 }, -+ { name: "NAND SSFDC partition", -+ offset: 64 * 0x100000, -+ size: 64 * 0x100000 }, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[]= { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10}; /* reserved blocks of mtd3 */ -+#elif CONFIG_JZ4730_PMPV1 -+static struct mtd_partition partition_info[] = { -+ { name: "NAND ROOTFS partition", -+ offset: 3 * 0x100000, -+ size: (32-3) * 0x100000 }, -+ { name: "NAND DATAFS partition", -+ offset: 32 * 0x100000, -+ size: 32 * 0x100000 }, -+}; -+static int partition_reserved_badblocks[]={ -+ 10, -+ 10}; -+#else -+static struct mtd_partition partition_info[] = { -+ { name: "NAND ROOTFS partition", -+ offset: 3 * 0x100000, -+ size: (128-3) * 0x100000 }, -+}; -+static int partition_reserved_badblocks[]={ -+ 20}; -+#endif -+ -+/*------------------------------------------------------------------------- -+ * Following three functions are exported and used by the mtdblock-jz.c -+ * NAND FTL driver only. -+ */ -+ -+unsigned short get_mtdblock_write_verify_enable(void) -+{ -+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ return 1; -+#endif -+ return 0; -+} -+EXPORT_SYMBOL(get_mtdblock_write_verify_enable); -+ -+unsigned short get_mtdblock_oob_copies(void) -+{ -+ return CONFIG_MTD_OOB_COPIES; -+} -+EXPORT_SYMBOL(get_mtdblock_oob_copies); -+ -+int *get_jz_badblock_table(void) -+{ -+ return partition_reserved_badblocks; -+} -+EXPORT_SYMBOL(get_jz_badblock_table); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, -+ unsigned int ctrl) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if ( ctrl & NAND_ALE ) -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00080000); -+ else -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00080000); -+ -+ if ( ctrl & NAND_CLE ) -+ nandaddr = nandaddr | 0x00040000; -+ else -+ nandaddr = nandaddr & ~0x00040000; -+ if ( ctrl & NAND_NCE ) -+ REG_EMC_NFCSR |= EMC_NFCSR_FCE; -+ else -+ REG_EMC_NFCSR &= ~EMC_NFCSR_FCE; -+ } -+ -+ this->IO_ADDR_W = (void __iomem *)nandaddr; -+ if (dat != NAND_CMD_NONE) -+ writeb(dat , this->IO_ADDR_W); -+ -+} -+ -+static int jz_device_ready(struct mtd_info *mtd) -+{ -+ int ready; -+ ready = (REG_EMC_NFCSR & EMC_NFCSR_RB) ? 1 : 0; -+ return ready; -+} -+ -+/* -+ * EMC setup -+ */ -+static void jz_device_setup(void) -+{ -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE; -+} -+ -+static void jzsoc_nand_enable_hwecc(struct mtd_info* mtd, int mode) -+{ -+ __nand_ecc_enable(); -+} -+ -+static int jzsoc_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, -+ u_char* ecc_code) -+{ -+ unsigned int calc_ecc; -+ unsigned char *tmp; -+ -+ __nand_ecc_disable(); -+ -+ calc_ecc = ~(__nand_ecc()) | 0x00030000; -+ -+ tmp = (unsigned char *)&calc_ecc; -+ -+ ecc_code[0] = tmp[1]; -+ ecc_code[1] = tmp[0]; -+ ecc_code[2] = tmp[2]; -+ -+ return 0; -+} -+ -+/* ECC handling functions */ -+ -+static int jzsoc_nand_correct_data(struct mtd_info *mtd, u_char *dat, -+ u_char *read_ecc, u_char *calc_ecc) -+{ -+ u_char a, b, c, d1, d2, d3, add, bit, i; -+ -+ /* Do error detection */ -+ d1 = calc_ecc[0] ^ read_ecc[0]; -+ d2 = calc_ecc[1] ^ read_ecc[1]; -+ d3 = calc_ecc[2] ^ read_ecc[2]; -+ -+ if ((d1 | d2 | d3) == 0) { -+ /* No errors */ -+ return 0; -+ } -+ else { -+ a = (d1 ^ (d1 >> 1)) & 0x55; -+ b = (d2 ^ (d2 >> 1)) & 0x55; -+ c = (d3 ^ (d3 >> 1)) & 0x54; -+ -+ /* Found and will correct single bit error in the data */ -+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { -+ c = 0x80; -+ add = 0; -+ a = 0x80; -+ for (i=0; i<4; i++) { -+ if (d1 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ c = 0x80; -+ for (i=0; i<4; i++) { -+ if (d2 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ bit = 0; -+ b = 0x04; -+ c = 0x80; -+ for (i=0; i<3; i++) { -+ if (d3 & c) -+ bit |= b; -+ c >>= 2; -+ b >>= 1; -+ } -+ b = 0x01; -+ a = dat[add]; -+ a ^= (b << bit); -+ dat[add] = a; -+ return 0; -+ } -+ else { -+ i = 0; -+ while (d1) { -+ if (d1 & 0x01) -+ ++i; -+ d1 >>= 1; -+ } -+ while (d2) { -+ if (d2 & 0x01) -+ ++i; -+ d2 >>= 1; -+ } -+ while (d3) { -+ if (d3 & 0x01) -+ ++i; -+ d3 >>= 1; -+ } -+ if (i == 1) { -+ /* ECC Code Error Correction */ -+ read_ecc[0] = calc_ecc[0]; -+ read_ecc[1] = calc_ecc[1]; -+ read_ecc[2] = calc_ecc[2]; -+ return 0; -+ } -+ else { -+ /* Uncorrectable Error */ -+ printk("uncorrectable ECC error\n"); -+ return -1; -+ } -+ } -+ } -+ -+ /* Should never happen */ -+ return -1; -+} -+ -+ -+/* -+ * Main initialization routine -+ */ -+int __init jznand_init(void) -+{ -+ struct nand_chip *this; -+ int nr_partitions; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!jz_mtd) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&jz_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ jz_mtd->priv = this; -+ -+ /* Set & initialize NAND Flash controller */ -+ jz_device_setup(); -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT; -+ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT; -+ this->cmd_ctrl = jz_hwcontrol; -+ this->dev_ready = jz_device_ready; -+ -+#ifdef CONFIG_MTD_HW_HM_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_ecc; -+ this->ecc.correct = jzsoc_nand_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 256; -+ this->ecc.bytes = 3; -+ -+#endif -+ -+#ifdef CONFIG_MTD_SW_HM_ECC -+ this->eccmode = NAND_ECC_SOFT; -+#endif -+ -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan(jz_mtd, 1)) { -+ kfree (jz_mtd); -+ return -ENXIO; -+ } -+ -+ /* Register the partitions */ -+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); -+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); -+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); -+ -+ return 0; -+} -+module_init(jznand_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+static void __exit jznand_cleanup(void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(jz_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (jz_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ kfree (jz_mtd); -+} -+module_exit(jznand_cleanup); -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/jz4740_nand.c linux-2.6.24.7/drivers/mtd/nand/jz4740_nand.c ---- linux-2.6.24.7.old/drivers/mtd/nand/jz4740_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/nand/jz4740_nand.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1037 @@ -+/* -+ * linux/drivers/mtd/nand/jz4740_nand.c -+ * -+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Ingenic JZ4740 NAND driver -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ -+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ -+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ -+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ -+ -+#define PAR_SIZE 9 -+ -+#define __nand_enable() (REG_EMC_NFCSR |= EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1) -+#define __nand_disable() (REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1) -+ -+#define __nand_ecc_enable() (REG_EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_ERST ) -+#define __nand_ecc_disable() (REG_EMC_NFECR &= ~EMC_NFECR_ECCE) -+ -+#define __nand_select_hm_ecc() (REG_EMC_NFECR &= ~EMC_NFECR_RS ) -+#define __nand_select_rs_ecc() (REG_EMC_NFECR |= EMC_NFECR_RS) -+ -+#define __nand_read_hm_ecc() (REG_EMC_NFECC & 0x00ffffff) -+ -+#define __nand_rs_ecc_encoding() (REG_EMC_NFECR |= EMC_NFECR_RS_ENCODING) -+#define __nand_rs_ecc_decoding() (REG_EMC_NFECR &= ~EMC_NFECR_RS_ENCODING) -+#define __nand_ecc_encode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_ENCF)) -+#define __nand_ecc_decode_sync() while (!(REG_EMC_NFINTS & EMC_NFINTS_DECF)) -+ -+/* -+ * MTD structure for JzSOC board -+ */ -+static struct mtd_info *jz_mtd = NULL; -+extern struct mtd_info *jz_mtd1; -+extern char all_use_planes; -+extern int global_page; /* for two-plane operations */ -+ -+/* -+ * Define partitions for flash devices -+ */ -+#ifdef CONFIG_JZ4740_PAVO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000, -+ use_planes: 0 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000, -+ use_planes: 1 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000, -+ use_planes: 1 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000, -+ use_planes: 1 }, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4740_PAVO */ -+ -+#ifdef CONFIG_JZ4740_LEO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 56 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 64 * 0x100000, -+ size: 64 * 0x100000 }, -+}; -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10}; /* reserved blocks of mtd3 */ -+#endif /* CONFIG_JZ4740_LEO */ -+ -+#ifdef CONFIG_JZ4740_LYRA -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000 }, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4740_LYRA */ -+ -+#ifdef CONFIG_JZ4725_DIPPER -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 56 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 64 * 0x100000, -+ size: 64 * 0x100000 }, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10}; /* reserved blocks of mtd3 */ -+#endif /* CONFIG_JZ4740_DIPPER */ -+ -+#ifdef CONFIG_JZ4720_VIRGO -+static struct mtd_partition partition_info[] = { -+ { name: "NAND BOOT partition", -+ offset: 0 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND KERNEL partition", -+ offset: 4 * 0x100000, -+ size: 4 * 0x100000 }, -+ { name: "NAND ROOTFS partition", -+ offset: 8 * 0x100000, -+ size: 120 * 0x100000 }, -+ { name: "NAND DATA1 partition", -+ offset: 128 * 0x100000, -+ size: 128 * 0x100000 }, -+ { name: "NAND DATA2 partition", -+ offset: 256 * 0x100000, -+ size: 256 * 0x100000 }, -+ { name: "NAND VFAT partition", -+ offset: 512 * 0x100000, -+ size: 512 * 0x100000 }, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4720_VIRGO */ -+/*------------------------------------------------------------------------- -+ * Following three functions are exported and used by the mtdblock-jz.c -+ * NAND FTL driver only. -+ */ -+ -+unsigned short get_mtdblock_write_verify_enable(void) -+{ -+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ return 1; -+#endif -+ return 0; -+} -+EXPORT_SYMBOL(get_mtdblock_write_verify_enable); -+ -+unsigned short get_mtdblock_oob_copies(void) -+{ -+ return CONFIG_MTD_OOB_COPIES; -+} -+EXPORT_SYMBOL(get_mtdblock_oob_copies); -+ -+int *get_jz_badblock_table(void) -+{ -+ return partition_reserved_badblocks; -+} -+EXPORT_SYMBOL(get_jz_badblock_table); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, -+ unsigned int ctrl) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; -+ extern u8 nand_nce; /* in nand_base.c, indicates which chip select is used for current nand chip */ -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if (ctrl & NAND_NCE) { -+ switch (nand_nce) { -+ case NAND_NCE1: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; -+ break; -+ case NAND_NCE2: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; -+ break; -+ case NAND_NCE3: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; -+ break; -+ case NAND_NCE4: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; -+ break; -+ default: -+ printk("error: no nand_nce 0x%x\n",nand_nce); -+ break; -+ } -+ } else { -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ } -+ -+ if ( ctrl & NAND_ALE ) -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) | 0x00010000); -+ else -+ nandaddr = (unsigned int)((unsigned long)(this->IO_ADDR_W) & ~0x00010000); -+ -+ if ( ctrl & NAND_CLE ) -+ nandaddr = nandaddr | 0x00008000; -+ else -+ nandaddr = nandaddr & ~0x00008000; -+ } -+ -+ this->IO_ADDR_W = (void __iomem *)nandaddr; -+ if (dat != NAND_CMD_NONE) -+ writeb(dat, this->IO_ADDR_W); -+} -+ -+static int jz_device_ready(struct mtd_info *mtd) -+{ -+ int ready, wait = 10; -+ while (wait--); -+ ready = __gpio_get_pin(94); -+ return ready; -+} -+ -+/* -+ * EMC setup -+ */ -+static void jz_device_setup(void) -+{ -+// PORT 0: -+// ... -+// PORT 1: -+// PIN/BIT N FUNC0 FUNC1 -+// 25 CS1# - -+// 26 CS2# - -+// 27 CS3# - -+// 28 CS4# - -+#define GPIO_CS2_N (32+26) -+#define GPIO_CS3_N (32+27) -+#define GPIO_CS4_N (32+28) -+#define SMCR_VAL 0x0d221200 -+ -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; -+ /* Read/Write timings */ -+ REG_EMC_SMCR1 = SMCR_VAL; -+ -+#if defined(CONFIG_MTD_NAND_CS2) -+ /* Set CS2# pin as function 0 */ -+ __gpio_as_func0(GPIO_CS2_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; -+ REG_EMC_SMCR2 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS3) -+ __gpio_as_func0(GPIO_CS3_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; -+ REG_EMC_SMCR3 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS4) -+ __gpio_as_func0(GPIO_CS4_N); -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; -+ REG_EMC_SMCR4 = SMCR_VAL; -+#endif -+} -+ -+#ifdef CONFIG_MTD_HW_HM_ECC -+ -+static int jzsoc_nand_calculate_hm_ecc(struct mtd_info* mtd, -+ const u_char* dat, u_char* ecc_code) -+{ -+ unsigned int calc_ecc; -+ unsigned char *tmp; -+ -+ __nand_ecc_disable(); -+ -+ calc_ecc = ~(__nand_read_hm_ecc()) | 0x00030000; -+ -+ tmp = (unsigned char *)&calc_ecc; -+ //adjust eccbytes order for compatible with software ecc -+ ecc_code[0] = tmp[1]; -+ ecc_code[1] = tmp[0]; -+ ecc_code[2] = tmp[2]; -+ -+ return 0; -+} -+ -+static void jzsoc_nand_enable_hm_hwecc(struct mtd_info* mtd, int mode) -+{ -+ __nand_ecc_enable(); -+ __nand_select_hm_ecc(); -+} -+ -+static int jzsoc_nand_hm_correct_data(struct mtd_info *mtd, u_char *dat, -+ u_char *read_ecc, u_char *calc_ecc) -+{ -+ u_char a, b, c, d1, d2, d3, add, bit, i; -+ -+ /* Do error detection */ -+ d1 = calc_ecc[0] ^ read_ecc[0]; -+ d2 = calc_ecc[1] ^ read_ecc[1]; -+ d3 = calc_ecc[2] ^ read_ecc[2]; -+ -+ if ((d1 | d2 | d3) == 0) { -+ /* No errors */ -+ return 0; -+ } -+ else { -+ a = (d1 ^ (d1 >> 1)) & 0x55; -+ b = (d2 ^ (d2 >> 1)) & 0x55; -+ c = (d3 ^ (d3 >> 1)) & 0x54; -+ -+ /* Found and will correct single bit error in the data */ -+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { -+ c = 0x80; -+ add = 0; -+ a = 0x80; -+ for (i=0; i<4; i++) { -+ if (d1 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ c = 0x80; -+ for (i=0; i<4; i++) { -+ if (d2 & c) -+ add |= a; -+ c >>= 2; -+ a >>= 1; -+ } -+ bit = 0; -+ b = 0x04; -+ c = 0x80; -+ for (i=0; i<3; i++) { -+ if (d3 & c) -+ bit |= b; -+ c >>= 2; -+ b >>= 1; -+ } -+ b = 0x01; -+ a = dat[add]; -+ a ^= (b << bit); -+ dat[add] = a; -+ return 0; -+ } -+ else { -+ i = 0; -+ while (d1) { -+ if (d1 & 0x01) -+ ++i; -+ d1 >>= 1; -+ } -+ while (d2) { -+ if (d2 & 0x01) -+ ++i; -+ d2 >>= 1; -+ } -+ while (d3) { -+ if (d3 & 0x01) -+ ++i; -+ d3 >>= 1; -+ } -+ if (i == 1) { -+ /* ECC Code Error Correction */ -+ read_ecc[0] = calc_ecc[0]; -+ read_ecc[1] = calc_ecc[1]; -+ read_ecc[2] = calc_ecc[2]; -+ return 0; -+ } -+ else { -+ /* Uncorrectable Error */ -+ printk("NAND: uncorrectable ECC error\n"); -+ return -1; -+ } -+ } -+ } -+ -+ /* Should never happen */ -+ return -1; -+} -+ -+#endif /* CONFIG_MTD_HW_HM_ECC */ -+ -+#ifdef CONFIG_MTD_HW_RS_ECC -+ -+static void jzsoc_nand_enable_rs_hwecc(struct mtd_info* mtd, int mode) -+{ -+ REG_EMC_NFINTS = 0x0; -+ __nand_ecc_enable(); -+ __nand_select_rs_ecc(); -+ -+ if (mode == NAND_ECC_READ) -+ __nand_rs_ecc_decoding(); -+ -+ if (mode == NAND_ECC_WRITE) -+ __nand_rs_ecc_encoding(); -+} -+ -+static void jzsoc_rs_correct(unsigned char *dat, int idx, int mask) -+{ -+ int i; -+ -+ idx--; -+ -+ i = idx + (idx >> 3); -+ if (i >= 512) -+ return; -+ -+ mask <<= (idx & 0x7); -+ -+ dat[i] ^= mask & 0xff; -+ if (i < 511) -+ dat[i+1] ^= (mask >> 8) & 0xff; -+} -+ -+/* -+ * calc_ecc points to oob_buf for us -+ */ -+static int jzsoc_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat, -+ u_char *read_ecc, u_char *calc_ecc) -+{ -+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; -+ short k; -+ u32 stat; -+ -+ /* Set PAR values */ -+ for (k = 0; k < PAR_SIZE; k++) { -+ *paraddr++ = read_ecc[k]; -+ } -+ -+ /* Set PRDY */ -+ REG_EMC_NFECR |= EMC_NFECR_PRDY; -+ -+ /* Wait for completion */ -+ __nand_ecc_decode_sync(); -+ __nand_ecc_disable(); -+ -+ /* Check decoding */ -+ stat = REG_EMC_NFINTS; -+ -+ if (stat & EMC_NFINTS_ERR) { -+ /* Error occurred */ -+ if (stat & EMC_NFINTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT; -+ switch (errcnt) { -+ case 4: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR3 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR3 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 3: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR2 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR2 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 2: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR1 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR1 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ /* FALL-THROUGH */ -+ case 1: -+ jzsoc_rs_correct(dat, (REG_EMC_NFERR0 & EMC_NFERR_INDEX_MASK) >> EMC_NFERR_INDEX_BIT, (REG_EMC_NFERR0 & EMC_NFERR_MASK_MASK) >> EMC_NFERR_MASK_BIT); -+ return 0; -+ default: -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int jzsoc_nand_calculate_rs_ecc(struct mtd_info* mtd, const u_char* dat, -+ u_char* ecc_code) -+{ -+ volatile u8 *paraddr = (volatile u8 *)EMC_NFPAR0; -+ short i; -+ -+ __nand_ecc_encode_sync(); -+ __nand_ecc_disable(); -+ -+ for(i = 0; i < PAR_SIZE; i++) { -+ ecc_code[i] = *paraddr++; -+ } -+ -+ return 0; -+} -+ -+#endif /* CONFIG_MTD_HW_RS_ECC */ -+ -+/* Nand optimized functions */ -+static int dma_chan; -+static unsigned int dma_src_phys_addr, dma_dst_phys_addr; -+extern int jz_request_dma(int dev_id, const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, void *irq_dev_id); -+ -+static void dma_setup(void) -+{ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", NULL, IRQF_DISABLED, NULL); -+ if (dma_chan < 0) { -+ printk("Setup irq for nand failed!\n"); -+ return; -+ } else -+ printk("Nand DMA request channel %d.\n",dma_chan); -+} -+ -+static void jz4740_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -+{ -+ int i; -+ struct nand_chip *chip = mtd->priv; -+ -+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) -+ { -+ for (i = 0; i < len; i++) -+ buf[i] = readb(chip->IO_ADDR_R); -+ } else { -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ dma_src_phys_addr = CPHYSADDR(chip->IO_ADDR_R); -+ dma_dst_phys_addr = CPHYSADDR(buf); -+ dma_cache_inv((u32)buf, len); -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = len / 16; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_DAI | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ } -+} -+ -+static void jz4740_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) -+{ -+ int i; -+ struct nand_chip *chip = mtd->priv; -+ -+ if ((len <= 32) || (len & 0xf) || ((u32)buf >= (u32)high_memory)) -+ { -+ for (i = 0; i < len; i++) -+ writeb(buf[i], chip->IO_ADDR_W); -+ } else { -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; -+ dma_dst_phys_addr = CPHYSADDR(chip->IO_ADDR_R); -+ dma_src_phys_addr = CPHYSADDR(buf); -+ dma_cache_wback((unsigned long)buf, len); -+ REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; -+ REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; -+ REG_DMAC_DTCR(dma_chan) = len / 16; -+ REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_16BYTE ; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ -+ -+ while(!(REG_DMAC_DCCSR(dma_chan) & DMAC_DCCSR_TT)); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ } -+} -+ -+static int nand_read_page_hwecc_rs_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps >> 1; -+ uint8_t *p; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ uint32_t page; -+ uint8_t flag = 0; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int ecctotal = chip->ecc.total >> 1; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page */ -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ if (ecc_code[i] != 0xff) flag = 1; -+ } -+ -+ p = buf; -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); -+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ int stat; -+ if (flag) { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ else { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ } -+ } -+ /* Read second page */ -+ page += ppb; -+ flag = 0; -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi + oobsize, oobsize); -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[oobsize + eccpos[i]]; -+ if (ecc_code[i] != 0xff) flag = 1; -+ } -+ -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); -+ eccsteps = chip->ecc.steps >> 1; -+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ int stat; -+ if (flag) { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ else { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ } -+ } -+ -+ return 0; -+} -+ -+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page, int sndcmd) -+{ -+ int page; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page OOB */ -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ } -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ /* Read second page OOB */ -+ page += ppb; -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ sndcmd = 0; -+ } -+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); -+ return 0; -+} -+ -+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page) -+{ -+ int status = 0,page; -+ int pagesize = mtd->writesize >> 1; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ const uint8_t *buf = chip->oob_poi; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send first command to program the OOB data */ -+ chip->cmdfunc(mtd, 0x11, -1, -1); -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ page += ppb; -+ buf += oobsize; -+ chip->cmdfunc(mtd, 0x81, pagesize, page); -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send command to program the OOB data */ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ /* Wait long R/B */ -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+static void nand_write_page_hwecc_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps >> 1; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *p = (uint8_t *)buf; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int ecctotal = chip->ecc.total >> 1; -+ int page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->write_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ } -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+ -+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ -+ ndelay(100); -+ while(!chip->dev_ready(mtd)); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x81, 0x00, page); /* send cmd 0x81 */ -+ eccsteps = chip->ecc.steps >> 1; -+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->write_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ } -+ -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+} -+ -+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) -+{ -+ struct nand_chip *chip = mtd->priv; -+ -+ /* Send commands to erase a block */ -+ int page; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x60, -1, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ -+ -+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ -+ /* Do not need wait R/B or check status */ -+} -+ -+/* -+ * Main initialization routine -+ */ -+int __init jznand_init(void) -+{ -+ struct nand_chip *this; -+ int nr_partitions, ret, i; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ jz_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!jz_mtd) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ jz_mtd1 = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!jz_mtd1) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); -+ kfree(jz_mtd); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&jz_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) jz_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ jz_mtd->priv = this; -+ -+ /* Set & initialize NAND Flash controller */ -+ jz_device_setup(); -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (void __iomem *) NAND_DATA_PORT1; -+ this->IO_ADDR_W = (void __iomem *) NAND_DATA_PORT1; -+ this->cmd_ctrl = jz_hwcontrol; -+ this->dev_ready = jz_device_ready; -+ -+#ifdef CONFIG_MTD_HW_HM_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_hm_ecc; -+ this->ecc.correct = jzsoc_nand_hm_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_hm_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 256; -+ this->ecc.bytes = 3; -+ -+#endif -+ -+#ifdef CONFIG_MTD_HW_RS_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_rs_ecc; -+ this->ecc.correct = jzsoc_nand_rs_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_rs_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 512; -+ this->ecc.bytes = 9; -+#endif -+ -+#ifdef CONFIG_MTD_SW_HM_ECC -+ this->ecc.mode = NAND_ECC_SOFT; -+#endif -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ -+ dma_setup(); -+ -+ /* Scan to find existance of the device */ -+ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); -+ if (!ret) { -+ if (this->planenum == 2) { -+ /* reset nand functions */ -+ this->erase_cmd = single_erase_cmd_planes; -+ this->ecc.read_page = nand_read_page_hwecc_rs_planes; //Muti planes read -+ this->ecc.write_page = nand_write_page_hwecc_planes; -+ this->ecc.read_oob = nand_read_oob_std_planes; -+ this->ecc.write_oob = nand_write_oob_std_planes; -+ this->write_buf = jz4740_nand_write_buf; -+ this->read_buf = jz4740_nand_read_buf; -+ -+ printk(KERN_INFO "Nand using two-plane mode, " -+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", -+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); -+ } else -+ return -ENXIO; -+ } -+ -+ /* Determine whether all the partitions will use multiple planes if supported */ -+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); -+ all_use_planes = 1; -+ for (i = 0; i < nr_partitions; i++) { -+ all_use_planes &= partition_info[i].use_planes; -+ } -+ -+ if (!ret) -+ ret = nand_scan_tail(jz_mtd); -+ -+ if (ret){ -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+ return -ENXIO; -+ } -+ -+ /* Register the partitions */ -+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); -+ -+ if ((this->planenum == 2) && !all_use_planes) { -+ for (i = 0; i < nr_partitions; i++) { -+ if (partition_info[i].use_planes) -+ add_mtd_partitions(jz_mtd, &partition_info[i], 1); -+ else -+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); -+ } -+ } else { -+ kfree(jz_mtd1); -+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); -+ } -+ return 0; -+} -+module_init(jznand_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+static void __exit jznand_cleanup(void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &jz_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(jz_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (jz_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ if ((this->planenum == 2) && !all_use_planes) -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+} -+module_exit(jznand_cleanup); -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/jz4750_nand.c linux-2.6.24.7/drivers/mtd/nand/jz4750_nand.c ---- linux-2.6.24.7.old/drivers/mtd/nand/jz4750_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/nand/jz4750_nand.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1746 @@ -+/* -+ * linux/drivers/mtd/nand/jz4750_nand.c -+ * -+ * JZ4750 NAND driver -+ * -+ * Copyright (c) 2005 - 2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+/* 32bit instead of 16byte burst is used by DMA to read or -+ write NAND and BCH avoiding grabbing bus for too long */ -+#define DMAC_DCMD_DS_NAND DMAC_DCMD_DS_32BIT -+#define DIV_DS_NAND 4 -+ -+#define DMAC_DCMD_DS_BCH DMAC_DCMD_DS_32BIT -+#define DIV_DS_BCH 4 -+ -+#define DEBUG1 0 -+#if DEBUG1 -+#define dprintk(n,x...) printk(n,##x) -+#else -+#define dprintk(n,x...) -+#endif -+ -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+#define __ECC_ENCODING __ecc_encoding_8bit -+#define __ECC_DECODING __ecc_decoding_8bit -+#define ERRS_SIZE 5 /* 5 words */ -+#else -+#define __ECC_ENCODING __ecc_encoding_4bit -+#define __ECC_DECODING __ecc_decoding_4bit -+#define ERRS_SIZE 3 /* 3 words */ -+#endif -+ -+#define NAND_DATA_PORT1 0xB8000000 /* read-write area in static bank 1 */ -+#define NAND_DATA_PORT2 0xB4000000 /* read-write area in static bank 2 */ -+#define NAND_DATA_PORT3 0xAC000000 /* read-write area in static bank 3 */ -+#define NAND_DATA_PORT4 0xA8000000 /* read-write area in static bank 4 */ -+ -+#define NAND_ADDR_OFFSET0 0x00010000 /* address port offset for share mode */ -+#define NAND_CMD_OFFSET0 0x00008000 /* command port offset for share mode */ -+#define NAND_ADDR_OFFSET1 0x00000010 /* address port offset for unshare mode */ -+#define NAND_CMD_OFFSET1 0x00000008 /* command port offset for unshare mode */ -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+#define USE_IRQ 1 -+enum { -+ NAND_NONE, -+ NAND_PROG, -+ NAND_READ -+}; -+static volatile u8 nand_status; -+static volatile int dma_ack = 0; -+static volatile int dma_ack1 = 0; -+static char nand_dma_chan; /* automatically select a free channel */ -+static char bch_dma_chan = 0; /* fixed to channel 0 */ -+static u32 *errs; -+static jz_dma_desc_8word *dma_desc_enc, *dma_desc_enc1, *dma_desc_dec, *dma_desc_dec1, *dma_desc_dec2, -+ *dma_desc_nand_prog, *dma_desc_nand_read; -+static u32 *pval_nand_ddr; -+static u8 *pval_nand_cmd_pgprog; /* for sending 0x11 or 0x10 when programing*/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+u8 *prog_buf, *read_buf; -+#endif -+DECLARE_WAIT_QUEUE_HEAD(nand_prog_wait_queue); -+DECLARE_WAIT_QUEUE_HEAD(nand_read_wait_queue); -+#endif -+ -+struct buf_be_corrected { -+ u8 *data; -+ u8 *oob; -+}; -+ -+static u32 addr_offset; -+static u32 cmd_offset; -+ -+extern int global_page; /* for two-plane operations */ -+ -+/* -+ * MTD structure for JzSOC board -+ */ -+static struct mtd_info *jz_mtd = NULL; -+extern struct mtd_info *jz_mtd1; -+extern char all_use_planes; -+ -+/* -+ * Define partitions for flash devices -+ */ -+#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750D_FUWA1) -+static struct mtd_partition partition_info[] = { -+ {name:"NAND BOOT partition", -+ offset:0 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND KERNEL partition", -+ offset:4 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND ROOTFS partition", -+ offset:8 * 0x100000, -+ size:120 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA1 partition", -+ offset:128 * 0x100000, -+ size:128 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND DATA2 partition", -+ offset:256 * 0x100000, -+ size:256 * 0x100000, -+ use_planes: 1}, -+ {name:"NAND VFAT partition", -+ offset:512 * 0x100000, -+ size:512 * 0x100000, -+ use_planes: 1}, -+}; -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+ 20, /* reserved blocks of mtd4 */ -+ 20 -+}; /* reserved blocks of mtd5 */ -+#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ -+ -+#if defined(CONFIG_JZ4750_APUS) -+static struct mtd_partition partition_info[] = { -+ {name:"NAND BOOT partition", -+ offset:0 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND KERNEL partition", -+ offset:4 * 0x100000, -+ size:4 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND ROOTFS partition", -+ offset:8 * 0x100000, -+ size:504 * 0x100000, -+ use_planes: 0}, -+ {name:"NAND VFAT partition", -+ offset:512 * 0x100000, -+ size:512 * 0x100000, -+ use_planes: 1}, -+}; -+ -+ -+/* Define max reserved bad blocks for each partition. -+ * This is used by the mtdblock-jz.c NAND FTL driver only. -+ * -+ * The NAND FTL driver reserves some good blocks which can't be -+ * seen by the upper layer. When the bad block number of a partition -+ * exceeds the max reserved blocks, then there is no more reserved -+ * good blocks to be used by the NAND FTL driver when another bad -+ * block generated. -+ */ -+static int partition_reserved_badblocks[] = { -+ 2, /* reserved blocks of mtd0 */ -+ 2, /* reserved blocks of mtd1 */ -+ 10, /* reserved blocks of mtd2 */ -+ 10, /* reserved blocks of mtd3 */ -+}; -+#endif /* CONFIG_JZ4750_FUWA or CONFIG_JZ4750_APUS */ -+ -+/*------------------------------------------------------------------------- -+ * Following three functions are exported and used by the mtdblock-jz.c -+ * NAND FTL driver only. -+ */ -+ -+unsigned short get_mtdblock_write_verify_enable(void) -+{ -+#ifdef CONFIG_MTD_MTDBLOCK_WRITE_VERIFY_ENABLE -+ return 1; -+#endif -+ return 0; -+} -+ -+EXPORT_SYMBOL(get_mtdblock_write_verify_enable); -+ -+unsigned short get_mtdblock_oob_copies(void) -+{ -+ return CONFIG_MTD_OOB_COPIES; -+} -+ -+EXPORT_SYMBOL(get_mtdblock_oob_copies); -+ -+int *get_jz_badblock_table(void) -+{ -+ return partition_reserved_badblocks; -+} -+ -+EXPORT_SYMBOL(get_jz_badblock_table); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_hwcontrol(struct mtd_info *mtd, int dat, u32 ctrl) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ u32 nandaddr = (u32)this->IO_ADDR_W; -+ extern u8 nand_nce; /* defined in nand_base.c, indicates which chip select is used for current nand chip */ -+ -+ if (ctrl & NAND_CTRL_CHANGE) { -+ if (ctrl & NAND_NCE) { -+ switch (nand_nce) { -+ case NAND_NCE1: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE1; -+ break; -+ case NAND_NCE2: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE2; -+ break; -+ case NAND_NCE3: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE3; -+ break; -+ case NAND_NCE4: -+ this->IO_ADDR_W = this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT4; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR |= EMC_NFCSR_NFCE4; -+ break; -+ default: -+ printk("error: no nand_nce 0x%x\n",nand_nce); -+ break; -+ } -+ } else { -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE1; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE2; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE3; -+ REG_EMC_NFCSR &= ~EMC_NFCSR_NFCE4; -+ } -+ -+ if (ctrl & NAND_ALE) -+ nandaddr = (u32)((u32)(this->IO_ADDR_W) | addr_offset); -+ else -+ nandaddr = (u32)((u32)(this->IO_ADDR_W) & ~addr_offset); -+ if (ctrl & NAND_CLE) -+ nandaddr = (u32)(nandaddr | cmd_offset); -+ else -+ nandaddr = (u32)(nandaddr & ~cmd_offset); -+ } -+ -+ this->IO_ADDR_W = (void __iomem *)nandaddr; -+ if (dat != NAND_CMD_NONE) { -+ writeb(dat, this->IO_ADDR_W); -+ /* printk("write cmd:0x%x to 0x%x\n",dat,(u32)this->IO_ADDR_W); */ -+ } -+} -+ -+static int jz_device_ready(struct mtd_info *mtd) -+{ -+ int ready, wait = 10; -+ while (wait--); -+ ready = __gpio_get_pin(91); -+ return ready; -+} -+ -+/* -+ * EMC setup -+ */ -+static void jz_device_setup(void) -+{ -+// PORT 0: -+// PORT 1: -+// PORT 2: -+// PIN/BIT N FUNC0 FUNC1 -+// 21 CS1# - -+// 22 CS2# - -+// 23 CS3# - -+// 24 CS4# - -+#define GPIO_CS2_N (32*2+22) -+#define GPIO_CS3_N (32*2+23) -+#define GPIO_CS4_N (32*2+24) -+#define SMCR_VAL 0x0d444400 -+ -+ __gpio_as_nand_8bit(1); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE1; -+ /* Read/Write timings */ -+ REG_EMC_SMCR1 = SMCR_VAL; -+ -+#if defined(CONFIG_MTD_NAND_CS2) -+ __gpio_as_func0(GPIO_CS2_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE2; -+ /* Read/Write timings */ -+ REG_EMC_SMCR2 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS3) -+ __gpio_as_func0(GPIO_CS3_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE3; -+ /* Read/Write timings */ -+ REG_EMC_SMCR3 = SMCR_VAL; -+#endif -+ -+#if defined(CONFIG_MTD_NAND_CS4) -+ __gpio_as_func0(GPIO_CS4_N); -+ /* Set NFE bit */ -+ REG_EMC_NFCSR |= EMC_NFCSR_NFE4; -+ /* Read/Write timings */ -+ REG_EMC_SMCR4 = SMCR_VAL; -+#endif -+} -+ -+#ifdef CONFIG_MTD_HW_BCH_ECC -+ -+static void jzsoc_nand_enable_bch_hwecc(struct mtd_info *mtd, int mode) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int oob_per_eccsize = this->ecc.layout->eccpos[0] / eccsteps; -+ -+ REG_BCH_INTS = 0xffffffff; -+ if (mode == NAND_ECC_READ) { -+ __ECC_DECODING(); -+ __ecc_cnt_dec(eccsize + oob_per_eccsize + eccbytes); -+#if defined(CONFIG_MTD_NAND_DMA) -+ __ecc_dma_enable(); -+#endif -+ } -+ -+ if (mode == NAND_ECC_WRITE) { -+ __ECC_ENCODING(); -+ __ecc_cnt_enc(eccsize + oob_per_eccsize); -+#if defined(CONFIG_MTD_NAND_DMA) -+ __ecc_dma_enable(); -+#endif -+ } -+} -+ -+/** -+ * bch_correct -+ * @dat: data to be corrected -+ * @idx: the index of error bit in an eccsize -+ */ -+static void bch_correct(struct mtd_info *mtd, u8 * dat, int idx) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int i, bit; /* the 'bit' of i byte is error */ -+ -+ i = (idx - 1) >> 3; -+ bit = (idx - 1) & 0x7; -+ -+ dprintk("error:i=%d, bit=%d\n",i,bit); -+ -+ if (i < eccsize){ -+ ((struct buf_be_corrected *)dat)->data[i] ^= (1 << bit); -+ } else if (i < eccsize + oob_per_eccsize) { -+ ((struct buf_be_corrected *)dat)->oob[i-eccsize] ^= (1 << bit); -+ } -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+/** -+ * jzsoc_nand_bch_correct_data -+ * @mtd: mtd info structure -+ * @dat: data to be corrected -+ * @errs0: pointer to the dma target buffer of bch decoding which stores BHINTS and -+ * BHERR0~3(8-bit BCH) or BHERR0~1(4-bit BCH) -+ * @calc_ecc: no used -+ */ -+static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * errs0, u_char * calc_ecc) -+{ -+ u32 stat; -+ u32 *errs = (u32 *)errs0; -+ -+ if (REG_DMAC_DCCSR(0) & DMAC_DCCSR_BERR) { -+ stat = errs[0]; -+ dprintk("stat=%x err0:%x err1:%x \n", stat, errs[1], errs[2]); -+ -+ if (stat & BCH_INTS_ERR) { -+ if (stat & BCH_INTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; -+ switch (errcnt) { -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ case 8: -+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 7: -+ bch_correct(mtd, dat, (errs[4] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ case 6: -+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 5: -+ bch_correct(mtd, dat, (errs[3] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+#endif -+ case 4: -+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 3: -+ bch_correct(mtd, dat, (errs[2] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ case 2: -+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ case 1: -+ bch_correct(mtd, dat, (errs[1] & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ default: -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+#else /* cpu mode */ -+ -+/** -+ * jzsoc_nand_bch_correct_data -+ * @mtd: mtd info structure -+ * @dat: data to be corrected -+ * @read_ecc: pointer to ecc buffer calculated when nand writing -+ * @calc_ecc: no used -+ */ -+static int jzsoc_nand_bch_correct_data(struct mtd_info *mtd, u_char * dat, u_char * read_ecc, u_char * calc_ecc) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ short k; -+ u32 stat; -+ -+ /* Write data to REG_BCH_DR */ -+ for (k = 0; k < eccsize; k++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[k]; -+ } -+ /* Write oob to REG_BCH_DR */ -+ for (k = 0; k < oob_per_eccsize; k++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[k]; -+ } -+ /* Write parities to REG_BCH_DR */ -+ for (k = 0; k < eccbytes; k++) { -+ REG_BCH_DR = read_ecc[k]; -+ } -+ -+ /* Wait for completion */ -+ __ecc_decode_sync(); -+ __ecc_disable(); -+ -+ /* Check decoding */ -+ stat = REG_BCH_INTS; -+ -+ if (stat & BCH_INTS_ERR) { -+ /* Error occurred */ -+ if (stat & BCH_INTS_UNCOR) { -+ printk("NAND: Uncorrectable ECC error--\n"); -+ return -1; -+ } else { -+ u32 errcnt = (stat & BCH_INTS_ERRC_MASK) >> BCH_INTS_ERRC_BIT; -+ switch (errcnt) { -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ case 8: -+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 7: -+ bch_correct(mtd, dat, (REG_BCH_ERR3 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+ case 6: -+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 5: -+ bch_correct(mtd, dat, (REG_BCH_ERR2 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+#endif -+ case 4: -+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 3: -+ bch_correct(mtd, dat, (REG_BCH_ERR1 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ /* FALL-THROUGH */ -+ case 2: -+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_ODD_MASK) >> BCH_ERR_INDEX_ODD_BIT); -+ /* FALL-THROUGH */ -+ case 1: -+ bch_correct(mtd, dat, (REG_BCH_ERR0 & BCH_ERR_INDEX_EVEN_MASK) >> BCH_ERR_INDEX_EVEN_BIT); -+ return 0; -+ default: -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+static int jzsoc_nand_calculate_bch_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) -+{ -+ struct nand_chip *this = (struct nand_chip *)(mtd->priv); -+ int eccsize = this->ecc.size; -+ int eccbytes = this->ecc.bytes; -+ int eccsteps = this->ecc.steps / this->planenum; -+ int ecc_pos = this->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ volatile u8 *paraddr = (volatile u8 *)BCH_PAR0; -+ short i; -+ -+ /* Write data to REG_BCH_DR */ -+ for (i = 0; i < eccsize; i++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->data[i]; -+ } -+ /* Write oob to REG_BCH_DR */ -+ for (i = 0; i < oob_per_eccsize; i++) { -+ REG_BCH_DR = ((struct buf_be_corrected *)dat)->oob[i]; -+ } -+ __ecc_encode_sync(); -+ __ecc_disable(); -+ -+ for (i = 0; i < eccbytes; i++) { -+ ecc_code[i] = *paraddr++; -+ } -+ -+ return 0; -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+/** -+ * nand_write_page_hwecc_bch - [REPLACABLE] hardware ecc based page write function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @buf: data buffer -+ */ -+static void nand_write_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, u8 cmd_pgprog) -+{ -+ int eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int i, err, timeout; -+ const u8 *databuf; -+ u8 *oobbuf; -+ jz_dma_desc_8word *desc; -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ memcpy(prog_buf, buf, pagesize); -+ memcpy(prog_buf + pagesize, chip->oob_poi, oobsize); -+ dma_cache_wback_inv((u32)prog_buf, pagesize + oobsize); -+#else -+ databuf = buf; -+ oobbuf = chip->oob_poi; -+ -+ /* descriptors for encoding data blocks */ -+ desc = dma_desc_enc; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+ dprintk("dma_desc_enc:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for encoding oob blocks */ -+ desc = dma_desc_enc1; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+ dprintk("dma_desc_enc1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptor for nand programing data block */ -+ desc = dma_desc_nand_prog; -+ desc->dsadr = CPHYSADDR((u32)databuf); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ -+ dprintk("dma_desc_nand_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for nand programing oob block */ -+ desc++; -+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_W); /* It will be changed when using multiply chip select */ -+ dprintk("dma_desc_oob_prog:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for __nand_cmd(CMD_PGPROG) */ -+ desc++; -+ *pval_nand_cmd_pgprog = cmd_pgprog; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ -+ if (cmd_pgprog == 0x10) -+ desc->dcmd |= DMAC_DCMD_LINK; /* __nand_sync() by a DMA descriptor */ -+ else if (cmd_pgprog == 0x11) -+ desc->dcmd &= ~DMAC_DCMD_LINK; /* __nand_sync() by polling */ -+ -+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 1) * (sizeof(jz_dma_desc_8word))); -+ dma_cache_wback_inv((u32)databuf, pagesize); -+ dma_cache_wback_inv((u32)oobbuf, oobsize); -+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ -+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ -+#endif -+ -+ REG_DMAC_DCCSR(bch_dma_chan) = 0; -+ REG_DMAC_DCCSR(nand_dma_chan) = 0; -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_enc); -+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_prog); -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_ENC; -+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_AUTO; -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(bch_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; -+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; -+ -+ /* Enable BCH encoding */ -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ -+ dma_ack1 = 0; -+ nand_status = NAND_PROG; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ __dmac_channel_set_doorbell(bch_dma_chan); -+ -+#if USE_IRQ -+ if (cmd_pgprog == 0x10) { -+ dprintk("nand prog before wake up\n"); -+ err = wait_event_interruptible_timeout(nand_prog_wait_queue, dma_ack1, 3 * HZ); -+ nand_status = NAND_NONE; -+ dprintk("nand prog after wake up\n"); -+ if (!err) { -+ printk("*** NAND WRITE, Warning, wait event 3s timeout!\n"); -+ dump_jz_dma_channel(0); -+ dump_jz_dma_channel(nand_dma_chan); -+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); -+ } -+ dprintk("timeout remain = %d\n", err); -+ } else if (cmd_pgprog == 0x11) { -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); -+ if (timeout <= 0) -+ printk("two-plane prog 0x11 timeout!\n"); -+ } -+#else -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(nand_dma_chan)) && (timeout--)); -+ while(!chip->dev_ready(mtd)); -+ if (timeout <= 0) -+ printk("not use irq, prog timeout!\n"); -+#endif -+} -+ -+static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) -+{ -+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x10); -+} -+ -+static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf) -+{ -+ int page; -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ nand_write_page_hwecc_bch0(mtd, chip, buf, 0x11); -+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); -+ nand_write_page_hwecc_bch0(mtd, chip, buf + pagesize, 0x10); -+} -+ -+#else /* nand write in cpu mode */ -+ -+static void nand_write_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int oob_per_eccsize = chip->ecc.layout->eccpos[0] / eccsteps; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int ecctotal = chip->ecc.total / chip->planenum; -+ uint8_t *p = (uint8_t *)buf; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ static struct buf_be_corrected buf_calc0; -+ struct buf_be_corrected *buf_calc = &buf_calc0; -+ -+ for (i = 0; i < eccsteps; i++, p += eccsize) { -+ buf_calc->data = (u8 *)buf + eccsize * i; -+ buf_calc->oob = chip->oob_poi + oob_per_eccsize * i; -+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE); -+ chip->ecc.calculate(mtd, (u8 *)buf_calc, &ecc_calc[eccbytes*i]); -+ chip->write_buf(mtd, p, eccsize); -+ } -+ -+ for (i = 0; i < ecctotal; i++) -+ chip->oob_poi[eccpos[i]] = ecc_calc[i]; -+ -+ chip->write_buf(mtd, chip->oob_poi, oobsize); -+} -+ -+/* nand write using two-plane mode */ -+static void nand_write_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf) -+{ -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ int page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, 0x00, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, 0x00, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ nand_write_page_hwecc_bch(mtd, chip, buf); -+ -+ chip->cmdfunc(mtd, 0x11, -1, -1); /* send cmd 0x11 */ -+ ndelay(100); -+ while(!chip->dev_ready(mtd)); -+ -+ chip->cmdfunc(mtd, 0x81, 0x00, page + ppb); /* send cmd 0x81 */ -+ nand_write_page_hwecc_bch(mtd, chip, buf + pagesize); -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+/** -+ * nand_read_page_hwecc_bch - [REPLACABLE] hardware ecc based page read function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @buf: buffer to store read data -+ * -+ * Not for syndrome calculating ecc controllers which need a special oob layout -+ */ -+#if defined(CONFIG_MTD_NAND_DMA) -+static int nand_read_page_hwecc_bch0(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, u32 page) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ u8 *databuf, *oobbuf; -+ jz_dma_desc_8word *desc; -+ int err; -+ u32 addrport, cmdport; -+ static struct buf_be_corrected buf_correct0; -+ -+ addrport = (u32)(chip->IO_ADDR_R) | addr_offset; -+ cmdport = (u32)(chip->IO_ADDR_R) | cmd_offset; -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ databuf = read_buf; -+ oobbuf = read_buf + pagesize; -+ -+ dma_cache_inv((u32)read_buf, pagesize + oobsize); // databuf should be invalidated. -+ memset(errs, 0, eccsteps * ERRS_SIZE * 4); -+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); -+#else -+ -+ databuf = buf; -+ oobbuf = chip->oob_poi; -+ -+ /* descriptor for nand reading data block */ -+ desc = dma_desc_nand_read; -+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ -+ desc->dtadr = CPHYSADDR((u32)databuf); /* DMA target address */ -+ -+ dprintk("desc_nand_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptor for nand reading oob block */ -+ desc++; -+ desc->dsadr = CPHYSADDR((u32)chip->IO_ADDR_R); /* It will be changed when using multiply chip select */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ -+ dprintk("desc_oob_read:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ -+ /* descriptors for data to be written to bch */ -+ desc = dma_desc_dec; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)databuf) + i * eccsize; /* DMA source address */ -+ dprintk("dma_desc_dec:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for oob to be written to bch */ -+ desc = dma_desc_dec1; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ -+ dprintk("dma_desc_dec1:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for parities to be written to bch */ -+ desc = dma_desc_dec2; -+ for (i = 0; i < eccsteps; i++) { -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ -+ dprintk("dma_desc_dec2:desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); -+ -+ memset(errs, 0, eccsteps * ERRS_SIZE * 4); -+ dma_cache_inv((u32)databuf, pagesize); // databuf should be invalidated. -+ dma_cache_inv((u32)oobbuf, oobsize); // oobbuf should be invalidated too -+ dma_cache_wback_inv((u32)errs, eccsteps * ERRS_SIZE * 4); -+#endif -+ REG_DMAC_DCCSR(bch_dma_chan) = 0; -+ REG_DMAC_DCCSR(nand_dma_chan) = 0; -+ -+ /* Setup DMA descriptor address */ -+ REG_DMAC_DDA(nand_dma_chan) = CPHYSADDR((u32)dma_desc_nand_read); -+ REG_DMAC_DDA(bch_dma_chan) = CPHYSADDR((u32)dma_desc_dec); -+ -+ /* Setup request source */ -+ REG_DMAC_DRSR(nand_dma_chan) = DMAC_DRSR_RS_NAND; -+ REG_DMAC_DRSR(bch_dma_chan) = DMAC_DRSR_RS_BCH_DEC; -+ -+ /* Enable DMA */ -+ REG_DMAC_DMACR(0) |= DMAC_DMACR_DMAE; -+ REG_DMAC_DMACR(nand_dma_chan/HALF_DMA_NUM) |= DMAC_DMACR_DMAE; -+ -+ /* Enable BCH decoding */ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ -+ dma_ack = 0; -+ nand_status = NAND_READ; -+ /* DMA doorbell set -- start nand DMA now ... */ -+ __dmac_channel_set_doorbell(nand_dma_chan); -+ -+ /* Setup DMA channel control/status register */ -+ REG_DMAC_DCCSR(nand_dma_chan) = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; -+ -+#define __nand_cmd(n) (REG8(cmdport) = (n)) -+#define __nand_addr(n) (REG8(addrport) = (n)) -+ -+ __nand_cmd(NAND_CMD_READ0); -+ -+ __nand_addr(0); -+ if (pagesize != 512) -+ __nand_addr(0); -+ -+ __nand_addr(page & 0xff); -+ __nand_addr((page >> 8) & 0xff); -+ -+ /* One more address cycle for the devices whose number of page address bits > 16 */ -+ if (((chip->chipsize >> chip->page_shift) >> 16) - 1 > 0) -+ __nand_addr((page >> 16) & 0xff); -+ -+ if (pagesize != 512) -+ __nand_cmd(NAND_CMD_READSTART); -+ -+#if USE_IRQ -+ do { -+ err = wait_event_interruptible_timeout(nand_read_wait_queue, dma_ack, 3 * HZ); -+ }while(err == -ERESTARTSYS); -+ nand_status = NAND_NONE; -+ -+ if (!err) { -+ printk("*** NAND READ, Warning, wait event 3s timeout!\n"); -+ dump_jz_dma_channel(0); -+ dump_jz_dma_channel(nand_dma_chan); -+ printk("REG_BCH_CR=%x REG_BCH_CNT=0x%x REG_BCH_INTS=%x\n", REG_BCH_CR, REG_BCH_CNT, REG_BCH_INTS); -+ printk("databuf[0]=%x\n", databuf[0]); -+ } -+ dprintk("timeout remain = %d\n", err); -+#else -+ int timeout; -+ timeout = 100000; -+ while ((!__dmac_channel_transmit_end_detected(bch_dma_chan)) && (timeout--)); -+ if (timeout <= 0) { -+ printk("not use irq, NAND READ timeout!\n"); -+ } -+#endif -+ -+ for (i = 0; i < eccsteps; i++) { -+ int stat; -+ struct buf_be_corrected *buf_correct = &buf_correct0; -+ -+ buf_correct->data = databuf + eccsize * i; -+ buf_correct->oob = oobbuf + oob_per_eccsize * i; -+ -+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, (u8 *)&errs[i * ERRS_SIZE], NULL); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ memcpy(buf, read_buf, pagesize); -+ memcpy(chip->oob_poi, read_buf + pagesize, oobsize); -+#endif -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ u32 page = global_page; -+ -+ nand_read_page_hwecc_bch0(mtd, chip, buf, page); -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ u32 page; -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* read 1st page */ -+ nand_read_page_hwecc_bch0(mtd, chip, buf, page); -+ -+ /* read 2nd page */ -+ nand_read_page_hwecc_bch0(mtd, chip, buf + pagesize, page + ppb); -+ return 0; -+} -+ -+#else /* nand read in cpu mode */ -+ -+static int nand_read_page_hwecc_bch(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int ecctotal = chip->ecc.total / chip->planenum; -+ static struct buf_be_corrected buf_correct0; -+ -+ chip->read_buf(mtd, buf, pagesize); -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ -+ for (i = 0; i < ecctotal; i++) { -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ } -+ -+ for (i = 0; i < eccsteps; i++) { -+ int stat; -+ struct buf_be_corrected *buf_correct = &buf_correct0; -+ -+ buf_correct->data = buf + eccsize * i; -+ buf_correct->oob = chip->oob_poi + oob_per_eccsize * i; -+ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ stat = chip->ecc.correct(mtd, (u8 *)buf_correct, &ecc_code[eccbytes*i], &ecc_calc[eccbytes*i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+ return 0; -+} -+ -+static int nand_read_page_hwecc_bch_planes(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf) -+{ -+ int pagesize = mtd->writesize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ uint32_t page; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page */ -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ nand_read_page_hwecc_bch(mtd, chip, buf); -+ -+ /* Read 2nd page */ -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page + ppb); -+ nand_read_page_hwecc_bch(mtd, chip, buf+pagesize); -+ return 0; -+} -+#endif /* CONFIG_MTD_NAND_DMA */ -+ -+#endif /* CONFIG_MTD_HW_BCH_ECC */ -+ -+/* read oob using two-plane mode */ -+static int nand_read_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page, int sndcmd) -+{ -+ int page; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* Read first page OOB */ -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ } -+ chip->read_buf(mtd, chip->oob_poi, oobsize); -+ /* Read second page OOB */ -+ page += ppb; -+ if (sndcmd) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ sndcmd = 0; -+ } -+ chip->read_buf(mtd, chip->oob_poi+oobsize, oobsize); -+ return 0; -+} -+ -+/* write oob using two-plane mode */ -+static int nand_write_oob_std_planes(struct mtd_info *mtd, struct nand_chip *chip, -+ int global_page) -+{ -+ int status = 0, page; -+ const uint8_t *buf = chip->oob_poi; -+ int pagesize = mtd->writesize >> 1; -+ int oobsize = mtd->oobsize >> 1; -+ int ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x80, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x80, pagesize, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x80, pagesize, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send first command to program the OOB data */ -+ chip->cmdfunc(mtd, 0x11, -1, -1); -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ page += ppb; -+ buf += oobsize; -+ chip->cmdfunc(mtd, 0x81, pagesize, page); -+ chip->write_buf(mtd, buf, oobsize); -+ /* Send command to program the OOB data */ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ /* Wait long R/B */ -+ ndelay(100); -+ status = chip->waitfunc(mtd, chip); -+ -+ return status & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+/* nand erase using two-plane mode */ -+static void single_erase_cmd_planes(struct mtd_info *mtd, int global_page) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int page, ppb = mtd->erasesize / mtd->writesize; -+ -+ page = (global_page / ppb) * ppb + global_page; /* = global_page%ppb + (global_page/ppb)*ppb*2 */ -+ -+ /* send cmd 0x60, the MSB should be valid if realplane is 4 */ -+ if (chip->realplanenum == 2) -+ chip->cmdfunc(mtd, 0x60, -1, 0x00); -+ else -+ chip->cmdfunc(mtd, 0x60, -1, page & (1 << (chip->chip_shift - chip->page_shift))); -+ -+ page += ppb; -+ chip->cmdfunc(mtd, 0x60, -1, page & (~(ppb-1))); /* send cmd 0x60 */ -+ -+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ -+ /* Do not need wait R/B or check status */ -+} -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ -+#if USE_IRQ -+static irqreturn_t nand_dma_irq(int irq, void *dev_id) -+{ -+ u8 dma_chan; -+ volatile int wakeup = 0; -+ -+ dma_chan = irq - IRQ_DMA_0; -+ -+ dprintk("jz4750_dma_irq %d, channel %d\n", irq, dma_chan); -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ wakeup = 1; -+ printk("DMA HALT\n"); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_address_error(dma_chan); -+ -+ REG_DMAC_DSAR(dma_chan) = 0; /* reset source address register */ -+ REG_DMAC_DTAR(dma_chan) = 0; /* reset destination address register */ -+ -+ /* clear address error in DMACR */ -+ REG_DMAC_DMACR((dma_chan / HALF_DMA_NUM)) &= ~(1 << 2); -+ wakeup = 1; -+ printk("DMA address error!\n"); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ wakeup = 1; -+ printk("DMA DESC INVALID\n"); -+ } -+#if 1 -+ -+ while (!__dmac_channel_transmit_end_detected(dma_chan)); -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ dprintk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ wakeup = 0; -+ } -+#endif -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ dprintk("DMA TT\n"); -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ __dmac_channel_clear_transmit_end(dma_chan); -+ wakeup = 1; -+ } -+ -+ if (wakeup) { -+ dprintk("ack %d irq , wake up dma_chan %d nand_status %d\n", dma_ack, dma_chan, nand_status); -+ /* wakeup wait event */ -+ if ((dma_chan == nand_dma_chan) && (nand_status == NAND_PROG)) { -+ dprintk("nand prog dma irq, wake up----\n"); -+ dma_ack1 = 1; -+ wake_up_interruptible(&nand_prog_wait_queue); -+ } -+ -+ if ((dma_chan == bch_dma_chan) && (nand_status == NAND_READ)) { -+ dprintk("nand read irq, wake up----\n"); -+ dma_ack = 1; -+ wake_up_interruptible(&nand_read_wait_queue); -+ } -+ wakeup = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+#endif /* USE_IRQ */ -+ -+static int jz4750_nand_dma_init(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int eccsize = chip->ecc.size; -+ int eccsteps = chip->ecc.steps / chip->planenum; -+ int eccbytes = chip->ecc.bytes; -+ int ecc_pos = chip->ecc.layout->eccpos[0]; -+ int oob_per_eccsize = ecc_pos / eccsteps; -+ int pagesize = mtd->writesize / chip->planenum; -+ int oobsize = mtd->oobsize / chip->planenum; -+ int i, err; -+ jz_dma_desc_8word *desc, *dma_desc_bch_ddr, *dma_desc_nand_ddr, *dma_desc_nand_cmd_pgprog; -+ u32 *pval_nand_dcs, *pval_bch_ddr, *pval_bch_dcs, *dummy; -+ u32 next; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ u8 *oobbuf; -+#endif -+ -+#if USE_IRQ -+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", nand_dma_irq, IRQF_DISABLED, NULL)) < 0) { -+ printk("can't reqeust DMA nand channel.\n"); -+ return 0; -+ } -+ dprintk("nand dma channel:%d----\n", nand_dma_chan); -+ -+ if ((err = request_irq(IRQ_DMA_0 + bch_dma_chan, nand_dma_irq, IRQF_DISABLED, "bch_dma", NULL))) { -+ printk("bch_dma irq request err\n"); -+ return 0; -+ } -+#else -+ if ((nand_dma_chan = jz_request_dma(DMA_ID_NAND, "nand read or write", NULL, IRQF_DISABLED, NULL)) < 0) { -+ printk("can't reqeust DMA nand channel.\n"); -+ return 0; -+ } -+ dprintk("nand dma channel:%d----\n", nand_dma_chan); -+#endif -+ -+ __dmac_channel_enable_clk(nand_dma_chan); -+ __dmac_channel_enable_clk(bch_dma_chan); -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ if (pagesize < 4096) { -+ read_buf = prog_buf = (u8 *) __get_free_page(GFP_KERNEL); -+ } else { -+ read_buf = prog_buf = (u8 *) __get_free_pages(GFP_KERNEL, 1); -+ } -+ if (!read_buf) -+ return -ENOMEM; -+#endif -+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), and the space for the value -+ * of ddr and dcs of channel 0 and channel nand_dma_chan (4 * (2 + 2) bytes) */ -+ errs = (u32 *)kmalloc(4 * (2 + 2 + 5 * eccsteps), GFP_KERNEL); -+ if (!errs) -+ return -ENOMEM; -+ -+ pval_nand_ddr = errs + 5 * eccsteps; -+ pval_nand_dcs = pval_nand_ddr + 1; -+ pval_bch_ddr = pval_nand_dcs + 1; -+ pval_bch_dcs = pval_bch_ddr + 1; -+ /* space for nand prog waiting target, the content is useless */ -+ dummy = pval_bch_dcs + 1; -+ /* space to store CMD_PGPROG(0x10) or 0x11 */ -+ pval_nand_cmd_pgprog = (u8 *)(dummy + 1); -+ -+ /* desc can't across 4KB boundary, as desc base address is fixed */ -+ /* space of descriptors for nand reading data and oob blocks */ -+ dma_desc_nand_read = (jz_dma_desc_8word *) __get_free_page(GFP_KERNEL); -+ if (!dma_desc_nand_read) -+ return -ENOMEM; -+ -+ /* space of descriptors for bch decoding */ -+ dma_desc_dec = dma_desc_nand_read + 2; -+ dma_desc_dec1 = dma_desc_dec + eccsteps; -+ dma_desc_dec2 = dma_desc_dec + eccsteps * 2; -+ -+ /* space of descriptors for notifying bch channel */ -+ dma_desc_bch_ddr = dma_desc_dec2 + eccsteps; -+ -+ /* space of descriptors for bch encoding */ -+ dma_desc_enc = dma_desc_bch_ddr + 2; -+ dma_desc_enc1 = dma_desc_enc + eccsteps; -+ -+ /* space of descriptors for nand programing data and oob blocks */ -+ dma_desc_nand_prog = dma_desc_enc1 + eccsteps; -+ -+ /* space of descriptors for nand prog waiting, including pgprog and sync */ -+ dma_desc_nand_cmd_pgprog = dma_desc_nand_prog + 2; -+ -+ /* space of descriptors for notifying nand channel, including ddr and dcsr */ -+ dma_desc_nand_ddr = dma_desc_nand_cmd_pgprog + 2; -+ -+/************************************* -+ * Setup of nand programing descriptors -+ *************************************/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ oobbuf = prog_buf + pagesize; -+#endif -+ /* set descriptor for encoding data blocks */ -+ desc = dma_desc_enc; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_enc1) + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)prog_buf) + i * eccsize; /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ desc++; -+ } -+ -+ /* set descriptor for encoding oob blocks */ -+ desc = dma_desc_enc1; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_enc) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | -+ DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address, 28/4 = 7bytes */ -+ desc->dtadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; /* size: 7 bytes -> 2 words */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_ENC; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ desc++; -+ } -+ -+ next = (CPHYSADDR((u32)dma_desc_nand_ddr)) >> 4; -+ desc--; -+ desc->ddadr = (next << 24) + (oob_per_eccsize + 3) / 4; -+ -+ /* set the descriptor to set door bell of nand_dma_chan for programing nand */ -+ desc = dma_desc_nand_ddr; -+ *pval_nand_ddr = 1 << (nand_dma_chan - nand_dma_chan / HALF_DMA_NUM * HALF_DMA_NUM); -+ next = (CPHYSADDR((u32)dma_desc_nand_ddr) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(nand_dma_chan / HALF_DMA_NUM)); /* nand_dma_chan's descriptor addres register */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("*pval_nand_ddr=0x%x\n", *pval_nand_ddr); -+ -+ /* set the descriptor to write dccsr of nand_dma_chan for programing nand, dccsr should be set at last */ -+ desc++; -+ *pval_nand_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; /* set value for writing ddr to enable channel nand_dma_chan */ -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_dcs); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(nand_dma_chan)); /* address of dma door bell set register */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("*pval_nand_dcs=0x%x\n", *pval_nand_dcs); -+ -+ /* set descriptor for nand programing data block */ -+ desc = dma_desc_nand_prog; -+ next = (CPHYSADDR((u32)dma_desc_nand_prog) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)prog_buf); /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address */ -+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for nand programing oob block */ -+ desc++; -+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf); /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)(chip->IO_ADDR_W)); /* DMA target address: dataport */ -+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for __nand_cmd(CMD_PGPROG) */ -+ desc = dma_desc_nand_cmd_pgprog; -+ *pval_nand_cmd_pgprog = NAND_CMD_PAGEPROG; -+ next = (CPHYSADDR((u32)dma_desc_nand_cmd_pgprog) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_8 | DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_nand_cmd_pgprog); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)chip->IO_ADDR_R | cmd_offset); /* DMA target address: cmdport */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 byte */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for __nand_sync() */ -+ desc++; -+#if USE_IRQ -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_TIE; -+#else -+ desc->dcmd = -+ DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+#endif -+ desc->dsadr = CPHYSADDR((u32)pval_nand_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR((u32)dummy); /* DMA target address, the content is useless */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_NAND; -+ dprintk("1cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* eccsteps*2 + 2 + 2 + 2: -+ dma_desc_enc + dma_desc_enc1 + dma_desc_nand_prog(oob) + dma_desc_nand_ddr(csr) -+ + dma_desc_nand_cmd_pgprog(sync) */ -+ dma_cache_wback_inv((u32)dma_desc_enc, (eccsteps * 2 + 2 + 2 + 2) * (sizeof(jz_dma_desc_8word))); -+ /* 4*6: pval_nand_ddr, pval_nand_dcs, pval_bch_ddr, pval_bch_dcs, dummy, pval_nand_cmd_pgprog */ -+ dma_cache_wback_inv((u32)pval_nand_ddr, 4 * 8); /* 8 words, a cache line */ -+ -+/************************************* -+ * Setup of nand reading descriptors -+ *************************************/ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ oobbuf = read_buf + pagesize; -+#endif -+ /* set descriptor for nand reading data block */ -+ desc = dma_desc_nand_read; -+ next = (CPHYSADDR((u32)dma_desc_nand_read) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dtadr = CPHYSADDR((u32)read_buf); /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + pagesize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_NAND; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set descriptor for nand reading oob block */ -+ desc++; -+ next = (CPHYSADDR((u32)dma_desc_bch_ddr)) >> 4; -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_NAND | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)(chip->IO_ADDR_R)); /* DMA source address */ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dtadr = CPHYSADDR((u32)oobbuf); /* DMA target address */ -+#endif -+ desc->ddadr = (next << 24) + oobsize / DIV_DS_NAND; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ dprintk("cmd:%x sadr:%x tadr:%x dadr:%x\n", desc->dcmd, desc->dsadr, desc->dtadr, desc->ddadr); -+ -+ /* set the descriptor to set door bell for bch */ -+ desc = dma_desc_bch_ddr; -+ *pval_bch_ddr = DMAC_DMADBSR_DBS0; // set value for writing ddr to enable channel 0 -+ next = (CPHYSADDR((u32)dma_desc_bch_ddr) + sizeof(jz_dma_desc_8word)) >> 4; -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_LINK; -+ desc->dsadr = CPHYSADDR((u32)pval_bch_ddr); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DMADBSR(0)); /* channel 1's descriptor addres register */ -+ desc->ddadr = (next << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ -+ /* set descriptor for writing dcsr */ -+ desc++; -+ *pval_bch_dcs = DMAC_DCCSR_DES8 | DMAC_DCCSR_EN; // set value for writing ddr to enable channel 1 -+ desc->dcmd = DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT; -+ desc->dsadr = CPHYSADDR((u32)pval_bch_dcs); /* DMA source address */ -+ desc->dtadr = CPHYSADDR(DMAC_DCCSR(bch_dma_chan)); /* address of dma door bell set register */ -+ desc->ddadr = (0 << 24) + 1; /* size: 1 word */ -+ desc->dreqt = DMAC_DRSR_RS_AUTO; -+ -+ /* descriptors for data to be written to bch */ -+ desc = dma_desc_dec; -+ for (i = 0; i < eccsteps; i++) { -+ next = CPHYSADDR((u32)dma_desc_dec1 + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)read_buf) + i * eccsize; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + eccsize / DIV_DS_BCH; /* size: eccsize bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for oob to be written to bch */ -+ desc = dma_desc_dec1; -+ for (i = 0; i < eccsteps; i++) { -+ next = CPHYSADDR((u32)dma_desc_dec2 + i * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + oob_per_eccsize * i; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + oob_per_eccsize; /* size: 7 bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ -+ /* descriptors for parities to be written to bch */ -+ desc = dma_desc_dec2; -+ for (i = 0; i < eccsteps; i++) { -+ next = (CPHYSADDR((u32)dma_desc_dec) + (i + 1) * (sizeof(jz_dma_desc_8word))) >> 4; -+ -+ desc->dcmd = -+ DMAC_DCMD_BLAST | DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_8 | -+ DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_BCH | DMAC_DCMD_LINK; -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ desc->dsadr = CPHYSADDR((u32)oobbuf) + ecc_pos + i * eccbytes; /* DMA source address */ -+#endif -+ desc->dtadr = CPHYSADDR((u32)errs) + i * 4 * ERRS_SIZE; /* DMA target address */ -+ desc->ddadr = (next << 24) + (eccbytes + 15) / DIV_DS_BCH; /* size: eccbytes bytes */ -+ desc->dreqt = DMAC_DRSR_RS_BCH_DEC; -+ dprintk("desc:%x cmd:%x sadr:%x tadr:%x dadr:%x\n", (u32)desc, desc->dcmd, desc->dsadr, desc->dtadr, -+ desc->ddadr); -+ desc++; -+ } -+ desc--; -+ desc->dcmd &= ~DMAC_DCMD_LINK; -+#if USE_IRQ -+ desc->dcmd |= DMAC_DCMD_TIE; -+#endif -+ -+ dma_cache_wback_inv((u32)dma_desc_nand_read, (2 + 2 + eccsteps * 3) * (sizeof(jz_dma_desc_8word))); -+ dma_cache_wback_inv((u32)pval_bch_ddr, 4 * 2); /* two words */ -+ -+ return 0; -+} -+ -+#endif /* CONFIG_MTD_NAND_DMA */ -+/* -+ * Main initialization routine -+ */ -+int __init jznand_init(void) -+{ -+ struct nand_chip *this; -+ int nr_partitions, ret, i; -+ -+ printk(KERN_INFO "JZ NAND init"); -+#if defined(CONFIG_MTD_NAND_DMA) -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ printk(KERN_INFO " DMA mode, using DMA buffer in NAND driver.\n"); -+#else -+ printk(KERN_INFO " DMA mode, using DMA buffer in upper layer.\n"); -+#endif -+#else -+ printk(KERN_INFO " CPU mode.\n"); -+#endif -+ -+ -+ /* Allocate memory for MTD device structure and private data */ -+ jz_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); -+ if (!jz_mtd) { -+ printk("Unable to allocate JzSOC NAND MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ /* Allocate memory for NAND when using only one plane */ -+ jz_mtd1 = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); -+ if (!jz_mtd1) { -+ printk ("Unable to allocate JzSOC NAND MTD device structure 1.\n"); -+ kfree(jz_mtd); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *)(&jz_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *)jz_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *)this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ jz_mtd->priv = this; -+ -+ if (is_share_mode()) { -+ addr_offset = NAND_ADDR_OFFSET0; -+ cmd_offset = NAND_CMD_OFFSET0; -+ } else { -+ addr_offset = NAND_ADDR_OFFSET1; -+ cmd_offset = NAND_CMD_OFFSET1; -+ } -+ -+ /* Set & initialize NAND Flash controller */ -+ jz_device_setup(); -+ -+ /* Set address of NAND IO lines to static bank1 by default */ -+ this->IO_ADDR_R = (void __iomem *)NAND_DATA_PORT1; -+ this->IO_ADDR_W = (void __iomem *)NAND_DATA_PORT1; -+ this->cmd_ctrl = jz_hwcontrol; -+ this->dev_ready = jz_device_ready; -+ -+#ifdef CONFIG_MTD_HW_BCH_ECC -+ this->ecc.calculate = jzsoc_nand_calculate_bch_ecc; -+ this->ecc.correct = jzsoc_nand_bch_correct_data; -+ this->ecc.hwctl = jzsoc_nand_enable_bch_hwecc; -+ this->ecc.mode = NAND_ECC_HW; -+ this->ecc.size = 512; -+ this->ecc.read_page = nand_read_page_hwecc_bch; -+ this->ecc.write_page = nand_write_page_hwecc_bch; -+#if defined(CONFIG_MTD_HW_BCH_8BIT) -+ this->ecc.bytes = 13; -+#else -+ this->ecc.bytes = 7; -+#endif -+#endif -+ -+#ifdef CONFIG_MTD_SW_HM_ECC -+ this->ecc.mode = NAND_ECC_SOFT; -+#endif -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ /* Scan to find existance of the device */ -+ ret = nand_scan_ident(jz_mtd, NAND_MAX_CHIPS); -+ -+ if (!ret) { -+ if (this->planenum == 2) { -+ /* reset nand functions */ -+ this->erase_cmd = single_erase_cmd_planes; -+ this->ecc.read_page = nand_read_page_hwecc_bch_planes; -+ this->ecc.write_page = nand_write_page_hwecc_bch_planes; -+ this->ecc.read_oob = nand_read_oob_std_planes; -+ this->ecc.write_oob = nand_write_oob_std_planes; -+ -+ printk(KERN_INFO "Nand using two-plane mode, " -+ "and resized to writesize:%d oobsize:%d blocksize:0x%x \n", -+ jz_mtd->writesize, jz_mtd->oobsize, jz_mtd->erasesize); -+ } -+ } -+ -+ /* Determine whether all the partitions will use multiple planes if supported */ -+ nr_partitions = sizeof(partition_info) / sizeof(struct mtd_partition); -+ all_use_planes = 1; -+ for (i = 0; i < nr_partitions; i++) { -+ all_use_planes &= partition_info[i].use_planes; -+ } -+ -+ if (!ret) -+ ret = nand_scan_tail(jz_mtd); -+ -+ if (ret){ -+ kfree (jz_mtd1); -+ kfree (jz_mtd); -+ return -ENXIO; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+ jz4750_nand_dma_init(jz_mtd); -+#endif -+ -+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.read_page = nand_read_page_hwecc_bch; -+ ((struct nand_chip *) (&jz_mtd1[1]))->ecc.write_page = nand_write_page_hwecc_bch; -+ -+ /* Register the partitions */ -+ printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nr_partitions, jz_mtd->name); -+ -+ if ((this->planenum == 2) && !all_use_planes) { -+ for (i = 0; i < nr_partitions; i++) { -+ if (partition_info[i].use_planes) -+ add_mtd_partitions(jz_mtd, &partition_info[i], 1); -+ else -+ add_mtd_partitions(jz_mtd1, &partition_info[i], 1); -+ } -+ } else { -+ kfree(jz_mtd1); -+ add_mtd_partitions(jz_mtd, partition_info, nr_partitions); -+ } -+ return 0; -+} -+ -+module_init(jznand_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+ -+#if defined(CONFIG_MTD_NAND_DMA) -+static int jz4750_nand_dma_exit(struct mtd_info *mtd) -+{ -+ int pagesize = mtd->writesize / chip->planenum; -+ -+#if USE_IRQ -+ free_irq(IRQ_DMA_0 + nand_dma_chan, NULL); -+ free_irq(IRQ_DMA_0 + bch_dma_chan, NULL); -+#endif -+ -+ /* space for the error reports of bch decoding((4 * 5 * eccsteps) bytes), -+ * and the space for the value of ddr and dcs of channel 0 and channel -+ * nand_dma_chan (4 * (2 + 2) bytes) */ -+ kfree(errs); -+ -+ /* space for dma_desc_nand_read contains dma_desc_nand_prog, -+ * dma_desc_enc and dma_desc_dec */ -+ free_page((u32)dma_desc_nand_read); -+ -+#if defined(CONFIG_MTD_NAND_DMABUF) -+ if (pagesize < 4096) { -+ free_page((u32)prog_buf); -+ } else { -+ free_pages((u32)prog_buf, 1); -+ } -+#endif -+ -+ return 0; -+} -+#endif -+ -+static void __exit jznand_cleanup(void) -+{ -+#if defined(CONFIG_MTD_NAND_DMA) -+ jz4750_nand_dma_exit(jz_mtd); -+#endif -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(jz_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device(jz_mtd); -+ -+ /* Free the MTD device structure */ -+ if ((this->planenum == 2) && !all_use_planes) -+ kfree (jz_mtd1); -+ kfree(jz_mtd); -+} -+ -+module_exit(jznand_cleanup); -+#endif -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/nand_base.c linux-2.6.24.7/drivers/mtd/nand/nand_base.c ---- linux-2.6.24.7.old/drivers/mtd/nand/nand_base.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/nand/nand_base.c 2009-04-12 18:13:57.000000000 +0200 -@@ -52,6 +52,16 @@ - #include - #endif - -+#include -+ -+u8 nand_nce; /* indicates which chip select on JZSOC is used for -+ current nand chip */ -+int global_page; /* page index of large page used for nand with multiple planes */ -+ -+struct mtd_info *jz_mtd1 = NULL; /* for 1 plane operation */ -+char all_use_planes = 1; /* indicates whether multiple planes operation is used -+ by all partitions if multiple planes is supported by NAND */ -+ - /* Define default oob placement schemes for large and small page devices */ - static struct nand_ecclayout nand_oob_8 = { - .eccbytes = 3, -@@ -72,6 +82,20 @@ - }; - - static struct nand_ecclayout nand_oob_64 = { -+#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC) -+/* Reed-Solomon ECC or BCH ECC */ -+ .eccbytes = 36, -+ .eccpos = { -+ 28, 29, 30, 31, -+ 32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63}, -+ .oobfree = { -+ {.offset = 2, -+ . length = 26}} -+#else -+/* HW&SW Hamming ECC */ - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, -@@ -80,12 +104,85 @@ - .oobfree = { - {.offset = 2, - .length = 38}} -+#endif -+}; -+ -+static struct nand_ecclayout nand_oob_128 = { -+#if defined(CONFIG_MTD_HW_RS_ECC) -+/* Reed-Solomon ECC */ -+ .eccbytes = 72, -+ .eccpos = { -+ 56, 57, 58, 59, 60, 61, 62, 63, -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { -+ {.offset = 2, -+ . length = 54}} -+ -+#elif defined(CONFIG_MTD_HW_BCH_ECC) -+#if !defined(CONFIG_MTD_HW_BCH_8BIT) -+/* 4-bit BCH ECC */ -+ .eccbytes = 56, -+ .eccpos = { -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { -+ {.offset = 2, -+ . length = 70}} -+ -+#else -+/* 8-bit BCH ECC */ -+ .eccbytes = 104, -+ .eccpos = { -+ 24, 25, 26, 27, 28, 29, 30, 31, -+ 32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63, -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103 -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { -+ {.offset = 2, -+ . length = 22}} -+ -+#endif -+#else -+/* HW&SW Hamming ECC */ -+ .eccbytes = 48, -+ .eccpos = { -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { -+ {.offset = 2, -+ .length = 78}} -+#endif - }; - - static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, - int new_state); - --static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, -+static int nand_do_write_oob(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops); - - /* -@@ -95,6 +192,35 @@ - DEFINE_LED_TRIGGER(nand_led_trigger); - - /** -+ * ffs_ll - find first bit set in a 64bit word. -+ * @word: The word to search -+ */ -+static inline int ffs_ll(u64 word) -+{ -+ u32 low = word & 0xffffffff; -+ u32 high = word >> 32; -+ int i; -+ -+ for(i = 0; i < 32; i++) { -+ if (low & 0x1) -+ break; -+ low >>= 1; -+ } -+ if (i == 32) { -+ for(i = 0; i < 32; i++) { -+ if (high & 0x1) -+ break; -+ high >>= 1; -+ } -+ i += 32; -+ } -+ if (i == 64) -+ return 0; -+ else -+ return (i+1); -+} -+ -+/** - * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure - * -@@ -169,6 +295,20 @@ - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - break; - case 0: -+ nand_nce = NAND_NCE1; -+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); -+ break; -+ case 1: -+ nand_nce = NAND_NCE2; -+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); -+ break; -+ case 2: -+ nand_nce = NAND_NCE3; -+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); -+ break; -+ case 3: -+ nand_nce = NAND_NCE4; -+ chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - break; - - default: -@@ -298,13 +438,19 @@ - * - * Check, if the block is bad. - */ --static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -+static int nand_block_bad(struct mtd_info *mtd, loff_mtd_t ofs, int getchip) - { -- int page, chipnr, res = 0; -+ int page, page1 = 0, chipnr, res = 0; - struct nand_chip *chip = mtd->priv; - u16 bad; - -- page = (int)(ofs >> chip->page_shift) & chip->pagemask; -+ if (chip->planenum > 1) { -+ page = ((int)(ofs >> chip->page_shift) * chip->planenum + CONFIG_MTD_BADBLOCK_FLAG_PAGE); -+ page1 = page + mtd->erasesize / mtd->writesize; -+ page &= chip->pagemask; -+ page1 &= chip->pagemask; -+ } else -+ page = ((int)(ofs >> chip->page_shift) + CONFIG_MTD_BADBLOCK_FLAG_PAGE) & chip->pagemask; - - if (getchip) { - chipnr = (int)(ofs >> chip->chip_shift); -@@ -327,6 +473,11 @@ - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); - if (chip->read_byte(mtd) != 0xff) - res = 1; -+ if (chip->planenum > 1) { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page1); -+ if (chip->read_byte(mtd) != 0xff) -+ res = 1; -+ } - } - - if (getchip) -@@ -343,7 +494,7 @@ - * This is the default implementation, which can be overridden by - * a hardware specific driver. - */ --static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) -+static int nand_default_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs) - { - struct nand_chip *chip = mtd->priv; - uint8_t buf[2] = { 0, 0 }; -@@ -363,6 +514,7 @@ - */ - nand_get_device(chip, mtd, FL_WRITING); - ofs += mtd->oobsize; -+ ofs += (CONFIG_MTD_BADBLOCK_FLAG_PAGE << chip->page_shift); - chip->ops.len = chip->ops.ooblen = 2; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = buf; -@@ -402,7 +554,7 @@ - * Check, if the block is bad. Either by reading the bad block table or - * calling of the scan function. - */ --static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, -+static int nand_block_checkbad(struct mtd_info *mtd, loff_mtd_t ofs, int getchip, - int allowbbt) - { - struct nand_chip *chip = mtd->priv; -@@ -554,7 +706,10 @@ - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { -- column += mtd->writesize; -+ if (chip->planenum > 1) -+ column += (mtd->writesize / chip->planenum); -+ else -+ column += mtd->writesize; - command = NAND_CMD_READ0; - } - -@@ -600,6 +755,8 @@ - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - case NAND_CMD_DEPLETE1: -+ case 0x81: /* for two-plane page program */ -+ case 0x11: /* for two-plane page program */ - return; - - /* -@@ -675,7 +832,6 @@ - spin_lock(lock); - - /* Hardware controller shared among independend devices */ -- /* Hardware controller shared among independend devices */ - if (!chip->controller->active) - chip->controller->active = chip; - -@@ -797,6 +953,7 @@ - return 0; - } - -+#ifndef CONFIG_MTD_HW_RS_ECC /* HW&SW Hamming ECC */ - /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd: mtd info structure -@@ -841,6 +998,63 @@ - return 0; - } - -+#else /* CONFIG_MTD_HW_RS_ECC */ -+ -+/** -+ * nand_read_page_hwecc_rs - [REPLACABLE] hardware rs ecc based page read function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @buf: buffer to store read data -+ * -+ * Not for syndrome calculating ecc controllers which need a special oob layout -+ */ -+static int nand_read_page_hwecc_rs(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf) -+{ -+ int i, eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ int eccsteps = chip->ecc.steps; -+ uint8_t *p = buf; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ uint32_t page; -+ uint8_t flag = 0; -+ -+ page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0]; -+ -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ for (i = 0; i < chip->ecc.total; i++) { -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ if (ecc_code[i] != 0xff) flag = 1; -+ } -+ -+ eccsteps = chip->ecc.steps; -+ p = buf; -+ -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1); -+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { -+ int stat; -+ if (flag) { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ else { -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ } -+ } -+ return 0; -+} -+ -+#endif /* CONFIG_MTD_HW_RS_ECC */ -+ - /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd: mtd info structure -@@ -903,7 +1117,7 @@ - * @len: size of oob to transfer - */ - static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, -- struct mtd_oob_ops *ops, size_t len) -+ struct mtd_oob_ops *ops, size_mtd_t len) - { - switch(ops->mode) { - -@@ -915,7 +1129,7 @@ - case MTD_OOB_AUTO: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, roffs = ops->ooboffs; -- size_t bytes = 0; -+ size_mtd_t bytes = 0; - - for(; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ -@@ -925,11 +1139,11 @@ - continue; - } - boffs = free->offset + roffs; -- bytes = min_t(size_t, len, -+ bytes = min_t(size_mtd_t, len, - (free->length - roffs)); - roffs = 0; - } else { -- bytes = min_t(size_t, len, free->length); -+ bytes = min_t(size_mtd_t, len, free->length); - boffs = free->offset; - } - memcpy(oob, chip->oob_poi + boffs, bytes); -@@ -952,7 +1166,7 @@ - * - * Internal function. Called with chip held. - */ --static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, -+static int nand_do_read_ops(struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops) - { - int chipnr, page, realpage, col, bytes, aligned; -@@ -986,10 +1200,18 @@ - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; - -+ global_page = page; -+#if defined(CONFIG_MTD_HW_RS_ECC) || defined(CONFIG_MTD_NAND_DMA) -+ bufpoi[0] = (uint8_t)page; -+ bufpoi[1] = (uint8_t)(page >> 8); -+ bufpoi[2] = (uint8_t)(page >> 16); -+ bufpoi[3] = (uint8_t)(page >> 24); -+#else - if (likely(sndcmd)) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - sndcmd = 0; - } -+#endif - - /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) -@@ -1065,7 +1287,7 @@ - sndcmd = 1; - } - -- ops->retlen = ops->len - (size_t) readlen; -+ ops->retlen = ops->len - (size_mtd_t) readlen; - if (oob) - ops->oobretlen = ops->ooblen - oobreadlen; - -@@ -1088,8 +1310,8 @@ - * - * Get hold of the chip and call nand_do_read - */ --static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, uint8_t *buf) -+static int nand_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, uint8_t *buf) - { - struct nand_chip *chip = mtd->priv; - int ret; -@@ -1262,7 +1484,7 @@ - * - * NAND read out-of-band data from the spare area - */ --static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, -+static int nand_do_read_oob(struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops) - { - int page, realpage, chipnr, sndcmd = 1; -@@ -1355,7 +1577,7 @@ - * - * NAND read data and/or out-of-band data - */ --static int nand_read_oob(struct mtd_info *mtd, loff_t from, -+static int nand_read_oob(struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops) - { - struct nand_chip *chip = mtd->priv; -@@ -1518,12 +1740,17 @@ - { - int status; - -- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -- -- if (unlikely(raw)) -- chip->ecc.write_page_raw(mtd, chip, buf); -- else -+ global_page = page; -+ if (chip->planenum > 1) - chip->ecc.write_page(mtd, chip, buf); -+ else { -+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -+ -+ if (unlikely(raw)) -+ chip->ecc.write_page_raw(mtd, chip, buf); -+ else -+ chip->ecc.write_page(mtd, chip, buf); -+ } - - /* - * Cached progamming disabled for now, Not sure if its worth the -@@ -1532,9 +1759,17 @@ - cached = 0; - - if (!cached || !(chip->options & NAND_CACHEPRG)) { -- -- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+/* -+* __nand_cmd(CMD_PAGEPROG) and __nand_sync() have been done by DMA for jz4750 and -+* later chip, status should still be read by "status = chip->waitfunc(mtd, chip)" -+*/ -+#if defined(CONFIG_SOC_JZ4730) || defined(CONFIG_SOC_JZ4740) || \ -+ (!defined(CONFIG_SOC_JZ4730) && !defined(CONFIG_SOC_JZ4740) \ -+ && !defined(CONFIG_MTD_NAND_DMA)) -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+#endif - status = chip->waitfunc(mtd, chip); -+ - /* - * See if operation failed and additional status checks are - * available -@@ -1569,7 +1804,7 @@ - static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, - struct mtd_oob_ops *ops) - { -- size_t len = ops->ooblen; -+ size_mtd_t len = ops->ooblen; - - switch(ops->mode) { - -@@ -1581,7 +1816,7 @@ - case MTD_OOB_AUTO: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, woffs = ops->ooboffs; -- size_t bytes = 0; -+ size_mtd_t bytes = 0; - - for(; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0 ? */ -@@ -1591,11 +1826,11 @@ - continue; - } - boffs = free->offset + woffs; -- bytes = min_t(size_t, len, -+ bytes = min_t(size_mtd_t, len, - (free->length - woffs)); - woffs = 0; - } else { -- bytes = min_t(size_t, len, free->length); -+ bytes = min_t(size_mtd_t, len, free->length); - boffs = free->offset; - } - memcpy(chip->oob_poi + boffs, oob, bytes); -@@ -1619,7 +1854,7 @@ - * - * NAND write with ECC - */ --static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, -+static int nand_do_write_ops(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops) - { - int chipnr, realpage, page, blockmask, column; -@@ -1722,8 +1957,8 @@ - * - * NAND write with ECC - */ --static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const uint8_t *buf) -+static int nand_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, -+ size_mtd_t *retlen, const uint8_t *buf) - { - struct nand_chip *chip = mtd->priv; - int ret; -@@ -1757,7 +1992,7 @@ - * - * NAND write out-of-band - */ --static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, -+static int nand_do_write_oob(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops) - { - int chipnr, page, status, len; -@@ -1835,7 +2070,7 @@ - * @to: offset to write to - * @ops: oob operation description structure - */ --static int nand_write_oob(struct mtd_info *mtd, loff_t to, -+static int nand_write_oob(struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops) - { - struct nand_chip *chip = mtd->priv; -@@ -1999,7 +2234,7 @@ - /* - * heck if we have a bad block, we do not erase bad blocks ! - */ -- if (nand_block_checkbad(mtd, ((loff_t) page) << -+ if (nand_block_checkbad(mtd, ((loff_mtd_t) page) << - chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "nand_erase: attempt to erase a " - "bad block at page 0x%08x\n", page); -@@ -2121,7 +2356,7 @@ - * @mtd: MTD device structure - * @offs: offset relative to mtd start - */ --static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) -+static int nand_block_isbad(struct mtd_info *mtd, loff_mtd_t offs) - { - /* Check for invalid offset */ - if (offs > mtd->size) -@@ -2135,7 +2370,7 @@ - * @mtd: MTD device structure - * @ofs: offset relative to mtd start - */ --static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) -+static int nand_block_markbad(struct mtd_info *mtd, loff_mtd_t ofs) - { - struct nand_chip *chip = mtd->priv; - int ret; -@@ -2274,7 +2509,21 @@ - extid >>= 2; - /* Get buswidth information */ - busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; -+ /* The 5th id byte */ -+#if defined(CONFIG_MTD_NAND_MULTI_PLANE) -+ extid = chip->read_byte(mtd); -+ chip->realplanenum = 1 << ((extid & 0x0c) >> 2); -+#else -+ chip->realplanenum = 1; -+#endif - -+ if (chip->realplanenum > 1) { /* use muti planes mode */ -+ chip->planenum = 2; -+ mtd->writesize *= 2; /* two pages as one page */ -+ mtd->oobsize *= 2; -+ mtd->erasesize *= 2; /* two blocks as one block */ -+ } else -+ chip->planenum = 1; - } else { - /* - * Old devices have chip data hardcoded in the device id table -@@ -2312,7 +2561,7 @@ - - chip->bbt_erase_shift = chip->phys_erase_shift = - ffs(mtd->erasesize) - 1; -- chip->chip_shift = ffs(chip->chipsize) - 1; -+ chip->chip_shift = ffs_ll(chip->chipsize) - 1; - - /* Set the bad block position */ - chip->badblockpos = mtd->writesize > 512 ? -@@ -2344,8 +2593,8 @@ - chip->cmdfunc = nand_command_lp; - - printk(KERN_INFO "NAND device: Manufacturer ID:" -- " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, -- nand_manuf_ids[maf_idx].name, type->name); -+ " 0x%02x, Chip ID: 0x%02x (%s %s) planenum:%d\n", *maf_id, dev_id, -+ nand_manuf_ids[maf_idx].name, type->name, chip->realplanenum); - - return type; - } -@@ -2412,7 +2661,7 @@ - */ - int nand_scan_tail(struct mtd_info *mtd) - { -- int i; -+ int i, res; - struct nand_chip *chip = mtd->priv; - - if (!(chip->options & NAND_OWN_BUFFERS)) -@@ -2437,6 +2686,16 @@ - case 64: - chip->ecc.layout = &nand_oob_64; - break; -+ case 128: -+ if (chip->planenum > 1) -+ chip->ecc.layout = &nand_oob_64; -+ else -+ chip->ecc.layout = &nand_oob_128; -+ break; -+ case 256: -+ if (chip->planenum > 1) -+ chip->ecc.layout = &nand_oob_128; -+ break; - default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); -@@ -2459,8 +2718,13 @@ - switch (chip->ecc.mode) { - case NAND_ECC_HW: - /* Use standard hwecc read page function ? */ -- if (!chip->ecc.read_page) -+ if (!chip->ecc.read_page) { -+#ifndef CONFIG_MTD_HW_RS_ECC - chip->ecc.read_page = nand_read_page_hwecc; -+#else -+ chip->ecc.read_page = nand_read_page_hwecc_rs; -+#endif -+ } - if (!chip->ecc.write_page) - chip->ecc.write_page = nand_write_page_hwecc; - if (!chip->ecc.read_oob) -@@ -2593,8 +2857,58 @@ - if (chip->options & NAND_SKIP_BBTSCAN) - return 0; - -- /* Build bad block table */ -- return chip->scan_bbt(mtd); -+ /* Create jz_mtd1 for one plane operation if the NAND support multiple -+ planes operation, because some partitions will only use one plane. */ -+ if ((chip->planenum == 2) && !all_use_planes) { -+ int i, len, numblocks; -+ struct nand_chip *this = (struct nand_chip *) (&jz_mtd1[1]); -+ -+ memcpy(jz_mtd1, mtd, sizeof(*mtd)); -+ jz_mtd1->priv = this; -+ memcpy(this, chip, sizeof(*chip)); -+ -+ this->planenum = 1; -+ jz_mtd1->writesize >>= 1; -+ jz_mtd1->oobsize >>= 1; -+ jz_mtd1->erasesize >>= 1; -+ this->page_shift = chip->page_shift - 1; -+ this->pagemask = (this->chipsize >> this->page_shift) - 1; -+ this->bbt_erase_shift = this->phys_erase_shift = -+ chip->phys_erase_shift - 1; -+ this->ecc.steps >>= 1; -+ this->ecc.total = this->ecc.steps * this->ecc.bytes; -+ this->subpagesize = jz_mtd1->writesize; -+ -+ this->erase_cmd = single_erase_cmd; -+#if defined(CONFIG_MTD_HW_RS_ECC) -+ this->ecc.read_page = nand_read_page_hwecc_rs; -+ this->ecc.write_page = nand_write_page_hwecc; -+#endif -+ this->ecc.read_oob = nand_read_oob_std; -+ this->ecc.write_oob = nand_write_oob_std; -+ this->write_buf = nand_write_buf; -+ this->read_buf = nand_read_buf; -+ -+ /* Firstly, build bad block table as one plane */ -+ res = this->scan_bbt(jz_mtd1); -+ -+ /* Secondly, build bad block table as 2 plane based on bbt of jz_mtd1 */ -+ numblocks = chip->chipsize >> (chip->bbt_erase_shift - 1); /* = (real numblocks * 2) */ -+ len = mtd->size >> (chip->bbt_erase_shift + 2); -+ chip->bbt = kzalloc(len, GFP_KERNEL); -+ -+#define isbad_2plane(block) (((this->bbt[(block) >> 3] >> ((block) & 0x06)) \ -+ | (this->bbt[((block)+2) >> 3] >> (((block)+2) & 0x06))) & 0x03) -+ -+ for (i = 0; i < numblocks; i += 2) { -+ if (isbad_2plane(2*i)) -+ chip->bbt[i >> 3] |= 0x03 << (i & 0x6); -+ } -+ } else { -+ res = chip->scan_bbt(mtd); -+ } -+ -+ return res; - } - - /* module_text_address() isn't exported, and it's mostly a pointless -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/nand_bbt.c linux-2.6.24.7/drivers/mtd/nand/nand_bbt.c ---- linux-2.6.24.7.old/drivers/mtd/nand/nand_bbt.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/nand/nand_bbt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -6,7 +6,7 @@ - * - * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) - * -- * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ -+ * $Id: nand_bbt.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -147,15 +147,15 @@ - { - int res, i, j, act = 0; - struct nand_chip *this = mtd->priv; -- size_t retlen, len, totlen; -- loff_t from; -+ size_mtd_t retlen, len, totlen; -+ loff_mtd_t from; - uint8_t msk = (uint8_t) ((1 << bits) - 1); - - totlen = (num * bits) >> 3; -- from = ((loff_t) page) << this->page_shift; -+ from = ((loff_mtd_t) page) << this->page_shift; - - while (totlen) { -- len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); -+ len = min(totlen, (size_mtd_t) (1 << this->bbt_erase_shift)); - res = mtd->read(mtd, from, len, &retlen, buf); - if (res < 0) { - if (retlen != len) { -@@ -235,8 +235,8 @@ - /* - * Scan read raw data from flash - */ --static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, -- size_t len) -+static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_mtd_t offs, -+ size_mtd_t len) - { - struct mtd_oob_ops ops; - -@@ -253,7 +253,7 @@ - /* - * Scan write data with oob to flash - */ --static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, -+static int scan_write_bbt(struct mtd_info *mtd, loff_mtd_t offs, size_mtd_t len, - uint8_t *buf, uint8_t *oob) - { - struct mtd_oob_ops ops; -@@ -308,7 +308,7 @@ - * Scan a given block full - */ - static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, -- loff_t offs, uint8_t *buf, size_t readlen, -+ loff_mtd_t offs, uint8_t *buf, size_mtd_t readlen, - int scanlen, int len) - { - int ret, j; -@@ -328,7 +328,7 @@ - * Scan a given block partially - */ - static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, -- loff_t offs, uint8_t *buf, int len) -+ loff_mtd_t offs, uint8_t *buf, int len) - { - struct mtd_oob_ops ops; - int j, ret; -@@ -374,8 +374,8 @@ - struct nand_chip *this = mtd->priv; - int i, numblocks, len, scanlen; - int startblock; -- loff_t from; -- size_t readlen; -+ loff_mtd_t from; -+ size_mtd_t readlen; - - printk(KERN_INFO "Scanning device for bad blocks\n"); - -@@ -403,7 +403,7 @@ - * below as it makes shifting and masking less painful */ - numblocks = mtd->size >> (this->bbt_erase_shift - 1); - startblock = 0; -- from = 0; -+ from = (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = 0; - } else { - if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", -@@ -413,7 +413,7 @@ - numblocks = this->chipsize >> (this->bbt_erase_shift - 1); - startblock = chip * numblocks; - numblocks += startblock; -- from = startblock << (this->bbt_erase_shift - 1); -+ from = (startblock << (this->bbt_erase_shift - 1)) + (CONFIG_MTD_BADBLOCK_FLAG_PAGE << this->page_shift); //from = startblock << (this->bbt_erase_shift - 1); - } - - for (i = startblock; i < numblocks;) { -@@ -430,8 +430,8 @@ - - if (ret) { - this->bbt[i >> 3] |= 0x03 << (i & 0x6); -- printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", -- i >> 1, (unsigned int)from); -+ printk(KERN_WARNING "Bad eraseblock %d at 0x%09llx\n", -+ i >> 1, (unsigned long long)from); - mtd->ecc_stats.badblocks++; - } - -@@ -497,7 +497,7 @@ - for (block = 0; block < td->maxblocks; block++) { - - int actblock = startblock + dir * block; -- loff_t offs = actblock << this->bbt_erase_shift; -+ loff_mtd_t offs = actblock << this->bbt_erase_shift; - - /* Read first page */ - scan_read_raw(mtd, buf, offs, mtd->writesize); -@@ -567,8 +567,8 @@ - int nrchips, bbtoffs, pageoffs, ooboffs; - uint8_t msk[4]; - uint8_t rcode = td->reserved_block_code; -- size_t retlen, len = 0; -- loff_t to; -+ size_mtd_t retlen, len = 0; -+ loff_mtd_t to; - struct mtd_oob_ops ops; - - ops.ooblen = mtd->oobsize; -@@ -655,12 +655,12 @@ - - bbtoffs = chip * (numblocks >> 2); - -- to = ((loff_t) page) << this->page_shift; -+ to = ((loff_mtd_t) page) << this->page_shift; - - /* Must we save the block contents ? */ - if (td->options & NAND_BBT_SAVECONTENT) { - /* Make it block aligned */ -- to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); -+ to &= ~((loff_mtd_t) ((1 << this->bbt_erase_shift) - 1)); - len = 1 << this->bbt_erase_shift; - res = mtd->read(mtd, to, len, &retlen, buf); - if (res < 0) { -@@ -685,12 +685,12 @@ - pageoffs = page - (int)(to >> this->page_shift); - offs = pageoffs << this->page_shift; - /* Preset the bbt area with 0xff */ -- memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); -+ memset(&buf[offs], 0xff, (size_mtd_t) (numblocks >> sft)); - ooboffs = len + (pageoffs * mtd->oobsize); - - } else { - /* Calc length */ -- len = (size_t) (numblocks >> sft); -+ len = (size_mtd_t) (numblocks >> sft); - /* Make it page aligned ! */ - len = (len + (mtd->writesize - 1)) & - ~(mtd->writesize - 1); -@@ -1017,7 +1017,7 @@ - * - * The function updates the bad block table(s) - */ --int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -+int nand_update_bbt(struct mtd_info *mtd, loff_mtd_t offs) - { - struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; -@@ -1193,7 +1193,7 @@ - * @allowbbt: allow access to bad block table region - * - */ --int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) -+int nand_isbad_bbt(struct mtd_info *mtd, loff_mtd_t offs, int allowbbt) - { - struct nand_chip *this = mtd->priv; - int block; -diff -urN linux-2.6.24.7.old/drivers/mtd/nand/nand_ids.c linux-2.6.24.7/drivers/mtd/nand/nand_ids.c ---- linux-2.6.24.7.old/drivers/mtd/nand/nand_ids.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/nand/nand_ids.c 2009-04-12 18:13:57.000000000 +0200 -@@ -111,6 +111,9 @@ - {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16}, - {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16}, - -+ /* 32 Gigabit */ -+ {"NAND 4GiB 3,3V 8-bit", 0xD7, 0, 4096, 0, LP_OPTIONS}, -+ - /* - * Renesas AND 1 Gigabit. Those chips do not support extended id and - * have a strange page/block layout ! The chosen minimum erasesize is -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/Kconfig linux-2.6.24.7/drivers/mtd/ubi/Kconfig ---- linux-2.6.24.7.old/drivers/mtd/ubi/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -55,4 +55,18 @@ - this if no legacy software will be used. - - source "drivers/mtd/ubi/Kconfig.debug" -+ -+config MTD_UBI_BLKDEVS -+ tristate "Common interface to block layer for UBI 'translation layers'" -+ depends on BLOCK -+ default n -+ -+config MTD_UBI_BLOCK -+ tristate "Emulate block devices" -+ default n -+ depends on MTD_UBI_BLKDEVS -+ help -+ This option enables Block layer emulation on top of UBI volumes: for -+ each UBI volumes an block device is created. This is handy to make -+ traditional filesystem (like ext2, VFAT) work on top of UBI. - endmenu -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/Makefile linux-2.6.24.7/drivers/mtd/ubi/Makefile ---- linux-2.6.24.7.old/drivers/mtd/ubi/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -5,3 +5,6 @@ - - ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o - ubi-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o -+ -+obj-$(CONFIG_MTD_UBI_BLKDEVS) += bdev.o -+obj-$(CONFIG_MTD_UBI_BLOCK) += ubiblk.o -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/bdev.c linux-2.6.24.7/drivers/mtd/ubi/bdev.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/bdev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/bdev.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,432 @@ -+/* -+ * -+ * (C) 2003 David Woodhouse -+ * -+ * Interface to Linux 2.5 block layer for UBI 'translation layers'. -+ * -+ * 2008 Yurong Tan : -+ * borrow from mtd_blkdevs.c for building block device layer on top of UBI -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi.h" -+#include "ubiblk.h" -+ -+static LIST_HEAD(blktrans_majors); -+extern struct mutex vol_table_mutex; -+extern struct ubi_volume *vol_table[]; -+ -+extern void register_vol_user (struct vol_notifier *new); -+extern int unregister_vol_user (struct vol_notifier *old); -+extern int ubi_major2num(int major); -+ -+struct ubi_blkcore_priv { -+ struct task_struct *thread; -+ struct request_queue *rq; -+ spinlock_t queue_lock; -+}; -+ -+static int do_blktrans_request(struct ubi_blktrans_ops *tr, -+ struct ubi_blktrans_dev *dev, -+ struct request *req) -+{ -+ unsigned long block, nsect; -+ char *buf; -+ -+ block = req->sector << 9 >> tr->blkshift; -+ nsect = req->current_nr_sectors << 9 >> tr->blkshift; -+ buf = req->buffer; -+ -+ if (!blk_fs_request(req)) -+ return 0; -+ -+ if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk)) -+ return 0; -+ -+ switch(rq_data_dir(req)) { -+ case READ: -+ for (; nsect > 0; nsect--, block++, buf += tr->blksize) -+ if (tr->readsect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ case WRITE: -+ if (!tr->writesect) -+ return 0; -+ -+ for (; nsect > 0; nsect--, block++, buf += tr->blksize) -+ if (tr->writesect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ default: -+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); -+ return 0; -+ } -+} -+ -+static int ubi_blktrans_thread(void *arg) -+{ -+ struct ubi_blktrans_ops *tr = arg; -+ struct request_queue *rq = tr->blkcore_priv->rq; -+ -+ /* we might get involved when memory gets low, so use PF_MEMALLOC */ -+ current->flags |= PF_MEMALLOC; -+ -+ spin_lock_irq(rq->queue_lock); -+ while (!kthread_should_stop()) { -+ struct request *req; -+ struct ubi_blktrans_dev *dev; -+ int res = 0; -+ -+ req = elv_next_request(rq); -+ -+ if (!req) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_unlock_irq(rq->queue_lock); -+ schedule(); -+ spin_lock_irq(rq->queue_lock); -+ continue; -+ } -+ dev = req->rq_disk->private_data; -+ tr = dev->tr; -+ -+ spin_unlock_irq(rq->queue_lock); -+ mutex_lock(&dev->lock); -+ res = do_blktrans_request(tr, dev, req); -+ mutex_unlock(&dev->lock); -+ spin_lock_irq(rq->queue_lock); -+ -+ end_request(req, res); -+ } -+ spin_unlock_irq(rq->queue_lock); -+ -+ return 0; -+} -+ -+static void ubi_blktrans_request(struct request_queue *rq) -+{ -+ struct ubi_blktrans_ops *tr = rq->queuedata; -+ wake_up_process(tr->blkcore_priv->thread); -+} -+ -+static int blktrans_open(struct inode *i, struct file *f) -+{ -+ struct ubi_blktrans_dev *dev; -+ struct ubi_blktrans_ops *tr; -+ int ret =0; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ -+ if (!try_module_get(tr->owner)) -+ goto out_tr; -+ -+ if(!tr->open) -+ return -1; -+ else -+ ret = tr->open(i,f); -+ -+ return ret; -+out_tr: -+ module_put(tr->owner); -+ return -1; -+} -+ -+static int blktrans_release(struct inode *i, struct file *f) -+{ -+ struct ubi_blktrans_dev *dev; -+ struct ubi_blktrans_ops *tr; -+ struct ubi_volume_desc *desc; -+ int ret = 0; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ desc = dev->uv; -+ -+ if (tr->release) -+ ret = tr->release(dev); -+ -+ module_put(tr->owner); -+ return ret; -+} -+ -+static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) -+{ -+ struct ubi_blktrans_dev *dev = bdev->bd_disk->private_data; -+ -+ if (dev->tr->getgeo) -+ return dev->tr->getgeo(dev, geo); -+ return -ENOTTY; -+} -+ -+static int blktrans_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct ubi_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; -+ struct ubi_blktrans_ops *tr = dev->tr; -+ -+ switch (cmd) { -+ case BLKFLSBUF: -+ if (tr->flush) -+ return tr->flush(dev); -+ /* The core code did the work, we had nothing to do. */ -+ return 0; -+ default: -+ return -ENOTTY; -+ } -+} -+ -+struct block_device_operations ubi_blktrans_ops = { -+ .owner = THIS_MODULE, -+ .open = blktrans_open, -+ .release = blktrans_release, -+ .ioctl = blktrans_ioctl, -+ .getgeo = blktrans_getgeo, -+}; -+ -+int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new) -+{ -+ struct ubi_blktrans_ops *tr = new->tr; -+ struct list_head *this; -+ int last_devnum = -1; -+ struct gendisk *gd; -+ -+ if (mutex_trylock(&vol_table_mutex)) { -+ mutex_unlock(&vol_table_mutex); -+ BUG(); -+ } -+ -+ list_for_each(this, &tr->devs) { -+ struct ubi_blktrans_dev *d = list_entry(this, struct ubi_blktrans_dev, list); -+ if (new->devnum == -1) { -+ /* Use first free number */ -+ if (d->devnum != last_devnum+1) { -+ /* Found a free devnum. Plug it in here */ -+ new->devnum = last_devnum+1; -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ } else if (d->devnum == new->devnum) { -+ /* Required number taken */ -+ return -EBUSY; -+ } else if (d->devnum > new->devnum) { -+ /* Required number was free */ -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ last_devnum = d->devnum; -+ } -+ if (new->devnum == -1) -+ new->devnum = last_devnum+1; -+ -+ if ((new->devnum << tr->part_bits) > 256) { -+ return -EBUSY; -+ } -+ -+ mutex_init(&new->lock); -+ list_add_tail(&new->list, &tr->devs); -+ added: -+ if (!tr->writesect) -+ new->readonly = 1; -+ -+ gd = alloc_disk(1 << tr->part_bits); -+ if (!gd) { -+ list_del(&new->list); -+ return -ENOMEM; -+ } -+ gd->major = tr->major; -+ gd->first_minor = (new->devnum) << tr->part_bits; -+ gd->fops = &ubi_blktrans_ops; -+ -+ if (tr->part_bits) -+ if (new->devnum < 26) -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%c", tr->name, 'a' + new->devnum); -+ else -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%c%c", tr->name, -+ 'a' - 1 + new->devnum / 26, -+ 'a' + new->devnum % 26); -+ else -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%d", tr->name, new->devnum); -+ -+ /* 2.5 has capacity in units of 512 bytes while still -+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ -+ set_capacity(gd, (new->size * tr->blksize) >> 9); -+ -+ gd->private_data = new; -+ new->blkcore_priv = gd; -+ gd->queue = tr->blkcore_priv->rq; -+ -+ if (new->readonly) -+ set_disk_ro(gd, 1); -+ -+ add_disk(gd); -+ -+ return 0; -+} -+ -+int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old) -+{ -+ if (mutex_trylock(&vol_table_mutex)) { -+ mutex_unlock(&vol_table_mutex); -+ BUG(); -+ } -+ -+ list_del(&old->list); -+ -+ del_gendisk(old->blkcore_priv); -+ put_disk(old->blkcore_priv); -+ -+ return 0; -+} -+ -+static void blktrans_notify_remove(struct ubi_volume *vol) -+{ -+ struct list_head *this, *this2, *next; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list); -+ -+ list_for_each_safe(this2, next, &tr->devs) { -+ struct ubi_blktrans_dev *dev = list_entry(this2, struct ubi_blktrans_dev, list); -+ -+ if (dev->uv->vol == vol) -+ tr->remove_vol(dev); -+ } -+ } -+} -+ -+static void blktrans_notify_add(struct ubi_volume *vol) -+{ -+ struct list_head *this; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct ubi_blktrans_ops *tr = list_entry(this, struct ubi_blktrans_ops, list); -+ -+ tr->add_vol(tr,vol); -+ } -+ -+} -+ -+static struct vol_notifier blktrans_notifier = { -+ .add = blktrans_notify_add, -+ .remove = blktrans_notify_remove, -+}; -+ -+ -+int register_ubi_blktrans(struct ubi_blktrans_ops *tr) -+{ -+ int i; -+ -+ /* Register the notifier if/when the first device type is -+ registered, to prevent the link/init ordering from fucking -+ us over. */ -+ if (!blktrans_notifier.list.next) -+ register_vol_user(&blktrans_notifier); -+ -+ tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); -+ if (!tr->blkcore_priv) -+ return -ENOMEM; -+ -+ mutex_lock(&vol_table_mutex); -+ tr->major = register_blkdev(0, tr->name); -+ spin_lock_init(&tr->blkcore_priv->queue_lock); -+ -+ tr->blkcore_priv->rq = blk_init_queue(ubi_blktrans_request, &tr->blkcore_priv->queue_lock); -+ if (!tr->blkcore_priv->rq) { -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ mutex_unlock(&vol_table_mutex); -+ return -ENOMEM; -+ } -+ -+ tr->blkcore_priv->rq->queuedata = tr; -+ blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); -+ tr->blkshift = ffs(tr->blksize) - 1; -+ -+ tr->blkcore_priv->thread = kthread_run(ubi_blktrans_thread, tr, -+ "%sd", tr->name); -+ if (IS_ERR(tr->blkcore_priv->thread)) { -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ mutex_unlock(&vol_table_mutex); -+ return PTR_ERR(tr->blkcore_priv->thread); -+ } -+ -+ INIT_LIST_HEAD(&tr->devs); -+ list_add(&tr->list, &blktrans_majors); -+ -+ for (i=0; iadd_vol(tr, vol_table[i]); -+ } -+ -+ mutex_unlock(&vol_table_mutex); -+ return 0; -+} -+ -+int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr) -+{ -+ struct list_head *this, *next; -+ -+ mutex_lock(&vol_table_mutex); -+ -+ /* Clean up the kernel thread */ -+ kthread_stop(tr->blkcore_priv->thread); -+ -+ /* Remove it from the list of active majors */ -+ list_del(&tr->list); -+ -+ list_for_each_safe(this, next, &tr->devs) { -+ struct ubi_blktrans_dev *dev = list_entry(this, struct ubi_blktrans_dev, list); -+ tr->remove_vol(dev); -+ } -+ -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ -+ mutex_unlock(&vol_table_mutex); -+ -+ kfree(tr->blkcore_priv); -+ -+ BUG_ON(!list_empty(&tr->devs)); -+ return 0; -+} -+ -+static void __exit ubi_blktrans_exit(void) -+{ -+ /* No race here -- if someone's currently in register_ubi_blktrans -+ we're screwed anyway. */ -+ if (blktrans_notifier.list.next) -+ unregister_vol_user(&blktrans_notifier); -+} -+ -+ -+module_exit(ubi_blktrans_exit); -+ -+EXPORT_SYMBOL_GPL(register_ubi_blktrans); -+EXPORT_SYMBOL_GPL(deregister_ubi_blktrans); -+EXPORT_SYMBOL_GPL(add_ubi_blktrans_dev); -+EXPORT_SYMBOL_GPL(del_ubi_blktrans_dev); -+ -+MODULE_AUTHOR("David Woodhouse , Yurong Tan "); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Common interface to block layer for UBI 'translation layers'"); -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/build.c linux-2.6.24.7/drivers/mtd/ubi/build.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/build.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/build.c 2009-04-12 18:13:57.000000000 +0200 -@@ -18,14 +18,20 @@ - * - * Author: Artem Bityutskiy (Битюцкий Ðртём), - * Frank Haverkamp -+ * Yurong tan(Nancy) - */ - - /* -- * This file includes UBI initialization and building of UBI devices. At the -- * moment UBI devices may only be added while UBI is initialized, but dynamic -- * device add/remove functionality is planned. Also, at the moment we only -- * attach UBI devices by scanning, which will become a bottleneck when flashes -- * reach certain large size. Then one may improve UBI and add other methods. -+ * This file includes UBI initialization and building of UBI devices. -+ * -+ * When UBI is initialized, it attaches all the MTD devices specified as the -+ * module load parameters or the kernel boot parameters. If MTD devices were -+ * specified, UBI does not attach any MTD device, but it is possible to do -+ * later using the "UBI control device". -+ * -+ * At the moment we only attach UBI devices by scanning, which will become a -+ * bottleneck when flashes reach certain large size. Then one may improve UBI -+ * and add other methods, although it does not seem to be easy to do. - */ - - #include -@@ -33,23 +39,130 @@ - #include - #include - #include -+#include - #include -+#include - #include "ubi.h" - - /* Maximum length of the 'mtd=' parameter */ - #define MTD_PARAM_LEN_MAX 64 - -+/* add by Nancy begin */ -+DEFINE_MUTEX(vol_table_mutex); -+struct ubi_volume *vol_table[UBI_MAX_VOLUMES]; -+ -+EXPORT_SYMBOL_GPL(vol_table_mutex); -+EXPORT_SYMBOL_GPL(vol_table); -+ -+static LIST_HEAD(vol_notifiers); -+ -+int add_vol_device(struct ubi_volume *vol) -+{ -+ mutex_lock(&vol_table_mutex); -+ if (!vol_table[vol->vol_id]) { -+ -+ struct list_head *this; -+ vol_table[vol->vol_id] = vol; -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the vol_table_mutex */ -+ list_for_each(this, &vol_notifiers) { -+ struct vol_notifier *not = list_entry(this, struct vol_notifier, list); -+ not->add(vol); -+ } -+ mutex_unlock(&vol_table_mutex); -+ /* We _know_ we aren't being removed, because -+ our caller is still holding us here. So none -+ of this try_ nonsense, and no bitching about it -+ either. :) */ -+ return 0; -+ } -+ mutex_unlock(&vol_table_mutex); -+ return 1; -+} -+ -+int del_vol_device (struct ubi_volume *vol) -+{ -+ int ret; -+ struct list_head *this; -+ -+ mutex_lock(&vol_table_mutex); -+ if (vol_table[vol->vol_id] != vol) { -+ ret = -ENODEV; -+ } else if (vol->readers ||vol->writers || vol->exclusive) { -+ printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count 0\n", -+ vol->vol_id, vol->name); -+ ret = -EBUSY; -+ } else { -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the vol_table_mutex */ -+ list_for_each(this, &vol_notifiers) { -+ struct vol_notifier *not = list_entry(this, struct vol_notifier, list); -+ not->remove(vol); -+ } -+ -+ vol_table[vol->vol_id] = NULL; -+ module_put(THIS_MODULE); -+ ret = 0; -+ } -+ mutex_unlock(&vol_table_mutex); -+ return ret; -+} -+ -+void register_vol_user(struct vol_notifier *new) -+{ -+ int i; -+ -+ mutex_lock(&vol_table_mutex); -+ list_add(&new->list, &vol_notifiers); -+ __module_get(THIS_MODULE); -+ -+ for (i=0; i< UBI_MAX_VOLUMES; i++) -+ if (vol_table[i]) -+ new->add(vol_table[i]); -+ -+ mutex_unlock(&vol_table_mutex); -+} -+ -+int unregister_vol_user(struct vol_notifier *old) -+{ -+ int i; -+ -+ mutex_lock(&vol_table_mutex); -+ module_put(THIS_MODULE); -+ -+ for (i=0; i< UBI_MAX_VOLUMES; i++) -+ if (vol_table[i]) -+ old->remove(vol_table[i]); -+ -+ list_del(&old->list); -+ mutex_unlock(&vol_table_mutex); -+ return 0; -+} -+ -+static int bdev_init(struct ubi_device *ubi){ -+ int i; -+ for(i=0; ivtbl_slots; i++) -+ if(ubi->volumes[i]) -+ add_vol_device(ubi->volumes[i]); -+ return 0; -+} -+ -+EXPORT_SYMBOL_GPL(add_vol_device); -+EXPORT_SYMBOL_GPL(del_vol_device); -+EXPORT_SYMBOL_GPL(register_vol_user); -+EXPORT_SYMBOL_GPL(unregister_vol_user); -+/* add by Nancy end*/ -+ -+ - /** - * struct mtd_dev_param - MTD device parameter description data structure. - * @name: MTD device name or number string - * @vid_hdr_offs: VID header offset -- * @data_offs: data offset - */ - struct mtd_dev_param - { - char name[MTD_PARAM_LEN_MAX]; - int vid_hdr_offs; -- int data_offs; - }; - - /* Numbers of elements set in the @mtd_dev_param array */ -@@ -58,14 +171,28 @@ - /* MTD devices specification parameters */ - static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; - --/* Number of UBI devices in system */ --int ubi_devices_cnt; -+/* Root UBI "class" object (corresponds to '//class/ubi/') */ -+struct class *ubi_class; -+ -+/* Slab cache for wear-leveling entries */ -+struct kmem_cache *ubi_wl_entry_slab; -+ -+/* UBI control character device */ -+static struct miscdevice ubi_ctrl_cdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "ubi_ctrl", -+ .fops = &ubi_ctrl_cdev_operations, -+}; - - /* All UBI devices in system */ --struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; -+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; - --/* Root UBI "class" object (corresponds to '//class/ubi/') */ --struct class *ubi_class; -+/* Serializes UBI devices creations and removals */ -+DEFINE_MUTEX(ubi_devices_mutex); -+ -+/* Protects @ubi_devices and @ubi->ref_count */ -+static DEFINE_SPINLOCK(ubi_devices_lock); -+EXPORT_SYMBOL_GPL(ubi_devices_lock); - - /* "Show" method for files in '//class/ubi/' */ - static ssize_t ubi_version_show(struct class *class, char *buf) -@@ -101,38 +228,152 @@ - __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); - static struct device_attribute dev_bgt_enabled = - __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); -+static struct device_attribute dev_mtd_num = -+ __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); -+ -+/** -+ * ubi_get_device - get UBI device. -+ * @ubi_num: UBI device number -+ * -+ * This function returns UBI device description object for UBI device number -+ * @ubi_num, or %NULL if the device does not exist. This function increases the -+ * device reference count to prevent removal of the device. In other words, the -+ * device cannot be removed if its reference count is not zero. -+ */ -+struct ubi_device *ubi_get_device(int ubi_num) -+{ -+ struct ubi_device *ubi; -+ -+ spin_lock(&ubi_devices_lock); -+ ubi = ubi_devices[ubi_num]; -+ if (ubi) { -+ ubi_assert(ubi->ref_count >= 0); -+ ubi->ref_count += 1; -+ get_device(&ubi->dev); -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return ubi; -+} -+ -+/** -+ * ubi_put_device - drop an UBI device reference. -+ * @ubi: UBI device description object -+ */ -+void ubi_put_device(struct ubi_device *ubi) -+{ -+ spin_lock(&ubi_devices_lock); -+ ubi->ref_count -= 1; -+ put_device(&ubi->dev); -+ spin_unlock(&ubi_devices_lock); -+} -+ -+/** -+ * ubi_get_by_major - get UBI device description object by character device -+ * major number. -+ * @major: major number -+ * -+ * This function is similar to 'ubi_get_device()', but it searches the device -+ * by its major number. -+ */ -+struct ubi_device *ubi_get_by_major(int major) -+{ -+ int i; -+ struct ubi_device *ubi; -+ -+ spin_lock(&ubi_devices_lock); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ ubi = ubi_devices[i]; -+ if (ubi && MAJOR(ubi->cdev.dev) == major) { -+ ubi_assert(ubi->ref_count >= 0); -+ ubi->ref_count += 1; -+ get_device(&ubi->dev); -+ spin_unlock(&ubi_devices_lock); -+ return ubi; -+ } -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return NULL; -+} -+ -+/** -+ * ubi_major2num - get UBI device number by character device major number. -+ * @major: major number -+ * -+ * This function searches UBI device number object by its major number. If UBI -+ * device was not found, this function returns -ENODEV, otherwise the UBI device -+ * number is returned. -+ */ -+int ubi_major2num(int major) -+{ -+ int i, ubi_num = -ENODEV; -+ -+ spin_lock(&ubi_devices_lock); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ struct ubi_device *ubi = ubi_devices[i]; -+ -+ if ( (ubi && MAJOR(ubi->cdev.dev) == major) || -+ (ubi && ubi->bdev_major == major)) { -+ ubi_num = ubi->ubi_num; -+ break; -+ } -+ } -+ spin_unlock(&ubi_devices_lock); -+ -+ return ubi_num; -+} -+EXPORT_SYMBOL_GPL(ubi_major2num); - - /* "Show" method for files in '//class/ubi/ubiX/' */ - static ssize_t dev_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) - { -- const struct ubi_device *ubi; -+ ssize_t ret; -+ struct ubi_device *ubi; - -+ /* -+ * The below code looks weird, but it actually makes sense. We get the -+ * UBI device reference from the contained 'struct ubi_device'. But it -+ * is unclear if the device was removed or not yet. Indeed, if the -+ * device was removed before we increased its reference count, -+ * 'ubi_get_device()' will return -ENODEV and we fail. -+ * -+ * Remember, 'struct ubi_device' is freed in the release function, so -+ * we still can use 'ubi->ubi_num'. -+ */ - ubi = container_of(dev, struct ubi_device, dev); -+ ubi = ubi_get_device(ubi->ubi_num); -+ if (!ubi) -+ return -ENODEV; -+ - if (attr == &dev_eraseblock_size) -- return sprintf(buf, "%d\n", ubi->leb_size); -+ ret = sprintf(buf, "%d\n", ubi->leb_size); - else if (attr == &dev_avail_eraseblocks) -- return sprintf(buf, "%d\n", ubi->avail_pebs); -+ ret = sprintf(buf, "%d\n", ubi->avail_pebs); - else if (attr == &dev_total_eraseblocks) -- return sprintf(buf, "%d\n", ubi->good_peb_count); -+ ret = sprintf(buf, "%d\n", ubi->good_peb_count); - else if (attr == &dev_volumes_count) -- return sprintf(buf, "%d\n", ubi->vol_count); -+ ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); - else if (attr == &dev_max_ec) -- return sprintf(buf, "%d\n", ubi->max_ec); -+ ret = sprintf(buf, "%d\n", ubi->max_ec); - else if (attr == &dev_reserved_for_bad) -- return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); -+ ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); - else if (attr == &dev_bad_peb_count) -- return sprintf(buf, "%d\n", ubi->bad_peb_count); -+ ret = sprintf(buf, "%d\n", ubi->bad_peb_count); - else if (attr == &dev_max_vol_count) -- return sprintf(buf, "%d\n", ubi->vtbl_slots); -+ ret = sprintf(buf, "%d\n", ubi->vtbl_slots); - else if (attr == &dev_min_io_size) -- return sprintf(buf, "%d\n", ubi->min_io_size); -+ ret = sprintf(buf, "%d\n", ubi->min_io_size); - else if (attr == &dev_bgt_enabled) -- return sprintf(buf, "%d\n", ubi->thread_enabled); -+ ret = sprintf(buf, "%d\n", ubi->thread_enabled); -+ else if (attr == &dev_mtd_num) -+ ret = sprintf(buf, "%d\n", ubi->mtd->index); - else -- BUG(); -+ ret = -EINVAL; - -- return 0; -+ ubi_put_device(ubi); -+ return ret; - } - - /* Fake "release" method for UBI devices */ -@@ -150,68 +391,44 @@ - int err; - - ubi->dev.release = dev_release; -- ubi->dev.devt = MKDEV(ubi->major, 0); -+ ubi->dev.devt = ubi->cdev.dev; - ubi->dev.class = ubi_class; - sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); - err = device_register(&ubi->dev); - if (err) -- goto out; -+ return err; - - err = device_create_file(&ubi->dev, &dev_eraseblock_size); - if (err) -- goto out_unregister; -+ return err; - err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); - if (err) -- goto out_eraseblock_size; -+ return err; - err = device_create_file(&ubi->dev, &dev_total_eraseblocks); - if (err) -- goto out_avail_eraseblocks; -+ return err; - err = device_create_file(&ubi->dev, &dev_volumes_count); - if (err) -- goto out_total_eraseblocks; -+ return err; - err = device_create_file(&ubi->dev, &dev_max_ec); - if (err) -- goto out_volumes_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_reserved_for_bad); - if (err) -- goto out_volumes_max_ec; -+ return err; - err = device_create_file(&ubi->dev, &dev_bad_peb_count); - if (err) -- goto out_reserved_for_bad; -+ return err; - err = device_create_file(&ubi->dev, &dev_max_vol_count); - if (err) -- goto out_bad_peb_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_min_io_size); - if (err) -- goto out_max_vol_count; -+ return err; - err = device_create_file(&ubi->dev, &dev_bgt_enabled); - if (err) -- goto out_min_io_size; -- -- return 0; -- --out_min_io_size: -- device_remove_file(&ubi->dev, &dev_min_io_size); --out_max_vol_count: -- device_remove_file(&ubi->dev, &dev_max_vol_count); --out_bad_peb_count: -- device_remove_file(&ubi->dev, &dev_bad_peb_count); --out_reserved_for_bad: -- device_remove_file(&ubi->dev, &dev_reserved_for_bad); --out_volumes_max_ec: -- device_remove_file(&ubi->dev, &dev_max_ec); --out_volumes_count: -- device_remove_file(&ubi->dev, &dev_volumes_count); --out_total_eraseblocks: -- device_remove_file(&ubi->dev, &dev_total_eraseblocks); --out_avail_eraseblocks: -- device_remove_file(&ubi->dev, &dev_avail_eraseblocks); --out_eraseblock_size: -- device_remove_file(&ubi->dev, &dev_eraseblock_size); --out_unregister: -- device_unregister(&ubi->dev); --out: -- ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); -+ return err; -+ err = device_create_file(&ubi->dev, &dev_mtd_num); - return err; - } - -@@ -221,6 +438,7 @@ - */ - static void ubi_sysfs_close(struct ubi_device *ubi) - { -+ device_remove_file(&ubi->dev, &dev_mtd_num); - device_remove_file(&ubi->dev, &dev_bgt_enabled); - device_remove_file(&ubi->dev, &dev_min_io_size); - device_remove_file(&ubi->dev, &dev_max_vol_count); -@@ -244,7 +462,7 @@ - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) -- ubi_free_volume(ubi, i); -+ ubi_free_volume(ubi, ubi->volumes[i]); - } - - /** -@@ -259,9 +477,6 @@ - int i, err; - dev_t dev; - -- mutex_init(&ubi->vtbl_mutex); -- spin_lock_init(&ubi->volumes_lock); -- - sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); - - /* -@@ -278,39 +493,40 @@ - return err; - } - -+ ubi_assert(MINOR(dev) == 0); - cdev_init(&ubi->cdev, &ubi_cdev_operations); -- ubi->major = MAJOR(dev); -- dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); -+ dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); - ubi->cdev.owner = THIS_MODULE; - -- dev = MKDEV(ubi->major, 0); - err = cdev_add(&ubi->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device %s", ubi->ubi_name); -+ ubi_err("cannot add character device"); - goto out_unreg; - } - - err = ubi_sysfs_init(ubi); - if (err) -- goto out_cdev; -+ goto out_sysfs; - - for (i = 0; i < ubi->vtbl_slots; i++) - if (ubi->volumes[i]) { -- err = ubi_add_volume(ubi, i); -- if (err) -+ err = ubi_add_volume(ubi, ubi->volumes[i]); -+ if (err) { -+ ubi_err("cannot add volume %d", i); - goto out_volumes; -+ } - } - - return 0; - - out_volumes: - kill_volumes(ubi); -+out_sysfs: - ubi_sysfs_close(ubi); --out_cdev: - cdev_del(&ubi->cdev); - out_unreg: -- unregister_chrdev_region(MKDEV(ubi->major, 0), -- ubi->vtbl_slots + 1); -+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); -+ ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); - return err; - } - -@@ -323,7 +539,7 @@ - kill_volumes(ubi); - ubi_sysfs_close(ubi); - cdev_del(&ubi->cdev); -- unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); -+ unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); - } - - /** -@@ -370,7 +586,11 @@ - out_wl: - ubi_wl_close(ubi); - out_vtbl: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - out_si: - ubi_scan_destroy_si(si); - return err; -@@ -384,15 +604,21 @@ - * assumed: - * o EC header is always at offset zero - this cannot be changed; - * o VID header starts just after the EC header at the closest address -- * aligned to @io->@hdrs_min_io_size; -+ * aligned to @io->hdrs_min_io_size; - * o data starts just after the VID header at the closest address aligned to -- * @io->@min_io_size -+ * @io->min_io_size - * - * This function returns zero in case of success and a negative error code in - * case of failure. - */ - static int io_init(struct ubi_device *ubi) - { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ printk("kmalloc instead of vmalloc is used.\n"); -+#else -+ printk("vmalloc is used.\n"); -+#endif -+ - if (ubi->mtd->numeraseregions != 0) { - /* - * Some flashes have several erase regions. Different regions -@@ -407,13 +633,18 @@ - return -EINVAL; - } - -+ if (ubi->vid_hdr_offset < 0) -+ return -EINVAL; -+ - /* - * Note, in this implementation we support MTD devices with 0x7FFFFFFF - * physical eraseblocks maximum. - */ - - ubi->peb_size = ubi->mtd->erasesize; -- ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; -+// ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; -+ ubi->peb_count = ubi->mtd->size >> (ffs(ubi->mtd->erasesize) - 1); -+ - ubi->flash_size = ubi->mtd->size; - - if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) -@@ -424,7 +655,8 @@ - - /* Make sure minimal I/O unit is power of 2 */ - if (!is_power_of_2(ubi->min_io_size)) { -- ubi_err("bad min. I/O unit"); -+ ubi_err("min. I/O unit (%d) is not power of 2", -+ ubi->min_io_size); - return -EINVAL; - } - -@@ -453,10 +685,8 @@ - } - - /* Similar for the data offset */ -- if (ubi->leb_start == 0) { -- ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; -- ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); -- } -+ ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; -+ ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); - - dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); - dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); -@@ -499,8 +729,16 @@ - ubi->ro_mode = 1; - } - -- dbg_msg("leb_size %d", ubi->leb_size); -- dbg_msg("ro_mode %d", ubi->ro_mode); -+ ubi_msg("physical eraseblock size: %d bytes (%d KiB)", -+ ubi->peb_size, ubi->peb_size >> 10); -+ ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); -+ ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); -+ if (ubi->hdrs_min_io_size != ubi->min_io_size) -+ ubi_msg("sub-page size: %d", -+ ubi->hdrs_min_io_size); -+ ubi_msg("VID header offset: %d (aligned %d)", -+ ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); -+ ubi_msg("data offset: %d", ubi->leb_start); - - /* - * Note, ideally, we have to initialize ubi->bad_peb_count here. But -@@ -514,87 +752,171 @@ - } - - /** -- * attach_mtd_dev - attach an MTD device. -- * @mtd_dev: MTD device name or number string -- * @vid_hdr_offset: VID header offset -- * @data_offset: data offset -+ * autoresize - re-size the volume which has the "auto-resize" flag set. -+ * @ubi: UBI device description object -+ * @vol_id: ID of the volume to re-size - * -- * This function attaches an MTD device to UBI. It first treats @mtd_dev as the -- * MTD device name, and tries to open it by this name. If it is unable to open, -- * it tries to convert @mtd_dev to an integer and open the MTD device by its -- * number. Returns zero in case of success and a negative error code in case of -- * failure. -+ * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in -+ * the volume table to the largest possible size. See comments in ubi-header.h -+ * for more description of the flag. Returns zero in case of success and a -+ * negative error code in case of failure. - */ --static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, -- int data_offset) -+static int autoresize(struct ubi_device *ubi, int vol_id) - { -- struct ubi_device *ubi; -- struct mtd_info *mtd; -- int i, err; -+ struct ubi_volume_desc desc; -+ struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err, old_reserved_pebs = vol->reserved_pebs; - -- mtd = get_mtd_device_nm(mtd_dev); -- if (IS_ERR(mtd)) { -- int mtd_num; -- char *endp; -+ /* -+ * Clear the auto-resize flag in the volume in-memory copy of the -+ * volume table, and 'ubi_resize_volume()' will propogate this change -+ * to the flash. -+ */ -+ ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; - -- if (PTR_ERR(mtd) != -ENODEV) -- return PTR_ERR(mtd); -+ if (ubi->avail_pebs == 0) { -+ struct ubi_vtbl_record vtbl_rec; - - /* -- * Probably this is not MTD device name but MTD device number - -- * check this out. -+ * No avalilable PEBs to re-size the volume, clear the flag on -+ * flash and exit. - */ -- mtd_num = simple_strtoul(mtd_dev, &endp, 0); -- if (*endp != '\0' || mtd_dev == endp) { -- ubi_err("incorrect MTD device: \"%s\"", mtd_dev); -- return -ENODEV; -- } -- -- mtd = get_mtd_device(NULL, mtd_num); -- if (IS_ERR(mtd)) -- return PTR_ERR(mtd); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol_id], -+ sizeof(struct ubi_vtbl_record)); -+ err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ if (err) -+ ubi_err("cannot clean auto-resize flag for volume %d", -+ vol_id); -+ } else { -+ desc.vol = vol; -+ err = ubi_resize_volume(&desc, -+ old_reserved_pebs + ubi->avail_pebs); -+ if (err) -+ ubi_err("cannot auto-resize volume %d", vol_id); - } - -- /* Check if we already have the same MTD device attached */ -- for (i = 0; i < ubi_devices_cnt; i++) -- if (ubi_devices[i]->mtd->index == mtd->index) { -- ubi_err("mtd%d is already attached to ubi%d", -+ if (err) -+ return err; -+ -+ ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, -+ vol->name, old_reserved_pebs, vol->reserved_pebs); -+ return 0; -+} -+ -+/** -+ * ubi_attach_mtd_dev - attach an MTD device. -+ * @mtd_dev: MTD device description object -+ * @ubi_num: number to assign to the new UBI device -+ * @vid_hdr_offset: VID header offset -+ * -+ * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number -+ * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in -+ * which case this function finds a vacant device nubert and assings it -+ * automatically. Returns the new UBI device number in case of success and a -+ * negative error code in case of failure. -+ * -+ * Note, the invocations of this function has to be serialized by the -+ * @ubi_devices_mutex. -+ */ -+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) -+{ -+ struct ubi_device *ubi; -+ int i, err; -+ -+ /* -+ * Check if we already have the same MTD device attached. -+ * -+ * Note, this function assumes that UBI devices creations and deletions -+ * are serialized, so it does not take the &ubi_devices_lock. -+ */ -+ for (i = 0; i < UBI_MAX_DEVICES; i++) { -+ ubi = ubi_devices[i]; -+ if (ubi && mtd->index == ubi->mtd->index) { -+ dbg_err("mtd%d is already attached to ubi%d", - mtd->index, i); -- err = -EINVAL; -- goto out_mtd; -+ return -EEXIST; - } -+ } - -- ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), -- GFP_KERNEL); -- if (!ubi) { -- err = -ENOMEM; -- goto out_mtd; -+ /* -+ * Make sure this MTD device is not emulated on top of an UBI volume -+ * already. Well, generally this recursion works fine, but there are -+ * different problems like the UBI module takes a reference to itself -+ * by attaching (and thus, opening) the emulated MTD device. This -+ * results in inability to unload the module. And in general it makes -+ * no sense to attach emulated MTD devices, so we prohibit this. -+ */ -+ if (mtd->type == MTD_UBIVOLUME) { -+ ubi_err("refuse attaching mtd%d - it is already emulated on " -+ "top of UBI", mtd->index); -+ return -EINVAL; - } - -- ubi->ubi_num = ubi_devices_cnt; -- ubi->mtd = mtd; -+ if (ubi_num == UBI_DEV_NUM_AUTO) { -+ /* Search for an empty slot in the @ubi_devices array */ -+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) -+ if (!ubi_devices[ubi_num]) -+ break; -+ if (ubi_num == UBI_MAX_DEVICES) { -+ dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); -+ return -ENFILE; -+ } -+ } else { -+ if (ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; -+ -+ /* Make sure ubi_num is not busy */ -+ if (ubi_devices[ubi_num]) { -+ dbg_err("ubi%d already exists", ubi_num); -+ return -EEXIST; -+ } -+ } - -- dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", -- ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset); -+ ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); -+ if (!ubi) -+ return -ENOMEM; - -+ ubi->mtd = mtd; -+ ubi->ubi_num = ubi_num; - ubi->vid_hdr_offset = vid_hdr_offset; -- ubi->leb_start = data_offset; -+ ubi->autoresize_vol_id = -1; -+ -+ mutex_init(&ubi->buf_mutex); -+ mutex_init(&ubi->ckvol_mutex); -+ mutex_init(&ubi->volumes_mutex); -+ spin_lock_init(&ubi->volumes_lock); -+ -+ dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", -+ mtd->index, ubi_num, vid_hdr_offset); - err = io_init(ubi); - if (err) - goto out_free; - -- mutex_init(&ubi->buf_mutex); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->peb_buf1 = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->peb_buf1 = vmalloc(ubi->peb_size); -+#endif -+ - if (!ubi->peb_buf1) - goto out_free; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->peb_buf2 = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->peb_buf2 = vmalloc(ubi->peb_size); -+#endif - if (!ubi->peb_buf2) - goto out_free; - - #ifdef CONFIG_MTD_UBI_DEBUG - mutex_init(&ubi->dbg_buf_mutex); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubi->dbg_peb_buf = kmalloc(ubi->peb_size, GFP_KERNEL); -+#else - ubi->dbg_peb_buf = vmalloc(ubi->peb_size); -+#endif -+ - if (!ubi->dbg_peb_buf) - goto out_free; - #endif -@@ -605,22 +927,33 @@ - goto out_free; - } - -+ if (ubi->autoresize_vol_id != -1) { -+ err = autoresize(ubi, ubi->autoresize_vol_id); -+ if (err) -+ goto out_detach; -+ } -+ - err = uif_init(ubi); - if (err) - goto out_detach; - -- ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); -- ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); -+ err = bdev_init(ubi); -+ if(err) -+ goto out_detach; -+ -+ ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); -+ if (IS_ERR(ubi->bgt_thread)) { -+ err = PTR_ERR(ubi->bgt_thread); -+ ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, -+ err); -+ goto out_uif; -+ } -+ -+ ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); -+ ubi_msg("MTD device name: \"%s\"", mtd->name); - ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); -- ubi_msg("physical eraseblock size: %d bytes (%d KiB)", -- ubi->peb_size, ubi->peb_size >> 10); -- ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); - ubi_msg("number of good PEBs: %d", ubi->good_peb_count); - ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); -- ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); -- ubi_msg("VID header offset: %d (aligned %d)", -- ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); -- ubi_msg("data offset: %d", ubi->leb_start); - ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); - ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); - ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); -@@ -638,50 +971,141 @@ - wake_up_process(ubi->bgt_thread); - } - -- ubi_devices_cnt += 1; -- return 0; -+ ubi_devices[ubi_num] = ubi; -+ return ubi_num; - -+out_uif: -+ uif_close(ubi); - out_detach: - ubi_eba_close(ubi); - ubi_wl_close(ubi); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->peb_buf1); -+ kfree(ubi->peb_buf2); -+#else - vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); -+#endif - #ifdef CONFIG_MTD_UBI_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->dbg_peb_buf); -+#else - vfree(ubi->dbg_peb_buf); - #endif -+#endif - kfree(ubi); --out_mtd: -- put_mtd_device(mtd); -- ubi_devices[ubi_devices_cnt] = NULL; - return err; - } - - /** -- * detach_mtd_dev - detach an MTD device. -- * @ubi: UBI device description object -+ * ubi_detach_mtd_dev - detach an MTD device. -+ * @ubi_num: UBI device number to detach from -+ * @anyway: detach MTD even if device reference count is not zero -+ * -+ * This function destroys an UBI device number @ubi_num and detaches the -+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the -+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not -+ * exist. -+ * -+ * Note, the invocations of this function has to be serialized by the -+ * @ubi_devices_mutex. - */ --static void detach_mtd_dev(struct ubi_device *ubi) -+int ubi_detach_mtd_dev(int ubi_num, int anyway) - { -- int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; -+ struct ubi_device *ubi; -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; -+ -+ spin_lock(&ubi_devices_lock); -+ ubi = ubi_devices[ubi_num]; -+ if (!ubi) { -+ spin_unlock(&ubi_devices_lock); -+ return -EINVAL; -+ } - -+ if (ubi->ref_count) { -+ if (!anyway) { -+ spin_unlock(&ubi_devices_lock); -+ return -EBUSY; -+ } -+ /* This may only happen if there is a bug */ -+ ubi_err("%s reference count %d, destroy anyway", -+ ubi->ubi_name, ubi->ref_count); -+ } -+ ubi_devices[ubi_num] = NULL; -+ spin_unlock(&ubi_devices_lock); -+ -+ ubi_assert(ubi_num == ubi->ubi_num); - dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); -+ -+ /* -+ * Before freeing anything, we have to stop the background thread to -+ * prevent it from doing anything on this device while we are freeing. -+ */ -+ if (ubi->bgt_thread) -+ kthread_stop(ubi->bgt_thread); -+ - uif_close(ubi); - ubi_eba_close(ubi); - ubi_wl_close(ubi); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - put_mtd_device(ubi->mtd); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->peb_buf1); -+ kfree(ubi->peb_buf2); -+#else - vfree(ubi->peb_buf1); - vfree(ubi->peb_buf2); -+#endif - #ifdef CONFIG_MTD_UBI_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->dbg_peb_buf); -+#else - vfree(ubi->dbg_peb_buf); - #endif -- kfree(ubi_devices[ubi_num]); -- ubi_devices[ubi_num] = NULL; -- ubi_devices_cnt -= 1; -- ubi_assert(ubi_devices_cnt >= 0); -- ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); -+#endif -+ ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); -+ kfree(ubi); -+ return 0; -+} -+ -+/** -+ * find_mtd_device - open an MTD device by its name or number. -+ * @mtd_dev: name or number of the device -+ * -+ * This function tries to open and MTD device described by @mtd_dev string, -+ * which is first treated as an ASCII number, and if it is not true, it is -+ * treated as MTD device name. Returns MTD device description object in case of -+ * success and a negative error code in case of failure. -+ */ -+static struct mtd_info * __init open_mtd_device(const char *mtd_dev) -+{ -+ struct mtd_info *mtd; -+ int mtd_num; -+ char *endp; -+ -+ mtd_num = simple_strtoul(mtd_dev, &endp, 0); -+ if (*endp != '\0' || mtd_dev == endp) { -+ /* -+ * This does not look like an ASCII integer, probably this is -+ * MTD device name. -+ */ -+ mtd = get_mtd_device_nm(mtd_dev); -+ } else -+ mtd = get_mtd_device(NULL, mtd_num); -+ -+ return mtd; - } - - static int __init ubi_init(void) -@@ -693,47 +1117,94 @@ - BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); - - if (mtd_devs > UBI_MAX_DEVICES) { -- printk("UBI error: too many MTD devices, maximum is %d\n", -- UBI_MAX_DEVICES); -+ ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); - return -EINVAL; - } - -+ /* Create base sysfs directory and sysfs files */ - ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); -- if (IS_ERR(ubi_class)) -- return PTR_ERR(ubi_class); -+ if (IS_ERR(ubi_class)) { -+ err = PTR_ERR(ubi_class); -+ ubi_err("cannot create UBI class"); -+ goto out; -+ } - - err = class_create_file(ubi_class, &ubi_version); -- if (err) -+ if (err) { -+ ubi_err("cannot create sysfs file"); - goto out_class; -+ } -+ -+ err = misc_register(&ubi_ctrl_cdev); -+ if (err) { -+ ubi_err("cannot register device"); -+ goto out_version; -+ } -+ -+ ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", -+ sizeof(struct ubi_wl_entry), -+ 0, 0, NULL); -+ if (!ubi_wl_entry_slab) -+ goto out_dev_unreg; - - /* Attach MTD devices */ - for (i = 0; i < mtd_devs; i++) { - struct mtd_dev_param *p = &mtd_dev_param[i]; -+ struct mtd_info *mtd; - - cond_resched(); -- err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); -- if (err) -+ -+ mtd = open_mtd_device(p->name); -+ if (IS_ERR(mtd)) { -+ err = PTR_ERR(mtd); -+ goto out_detach; -+ } -+ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, -+ p->vid_hdr_offs); -+ mutex_unlock(&ubi_devices_mutex); -+ if (err < 0) { -+ put_mtd_device(mtd); -+ ubi_err("cannot attach mtd%d", mtd->index); - goto out_detach; -+ } - } - - return 0; - - out_detach: - for (k = 0; k < i; k++) -- detach_mtd_dev(ubi_devices[k]); -+ if (ubi_devices[k]) { -+ mutex_lock(&ubi_devices_mutex); -+ ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1); -+ mutex_unlock(&ubi_devices_mutex); -+ } -+ kmem_cache_destroy(ubi_wl_entry_slab); -+out_dev_unreg: -+ misc_deregister(&ubi_ctrl_cdev); -+out_version: - class_remove_file(ubi_class, &ubi_version); - out_class: - class_destroy(ubi_class); -+out: -+ ubi_err("UBI error: cannot initialize UBI, error %d", err); - return err; - } - module_init(ubi_init); - - static void __exit ubi_exit(void) - { -- int i, n = ubi_devices_cnt; -+ int i; - -- for (i = 0; i < n; i++) -- detach_mtd_dev(ubi_devices[i]); -+ for (i = 0; i < UBI_MAX_DEVICES; i++) -+ if (ubi_devices[i]) { -+ mutex_lock(&ubi_devices_mutex); -+ ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1); -+ mutex_unlock(&ubi_devices_mutex); -+ } -+ kmem_cache_destroy(ubi_wl_entry_slab); -+ misc_deregister(&ubi_ctrl_cdev); - class_remove_file(ubi_class, &ubi_version); - class_destroy(ubi_class); - } -@@ -754,7 +1225,8 @@ - - result = simple_strtoul(str, &endp, 0); - if (str == endp || result < 0) { -- printk("UBI error: incorrect bytes count: \"%s\"\n", str); -+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", -+ str); - return -EINVAL; - } - -@@ -764,15 +1236,14 @@ - case 'M': - result *= 1024; - case 'K': -- case 'k': - result *= 1024; -- if (endp[1] == 'i' && (endp[2] == '\0' || -- endp[2] == 'B' || endp[2] == 'b')) -+ if (endp[1] == 'i' && endp[2] == 'B') - endp += 2; - case '\0': - break; - default: -- printk("UBI error: incorrect bytes count: \"%s\"\n", str); -+ printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", -+ str); - return -EINVAL; - } - -@@ -793,23 +1264,27 @@ - struct mtd_dev_param *p; - char buf[MTD_PARAM_LEN_MAX]; - char *pbuf = &buf[0]; -- char *tokens[3] = {NULL, NULL, NULL}; -+ char *tokens[2] = {NULL, NULL}; -+ -+ if (!val) -+ return -EINVAL; - - if (mtd_devs == UBI_MAX_DEVICES) { -- printk("UBI error: too many parameters, max. is %d\n", -+ printk(KERN_ERR "UBI error: too many parameters, max. is %d\n", - UBI_MAX_DEVICES); - return -EINVAL; - } - - len = strnlen(val, MTD_PARAM_LEN_MAX); - if (len == MTD_PARAM_LEN_MAX) { -- printk("UBI error: parameter \"%s\" is too long, max. is %d\n", -- val, MTD_PARAM_LEN_MAX); -+ printk(KERN_ERR "UBI error: parameter \"%s\" is too long, " -+ "max. is %d\n", val, MTD_PARAM_LEN_MAX); - return -EINVAL; - } - - if (len == 0) { -- printk("UBI warning: empty 'mtd=' parameter - ignored\n"); -+ printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - " -+ "ignored\n"); - return 0; - } - -@@ -819,11 +1294,12 @@ - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - -- for (i = 0; i < 3; i++) -+ for (i = 0; i < 2; i++) - tokens[i] = strsep(&pbuf, ","); - - if (pbuf) { -- printk("UBI error: too many arguments at \"%s\"\n", val); -+ printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n", -+ val); - return -EINVAL; - } - -@@ -832,13 +1308,9 @@ - - if (tokens[1]) - p->vid_hdr_offs = bytes_str_to_int(tokens[1]); -- if (tokens[2]) -- p->data_offs = bytes_str_to_int(tokens[2]); - - if (p->vid_hdr_offs < 0) - return p->vid_hdr_offs; -- if (p->data_offs < 0) -- return p->data_offs; - - mtd_devs += 1; - return 0; -@@ -846,16 +1318,15 @@ - - module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); - MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " -- "mtd=[,,]. " -+ "mtd=[,].\n" - "Multiple \"mtd\" parameters may be specified.\n" -- "MTD devices may be specified by their number or name. " -- "Optional \"vid_hdr_offs\" and \"data_offs\" parameters " -- "specify UBI VID header position and data starting " -- "position to be used by UBI.\n" -- "Example: mtd=content,1984,2048 mtd=4 - attach MTD device" -- "with name content using VID header offset 1984 and data " -- "start 2048, and MTD device number 4 using default " -- "offsets"); -+ "MTD devices may be specified by their number or name.\n" -+ "Optional \"vid_hdr_offs\" parameter specifies UBI VID " -+ "header position and data starting position to be used " -+ "by UBI.\n" -+ "Example: mtd=content,1984 mtd=4 - attach MTD device" -+ "with name \"content\" using VID header offset 1984, and " -+ "MTD device number 4 with default VID header offset."); - - MODULE_VERSION(__stringify(UBI_VERSION)); - MODULE_DESCRIPTION("UBI - Unsorted Block Images"); -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/cdev.c linux-2.6.24.7/drivers/mtd/ubi/cdev.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/cdev.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/cdev.c 2009-04-12 18:13:57.000000000 +0200 -@@ -28,6 +28,11 @@ - * - * Major and minor numbers are assigned dynamically to both UBI and volume - * character devices. -+ * -+ * Well, there is the third kind of character devices - the UBI control -+ * character device, which allows to manipulate by UBI devices - create and -+ * delete them. In other words, it is used for attaching and detaching MTD -+ * devices. - */ - - #include -@@ -39,34 +44,6 @@ - #include - #include "ubi.h" - --/* -- * Maximum sequence numbers of UBI and volume character device IOCTLs (direct -- * logical eraseblock erase is a debug-only feature). -- */ --#define UBI_CDEV_IOC_MAX_SEQ 2 --#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO --#define VOL_CDEV_IOC_MAX_SEQ 1 --#else --#define VOL_CDEV_IOC_MAX_SEQ 2 --#endif -- --/** -- * major_to_device - get UBI device object by character device major number. -- * @major: major number -- * -- * This function returns a pointer to the UBI device object. -- */ --static struct ubi_device *major_to_device(int major) --{ -- int i; -- -- for (i = 0; i < ubi_devices_cnt; i++) -- if (ubi_devices[i] && ubi_devices[i]->major == major) -- return ubi_devices[i]; -- BUG(); -- return NULL; --} -- - /** - * get_exclusive - get exclusive access to an UBI volume. - * @desc: volume descriptor -@@ -124,9 +101,11 @@ - static int vol_cdev_open(struct inode *inode, struct file *file) - { - struct ubi_volume_desc *desc; -- const struct ubi_device *ubi = major_to_device(imajor(inode)); -- int vol_id = iminor(inode) - 1; -- int mode; -+ int vol_id = iminor(inode) - 1, mode, ubi_num; -+ -+ ubi_num = ubi_major2num(imajor(inode)); -+ if (ubi_num < 0) -+ return ubi_num; - - if (file->f_mode & FMODE_WRITE) - mode = UBI_READWRITE; -@@ -135,7 +114,7 @@ - - dbg_msg("open volume %d, mode %d", vol_id, mode); - -- desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); -+ desc = ubi_open_volume(ubi_num, vol_id, mode); - if (IS_ERR(desc)) - return PTR_ERR(desc); - -@@ -153,8 +132,23 @@ - if (vol->updating) { - ubi_warn("update of volume %d not finished, volume is damaged", - vol->vol_id); -+ ubi_assert(!vol->changing_leb); - vol->updating = 0; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else - vfree(vol->upd_buf); -+#endif -+ } else if (vol->changing_leb) { -+ dbg_msg("only %lld of %lld bytes received for atomic LEB change" -+ " for volume %d:%d, cancel", vol->upd_received, -+ vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id); -+ vol->changing_leb = 0; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else -+ vfree(vol->upd_buf); -+#endif - } - - ubi_close_volume(desc); -@@ -205,13 +199,13 @@ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; -+ int err, lnum, off, len, tbuf_size; - size_t count_save = count; - void *tbuf; - uint64_t tmp; - - dbg_msg("read %zd bytes from offset %lld of volume %d", -- count, *offp, vol_id); -+ count, *offp, vol->vol_id); - - if (vol->updating) { - dbg_err("updating"); -@@ -225,7 +219,7 @@ - return 0; - - if (vol->corrupted) -- dbg_msg("read from corrupted volume %d", vol_id); -+ dbg_msg("read from corrupted volume %d", vol->vol_id); - - if (*offp + count > vol->used_bytes) - count_save = count = vol->used_bytes - *offp; -@@ -233,7 +227,11 @@ - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ tbuf = kmalloc(tbuf_size, GFP_KERNEL); -+#else - tbuf = vmalloc(tbuf_size); -+#endif - if (!tbuf) - return -ENOMEM; - -@@ -249,7 +247,7 @@ - if (off + len >= vol->usable_leb_size) - len = vol->usable_leb_size - off; - -- err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0); -+ err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0); - if (err) - break; - -@@ -272,7 +270,11 @@ - len = count > tbuf_size ? tbuf_size : count; - } while (count); - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(tbuf); -+#else - vfree(tbuf); -+#endif - return err ? err : count_save - count; - } - -@@ -289,13 +291,13 @@ - struct ubi_volume_desc *desc = file->private_data; - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0; -+ int lnum, off, len, tbuf_size, err = 0; - size_t count_save = count; - char *tbuf; - uint64_t tmp; - - dbg_msg("requested: write %zd bytes to offset %lld of volume %u", -- count, *offp, desc->vol->vol_id); -+ count, *offp, vol->vol_id); - - if (vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -321,7 +323,12 @@ - tbuf_size = vol->usable_leb_size; - if (count < tbuf_size) - tbuf_size = ALIGN(count, ubi->min_io_size); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ tbuf = kmalloc(tbuf_size, GFP_KERNEL); -+#else - tbuf = vmalloc(tbuf_size); -+#endif - if (!tbuf) - return -ENOMEM; - -@@ -339,7 +346,7 @@ - break; - } - -- err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len, -+ err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len, - UBI_UNKNOWN); - if (err) - break; -@@ -356,7 +363,11 @@ - len = count > tbuf_size ? tbuf_size : count; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(tbuf); -+#else - vfree(tbuf); -+#endif - return err ? err : count_save - count; - } - -@@ -372,22 +383,32 @@ - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; - -- if (!vol->updating) -+ if (!vol->updating && !vol->changing_leb) - return vol_cdev_direct_write(file, buf, count, offp); - -- err = ubi_more_update_data(ubi, vol->vol_id, buf, count); -+ if (vol->updating) -+ err = ubi_more_update_data(ubi, vol, buf, count); -+ else -+ err = ubi_more_leb_change_data(ubi, vol, buf, count); -+ - if (err < 0) { -- ubi_err("cannot write %zd bytes of update data", count); -+ ubi_err("cannot accept more %zd bytes of data, error %d", -+ count, err); - return err; - } - - if (err) { - /* -- * Update is finished, @err contains number of actually written -- * bytes now. -+ * The operation is finished, @err contains number of actually -+ * written bytes. - */ - count = err; - -+ if (vol->changing_leb) { -+ revoke_exclusive(desc, UBI_READWRITE); -+ return count; -+ } -+ - err = ubi_check_volume(ubi, vol->vol_id); - if (err < 0) - return err; -@@ -402,7 +423,6 @@ - revoke_exclusive(desc, UBI_READWRITE); - } - -- *offp += count; - return count; - } - -@@ -416,6 +436,47 @@ - void __user *argp = (void __user *)arg; - - switch (cmd) { -+ /* LEB read command */ -+ case UBI_IOCLEBREAD: -+ { -+ struct ubi_leb leb; -+ int pnum; -+ char *lebbuf; -+ -+ if (copy_from_user(&leb, argp, sizeof(struct ubi_leb))){ -+ err = -EFAULT; -+ break; -+ } -+ -+ pnum = vol->eba_tbl[leb.lnum]; -+ if (pnum < 0) { -+ //the LEB is clean, no need dump -+ err = 1; -+ break; -+ } -+ -+ lebbuf = kmalloc(vol->ubi->leb_size, GFP_KERNEL); -+ if (!lebbuf){ -+ err = -ENOMEM; -+ break; -+ } -+ -+ err= ubi_eba_read_leb(ubi, vol, leb.lnum, lebbuf, 0, vol->ubi->leb_size, 0); -+ if (err){ -+ kfree(lebbuf); -+ break; -+ } -+ -+ err = copy_to_user(leb.buf, lebbuf, vol->ubi->leb_size); -+ if (err) { -+ kfree(lebbuf); -+ err = -EFAULT; -+ break; -+ } -+ kfree(lebbuf); -+ break; -+ } -+ - /* Volume update command */ - case UBI_IOCVOLUP: - { -@@ -447,11 +508,46 @@ - if (err < 0) - break; - -- err = ubi_start_update(ubi, vol->vol_id, bytes); -+ err = ubi_start_update(ubi, vol, bytes); - if (bytes == 0) - revoke_exclusive(desc, UBI_READWRITE); -+ break; -+ } -+ -+ /* Atomic logical eraseblock change command */ -+ case UBI_IOCEBCH: -+ { -+ struct ubi_leb_change_req req; -+ -+ err = copy_from_user(&req, argp, -+ sizeof(struct ubi_leb_change_req)); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ if (desc->mode == UBI_READONLY || -+ vol->vol_type == UBI_STATIC_VOLUME) { -+ err = -EROFS; -+ break; -+ } -+ -+ /* Validate the request */ -+ err = -EINVAL; -+ if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || -+ req.bytes < 0 || req.lnum >= vol->usable_leb_size) -+ break; -+ if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM && -+ req.dtype != UBI_UNKNOWN) -+ break; - -- file->f_pos = 0; -+ err = get_exclusive(desc); -+ if (err < 0) -+ break; -+ -+ err = ubi_start_leb_change(ubi, vol, &req); -+ if (req.bytes == 0) -+ revoke_exclusive(desc, UBI_READWRITE); - break; - } - -@@ -467,7 +563,8 @@ - break; - } - -- if (desc->mode == UBI_READONLY) { -+ if (desc->mode == UBI_READONLY || -+ vol->vol_type == UBI_STATIC_VOLUME) { - err = -EROFS; - break; - } -@@ -477,13 +574,8 @@ - break; - } - -- if (vol->vol_type != UBI_DYNAMIC_VOLUME) { -- err = -EROFS; -- break; -- } -- - dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); -- err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); - if (err) - break; - -@@ -580,9 +672,9 @@ - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - -- ubi = major_to_device(imajor(inode)); -- if (IS_ERR(ubi)) -- return PTR_ERR(ubi); -+ ubi = ubi_get_by_major(imajor(inode)); -+ if (!ubi) -+ return -ENODEV; - - switch (cmd) { - /* Create volume command */ -@@ -591,8 +683,7 @@ - struct ubi_mkvol_req req; - - dbg_msg("create volume"); -- err = copy_from_user(&req, argp, -- sizeof(struct ubi_mkvol_req)); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); - if (err) { - err = -EFAULT; - break; -@@ -604,7 +695,9 @@ - - req.name[req.name_len] = '\0'; - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_create_volume(ubi, &req); -+ mutex_unlock(&ubi->volumes_mutex); - if (err) - break; - -@@ -633,10 +726,16 @@ - break; - } - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_remove_volume(desc); -- if (err) -- ubi_close_volume(desc); -+ mutex_unlock(&ubi->volumes_mutex); - -+ /* -+ * The volume is deleted (unless an error occurred), and the -+ * 'struct ubi_volume' object will be freed when -+ * 'ubi_close_volume()' will call 'put_device()'. -+ */ -+ ubi_close_volume(desc); - break; - } - -@@ -648,8 +747,7 @@ - struct ubi_rsvol_req req; - - dbg_msg("re-size volume"); -- err = copy_from_user(&req, argp, -- sizeof(struct ubi_rsvol_req)); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); - if (err) { - err = -EFAULT; - break; -@@ -669,7 +767,9 @@ - pebs = !!do_div(tmp, desc->vol->usable_leb_size); - pebs += tmp; - -+ mutex_lock(&ubi->volumes_mutex); - err = ubi_resize_volume(desc, pebs); -+ mutex_unlock(&ubi->volumes_mutex); - ubi_close_volume(desc); - break; - } -@@ -679,9 +779,93 @@ - break; - } - -+ ubi_put_device(ubi); -+ return err; -+} -+ -+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int err = 0; -+ void __user *argp = (void __user *)arg; -+ -+ if (!capable(CAP_SYS_RESOURCE)) -+ return -EPERM; -+ -+ switch (cmd) { -+ /* Attach an MTD device command */ -+ case UBI_IOCATT: -+ { -+ struct ubi_attach_req req; -+ struct mtd_info *mtd; -+ -+ dbg_msg("attach MTD device"); -+ err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ if (req.mtd_num < 0 || -+ (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) { -+ err = -EINVAL; -+ break; -+ } -+ -+ mtd = get_mtd_device(NULL, req.mtd_num); -+ if (IS_ERR(mtd)) { -+ err = PTR_ERR(mtd); -+ break; -+ } -+ -+ /* -+ * Note, further request verification is done by -+ * 'ubi_attach_mtd_dev()'. -+ */ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset); -+ mutex_unlock(&ubi_devices_mutex); -+ if (err < 0) -+ put_mtd_device(mtd); -+ else -+ /* @err contains UBI device number */ -+ err = put_user(err, (__user int32_t *)argp); -+ -+ break; -+ } -+ -+ /* Detach an MTD device command */ -+ case UBI_IOCDET: -+ { -+ int ubi_num; -+ -+ dbg_msg("dettach MTD device"); -+ err = get_user(ubi_num, (__user int32_t *)argp); -+ if (err) { -+ err = -EFAULT; -+ break; -+ } -+ -+ mutex_lock(&ubi_devices_mutex); -+ err = ubi_detach_mtd_dev(ubi_num, 0); -+ mutex_unlock(&ubi_devices_mutex); -+ break; -+ } -+ -+ default: -+ err = -ENOTTY; -+ break; -+ } -+ - return err; - } - -+/* UBI control character device operations */ -+struct file_operations ubi_ctrl_cdev_operations = { -+ .ioctl = ctrl_cdev_ioctl, -+ .owner = THIS_MODULE, -+}; -+ - /* UBI character device operations */ - struct file_operations ubi_cdev_operations = { - .owner = THIS_MODULE, -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/debug.h linux-2.6.24.7/drivers/mtd/ubi/debug.h ---- linux-2.6.24.7.old/drivers/mtd/ubi/debug.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/debug.h 2009-04-12 18:13:57.000000000 +0200 -@@ -39,8 +39,9 @@ - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG - /* Generic debugging message */ --#define dbg_msg(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) -+#define dbg_msg(fmt, ...) \ -+ printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ -+ current->pid, __FUNCTION__, ##__VA_ARGS__) - - #define ubi_dbg_dump_stack() dump_stack() - -@@ -76,38 +77,32 @@ - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA - /* Messages from the eraseblock association unit */ --#define dbg_eba(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_eba(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL - /* Messages from the wear-leveling unit */ --#define dbg_wl(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_wl(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO - /* Messages from the input/output unit */ --#define dbg_io(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) - #else - #define dbg_io(fmt, ...) ({}) - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD - /* Initialization and build messages */ --#define dbg_bld(fmt, ...) \ -- printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \ -- ##__VA_ARGS__) -+#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) -+#define UBI_IO_DEBUG 1 - #else - #define dbg_bld(fmt, ...) ({}) -+#define UBI_IO_DEBUG 0 - #endif - - #ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/eba.c linux-2.6.24.7/drivers/mtd/ubi/eba.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/eba.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/eba.c 2009-04-12 18:13:57.000000000 +0200 -@@ -31,7 +31,7 @@ - * logical eraseblock it is locked for reading or writing. The per-logical - * eraseblock locking is implemented by means of the lock tree. The lock tree - * is an RB-tree which refers all the currently locked logical eraseblocks. The -- * lock tree elements are &struct ltree_entry objects. They are indexed by -+ * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by - * (@vol_id, @lnum) pairs. - * - * EBA also maintains the global sequence counter which is incremented each -@@ -45,34 +45,11 @@ - #include - #include - #include "ubi.h" -- -+#include "ubiblk.h" - /* Number of physical eraseblocks reserved for atomic LEB change operation */ - #define EBA_RESERVED_PEBS 1 - - /** -- * struct ltree_entry - an entry in the lock tree. -- * @rb: links RB-tree nodes -- * @vol_id: volume ID of the locked logical eraseblock -- * @lnum: locked logical eraseblock number -- * @users: how many tasks are using this logical eraseblock or wait for it -- * @mutex: read/write mutex to implement read/write access serialization to -- * the (@vol_id, @lnum) logical eraseblock -- * -- * When a logical eraseblock is being locked - corresponding &struct ltree_entry -- * object is inserted to the lock tree (@ubi->ltree). -- */ --struct ltree_entry { -- struct rb_node rb; -- int vol_id; -- int lnum; -- int users; -- struct rw_semaphore mutex; --}; -- --/* Slab cache for lock-tree entries */ --static struct kmem_cache *ltree_slab; -- --/** - * next_sqnum - get next sequence number. - * @ubi: UBI device description object - * -@@ -101,7 +78,7 @@ - */ - static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) - { -- if (vol_id == UBI_LAYOUT_VOL_ID) -+ if (vol_id == UBI_LAYOUT_VOLUME_ID) - return UBI_LAYOUT_VOLUME_COMPAT; - return 0; - } -@@ -112,20 +89,20 @@ - * @vol_id: volume ID - * @lnum: logical eraseblock number - * -- * This function returns a pointer to the corresponding &struct ltree_entry -+ * This function returns a pointer to the corresponding &struct ubi_ltree_entry - * object if the logical eraseblock is locked and %NULL if it is not. - * @ubi->ltree_lock has to be locked. - */ --static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, -- int lnum) -+static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, -+ int lnum) - { - struct rb_node *p; - - p = ubi->ltree.rb_node; - while (p) { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - -- le = rb_entry(p, struct ltree_entry, rb); -+ le = rb_entry(p, struct ubi_ltree_entry, rb); - - if (vol_id < le->vol_id) - p = p->rb_left; -@@ -155,15 +132,17 @@ - * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation - * failed. - */ --static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, -- int lnum) -+static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, -+ int vol_id, int lnum) - { -- struct ltree_entry *le, *le1, *le_free; -+ struct ubi_ltree_entry *le, *le1, *le_free; - -- le = kmem_cache_alloc(ltree_slab, GFP_NOFS); -+ le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS); - if (!le) - return ERR_PTR(-ENOMEM); - -+ le->users = 0; -+ init_rwsem(&le->mutex); - le->vol_id = vol_id; - le->lnum = lnum; - -@@ -189,7 +168,7 @@ - p = &ubi->ltree.rb_node; - while (*p) { - parent = *p; -- le1 = rb_entry(parent, struct ltree_entry, rb); -+ le1 = rb_entry(parent, struct ubi_ltree_entry, rb); - - if (vol_id < le1->vol_id) - p = &(*p)->rb_left; -@@ -211,7 +190,7 @@ - spin_unlock(&ubi->ltree_lock); - - if (le_free) -- kmem_cache_free(ltree_slab, le_free); -+ kfree(le_free); - - return le; - } -@@ -227,7 +206,7 @@ - */ - static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) - { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) -@@ -245,7 +224,7 @@ - static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) - { - int free = 0; -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); -@@ -259,7 +238,7 @@ - - up_read(&le->mutex); - if (free) -- kmem_cache_free(ltree_slab, le); -+ kfree(le); - } - - /** -@@ -273,7 +252,7 @@ - */ - static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) - { -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - le = ltree_add_entry(ubi, vol_id, lnum); - if (IS_ERR(le)) -@@ -283,6 +262,44 @@ - } - - /** -+ * leb_write_lock - lock logical eraseblock for writing. -+ * @ubi: UBI device description object -+ * @vol_id: volume ID -+ * @lnum: logical eraseblock number -+ * -+ * This function locks a logical eraseblock for writing if there is no -+ * contention and does nothing if there is contention. Returns %0 in case of -+ * success, %1 in case of contention, and and a negative error code in case of -+ * failure. -+ */ -+static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) -+{ -+ int free; -+ struct ubi_ltree_entry *le; -+ -+ le = ltree_add_entry(ubi, vol_id, lnum); -+ if (IS_ERR(le)) -+ return PTR_ERR(le); -+ if (down_write_trylock(&le->mutex)) -+ return 0; -+ -+ /* Contention, cancel */ -+ spin_lock(&ubi->ltree_lock); -+ le->users -= 1; -+ ubi_assert(le->users >= 0); -+ if (le->users == 0) { -+ rb_erase(&le->rb, &ubi->ltree); -+ free = 1; -+ } else -+ free = 0; -+ spin_unlock(&ubi->ltree_lock); -+ if (free) -+ kfree(le); -+ -+ return 1; -+} -+ -+/** - * leb_write_unlock - unlock logical eraseblock. - * @ubi: UBI device description object - * @vol_id: volume ID -@@ -291,7 +308,7 @@ - static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) - { - int free; -- struct ltree_entry *le; -+ struct ubi_ltree_entry *le; - - spin_lock(&ubi->ltree_lock); - le = ltree_lookup(ubi, vol_id, lnum); -@@ -306,23 +323,23 @@ - - up_write(&le->mutex); - if (free) -- kmem_cache_free(ltree_slab, le); -+ kfree(le); - } - - /** - * ubi_eba_unmap_leb - un-map logical eraseblock. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * - * This function un-maps logical eraseblock @lnum and schedules corresponding - * physical eraseblock for erasure. Returns zero in case of success and a - * negative error code in case of failure. - */ --int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum) -+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum) - { -- int idx = vol_id2idx(ubi, vol_id), err, pnum; -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, vol_id = vol->vol_id; - - if (ubi->ro_mode) - return -EROFS; -@@ -349,7 +366,7 @@ - /** - * ubi_eba_read_leb - read data. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: buffer to store the read data - * @offset: offset from where to read -@@ -365,12 +382,11 @@ - * returned for any volume type if an ECC error was detected by the MTD device - * driver. Other negative error cored may be returned in case of other errors. - */ --int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int offset, int len, int check) -+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int offset, int len, int check) - { -- int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id); -+ int err, pnum, scrub = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; -- struct ubi_volume *vol = ubi->volumes[idx]; - uint32_t uninitialized_var(crc); - - err = leb_read_lock(ubi, vol_id, lnum); -@@ -578,7 +594,7 @@ - /** - * ubi_eba_write_leb - write data to dynamic volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: the data to write - * @offset: offset within the logical eraseblock where to write -@@ -586,15 +602,14 @@ - * @dtype: data type - * - * This function writes data to logical eraseblock @lnum of a dynamic volume -- * @vol_id. Returns zero in case of success and a negative error code in case -+ * @vol. Returns zero in case of success and a negative error code in case - * of failure. In case of error, it is possible that something was still - * written to the flash media, but may be some garbage. - */ --int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, -+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, - const void *buf, int offset, int len, int dtype) - { -- int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0; -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - - if (ubi->ro_mode) -@@ -613,7 +628,8 @@ - if (err) { - ubi_warn("failed to write data to PEB %d", pnum); - if (err == -EIO && ubi->bad_allowed) -- err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); -+ err = recover_peb(ubi, pnum, vol_id, lnum, buf, -+ offset, len); - if (err) - ubi_ro_mode(ubi); - } -@@ -656,11 +672,14 @@ - goto write_error; - } - -- err = ubi_io_write_data(ubi, buf, pnum, offset, len); -- if (err) { -- ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, " -- "PEB %d", len, offset, vol_id, lnum, pnum); -- goto write_error; -+ if (len) { -+ err = ubi_io_write_data(ubi, buf, pnum, offset, len); -+ if (err) { -+ ubi_warn("failed to write %d bytes at offset %d of " -+ "LEB %d:%d, PEB %d", len, offset, vol_id, -+ lnum, pnum); -+ goto write_error; -+ } - } - - vol->eba_tbl[lnum] = pnum; -@@ -698,7 +717,7 @@ - /** - * ubi_eba_write_leb_st - write data to static volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write -@@ -706,7 +725,7 @@ - * @used_ebs: how many logical eraseblocks will this volume contain - * - * This function writes data to logical eraseblock @lnum of static volume -- * @vol_id. The @used_ebs argument should contain total number of logical -+ * @vol. The @used_ebs argument should contain total number of logical - * eraseblock in this static volume. - * - * When writing to the last logical eraseblock, the @len argument doesn't have -@@ -718,12 +737,11 @@ - * volumes. This function returns zero in case of success and a negative error - * code in case of failure. - */ --int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype, int used_ebs) -+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype, -+ int used_ebs) - { -- int err, pnum, tries = 0, data_size = len; -- int idx = vol_id2idx(ubi, vol_id); -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - -@@ -819,7 +837,7 @@ - /* - * ubi_eba_atomic_leb_change - change logical eraseblock atomically. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: how many bytes to write -@@ -834,17 +852,27 @@ - * UBI reserves one LEB for the "atomic LEB change" operation, so only one - * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. - */ --int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype) -+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype) - { -- int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id); -- struct ubi_volume *vol = ubi->volumes[idx]; -+ int err, pnum, tries = 0, vol_id = vol->vol_id; - struct ubi_vid_hdr *vid_hdr; - uint32_t crc; - - if (ubi->ro_mode) - return -EROFS; - -+ if (len == 0) { -+ /* -+ * Special case when data length is zero. In this case the LEB -+ * has to be unmapped and mapped somewhere else. -+ */ -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); -+ if (err) -+ return err; -+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); -+ } -+ - vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); - if (!vid_hdr) - return -ENOMEM; -@@ -928,20 +956,6 @@ - } - - /** -- * ltree_entry_ctor - lock tree entries slab cache constructor. -- * @obj: the lock-tree entry to construct -- * @cache: the lock tree entry slab cache -- * @flags: constructor flags -- */ --static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) --{ -- struct ltree_entry *le = obj; -- -- le->users = 0; -- init_rwsem(&le->mutex); --} -- --/** - * ubi_eba_copy_leb - copy logical eraseblock. - * @ubi: UBI device description object - * @from: physical eraseblock number from where to copy -@@ -950,14 +964,16 @@ - * - * This function copies logical eraseblock from physical eraseblock @from to - * physical eraseblock @to. The @vid_hdr buffer may be changed by this -- * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation -- * was canceled because bit-flips were detected at the target PEB, and a -- * negative error code in case of failure. -+ * function. Returns: -+ * o %0 in case of success; -+ * o %1 if the operation was canceled and should be tried later (e.g., -+ * because a bit-flip was detected at the target PEB); -+ * o %2 if the volume is being deleted and this LEB should not be moved. - */ - int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr) - { -- int err, vol_id, lnum, data_size, aldata_size, pnum, idx; -+ int err, vol_id, lnum, data_size, aldata_size, idx; - struct ubi_volume *vol; - uint32_t crc; - -@@ -973,51 +989,67 @@ - data_size = aldata_size = - ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); - -- /* -- * We do not want anybody to write to this logical eraseblock while we -- * are moving it, so we lock it. -- */ -- err = leb_write_lock(ubi, vol_id, lnum); -- if (err) -- return err; -- -- mutex_lock(&ubi->buf_mutex); -- -- /* -- * But the logical eraseblock might have been put by this time. -- * Cancel if it is true. -- */ - idx = vol_id2idx(ubi, vol_id); -- -+ spin_lock(&ubi->volumes_lock); - /* -- * We may race with volume deletion/re-size, so we have to hold -- * @ubi->volumes_lock. -+ * Note, we may race with volume deletion, which means that the volume -+ * this logical eraseblock belongs to might be being deleted. Since the -+ * volume deletion unmaps all the volume's logical eraseblocks, it will -+ * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. - */ -- spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[idx]; - if (!vol) { -- dbg_eba("volume %d was removed meanwhile", vol_id); -+ /* No need to do further work, cancel */ -+ dbg_eba("volume %d is being removed, cancel", vol_id); - spin_unlock(&ubi->volumes_lock); -- goto out_unlock; -+ return 2; - } -+ spin_unlock(&ubi->volumes_lock); - -- pnum = vol->eba_tbl[lnum]; -- if (pnum != from) { -- dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " -- "PEB %d, cancel", vol_id, lnum, from, pnum); -- spin_unlock(&ubi->volumes_lock); -- goto out_unlock; -+ /* -+ * We do not want anybody to write to this logical eraseblock while we -+ * are moving it, so lock it. -+ * -+ * Note, we are using non-waiting locking here, because we cannot sleep -+ * on the LEB, since it may cause deadlocks. Indeed, imagine a task is -+ * unmapping the LEB which is mapped to the PEB we are going to move -+ * (@from). This task locks the LEB and goes sleep in the -+ * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are -+ * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the -+ * LEB is already locked, we just do not move it and return %1. -+ */ -+ err = leb_write_trylock(ubi, vol_id, lnum); -+ if (err) { -+ dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); -+ return err; - } -- spin_unlock(&ubi->volumes_lock); - -- /* OK, now the LEB is locked and we can safely start moving it */ -+ /* -+ * The LEB might have been put meanwhile, and the task which put it is -+ * probably waiting on @ubi->move_mutex. No need to continue the work, -+ * cancel it. -+ */ -+ if (vol->eba_tbl[lnum] != from) { -+ dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " -+ "PEB %d, cancel", vol_id, lnum, from, -+ vol->eba_tbl[lnum]); -+ err = 1; -+ goto out_unlock_leb; -+ } - -+ /* -+ * OK, now the LEB is locked and we can safely start moving iy. Since -+ * this function utilizes thie @ubi->peb1_buf buffer which is shared -+ * with some other functions, so lock the buffer by taking the -+ * @ubi->buf_mutex. -+ */ -+ mutex_lock(&ubi->buf_mutex); - dbg_eba("read %d bytes of data", aldata_size); - err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); - if (err && err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data from PEB %d", - err, from); -- goto out_unlock; -+ goto out_unlock_buf; - } - - /* -@@ -1053,7 +1085,7 @@ - - err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); - if (err) -- goto out_unlock; -+ goto out_unlock_buf; - - cond_resched(); - -@@ -1062,13 +1094,15 @@ - if (err) { - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read VID header back from PEB %d", to); -- goto out_unlock; -+ else -+ err = 1; -+ goto out_unlock_buf; - } - - if (data_size > 0) { - err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); - if (err) -- goto out_unlock; -+ goto out_unlock_buf; - - cond_resched(); - -@@ -1082,7 +1116,9 @@ - if (err != UBI_IO_BITFLIPS) - ubi_warn("cannot read data back from PEB %d", - to); -- goto out_unlock; -+ else -+ err = 1; -+ goto out_unlock_buf; - } - - cond_resched(); -@@ -1090,15 +1126,16 @@ - if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { - ubi_warn("read data back from PEB %d - it is different", - to); -- goto out_unlock; -+ goto out_unlock_buf; - } - } - - ubi_assert(vol->eba_tbl[lnum] == from); - vol->eba_tbl[lnum] = to; - --out_unlock: -+out_unlock_buf: - mutex_unlock(&ubi->buf_mutex); -+out_unlock_leb: - leb_write_unlock(ubi, vol_id, lnum); - return err; - } -@@ -1125,14 +1162,6 @@ - mutex_init(&ubi->alc_mutex); - ubi->ltree = RB_ROOT; - -- if (ubi_devices_cnt == 0) { -- ltree_slab = kmem_cache_create("ubi_ltree_slab", -- sizeof(struct ltree_entry), 0, -- 0, <ree_entry_ctor); -- if (!ltree_slab) -- return -ENOMEM; -- } -- - ubi->global_sqnum = si->max_sqnum + 1; - num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; - -@@ -1168,6 +1197,15 @@ - } - } - -+ if (ubi->avail_pebs < EBA_RESERVED_PEBS) { -+ ubi_err("no enough physical eraseblocks (%d, need %d)", -+ ubi->avail_pebs, EBA_RESERVED_PEBS); -+ err = -ENOSPC; -+ goto out_free; -+ } -+ ubi->avail_pebs -= EBA_RESERVED_PEBS; -+ ubi->rsvd_pebs += EBA_RESERVED_PEBS; -+ - if (ubi->bad_allowed) { - ubi_calculate_reserved(ubi); - -@@ -1184,15 +1222,6 @@ - ubi->rsvd_pebs += ubi->beb_rsvd_pebs; - } - -- if (ubi->avail_pebs < EBA_RESERVED_PEBS) { -- ubi_err("no enough physical eraseblocks (%d, need %d)", -- ubi->avail_pebs, EBA_RESERVED_PEBS); -- err = -ENOSPC; -- goto out_free; -- } -- ubi->avail_pebs -= EBA_RESERVED_PEBS; -- ubi->rsvd_pebs += EBA_RESERVED_PEBS; -- - dbg_eba("EBA unit is initialized"); - return 0; - -@@ -1202,8 +1231,6 @@ - continue; - kfree(ubi->volumes[i]->eba_tbl); - } -- if (ubi_devices_cnt == 0) -- kmem_cache_destroy(ltree_slab); - return err; - } - -@@ -1222,6 +1249,141 @@ - continue; - kfree(ubi->volumes[i]->eba_tbl); - } -- if (ubi_devices_cnt == 1) -- kmem_cache_destroy(ltree_slab); - } -+ -+/* add by Nancy begin */ -+ -+static int ubiblk_fill_writecache(struct ubiblk_dev *ubiblk) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short subpage_shift = 9; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ unsigned short page_shift = ffs(ubi->min_io_size) - 1; -+ unsigned short sectors_in_page_shift = ffs(ubi->min_io_size / 512) - 1; -+ unsigned short page, sector; -+ char page_buf[ubi->min_io_size]; -+ -+ if (!page_buf) -+ return -ENOMEM; -+ -+ for (page = 0; page < ppb; page++) { -+ if ( !ubiblk->page_sts[page]) { -+ ubi_leb_read(uv, ubiblk->vbw, -+ &ubiblk->write_cache[page<min_io_size, 0); -+ }else{ -+ for(sector = 0; sector < spp; sector++) -+ if( !ubiblk->subpage_sts[(page<vbw, -+ page_buf, -+ page<min_io_size, 0); -+ for(sector = 0; sector < spp; sector++) -+ if(!ubiblk->subpage_sts[(page<write_cache[ \ -+ (page<vol_id; -+ struct ubi_vid_hdr *vid_hdr; -+ uint32_t crc; -+ -+ if (ubi->ro_mode) -+ return -EROFS; -+ -+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); -+ if (!vid_hdr) -+ return -ENOMEM; -+ -+ ubiblk_fill_writecache(ubiblk); -+ mutex_lock(&ubi->alc_mutex); -+ err = leb_write_lock(ubi, vol_id, lnum); -+ if (err) -+ goto out_mutex; -+ -+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); -+ vid_hdr->vol_id = cpu_to_be32(vol_id); -+ vid_hdr->lnum = cpu_to_be32(lnum); -+ vid_hdr->compat = ubi_get_compat(ubi, vol_id); -+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad); -+ -+ crc = crc32(UBI_CRC32_INIT, buf, len); -+ vid_hdr->vol_type = UBI_VID_DYNAMIC; -+ vid_hdr->data_size = cpu_to_be32(len); -+ vid_hdr->copy_flag = 1; -+ vid_hdr->data_crc = cpu_to_be32(crc); -+ -+retry: -+ pnum = ubi_wl_get_peb(ubi, dtype); -+ if (pnum < 0) { -+ err = pnum; -+ goto out_leb_unlock; -+ } -+ -+ dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", -+ vol_id, lnum, vol->eba_tbl[lnum], pnum); -+ -+ err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); -+ if (err) { -+ ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", -+ vol_id, lnum, pnum); -+ goto write_error; -+ } -+ -+ err = ubi_io_write_data(ubi, buf, pnum, 0, len); -+ if (err) { -+ ubi_warn("failed to write %d bytes of data to PEB %d", -+ len, pnum); -+ goto write_error; -+ } -+ if (vol->eba_tbl[lnum] >= 0) { -+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0); -+ if (err) -+ goto out_leb_unlock; -+ } -+ -+ vol->eba_tbl[lnum] = pnum; -+ -+out_leb_unlock: -+ leb_write_unlock(ubi, vol_id, lnum); -+out_mutex: -+ mutex_unlock(&ubi->alc_mutex); -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ return err; -+ -+write_error: -+ if (err != -EIO || !ubi->bad_allowed) { -+ /* -+ * This flash device does not admit of bad eraseblocks or -+ * something nasty and unexpected happened. Switch to read-only -+ * mode just in case. -+ */ -+ ubi_ro_mode(ubi); -+ goto out_leb_unlock; -+ } -+ -+ err = ubi_wl_put_peb(ubi, pnum, 1); -+ if (err || ++tries > UBI_IO_RETRIES) { -+ ubi_ro_mode(ubi); -+ goto out_leb_unlock; -+ } -+ -+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); -+ ubi_msg("try another PEB"); -+ goto retry; -+} -+ -+/* add by Nancy end*/ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/gluebi.c linux-2.6.24.7/drivers/mtd/ubi/gluebi.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/gluebi.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/gluebi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -103,15 +103,15 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, unsigned char *buf) -+static int gluebi_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t *retlen, unsigned char *buf) - { - int err = 0, lnum, offs, total_read; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = from; - -- dbg_msg("read %zd bytes from offset %lld", len, from); -+ dbg_msg("read %lld bytes from offset %lld", len, from); - - if (len < 0 || from < 0 || from + len > mtd->size) - return -EINVAL; -@@ -129,8 +129,7 @@ - if (to_read > total_read) - to_read = total_read; - -- err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs, -- to_read, 0); -+ err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); - if (err) - break; - -@@ -155,15 +154,15 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const u_char *buf) -+static int gluebi_write(struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, -+ size_mtd_t *retlen, const u_char *buf) - { - int err = 0, lnum, offs, total_written; - struct ubi_volume *vol; - struct ubi_device *ubi; - uint64_t tmp = to; - -- dbg_msg("write %zd bytes to offset %lld", len, to); -+ dbg_msg("write %lld bytes to offset %lld", len, to); - - if (len < 0 || to < 0 || len + to > mtd->size) - return -EINVAL; -@@ -177,7 +176,7 @@ - offs = do_div(tmp, mtd->erasesize); - lnum = tmp; - -- if (len % mtd->writesize || offs % mtd->writesize) -+ if ((u32)len % mtd->writesize || offs % mtd->writesize) - return -EINVAL; - - total_written = len; -@@ -187,8 +186,8 @@ - if (to_write > total_written) - to_write = total_written; - -- err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs, -- to_write, UBI_UNKNOWN); -+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, -+ UBI_UNKNOWN); - if (err) - break; - -@@ -216,7 +215,7 @@ - struct ubi_volume *vol; - struct ubi_device *ubi; - -- dbg_msg("erase %u bytes at offset %u", instr->len, instr->addr); -+ dbg_msg("erase %llu bytes at offset %llu", instr->len, instr->addr); - - if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) - return -EINVAL; -@@ -224,11 +223,11 @@ - if (instr->len < 0 || instr->addr + instr->len > mtd->size) - return -EINVAL; - -- if (instr->addr % mtd->writesize || instr->len % mtd->writesize) -+ if ((u32)instr->addr % mtd->writesize || (u32)instr->len % mtd->writesize) - return -EINVAL; - -- lnum = instr->addr / mtd->erasesize; -- count = instr->len / mtd->erasesize; -+ lnum = instr->addr >> (ffs(mtd->erasesize)-1); -+ count = instr->len >> (ffs(mtd->erasesize)-1); - - vol = container_of(mtd, struct ubi_volume, gluebi_mtd); - ubi = vol->ubi; -@@ -237,7 +236,7 @@ - return -EROFS; - - for (i = 0; i < count; i++) { -- err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum + i); - if (err) - goto out_err; - } -@@ -292,11 +291,12 @@ - /* - * In case of dynamic volume, MTD device size is just volume size. In - * case of a static volume the size is equivalent to the amount of data -- * bytes, which is zero at this moment and will be changed after volume -- * update. -+ * bytes. - */ - if (vol->vol_type == UBI_DYNAMIC_VOLUME) - mtd->size = vol->usable_leb_size * vol->reserved_pebs; -+ else -+ mtd->size = vol->used_bytes; - - if (add_mtd_device(mtd)) { - ubi_err("cannot not add MTD device\n"); -@@ -304,7 +304,7 @@ - return -ENFILE; - } - -- dbg_msg("added mtd%d (\"%s\"), size %u, EB size %u", -+ dbg_msg("added mtd%d (\"%s\"), size %llu, EB size %u", - mtd->index, mtd->name, mtd->size, mtd->erasesize); - return 0; - } -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/io.c linux-2.6.24.7/drivers/mtd/ubi/io.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/io.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/io.c 2009-04-12 18:13:57.000000000 +0200 -@@ -135,8 +135,8 @@ - int len) - { - int err, retries = 0; -- size_t read; -- loff_t addr; -+ size_mtd_t read; -+ loff_mtd_t addr; - - dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset); - -@@ -148,7 +148,7 @@ - if (err) - return err > 0 ? -EINVAL : err; - -- addr = (loff_t)pnum * ubi->peb_size + offset; -+ addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - retry: - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err) { -@@ -164,15 +164,25 @@ - - if (read != len && retries++ < UBI_IO_RETRIES) { - dbg_io("error %d while reading %d bytes from PEB %d:%d, " -- "read only %zd bytes, retry", -+ "read only %lld bytes, retry", - err, len, pnum, offset, read); - yield(); - goto retry; - } - - ubi_err("error %d while reading %d bytes from PEB %d:%d, " -- "read %zd bytes", err, len, pnum, offset, read); -+ "read %lld bytes", err, len, pnum, offset, read); - ubi_dbg_dump_stack(); -+ -+ /* -+ * The driver should never return -EBADMSG if it failed to read -+ * all the requested data. But some buggy drivers might do -+ * this, so we change it to -EIO. -+ */ -+ if (read != len && err == -EBADMSG) { -+ ubi_assert(0); -+ err = -EIO; -+ } - } else { - ubi_assert(len == read); - -@@ -206,8 +216,8 @@ - int len) - { - int err; -- size_t written; -- loff_t addr; -+ size_mtd_t written; -+ loff_mtd_t addr; - - dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset); - -@@ -252,11 +262,11 @@ - return -EIO; - } - -- addr = (loff_t)pnum * ubi->peb_size + offset; -+ addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); - if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written" -- " %zd bytes", err, len, pnum, offset, written); -+ " %lld bytes", err, len, pnum, offset, written); - ubi_dbg_dump_stack(); - } else - ubi_assert(written == len); -@@ -298,7 +308,7 @@ - memset(&ei, 0, sizeof(struct erase_info)); - - ei.mtd = ubi->mtd; -- ei.addr = (loff_t)pnum * ubi->peb_size; -+ ei.addr = (loff_mtd_t)pnum * ubi->peb_size; - ei.len = ubi->peb_size; - ei.callback = erase_callback; - ei.priv = (unsigned long)&wq; -@@ -501,7 +511,7 @@ - if (ubi->bad_allowed) { - int ret; - -- ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); -+ ret = mtd->block_isbad(mtd, (loff_mtd_t)pnum * ubi->peb_size); - if (ret < 0) - ubi_err("error %d while checking if PEB %d is bad", - ret, pnum); -@@ -536,7 +546,7 @@ - if (!ubi->bad_allowed) - return 0; - -- err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); -+ err = mtd->block_markbad(mtd, (loff_mtd_t)pnum * ubi->peb_size); - if (err) - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); - return err; -@@ -621,6 +631,8 @@ - - dbg_io("read EC header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); -+ if (UBI_IO_DEBUG) -+ verbose = 1; - - err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err) { -@@ -894,6 +906,8 @@ - - dbg_io("read VID header from PEB %d", pnum); - ubi_assert(pnum >= 0 && pnum < ubi->peb_count); -+ if (UBI_IO_DEBUG) -+ verbose = 1; - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, -@@ -1218,15 +1232,15 @@ - static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, - int len) - { -- size_t read; -+ size_mtd_t read; - int err; -- loff_t addr = (loff_t)pnum * ubi->peb_size + offset; -+ loff_mtd_t addr = (loff_mtd_t)pnum * ubi->peb_size + offset; - - mutex_lock(&ubi->dbg_buf_mutex); - err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); - if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, " -- "read %zd bytes", err, len, pnum, offset, read); -+ "read %lld bytes", err, len, pnum, offset, read); - goto error; - } - -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/kapi.c linux-2.6.24.7/drivers/mtd/ubi/kapi.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/kapi.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/kapi.c 2009-04-12 18:13:57.000000000 +0200 -@@ -24,29 +24,36 @@ - #include - #include - #include "ubi.h" -+#include "ubiblk.h" - -+extern int ubiblk_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, void *buf, int len, int dtype, struct ubiblk_dev *ubiblk); - /** - * ubi_get_device_info - get information about UBI device. - * @ubi_num: UBI device number - * @di: the information is stored here - * -- * This function returns %0 in case of success and a %-ENODEV if there is no -- * such UBI device. -+ * This function returns %0 in case of success, %-EINVAL if the UBI device -+ * number is invalid, and %-ENODEV if there is no such UBI device. - */ - int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) - { -- const struct ubi_device *ubi; -+ struct ubi_device *ubi; -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return -EINVAL; - -- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || -- !ubi_devices[ubi_num]) -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) - return -ENODEV; - -- ubi = ubi_devices[ubi_num]; - di->ubi_num = ubi->ubi_num; - di->leb_size = ubi->leb_size; - di->min_io_size = ubi->min_io_size; - di->ro_mode = ubi->ro_mode; -- di->cdev = MKDEV(ubi->major, 0); -+ di->cdev = ubi->cdev.dev; -+ -+ ubi_put_device(ubi); - return 0; - } - EXPORT_SYMBOL_GPL(ubi_get_device_info); -@@ -73,7 +80,7 @@ - vi->usable_leb_size = vol->usable_leb_size; - vi->name_len = vol->name_len; - vi->name = vol->name; -- vi->cdev = MKDEV(ubi->major, vi->vol_id + 1); -+ vi->cdev = vol->cdev.dev; - } - EXPORT_SYMBOL_GPL(ubi_get_volume_info); - -@@ -104,37 +111,39 @@ - - dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); - -- err = -ENODEV; -- if (ubi_num < 0) -- return ERR_PTR(err); -- -- ubi = ubi_devices[ubi_num]; -- -- if (!try_module_get(THIS_MODULE)) -- return ERR_PTR(err); -- -- if (ubi_num >= UBI_MAX_DEVICES || !ubi) -- goto out_put; -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return ERR_PTR(-EINVAL); - -- err = -EINVAL; -- if (vol_id < 0 || vol_id >= ubi->vtbl_slots) -- goto out_put; - if (mode != UBI_READONLY && mode != UBI_READWRITE && - mode != UBI_EXCLUSIVE) -- goto out_put; -+ return ERR_PTR(-EINVAL); -+ -+ /* -+ * First of all, we have to get the UBI device to prevent its removal. -+ */ -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return ERR_PTR(-ENODEV); -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { -+ err = -EINVAL; -+ goto out_put_ubi; -+ } - - desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); - if (!desc) { - err = -ENOMEM; -- goto out_put; -+ goto out_put_ubi; - } - -+ err = -ENODEV; -+ if (!try_module_get(THIS_MODULE)) -+ goto out_free; -+ - spin_lock(&ubi->volumes_lock); - vol = ubi->volumes[vol_id]; -- if (!vol) { -- err = -ENODEV; -+ if (!vol) - goto out_unlock; -- } - - err = -EBUSY; - switch (mode) { -@@ -156,21 +165,19 @@ - vol->exclusive = 1; - break; - } -+ get_device(&vol->dev); -+ vol->ref_count += 1; - spin_unlock(&ubi->volumes_lock); - - desc->vol = vol; - desc->mode = mode; - -- /* -- * To prevent simultaneous checks of the same volume we use @vtbl_mutex, -- * although it is not the purpose it was introduced for. -- */ -- mutex_lock(&ubi->vtbl_mutex); -+ mutex_lock(&ubi->ckvol_mutex); - if (!vol->checked) { - /* This is the first open - check the volume */ - err = ubi_check_volume(ubi, vol_id); - if (err < 0) { -- mutex_unlock(&ubi->vtbl_mutex); -+ mutex_unlock(&ubi->ckvol_mutex); - ubi_close_volume(desc); - return ERR_PTR(err); - } -@@ -181,14 +188,17 @@ - } - vol->checked = 1; - } -- mutex_unlock(&ubi->vtbl_mutex); -+ mutex_unlock(&ubi->ckvol_mutex); -+ - return desc; - - out_unlock: - spin_unlock(&ubi->volumes_lock); -- kfree(desc); --out_put: - module_put(THIS_MODULE); -+out_free: -+ kfree(desc); -+out_put_ubi: -+ ubi_put_device(ubi); - return ERR_PTR(err); - } - EXPORT_SYMBOL_GPL(ubi_open_volume); -@@ -205,8 +215,8 @@ - int mode) - { - int i, vol_id = -1, len; -- struct ubi_volume_desc *ret; - struct ubi_device *ubi; -+ struct ubi_volume_desc *ret; - - dbg_msg("open volume %s, mode %d", name, mode); - -@@ -217,14 +227,12 @@ - if (len > UBI_VOL_NAME_MAX) - return ERR_PTR(-EINVAL); - -- ret = ERR_PTR(-ENODEV); -- if (!try_module_get(THIS_MODULE)) -- return ret; -- -- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num]) -- goto out_put; -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return ERR_PTR(-EINVAL); - -- ubi = ubi_devices[ubi_num]; -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return ERR_PTR(-ENODEV); - - spin_lock(&ubi->volumes_lock); - /* Walk all volumes of this UBI device */ -@@ -238,13 +246,16 @@ - } - spin_unlock(&ubi->volumes_lock); - -- if (vol_id < 0) -- goto out_put; -- -- ret = ubi_open_volume(ubi_num, vol_id, mode); -+ if (vol_id >= 0) -+ ret = ubi_open_volume(ubi_num, vol_id, mode); -+ else -+ ret = ERR_PTR(-ENODEV); - --out_put: -- module_put(THIS_MODULE); -+ /* -+ * We should put the UBI device even in case of success, because -+ * 'ubi_open_volume()' took a reference as well. -+ */ -+ ubi_put_device(ubi); - return ret; - } - EXPORT_SYMBOL_GPL(ubi_open_volume_nm); -@@ -256,10 +267,11 @@ - void ubi_close_volume(struct ubi_volume_desc *desc) - { - struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; - - dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); - -- spin_lock(&vol->ubi->volumes_lock); -+ spin_lock(&ubi->volumes_lock); - switch (desc->mode) { - case UBI_READONLY: - vol->readers -= 1; -@@ -270,9 +282,12 @@ - case UBI_EXCLUSIVE: - vol->exclusive = 0; - } -- spin_unlock(&vol->ubi->volumes_lock); -+ vol->ref_count -= 1; -+ spin_unlock(&ubi->volumes_lock); - - kfree(desc); -+ put_device(&vol->dev); -+ ubi_put_device(ubi); - module_put(THIS_MODULE); - } - EXPORT_SYMBOL_GPL(ubi_close_volume); -@@ -332,7 +347,7 @@ - if (len == 0) - return 0; - -- err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check); -+ err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { - ubi_warn("mark volume %d as corrupted", vol_id); - vol->corrupted = 1; -@@ -399,7 +414,7 @@ - if (len == 0) - return 0; - -- return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype); -+ return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype); - } - EXPORT_SYMBOL_GPL(ubi_leb_write); - -@@ -448,7 +463,7 @@ - if (len == 0) - return 0; - -- return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype); -+ return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype); - } - EXPORT_SYMBOL_GPL(ubi_leb_change); - -@@ -468,9 +483,9 @@ - { - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int err, vol_id = vol->vol_id; -+ int err; - -- dbg_msg("erase LEB %d:%d", vol_id, lnum); -+ dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -481,7 +496,7 @@ - if (vol->upd_marker) - return -EBADF; - -- err = ubi_eba_unmap_leb(ubi, vol_id, lnum); -+ err = ubi_eba_unmap_leb(ubi, vol, lnum); - if (err) - return err; - -@@ -529,9 +544,8 @@ - { - struct ubi_volume *vol = desc->vol; - struct ubi_device *ubi = vol->ubi; -- int vol_id = vol->vol_id; - -- dbg_msg("unmap LEB %d:%d", vol_id, lnum); -+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); - - if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) - return -EROFS; -@@ -542,11 +556,55 @@ - if (vol->upd_marker) - return -EBADF; - -- return ubi_eba_unmap_leb(ubi, vol_id, lnum); -+ return ubi_eba_unmap_leb(ubi, vol, lnum); - } - EXPORT_SYMBOL_GPL(ubi_leb_unmap); - - /** -+ * ubi_leb_map - map logical erasblock to a physical eraseblock. -+ * @desc: volume descriptor -+ * @lnum: logical eraseblock number -+ * @dtype: expected data type -+ * -+ * This function maps an un-mapped logical eraseblock @lnum to a physical -+ * eraseblock. This means, that after a successfull invocation of this -+ * function the logical eraseblock @lnum will be empty (contain only %0xFF -+ * bytes) and be mapped to a physical eraseblock, even if an unclean reboot -+ * happens. -+ * -+ * This function returns zero in case of success, %-EBADF if the volume is -+ * damaged because of an interrupted update, %-EBADMSG if the logical -+ * eraseblock is already mapped, and other negative error codes in case of -+ * other failures. -+ */ -+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) -+{ -+ struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; -+ -+ dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); -+ -+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) -+ return -EROFS; -+ -+ if (lnum < 0 || lnum >= vol->reserved_pebs) -+ return -EINVAL; -+ -+ if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && -+ dtype != UBI_UNKNOWN) -+ return -EINVAL; -+ -+ if (vol->upd_marker) -+ return -EBADF; -+ -+ if (vol->eba_tbl[lnum] >= 0) -+ return -EBADMSG; -+ -+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); -+} -+EXPORT_SYMBOL_GPL(ubi_leb_map); -+ -+/** - * ubi_is_mapped - check if logical eraseblock is mapped. - * @desc: volume descriptor - * @lnum: logical eraseblock number -@@ -577,3 +635,138 @@ - return vol->eba_tbl[lnum] >= 0; - } - EXPORT_SYMBOL_GPL(ubi_is_mapped); -+ -+/* add by Nancy start */ -+ -+int ubiblk_leb_change(struct ubiblk_dev *ubiblk) -+{ -+ struct ubi_volume *vol = ubiblk->uv->vol; -+ struct ubi_device *ubi = vol->ubi; -+ int vol_id = vol->vol_id; -+ -+ struct ubi_volume_desc *desc = ubiblk->uv; -+ int lnum = ubiblk->vbw; -+ int len = ubi->leb_size; -+ int dtype = UBI_UNKNOWN; -+ void *buf = ubiblk->write_cache; -+ -+ dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum); -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) -+ return -EINVAL; -+ -+ if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) -+ return -EROFS; -+ -+ if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || -+ len > vol->usable_leb_size || len % ubi->min_io_size) -+ return -EINVAL; -+ -+ if (vol->upd_marker) -+ return -EBADF; -+ -+ if (len == 0) -+ return 0; -+ -+ return ubiblk_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype, ubiblk); -+} -+EXPORT_SYMBOL_GPL(ubiblk_leb_change); -+ -+ -+void ubi_open_blkdev(int ubi_num, int vol_id, int mode) -+{ -+ int err; -+ struct ubi_device *ubi; -+ struct ubi_volume *vol; -+ -+ dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); -+ -+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) -+ return; -+ -+ if (mode != UBI_READONLY && mode != UBI_READWRITE && -+ mode != UBI_EXCLUSIVE) -+ return; -+ /* -+ * First of all, we have to get the UBI device to prevent its removal. -+ */ -+ ubi = ubi_get_device(ubi_num); -+ if (!ubi) -+ return; -+ -+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { -+ err = -EINVAL; -+ goto out_put_ubi; -+ } -+ -+ err = -ENODEV; -+ if (!try_module_get(THIS_MODULE)) -+ goto out_put_ubi; -+ -+ spin_lock(&ubi->volumes_lock); -+ vol = ubi->volumes[vol_id]; -+ if (!vol) -+ goto out_unlock; -+ -+ err = -EBUSY; -+ switch (mode) { -+ case UBI_READONLY: -+ if (vol->exclusive) -+ goto out_unlock; -+ vol->readers += 1; -+ break; -+ -+ case UBI_READWRITE: -+ if (vol->exclusive || vol->writers > 0) -+ goto out_unlock; -+ vol->writers += 1; -+ break; -+ -+ case UBI_EXCLUSIVE: -+ if (vol->exclusive || vol->writers || vol->readers) -+ goto out_unlock; -+ vol->exclusive = 1; -+ break; -+ } -+ get_device(&vol->dev); -+ vol->ref_count += 1; -+ spin_unlock(&ubi->volumes_lock); -+ return; -+ -+out_unlock: -+ spin_unlock(&ubi->volumes_lock); -+ module_put(THIS_MODULE); -+out_put_ubi: -+ ubi_put_device(ubi); -+ return; -+} -+EXPORT_SYMBOL_GPL(ubi_open_blkdev); -+ -+ -+void ubi_close_blkdev(struct ubi_volume_desc *desc) -+{ -+ struct ubi_volume *vol = desc->vol; -+ struct ubi_device *ubi = vol->ubi; -+ -+ dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); -+ -+ spin_lock(&ubi->volumes_lock); -+ switch (desc->mode) { -+ case UBI_READONLY: -+ vol->readers -= 1; -+ break; -+ case UBI_READWRITE: -+ vol->writers -= 1; -+ break; -+ case UBI_EXCLUSIVE: -+ vol->exclusive = 0; -+ } -+ vol->ref_count -= 1; -+ spin_unlock(&ubi->volumes_lock); -+ put_device(&vol->dev); -+ ubi_put_device(ubi); -+ module_put(THIS_MODULE); -+} -+EXPORT_SYMBOL_GPL(ubi_close_blkdev); -+/* add by Nancy end */ -+ -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/misc.c linux-2.6.24.7/drivers/mtd/ubi/misc.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/misc.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/misc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -67,7 +67,12 @@ - if (vol->vol_type != UBI_STATIC_VOLUME) - return 0; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(vol->usable_leb_size, GFP_KERNEL); -+#else - buf = vmalloc(vol->usable_leb_size); -+#endif -+ - if (!buf) - return -ENOMEM; - -@@ -79,7 +84,7 @@ - else - size = vol->usable_leb_size; - -- err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1); -+ err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); - if (err) { - if (err == -EBADMSG) - err = 1; -@@ -87,7 +92,11 @@ - } - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif - return err; - } - -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/scan.c linux-2.6.24.7/drivers/mtd/ubi/scan.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/scan.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/scan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -42,6 +42,7 @@ - - #include - #include -+#include - #include "ubi.h" - - #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -@@ -92,27 +93,6 @@ - } - - /** -- * commit_to_mean_value - commit intermediate results to the final mean erase -- * counter value. -- * @si: scanning information -- * -- * This is a helper function which calculates partial mean erase counter mean -- * value and adds it to the resulting mean value. As we can work only in -- * integer arithmetic and we want to calculate the mean value of erase counter -- * accurately, we first sum erase counter values in @si->ec_sum variable and -- * count these components in @si->ec_count. If this temporary @si->ec_sum is -- * going to overflow, we calculate the partial mean value -- * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec. -- */ --static void commit_to_mean_value(struct ubi_scan_info *si) --{ -- si->ec_sum /= si->ec_count; -- if (si->ec_sum % si->ec_count >= si->ec_count / 2) -- si->mean_ec += 1; -- si->mean_ec += si->ec_sum; --} -- --/** - * validate_vid_hdr - check that volume identifier header is correct and - * consistent. - * @vid_hdr: the volume identifier header to check -@@ -286,9 +266,14 @@ - * FIXME: but this is anyway obsolete and will be removed at - * some point. - */ -- - dbg_bld("using old crappy leb_ver stuff"); - -+ if (v1 == v2) { -+ ubi_err("PEB %d and PEB %d have the same version %lld", -+ seb->pnum, pnum, v1); -+ return -EINVAL; -+ } -+ - abs = v1 - v2; - if (abs < 0) - abs = -abs; -@@ -353,7 +338,11 @@ - /* Read the data of the copy and check the CRC */ - - len = be32_to_cpu(vid_hdr->data_size); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(len, GFP_KERNEL); -+#else - buf = vmalloc(len); -+#endif - if (!buf) { - err = -ENOMEM; - goto out_free_vidh; -@@ -376,7 +365,11 @@ - bitflips = !!err; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif - ubi_free_vid_hdr(ubi, vh); - - if (second_is_newer) -@@ -387,10 +380,14 @@ - return second_is_newer | (bitflips << 1) | (corrupted << 2); - - out_free_buf: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else - vfree(buf); -+#endif -+ - out_free_vidh: - ubi_free_vid_hdr(ubi, vh); -- ubi_assert(err < 0); - return err; - } - -@@ -769,7 +766,7 @@ - */ - static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) - { -- long long ec; -+ long long uninitialized_var(ec); - int err, bitflips = 0, vol_id, ec_corr = 0; - - dbg_bld("scan PEB %d", pnum); -@@ -854,7 +851,7 @@ - } - - vol_id = be32_to_cpu(vidh->vol_id); -- if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { -+ if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { - int lnum = be32_to_cpu(vidh->lnum); - - /* Unsupported internal volume */ -@@ -897,15 +894,8 @@ - - adjust_mean_ec: - if (!ec_corr) { -- if (si->ec_sum + ec < ec) { -- commit_to_mean_value(si); -- si->ec_sum = 0; -- si->ec_count = 0; -- } else { -- si->ec_sum += ec; -- si->ec_count += 1; -- } -- -+ si->ec_sum += ec; -+ si->ec_count += 1; - if (ec > si->max_ec) - si->max_ec = ec; - if (ec < si->min_ec) -@@ -961,9 +951,11 @@ - - dbg_msg("scanning is finished"); - -- /* Finish mean erase counter calculations */ -- if (si->ec_count) -- commit_to_mean_value(si); -+ /* Calculate mean erase counter */ -+ if (si->ec_count) { -+ do_div(si->ec_sum, si->ec_count); -+ si->mean_ec = si->ec_sum; -+ } - - if (si->is_empty) - ubi_msg("empty MTD device detected"); -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/scan.h linux-2.6.24.7/drivers/mtd/ubi/scan.h ---- linux-2.6.24.7.old/drivers/mtd/ubi/scan.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/scan.h 2009-04-12 18:13:57.000000000 +0200 -@@ -124,7 +124,7 @@ - int max_ec; - unsigned long long max_sqnum; - int mean_ec; -- int ec_sum; -+ uint64_t ec_sum; - int ec_count; - }; - -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/ubi-media.h linux-2.6.24.7/drivers/mtd/ubi/ubi-media.h ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubi-media.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubi-media.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,372 @@ -+/* -+ * Copyright (c) International Business Machines Corp., 2006 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -+ * the GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Thomas Gleixner -+ * Frank Haverkamp -+ * Oliver Lohmann -+ * Andreas Arnez -+ */ -+ -+/* -+ * This file defines the layout of UBI headers and all the other UBI on-flash -+ * data structures. -+ */ -+ -+#ifndef __UBI_MEDIA_H__ -+#define __UBI_MEDIA_H__ -+ -+#include -+ -+/* The version of UBI images supported by this implementation */ -+#define UBI_VERSION 1 -+ -+/* The highest erase counter value supported by this implementation */ -+#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF -+ -+/* The initial CRC32 value used when calculating CRC checksums */ -+#define UBI_CRC32_INIT 0xFFFFFFFFU -+ -+/* Erase counter header magic number (ASCII "UBI#") */ -+#define UBI_EC_HDR_MAGIC 0x55424923 -+/* Volume identifier header magic number (ASCII "UBI!") */ -+#define UBI_VID_HDR_MAGIC 0x55424921 -+ -+/* -+ * Volume type constants used in the volume identifier header. -+ * -+ * @UBI_VID_DYNAMIC: dynamic volume -+ * @UBI_VID_STATIC: static volume -+ */ -+enum { -+ UBI_VID_DYNAMIC = 1, -+ UBI_VID_STATIC = 2 -+}; -+ -+/* -+ * Volume flags used in the volume table record. -+ * -+ * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume -+ * -+ * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume -+ * table. UBI automatically re-sizes the volume which has this flag and makes -+ * the volume to be of largest possible size. This means that if after the -+ * initialization UBI finds out that there are available physical eraseblocks -+ * present on the device, it automatically appends all of them to the volume -+ * (the physical eraseblocks reserved for bad eraseblocks handling and other -+ * reserved physical eraseblocks are not taken). So, if there is a volume with -+ * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical -+ * eraseblocks will be zero after UBI is loaded, because all of them will be -+ * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared -+ * after the volume had been initialized. -+ * -+ * The auto-resize feature is useful for device production purposes. For -+ * example, different NAND flash chips may have different amount of initial bad -+ * eraseblocks, depending of particular chip instance. Manufacturers of NAND -+ * chips usually guarantee that the amount of initial bad eraseblocks does not -+ * exceed certain percent, e.g. 2%. When one creates an UBI image which will be -+ * flashed to the end devices in production, he does not know the exact amount -+ * of good physical eraseblocks the NAND chip on the device will have, but this -+ * number is required to calculate the volume sized and put them to the volume -+ * table of the UBI image. In this case, one of the volumes (e.g., the one -+ * which will store the root file system) is marked as "auto-resizable", and -+ * UBI will adjust its size on the first boot if needed. -+ * -+ * Note, first UBI reserves some amount of physical eraseblocks for bad -+ * eraseblock handling, and then re-sizes the volume, not vice-versa. This -+ * means that the pool of reserved physical eraseblocks will always be present. -+ */ -+enum { -+ UBI_VTBL_AUTORESIZE_FLG = 0x01, -+}; -+ -+/* -+ * Compatibility constants used by internal volumes. -+ * -+ * @UBI_COMPAT_DELETE: delete this internal volume before anything is written -+ * to the flash -+ * @UBI_COMPAT_RO: attach this device in read-only mode -+ * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its -+ * physical eraseblocks, don't allow the wear-leveling unit to move them -+ * @UBI_COMPAT_REJECT: reject this UBI image -+ */ -+enum { -+ UBI_COMPAT_DELETE = 1, -+ UBI_COMPAT_RO = 2, -+ UBI_COMPAT_PRESERVE = 4, -+ UBI_COMPAT_REJECT = 5 -+}; -+ -+/* Sizes of UBI headers */ -+#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) -+#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) -+ -+/* Sizes of UBI headers without the ending CRC */ -+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) -+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) -+ -+/** -+ * struct ubi_ec_hdr - UBI erase counter header. -+ * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) -+ * @version: version of UBI implementation which is supposed to accept this -+ * UBI image -+ * @padding1: reserved for future, zeroes -+ * @ec: the erase counter -+ * @vid_hdr_offset: where the VID header starts -+ * @data_offset: where the user data start -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: erase counter header CRC checksum -+ * -+ * The erase counter header takes 64 bytes and has a plenty of unused space for -+ * future usage. The unused fields are zeroed. The @version field is used to -+ * indicate the version of UBI implementation which is supposed to be able to -+ * work with this UBI image. If @version is greater then the current UBI -+ * version, the image is rejected. This may be useful in future if something -+ * is changed radically. This field is duplicated in the volume identifier -+ * header. -+ * -+ * The @vid_hdr_offset and @data_offset fields contain the offset of the the -+ * volume identifier header and user data, relative to the beginning of the -+ * physical eraseblock. These values have to be the same for all physical -+ * eraseblocks. -+ */ -+struct ubi_ec_hdr { -+ __be32 magic; -+ __u8 version; -+ __u8 padding1[3]; -+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */ -+ __be32 vid_hdr_offset; -+ __be32 data_offset; -+ __u8 padding2[36]; -+ __be32 hdr_crc; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_vid_hdr - on-flash UBI volume identifier header. -+ * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) -+ * @version: UBI implementation version which is supposed to accept this UBI -+ * image (%UBI_VERSION) -+ * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) -+ * @copy_flag: if this logical eraseblock was copied from another physical -+ * eraseblock (for wear-leveling reasons) -+ * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, -+ * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) -+ * @vol_id: ID of this volume -+ * @lnum: logical eraseblock number -+ * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be -+ * removed, kept only for not breaking older UBI users) -+ * @data_size: how many bytes of data this logical eraseblock contains -+ * @used_ebs: total number of used logical eraseblocks in this volume -+ * @data_pad: how many bytes at the end of this physical eraseblock are not -+ * used -+ * @data_crc: CRC checksum of the data stored in this logical eraseblock -+ * @padding1: reserved for future, zeroes -+ * @sqnum: sequence number -+ * @padding2: reserved for future, zeroes -+ * @hdr_crc: volume identifier header CRC checksum -+ * -+ * The @sqnum is the value of the global sequence counter at the time when this -+ * VID header was created. The global sequence counter is incremented each time -+ * UBI writes a new VID header to the flash, i.e. when it maps a logical -+ * eraseblock to a new physical eraseblock. The global sequence counter is an -+ * unsigned 64-bit integer and we assume it never overflows. The @sqnum -+ * (sequence number) is used to distinguish between older and newer versions of -+ * logical eraseblocks. -+ * -+ * There are 2 situations when there may be more then one physical eraseblock -+ * corresponding to the same logical eraseblock, i.e., having the same @vol_id -+ * and @lnum values in the volume identifier header. Suppose we have a logical -+ * eraseblock L and it is mapped to the physical eraseblock P. -+ * -+ * 1. Because UBI may erase physical eraseblocks asynchronously, the following -+ * situation is possible: L is asynchronously erased, so P is scheduled for -+ * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, -+ * so P1 is written to, then an unclean reboot happens. Result - there are 2 -+ * physical eraseblocks P and P1 corresponding to the same logical eraseblock -+ * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the -+ * flash. -+ * -+ * 2. From time to time UBI moves logical eraseblocks to other physical -+ * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P -+ * to P1, and an unclean reboot happens before P is physically erased, there -+ * are two physical eraseblocks P and P1 corresponding to L and UBI has to -+ * select one of them when the flash is attached. The @sqnum field says which -+ * PEB is the original (obviously P will have lower @sqnum) and the copy. But -+ * it is not enough to select the physical eraseblock with the higher sequence -+ * number, because the unclean reboot could have happen in the middle of the -+ * copying process, so the data in P is corrupted. It is also not enough to -+ * just select the physical eraseblock with lower sequence number, because the -+ * data there may be old (consider a case if more data was added to P1 after -+ * the copying). Moreover, the unclean reboot may happen when the erasure of P -+ * was just started, so it result in unstable P, which is "mostly" OK, but -+ * still has unstable bits. -+ * -+ * UBI uses the @copy_flag field to indicate that this logical eraseblock is a -+ * copy. UBI also calculates data CRC when the data is moved and stores it at -+ * the @data_crc field of the copy (P1). So when UBI needs to pick one physical -+ * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is -+ * examined. If it is cleared, the situation* is simple and the newer one is -+ * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC -+ * checksum is correct, this physical eraseblock is selected (P1). Otherwise -+ * the older one (P) is selected. -+ * -+ * Note, there is an obsolete @leb_ver field which was used instead of @sqnum -+ * in the past. But it is not used anymore and we keep it in order to be able -+ * to deal with old UBI images. It will be removed at some point. -+ * -+ * There are 2 sorts of volumes in UBI: user volumes and internal volumes. -+ * Internal volumes are not seen from outside and are used for various internal -+ * UBI purposes. In this implementation there is only one internal volume - the -+ * layout volume. Internal volumes are the main mechanism of UBI extensions. -+ * For example, in future one may introduce a journal internal volume. Internal -+ * volumes have their own reserved range of IDs. -+ * -+ * The @compat field is only used for internal volumes and contains the "degree -+ * of their compatibility". It is always zero for user volumes. This field -+ * provides a mechanism to introduce UBI extensions and to be still compatible -+ * with older UBI binaries. For example, if someone introduced a journal in -+ * future, he would probably use %UBI_COMPAT_DELETE compatibility for the -+ * journal volume. And in this case, older UBI binaries, which know nothing -+ * about the journal volume, would just delete this volume and work perfectly -+ * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image -+ * - it just ignores the Ext3fs journal. -+ * -+ * The @data_crc field contains the CRC checksum of the contents of the logical -+ * eraseblock if this is a static volume. In case of dynamic volumes, it does -+ * not contain the CRC checksum as a rule. The only exception is when the -+ * data of the physical eraseblock was moved by the wear-leveling unit, then -+ * the wear-leveling unit calculates the data CRC and stores it in the -+ * @data_crc field. And of course, the @copy_flag is %in this case. -+ * -+ * The @data_size field is used only for static volumes because UBI has to know -+ * how many bytes of data are stored in this eraseblock. For dynamic volumes, -+ * this field usually contains zero. The only exception is when the data of the -+ * physical eraseblock was moved to another physical eraseblock for -+ * wear-leveling reasons. In this case, UBI calculates CRC checksum of the -+ * contents and uses both @data_crc and @data_size fields. In this case, the -+ * @data_size field contains data size. -+ * -+ * The @used_ebs field is used only for static volumes and indicates how many -+ * eraseblocks the data of the volume takes. For dynamic volumes this field is -+ * not used and always contains zero. -+ * -+ * The @data_pad is calculated when volumes are created using the alignment -+ * parameter. So, effectively, the @data_pad field reduces the size of logical -+ * eraseblocks of this volume. This is very handy when one uses block-oriented -+ * software (say, cramfs) on top of the UBI volume. -+ */ -+struct ubi_vid_hdr { -+ __be32 magic; -+ __u8 version; -+ __u8 vol_type; -+ __u8 copy_flag; -+ __u8 compat; -+ __be32 vol_id; -+ __be32 lnum; -+ __be32 leb_ver; /* obsolete, to be removed, don't use */ -+ __be32 data_size; -+ __be32 used_ebs; -+ __be32 data_pad; -+ __be32 data_crc; -+ __u8 padding1[4]; -+ __be64 sqnum; -+ __u8 padding2[12]; -+ __be32 hdr_crc; -+} __attribute__ ((packed)); -+ -+/* Internal UBI volumes count */ -+#define UBI_INT_VOL_COUNT 1 -+ -+/* -+ * Starting ID of internal volumes. There is reserved room for 4096 internal -+ * volumes. -+ */ -+#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) -+ -+/* The layout volume contains the volume table */ -+ -+#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START -+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC -+#define UBI_LAYOUT_VOLUME_ALIGN 1 -+#define UBI_LAYOUT_VOLUME_EBS 2 -+#define UBI_LAYOUT_VOLUME_NAME "layout volume" -+#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT -+ -+/* The maximum number of volumes per one UBI device */ -+#define UBI_MAX_VOLUMES 128 -+ -+/* The maximum volume name length */ -+#define UBI_VOL_NAME_MAX 127 -+ -+/* Size of the volume table record */ -+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) -+ -+/* Size of the volume table record without the ending CRC */ -+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) -+ -+/** -+ * struct ubi_vtbl_record - a record in the volume table. -+ * @reserved_pebs: how many physical eraseblocks are reserved for this volume -+ * @alignment: volume alignment -+ * @data_pad: how many bytes are unused at the end of the each physical -+ * eraseblock to satisfy the requested alignment -+ * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -+ * @upd_marker: if volume update was started but not finished -+ * @name_len: volume name length -+ * @name: the volume name -+ * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) -+ * @padding: reserved, zeroes -+ * @crc: a CRC32 checksum of the record -+ * -+ * The volume table records are stored in the volume table, which is stored in -+ * the layout volume. The layout volume consists of 2 logical eraseblock, each -+ * of which contains a copy of the volume table (i.e., the volume table is -+ * duplicated). The volume table is an array of &struct ubi_vtbl_record -+ * objects indexed by the volume ID. -+ * -+ * If the size of the logical eraseblock is large enough to fit -+ * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES -+ * records. Otherwise, it contains as many records as it can fit (i.e., size of -+ * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). -+ * -+ * The @upd_marker flag is used to implement volume update. It is set to %1 -+ * before update and set to %0 after the update. So if the update operation was -+ * interrupted, UBI knows that the volume is corrupted. -+ * -+ * The @alignment field is specified when the volume is created and cannot be -+ * later changed. It may be useful, for example, when a block-oriented file -+ * system works on top of UBI. The @data_pad field is calculated using the -+ * logical eraseblock size and @alignment. The alignment must be multiple to the -+ * minimal flash I/O unit. If @alignment is 1, all the available space of -+ * the physical eraseblocks is used. -+ * -+ * Empty records contain all zeroes and the CRC checksum of those zeroes. -+ */ -+struct ubi_vtbl_record { -+ __be32 reserved_pebs; -+ __be32 alignment; -+ __be32 data_pad; -+ __u8 vol_type; -+ __u8 upd_marker; -+ __be16 name_len; -+ __u8 name[UBI_VOL_NAME_MAX+1]; -+ __u8 flags; -+ __u8 padding[23]; -+ __be32 crc; -+} __attribute__ ((packed)); -+ -+#endif /* !__UBI_MEDIA_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/ubi.h linux-2.6.24.7/drivers/mtd/ubi/ubi.h ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubi.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -37,10 +37,9 @@ - #include - #include - #include -- --#include - #include - -+#include "ubi-media.h" - #include "scan.h" - #include "debug.h" - -@@ -94,8 +93,43 @@ - UBI_IO_BITFLIPS - }; - --extern int ubi_devices_cnt; --extern struct ubi_device *ubi_devices[]; -+/** -+ * struct ubi_wl_entry - wear-leveling entry. -+ * @rb: link in the corresponding RB-tree -+ * @ec: erase counter -+ * @pnum: physical eraseblock number -+ * -+ * This data structure is used in the WL unit. Each physical eraseblock has a -+ * corresponding &struct wl_entry object which may be kept in different -+ * RB-trees. See WL unit for details. -+ */ -+struct ubi_wl_entry { -+ struct rb_node rb; -+ int ec; -+ int pnum; -+}; -+ -+/** -+ * struct ubi_ltree_entry - an entry in the lock tree. -+ * @rb: links RB-tree nodes -+ * @vol_id: volume ID of the locked logical eraseblock -+ * @lnum: locked logical eraseblock number -+ * @users: how many tasks are using this logical eraseblock or wait for it -+ * @mutex: read/write mutex to implement read/write access serialization to -+ * the (@vol_id, @lnum) logical eraseblock -+ * -+ * This data structure is used in the EBA unit to implement per-LEB locking. -+ * When a logical eraseblock is being locked - corresponding -+ * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree). -+ * See EBA unit for details. -+ */ -+struct ubi_ltree_entry { -+ struct rb_node rb; -+ int vol_id; -+ int lnum; -+ int users; -+ struct rw_semaphore mutex; -+}; - - struct ubi_volume_desc; - -@@ -105,11 +139,10 @@ - * @cdev: character device object to create character device - * @ubi: reference to the UBI device description object - * @vol_id: volume ID -+ * @ref_count: volume reference count - * @readers: number of users holding this volume in read-only mode - * @writers: number of users holding this volume in read-write mode - * @exclusive: whether somebody holds this volume in exclusive mode -- * @removed: if the volume was removed -- * @checked: if this static volume was checked - * - * @reserved_pebs: how many physical eraseblocks are reserved for this volume - * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -@@ -117,21 +150,30 @@ - * @used_ebs: how many logical eraseblocks in this volume contain data - * @last_eb_bytes: how many bytes are stored in the last logical eraseblock - * @used_bytes: how many bytes of data this volume contains -- * @upd_marker: non-zero if the update marker is set for this volume -- * @corrupted: non-zero if the volume is corrupted (static volumes only) - * @alignment: volume alignment - * @data_pad: how many bytes are not used at the end of physical eraseblocks to -- * satisfy the requested alignment -+ * satisfy the requested alignment - * @name_len: volume name length - * @name: volume name - * -- * @updating: whether the volume is being updated - * @upd_ebs: how many eraseblocks are expected to be updated -- * @upd_bytes: how many bytes are expected to be received -- * @upd_received: how many update bytes were already received -- * @upd_buf: update buffer which is used to collect update data -+ * @ch_lnum: LEB number which is being changing by the atomic LEB change -+ * operation -+ * @ch_dtype: data persistency type which is being changing by the atomic LEB -+ * change operation -+ * @upd_bytes: how many bytes are expected to be received for volume update or -+ * atomic LEB change -+ * @upd_received: how many bytes were already received for volume update or -+ * atomic LEB change -+ * @upd_buf: update buffer which is used to collect update data or data for -+ * atomic LEB change - * - * @eba_tbl: EBA table of this volume (LEB->PEB mapping) -+ * @checked: %1 if this static volume was checked -+ * @corrupted: %1 if the volume is corrupted (static volumes only) -+ * @upd_marker: %1 if the update marker is set for this volume -+ * @updating: %1 if the volume is being updated -+ * @changing_leb: %1 if the atomic LEB change ioctl command is in progress - * - * @gluebi_desc: gluebi UBI volume descriptor - * @gluebi_refcount: reference count of the gluebi MTD device -@@ -150,11 +192,10 @@ - struct cdev cdev; - struct ubi_device *ubi; - int vol_id; -+ int ref_count; - int readers; - int writers; - int exclusive; -- int removed; -- int checked; - - int reserved_pebs; - int vol_type; -@@ -162,29 +203,45 @@ - int used_ebs; - int last_eb_bytes; - long long used_bytes; -- int upd_marker; -- int corrupted; - int alignment; - int data_pad; - int name_len; - char name[UBI_VOL_NAME_MAX+1]; - -- int updating; - int upd_ebs; -+ int ch_lnum; -+ int ch_dtype; - long long upd_bytes; - long long upd_received; - void *upd_buf; - - int *eba_tbl; -+ unsigned int checked:1; -+ unsigned int corrupted:1; -+ unsigned int upd_marker:1; -+ unsigned int updating:1; -+ unsigned int changing_leb:1; - - #ifdef CONFIG_MTD_UBI_GLUEBI -- /* Gluebi-related stuff may be compiled out */ -+ /* -+ * Gluebi-related stuff may be compiled out. -+ * TODO: this should not be built into UBI but should be a separate -+ * ubimtd driver which works on top of UBI and emulates MTD devices. -+ */ - struct ubi_volume_desc *gluebi_desc; - int gluebi_refcount; - struct mtd_info gluebi_mtd; - #endif -+ int bdev_mode; //add by Nancy - }; - -+struct vol_notifier { -+ void (*add)(struct ubi_volume *vol); -+ void (*remove)(struct ubi_volume *vol); -+ struct list_head list; -+}; -+ -+ - /** - * struct ubi_volume_desc - descriptor of the UBI volume returned when it is - * opened. -@@ -200,28 +257,31 @@ - - /** - * struct ubi_device - UBI device description structure -- * @dev: class device object to use the the Linux device model -+ * @dev: UBI device object to use the the Linux device model - * @cdev: character device object to create character device - * @ubi_num: UBI device number - * @ubi_name: UBI device name -- * @major: character device major number - * @vol_count: number of volumes in this UBI device - * @volumes: volumes of this UBI device - * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, -- * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers, -- * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and -- * @vol->eba_tbl. -+ * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, -+ * @vol->readers, @vol->writers, @vol->exclusive, -+ * @vol->ref_count, @vol->mapping and @vol->eba_tbl. -+ * @ref_count: count of references on the UBI device - * - * @rsvd_pebs: count of reserved physical eraseblocks - * @avail_pebs: count of available physical eraseblocks - * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB -- * handling -+ * handling - * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling - * -+ * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end -+ * of UBI ititializetion - * @vtbl_slots: how many slots are available in the volume table - * @vtbl_size: size of the volume table in bytes - * @vtbl: in-RAM volume table copy -- * @vtbl_mutex: protects on-flash volume table -+ * @volumes_mutex: protects on-flash volume table and serializes volume -+ * changes, like creation, deletion, update, resize - * - * @max_ec: current highest erase counter value - * @mean_ec: current mean erase counter value -@@ -238,15 +298,15 @@ - * @prot.pnum: protection tree indexed by physical eraseblock numbers - * @prot.aec: protection tree indexed by absolute erase counter value - * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, -- * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works -- * fields -+ * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works -+ * fields -+ * @move_mutex: serializes eraseblock moves - * @wl_scheduled: non-zero if the wear-leveling was scheduled - * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any -- * physical eraseblock -+ * physical eraseblock - * @abs_ec: absolute erase counter - * @move_from: physical eraseblock from where the data is being moved - * @move_to: physical eraseblock where the data is being moved to -- * @move_from_put: if the "from" PEB was put - * @move_to_put: if the "to" PEB was put - * @works: list of pending works - * @works_count: count of pending works -@@ -273,36 +333,39 @@ - * @hdrs_min_io_size - * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset - * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or -- * not -+ * not - * @mtd: MTD device descriptor - * - * @peb_buf1: a buffer of PEB size used for different purposes - * @peb_buf2: another buffer of PEB size used for different purposes - * @buf_mutex: proptects @peb_buf1 and @peb_buf2 -- * @dbg_peb_buf: buffer of PEB size used for debugging -+ * @dbg_peb_buf: buffer of PEB size used for debugging - * @dbg_buf_mutex: proptects @dbg_peb_buf - */ - struct ubi_device { - struct cdev cdev; -+ int bdev_major; //add by Nancy - struct device dev; - int ubi_num; - char ubi_name[sizeof(UBI_NAME_STR)+5]; -- int major; - int vol_count; - struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; - spinlock_t volumes_lock; -+ int ref_count; - - int rsvd_pebs; - int avail_pebs; - int beb_rsvd_pebs; - int beb_rsvd_level; - -+ int autoresize_vol_id; - int vtbl_slots; - int vtbl_size; - struct ubi_vtbl_record *vtbl; -- struct mutex vtbl_mutex; -+ struct mutex volumes_mutex; - - int max_ec; -+ /* TODO: mean_ec is not updated run-time, fix */ - int mean_ec; - - /* EBA unit's stuff */ -@@ -320,12 +383,13 @@ - struct rb_root aec; - } prot; - spinlock_t wl_lock; -+ struct mutex move_mutex; -+ struct rw_semaphore work_sem; - int wl_scheduled; - struct ubi_wl_entry **lookuptbl; - unsigned long long abs_ec; - struct ubi_wl_entry *move_from; - struct ubi_wl_entry *move_to; -- int move_from_put; - int move_to_put; - struct list_head works; - int works_count; -@@ -355,15 +419,19 @@ - void *peb_buf1; - void *peb_buf2; - struct mutex buf_mutex; -+ struct mutex ckvol_mutex; - #ifdef CONFIG_MTD_UBI_DEBUG - void *dbg_peb_buf; - struct mutex dbg_buf_mutex; - #endif - }; - -+extern struct kmem_cache *ubi_wl_entry_slab; -+extern struct file_operations ubi_ctrl_cdev_operations; - extern struct file_operations ubi_cdev_operations; - extern struct file_operations ubi_vol_cdev_operations; - extern struct class *ubi_class; -+extern struct mutex ubi_devices_mutex; - - /* vtbl.c */ - int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, -@@ -374,13 +442,18 @@ - int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); - int ubi_remove_volume(struct ubi_volume_desc *desc); - int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); --int ubi_add_volume(struct ubi_device *ubi, int vol_id); --void ubi_free_volume(struct ubi_device *ubi, int vol_id); -+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); -+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); - - /* upd.c */ --int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes); --int ubi_more_update_data(struct ubi_device *ubi, int vol_id, -+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes); -+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, - const void __user *buf, int count); -+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ const struct ubi_leb_change_req *req); -+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, -+ const void __user *buf, int count); - - /* misc.c */ - int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); -@@ -399,16 +472,17 @@ - #endif - - /* eba.c */ --int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum); --int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int offset, int len, int check); --int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, -+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum); -+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int offset, int len, int check); -+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, - const void *buf, int offset, int len, int dtype); --int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype, -+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype, - int used_ebs); --int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, -- const void *buf, int len, int dtype); -+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ int lnum, const void *buf, int len, int dtype); - int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, - struct ubi_vid_hdr *vid_hdr); - int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); -@@ -421,6 +495,7 @@ - int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); - int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); - void ubi_wl_close(struct ubi_device *ubi); -+int ubi_thread(void *u); - - /* io.c */ - int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, -@@ -438,6 +513,14 @@ - struct ubi_vid_hdr *vid_hdr, int verbose); - int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, - struct ubi_vid_hdr *vid_hdr); -+ -+/* build.c */ -+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); -+int ubi_detach_mtd_dev(int ubi_num, int anyway); -+struct ubi_device *ubi_get_device(int ubi_num); -+void ubi_put_device(struct ubi_device *ubi); -+struct ubi_device *ubi_get_by_major(int major); -+int ubi_major2num(int major); - - /* - * ubi_rb_for_each_entry - walk an RB-tree. -@@ -523,8 +606,10 @@ - */ - static inline void ubi_ro_mode(struct ubi_device *ubi) - { -- ubi->ro_mode = 1; -- ubi_warn("switch to read-only mode"); -+ if (!ubi->ro_mode) { -+ ubi->ro_mode = 1; -+ ubi_warn("switch to read-only mode"); -+ } - } - - /** -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.c linux-2.6.24.7/drivers/mtd/ubi/ubiblk.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubiblk.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,359 @@ -+/* -+ * Direct UBI block device access -+ * -+ * (C) 2000-2003 Nicolas Pitre -+ * (C) 1999-2003 David Woodhouse -+ * (C) 2008 Yurong Tan : -+ * borrow mtdblock.c to work on top of UBI -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubi.h" -+#include "ubiblk.h" -+ -+#define UBIBLK_UNMAPPED 0 -+#define UBIBLK_SECTOR_SIZE 512 -+ -+extern void ubi_open_blkdev(int ubi_num, int vol_id, int mode); -+extern void ubi_close_blkdev(struct ubi_volume_desc *desc); -+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block); -+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk); -+extern int ubiblk_leb_change(struct ubiblk_dev *ubiblk); -+ -+struct ubiblk_dev *ubiblks[UBI_MAX_VOLUMES]; -+static unsigned short subpage_shift; -+ -+static int ubiblk_flush_writecache(struct ubiblk_dev *ubiblk) -+{ -+ if (STATE_UNUSED == ubiblk->write_cache_state) -+ return 0; -+ ubiblk_leb_change(ubiblk); -+ ubiblk->write_cache_state = STATE_UNUSED; -+ -+ return 0; -+} -+ -+static void ubiblk_setup_writecache(struct ubiblk_dev *ubiblk, int virt_block) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ -+ ubiblk->vbw = virt_block; -+ ubiblk->write_cache_state = STATE_USED; -+ -+ memset(ubiblk->page_sts, 0, ppb); -+ memset(ubiblk->subpage_sts, 0, ppb*spp); -+} -+ -+static int do_cached_write (struct ubiblk_dev *ubiblk, unsigned long sector, -+ int len, const char *buf) -+{ -+ struct ubi_volume_desc *uv = ubiblk->uv; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short sectors_per_page = ubi->min_io_size / len; -+ unsigned short sectors_in_page_shift = ffs(sectors_per_page) - 1; -+ unsigned short page_shift = ffs(ubi->min_io_size) - 1; -+ unsigned short virt_block, page, subpage; -+ unsigned long virt_page; -+ -+ virt_page = sector / sectors_per_page; -+ subpage = sector % sectors_per_page; -+ virt_block = virt_page / ppb; -+ page = virt_page % ppb; -+ -+ if(ubi_is_mapped(uv, virt_block) == UBIBLK_UNMAPPED ){ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } else { -+ if ( STATE_USED == ubiblk->write_cache_state ) { -+ if ( ubiblk->vbw != virt_block) { -+ // Commit before we start a new cache. -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } else { -+ //printk("cache hit: 0x%x\n", virt_page); -+ } -+ } else { -+// printk("with existing mapping\n"); -+ ubiblk_setup_writecache(ubiblk, virt_block); -+ } -+ } -+ ubiblk->page_sts[page] = 1; -+ ubiblk->subpage_sts[(page<write_cache[(page<uv; -+ int ppb = uv->vol->ubi->leb_size / uv->vol->ubi->min_io_size; -+ unsigned short sectors_per_page = uv->vol->ubi->min_io_size >> 9; -+ unsigned short page_shift = ffs(uv->vol->ubi->min_io_size) - 1; -+ unsigned short virt_block, page, page_offset; -+ unsigned long virt_page; -+ -+ virt_page = sector / sectors_per_page; -+ page_offset = sector % sectors_per_page; -+ virt_block = virt_page / ppb; -+ page = virt_page % ppb; -+ -+ if(ubiblk->vbw == virt_block){ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ } -+ -+ if ( ubi_is_mapped( uv, virt_block) == UBIBLK_UNMAPPED){ -+ /* In a Flash Memory device, there might be a logical block that is -+ * not allcated to a physical block due to the block not being used. -+ * All data returned should be set to 0xFF when accessing this logical -+ * block. -+ */ -+ -+ //printk("address translate fail\n"); -+ memset(buf, 0xFF, UBIBLK_SECTOR_SIZE); -+ } else { -+ -+ if( ubiblk->vbr != virt_block ||ubiblk->read_cache_state == STATE_UNUSED ){ -+ ubiblk->vbr = virt_block; -+ ubi_leb_read(uv, virt_block, ubiblk->read_cache, 0, uv->vol->usable_leb_size, 0); -+ ubiblk->read_cache_state = STATE_USED; -+ } -+ memcpy(buf, &ubiblk->read_cache[(page<devnum]; -+ return do_cached_read(ubiblk, block, UBIBLK_SECTOR_SIZE, buf); -+} -+ -+static int ubiblk_writesect(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buf) -+{ -+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum]; -+ return do_cached_write(ubiblk, block, UBIBLK_SECTOR_SIZE, buf); -+} -+ -+static int ubiblk_init_vol(int dev, struct ubi_volume_desc *uv) -+{ -+ struct ubiblk_dev *ubiblk; -+ struct ubi_device *ubi = uv->vol->ubi; -+ int ppb = ubi->leb_size / ubi->min_io_size; -+ unsigned short spp = ubi->min_io_size >> subpage_shift; -+ -+ ubiblk = kmalloc(sizeof(struct ubiblk_dev), GFP_KERNEL); -+ if (!ubiblk) -+ return -ENOMEM; -+ -+ memset(ubiblk, 0, sizeof(*ubiblk)); -+ -+ ubiblk->count = 1; -+ ubiblk->uv = uv; -+ mutex_init (&ubiblk->cache_mutex); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ ubiblk->write_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL); -+ ubiblk->read_cache = kmalloc(ubiblk->uv->vol->usable_leb_size, GFP_KERNEL); -+ ubiblk->page_sts = kmalloc(ppb, GFP_KERNEL); -+ ubiblk->subpage_sts = kmalloc(ppb*spp, GFP_KERNEL); -+#else -+ ubiblk->write_cache = vmalloc(ubiblk->uv->vol->usable_leb_size); -+ ubiblk->read_cache = vmalloc(ubiblk->uv->vol->usable_leb_size); -+ ubiblk->page_sts = vmalloc(ppb); -+ ubiblk->subpage_sts = vmalloc(ppb*spp); -+#endif -+ -+ if(!ubiblk->write_cache || -+ !ubiblk->read_cache || -+ !ubiblk->page_sts || -+ !ubiblk->subpage_sts) -+ return -ENOMEM; -+ -+ ubiblk->write_cache_state = STATE_UNUSED; -+ ubiblk->read_cache_state = STATE_UNUSED; -+ -+ ubiblks[dev] = ubiblk; -+ DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); -+ return 0; -+} -+ -+static int ubiblk_open(struct inode *i, struct file *f ) -+{ -+ struct ubi_volume_desc *desc; -+ struct ubi_blktrans_dev *dev; -+ int ubi_num = ubi_major2num(imajor(i)); -+ int vol_id = iminor(i); -+ int mode; -+ int ret = 0; -+ -+ if (f->f_mode & FMODE_WRITE) -+ mode = UBI_READWRITE; -+ else -+ mode = UBI_READONLY; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ if (ubiblks[dev->devnum]) { -+ ubiblks[dev->devnum]->count++; -+ ubi_open_blkdev(ubi_num, vol_id, mode); -+ printk("%s: increase use count\n",__FUNCTION__); -+ return 0; -+ } -+ -+ desc = ubi_open_volume(ubi_num, vol_id, mode); -+ if (IS_ERR(desc)) -+ return PTR_ERR(desc); -+ -+ desc->vol->bdev_mode = mode; -+ dev->uv = desc; -+ -+ subpage_shift = ffs(UBIBLK_SECTOR_SIZE)-1; -+ ret = ubiblk_init_vol(dev->devnum, desc); -+ return ret; -+} -+ -+static int ubiblk_release(struct ubi_blktrans_dev *ubd) -+{ -+ int dev = ubd->devnum; -+ struct ubiblk_dev *ubiblk = ubiblks[dev]; -+ struct ubi_device *ubi = ubiblk->uv->vol->ubi; -+ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ ubiblk->count --; -+ if (!ubiblk->count) { -+ /* It was the last usage. Free the device */ -+ ubiblks[dev] = NULL; -+ -+ if (ubi->mtd->sync) -+ ubi->mtd->sync(ubi->mtd); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubiblk->write_cache); -+ kfree(ubiblk->read_cache); -+#else -+ vfree(ubiblk->write_cache); -+ vfree(ubiblk->read_cache); -+#endif -+ kfree(ubiblk); -+ -+ ubi_close_volume(ubiblk->uv); -+ return 0; -+ } -+ else{ -+ printk("%s: decrease use count\n",__FUNCTION__); -+ ubi_close_blkdev(ubiblk->uv); -+ return 0; -+ } -+ return 1; -+} -+static int ubiblk_flush(struct ubi_blktrans_dev *dev) -+{ -+ struct ubiblk_dev *ubiblk = ubiblks[dev->devnum]; -+ struct ubi_device *ubi = ubiblk->uv->vol->ubi; -+ -+ mutex_lock(&ubiblk->cache_mutex); -+ ubiblk_flush_writecache(ubiblk); -+ mutex_unlock(&ubiblk->cache_mutex); -+ -+ if (ubi->mtd->sync) -+ ubi->mtd->sync(ubi->mtd); -+ return 0; -+} -+ -+void ubiblk_add_vol_dev(struct ubi_blktrans_ops *tr, struct ubi_volume *vol) -+{ -+ struct ubi_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return; -+ -+ dev->devnum = vol->vol_id; -+ dev->size = vol->used_bytes >> 9; -+ dev->tr = tr; -+ -+ if (vol->bdev_mode == UBI_READONLY) -+ dev->readonly = 1; -+ -+ vol->ubi->bdev_major = tr->major; -+ -+ add_ubi_blktrans_dev(dev); -+} -+ -+void ubiblk_remove_vol_dev(struct ubi_blktrans_dev *dev) -+{ -+ del_ubi_blktrans_dev(dev); -+ kfree(dev); -+} -+ -+static int ubiblk_getgeo(struct ubi_blktrans_dev *dev, struct hd_geometry *geo) -+{ -+ memset(geo, 0, sizeof(*geo)); -+ geo->heads = 4; -+ geo->sectors = 16; -+ geo->cylinders = dev->size/(4*16); -+ return 0; -+} -+ -+static struct ubi_blktrans_ops ubiblk_tr = { -+ .name = "ubiblock", -+ .major = 0, -+ .part_bits = 0, -+ .blksize = UBIBLK_SECTOR_SIZE, -+ .open = ubiblk_open, -+ .release = ubiblk_release, -+ .readsect = ubiblk_readsect, -+ .writesect = ubiblk_writesect, -+ .getgeo = ubiblk_getgeo, -+ .flush = ubiblk_flush, -+ .add_vol = ubiblk_add_vol_dev, -+ .remove_vol = ubiblk_remove_vol_dev, -+ .owner = THIS_MODULE, -+}; -+ -+static int __init init_ubiblock(void) -+{ -+ return register_ubi_blktrans(&ubiblk_tr); -+} -+ -+static void __exit cleanup_ubiblock(void) -+{ -+ deregister_ubi_blktrans(&ubiblk_tr); -+} -+ -+module_init(init_ubiblock); -+module_exit(cleanup_ubiblock); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Nicolas Pitre , Yurong Tan "); -+MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to UBI volumes"); -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.h linux-2.6.24.7/drivers/mtd/ubi/ubiblk.h ---- linux-2.6.24.7.old/drivers/mtd/ubi/ubiblk.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/ubi/ubiblk.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+/* -+ * (C) 2003 David Woodhouse -+ * (C) 2008 Yurong Tan : borrow from MTD blktrans.h for UBI used -+ * Interface to Linux block layer for UBI 'translation layers'. -+ */ -+ -+#ifndef __UBI_TRANS_H__ -+#define __UBI_TRANS_H__ -+ -+#include -+#include -+#include "ubi.h" -+ -+struct hd_geometry; -+struct ubi_volume_desc; -+struct ubi_blktrans_ops; -+struct file; -+struct inode; -+ -+struct ubiblk_dev { -+ struct ubi_volume_desc *uv; -+ int count; -+ struct mutex cache_mutex; -+ unsigned short vbw; //virt block number of write cache -+ unsigned short vbr; //virt block number of read cache -+ -+ unsigned char *write_cache; -+ unsigned char *page_sts; -+ unsigned char *subpage_sts; -+ -+ unsigned char *read_cache; -+ enum { STATE_UNUSED, STATE_USED } read_cache_state, write_cache_state; -+}; -+ -+struct ubi_blktrans_dev { -+ struct ubi_blktrans_ops *tr; -+ struct list_head list; -+ struct ubi_volume_desc *uv; -+ struct mutex lock; -+ int devnum; -+ unsigned long size; -+ int readonly; -+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ -+}; -+ -+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ -+ -+struct ubi_blktrans_ops { -+ char *name; -+ int major; -+ int part_bits; -+ int blksize; -+ int blkshift; -+ -+ /* Access functions */ -+ int (*readsect)(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ int (*writesect)(struct ubi_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ -+ /* Block layer ioctls */ -+ int (*getgeo)(struct ubi_blktrans_dev *dev, struct hd_geometry *geo); -+ int (*flush)(struct ubi_blktrans_dev *dev); -+ -+ /* Called with mtd_table_mutex held; no race with add/remove */ -+ int (*open)(struct inode *i, struct file *f); -+ int (*release)(struct ubi_blktrans_dev *dev); -+ -+ /* Called on {de,}registration and on subsequent addition/removal -+ of devices, with mtd_table_mutex held. */ -+ void (*add_vol)(struct ubi_blktrans_ops *tr, struct ubi_volume *vol); -+ void (*remove_vol)(struct ubi_blktrans_dev *dev); -+ -+ struct list_head devs; -+ struct list_head list; -+ struct module *owner; -+ -+ struct ubi_blkcore_priv *blkcore_priv; -+}; -+ -+extern int add_ubi_blktrans_dev(struct ubi_blktrans_dev *new); -+extern int del_ubi_blktrans_dev(struct ubi_blktrans_dev *old); -+extern int register_ubi_blktrans(struct ubi_blktrans_ops *tr); -+extern int deregister_ubi_blktrans(struct ubi_blktrans_ops *tr); -+#endif /* __UBI_TRANS_H__ */ -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/upd.c linux-2.6.24.7/drivers/mtd/ubi/upd.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/upd.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/upd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -22,7 +22,8 @@ - */ - - /* -- * This file contains implementation of the volume update functionality. -+ * This file contains implementation of the volume update and atomic LEB change -+ * functionality. - * - * The update operation is based on the per-volume update marker which is - * stored in the volume table. The update marker is set before the update -@@ -45,29 +46,31 @@ - /** - * set_update_marker - set update marker. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function sets the update marker flag for volume @vol_id. Returns zero -+ * This function sets the update marker flag for volume @vol. Returns zero - * in case of success and a negative error code in case of failure. - */ --static int set_update_marker(struct ubi_device *ubi, int vol_id) -+static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) - { - int err; - struct ubi_vtbl_record vtbl_rec; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("set update marker for volume %d", vol_id); -+ dbg_msg("set update marker for volume %d", vol->vol_id); - - if (vol->upd_marker) { -- ubi_assert(ubi->vtbl[vol_id].upd_marker); -+ ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); - dbg_msg("already set"); - return 0; - } - -- memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], -+ sizeof(struct ubi_vtbl_record)); - vtbl_rec.upd_marker = 1; - -- err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ mutex_lock(&ubi->volumes_mutex); -+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); -+ mutex_unlock(&ubi->volumes_mutex); - vol->upd_marker = 1; - return err; - } -@@ -75,23 +78,24 @@ - /** - * clear_update_marker - clear update marker. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @bytes: new data size in bytes - * -- * This function clears the update marker for volume @vol_id, sets new volume -+ * This function clears the update marker for volume @vol, sets new volume - * data size and clears the "corrupted" flag (static volumes only). Returns - * zero in case of success and a negative error code in case of failure. - */ --static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes) -+static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes) - { - int err; - uint64_t tmp; - struct ubi_vtbl_record vtbl_rec; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("clear update marker for volume %d", vol_id); -+ dbg_msg("clear update marker for volume %d", vol->vol_id); - -- memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); -+ memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], -+ sizeof(struct ubi_vtbl_record)); - ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); - vtbl_rec.upd_marker = 0; - -@@ -106,7 +110,9 @@ - vol->last_eb_bytes = vol->usable_leb_size; - } - -- err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); -+ mutex_lock(&ubi->volumes_mutex); -+ err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); -+ mutex_unlock(&ubi->volumes_mutex); - vol->upd_marker = 0; - return err; - } -@@ -114,35 +120,36 @@ - /** - * ubi_start_update - start volume update. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @bytes: update bytes - * - * This function starts volume update operation. If @bytes is zero, the volume - * is just wiped out. Returns zero in case of success and a negative error code - * in case of failure. - */ --int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) -+int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, -+ long long bytes) - { - int i, err; - uint64_t tmp; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes); -+ dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); -+ ubi_assert(!vol->updating && !vol->changing_leb); - vol->updating = 1; - -- err = set_update_marker(ubi, vol_id); -+ err = set_update_marker(ubi, vol); - if (err) - return err; - - /* Before updating - wipe out the volume */ - for (i = 0; i < vol->reserved_pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, i); -+ err = ubi_eba_unmap_leb(ubi, vol, i); - if (err) - return err; - } - - if (bytes == 0) { -- err = clear_update_marker(ubi, vol_id, 0); -+ err = clear_update_marker(ubi, vol, 0); - if (err) - return err; - err = ubi_wl_flush(ubi); -@@ -150,7 +157,11 @@ - vol->updating = 0; - } - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL); -+#else - vol->upd_buf = vmalloc(ubi->leb_size); -+#endif - if (!vol->upd_buf) - return -ENOMEM; - -@@ -163,9 +174,46 @@ - } - - /** -+ * ubi_start_leb_change - start atomic LEB change. -+ * @ubi: UBI device description object -+ * @vol: volume description object -+ * @req: operation request -+ * -+ * This function starts atomic LEB change operation. Returns zero in case of -+ * success and a negative error code in case of failure. -+ */ -+int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, -+ const struct ubi_leb_change_req *req) -+{ -+ ubi_assert(!vol->updating && !vol->changing_leb); -+ -+ dbg_msg("start changing LEB %d:%d, %u bytes", -+ vol->vol_id, req->lnum, req->bytes); -+ if (req->bytes == 0) -+ return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, -+ req->dtype); -+ -+ vol->upd_bytes = req->bytes; -+ vol->upd_received = 0; -+ vol->changing_leb = 1; -+ vol->ch_lnum = req->lnum; -+ vol->ch_dtype = req->dtype; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vol->upd_buf = kmalloc(req->bytes, GFP_KERNEL); -+#else -+ vol->upd_buf = vmalloc(req->bytes); -+#endif -+ if (!vol->upd_buf) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+/** - * write_leb - write update data. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * @lnum: logical eraseblock number - * @buf: data to write - * @len: data size -@@ -191,26 +239,22 @@ - * This function returns zero in case of success and a negative error code in - * case of failure. - */ --static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, -- int len, int used_ebs) -+static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, -+ void *buf, int len, int used_ebs) - { -- int err, l; -- struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err; - - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { -- l = ALIGN(len, ubi->min_io_size); -- memset(buf + len, 0xFF, l - len); -+ len = ALIGN(len, ubi->min_io_size); -+ memset(buf + len, 0xFF, len - len); - -- l = ubi_calc_data_len(ubi, buf, l); -- if (l == 0) { -+ len = ubi_calc_data_len(ubi, buf, len); -+ if (len == 0) { - dbg_msg("all %d bytes contain 0xFF - skip", len); - return 0; - } -- if (len != l) -- dbg_msg("skip last %d bytes (0xFF)", len - l); - -- err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l, -- UBI_UNKNOWN); -+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); - } else { - /* - * When writing static volume, and this is the last logical -@@ -222,7 +266,7 @@ - * contain zeros, not random trash. - */ - memset(buf + len, 0, vol->usable_leb_size - len); -- err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len, -+ err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, - UBI_UNKNOWN, used_ebs); - } - -@@ -236,16 +280,15 @@ - * @count: how much bytes to write - * - * This function writes more data to the volume which is being updated. It may -- * be called arbitrary number of times until all of the update data arrive. -- * This function returns %0 in case of success, number of bytes written during -- * the last call if the whole volume update was successfully finished, and a -+ * be called arbitrary number of times until all the update data arriveis. This -+ * function returns %0 in case of success, number of bytes written during the -+ * last call if the whole volume update has been successfully finished, and a - * negative error code in case of failure. - */ --int ubi_more_update_data(struct ubi_device *ubi, int vol_id, -+int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, - const void __user *buf, int count) - { - uint64_t tmp; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - int lnum, offs, err = 0, len, to_write = count; - - dbg_msg("write %d of %lld bytes, %lld already passed", -@@ -290,8 +333,8 @@ - * is the last chunk, it's time to flush the buffer. - */ - ubi_assert(flush_len <= vol->usable_leb_size); -- err = write_leb(ubi, vol_id, lnum, vol->upd_buf, -- flush_len, vol->upd_ebs); -+ err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len, -+ vol->upd_ebs); - if (err) - return err; - } -@@ -312,37 +355,102 @@ - else - len = count; - -- err = copy_from_user(vol->upd_buf, buf, len); -+ err= copy_from_user(&lnum, buf, sizeof(lnum)); -+ if (err) -+ return -EFAULT; -+ err = copy_from_user(vol->upd_buf, &(((char*)buf)[sizeof(unsigned int)]), len); - if (err) - return -EFAULT; - - if (len == vol->usable_leb_size || - vol->upd_received + len == vol->upd_bytes) { -- err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len, -- vol->upd_ebs); -+ err = write_leb(ubi, vol, lnum, vol->upd_buf, -+ len, vol->upd_ebs); - if (err) - break; - } - - vol->upd_received += len; - count -= len; -- lnum += 1; -+// lnum += 1; - buf += len; - } - - ubi_assert(vol->upd_received <= vol->upd_bytes); - if (vol->upd_received == vol->upd_bytes) { - /* The update is finished, clear the update marker */ -- err = clear_update_marker(ubi, vol_id, vol->upd_bytes); -+ err = clear_update_marker(ubi, vol, vol->upd_bytes); - if (err) - return err; - err = ubi_wl_flush(ubi); - if (err == 0) { -+ vol->updating = 0; - err = to_write; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else - vfree(vol->upd_buf); -- vol->updating = 0; -+#endif - } - } - - return err; - } -+ -+/** -+ * ubi_more_leb_change_data - accept more data for atomic LEB change. -+ * @vol: volume description object -+ * @buf: write data (user-space memory buffer) -+ * @count: how much bytes to write -+ * -+ * This function accepts more data to the volume which is being under the -+ * "atomic LEB change" operation. It may be called arbitrary number of times -+ * until all data arrives. This function returns %0 in case of success, number -+ * of bytes written during the last call if the whole "atomic LEB change" -+ * operation has been successfully finished, and a negative error code in case -+ * of failure. -+ */ -+int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, -+ const void __user *buf, int count) -+{ -+ int err; -+ -+ dbg_msg("write %d of %lld bytes, %lld already passed", -+ count, vol->upd_bytes, vol->upd_received); -+ -+ if (ubi->ro_mode) -+ return -EROFS; -+ -+ if (vol->upd_received + count > vol->upd_bytes) -+ count = vol->upd_bytes - vol->upd_received; -+ -+ err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); -+ if (err) -+ return -EFAULT; -+ -+ vol->upd_received += count; -+ -+ if (vol->upd_received == vol->upd_bytes) { -+ int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); -+ -+ memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); -+ len = ubi_calc_data_len(ubi, vol->upd_buf, len); -+ err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, -+ vol->upd_buf, len, UBI_UNKNOWN); -+ if (err) -+ return err; -+ } -+ -+ ubi_assert(vol->upd_received <= vol->upd_bytes); -+ if (vol->upd_received == vol->upd_bytes) { -+ vol->changing_leb = 0; -+ err = count; -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vol->upd_buf); -+#else -+ vfree(vol->upd_buf); -+#endif -+ } -+ -+ return err; -+} -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/vmt.c linux-2.6.24.7/drivers/mtd/ubi/vmt.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/vmt.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/vmt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -63,21 +63,30 @@ - * B. process 2 removes volume Y; - * C. process 1 starts reading the //class/ubi/ubiX_Y/reserved_ebs file; - * -- * What we want to do in a situation like that is to return error when the file -- * is read. This is done by means of the 'removed' flag and the 'vol_lock' of -- * the UBI volume description object. -+ * In this situation, this function will return %-ENODEV because it will find -+ * out that the volume was removed from the @ubi->volumes array. - */ - static ssize_t vol_attribute_show(struct device *dev, - struct device_attribute *attr, char *buf) - { - int ret; - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); -+ struct ubi_device *ubi; - -- spin_lock(&vol->ubi->volumes_lock); -- if (vol->removed) { -- spin_unlock(&vol->ubi->volumes_lock); -+ ubi = ubi_get_device(vol->ubi->ubi_num); -+ if (!ubi) -+ return -ENODEV; -+ -+ spin_lock(&ubi->volumes_lock); -+ if (!ubi->volumes[vol->vol_id]) { -+ spin_unlock(&ubi->volumes_lock); -+ ubi_put_device(ubi); - return -ENODEV; - } -+ /* Take a reference to prevent volume removal */ -+ vol->ref_count += 1; -+ spin_unlock(&ubi->volumes_lock); -+ - if (attr == &attr_vol_reserved_ebs) - ret = sprintf(buf, "%d\n", vol->reserved_pebs); - else if (attr == &attr_vol_type) { -@@ -94,15 +103,22 @@ - ret = sprintf(buf, "%d\n", vol->corrupted); - else if (attr == &attr_vol_alignment) - ret = sprintf(buf, "%d\n", vol->alignment); -- else if (attr == &attr_vol_usable_eb_size) { -+ else if (attr == &attr_vol_usable_eb_size) - ret = sprintf(buf, "%d\n", vol->usable_leb_size); -- } else if (attr == &attr_vol_data_bytes) -+ else if (attr == &attr_vol_data_bytes) - ret = sprintf(buf, "%lld\n", vol->used_bytes); - else if (attr == &attr_vol_upd_marker) - ret = sprintf(buf, "%d\n", vol->upd_marker); - else -- BUG(); -- spin_unlock(&vol->ubi->volumes_lock); -+ /* This must be a bug */ -+ ret = -EINVAL; -+ -+ /* We've done the operation, drop volume and UBI device references */ -+ spin_lock(&ubi->volumes_lock); -+ vol->ref_count -= 1; -+ ubi_assert(vol->ref_count >= 0); -+ spin_unlock(&ubi->volumes_lock); -+ ubi_put_device(ubi); - return ret; - } - -@@ -110,7 +126,7 @@ - static void vol_release(struct device *dev) - { - struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); -- ubi_assert(vol->removed); -+ - kfree(vol); - } - -@@ -152,9 +168,7 @@ - if (err) - return err; - err = device_create_file(&vol->dev, &attr_vol_upd_marker); -- if (err) -- return err; -- return 0; -+ return err; - } - - /** -@@ -180,16 +194,18 @@ - * @req: volume creation request - * - * This function creates volume described by @req. If @req->vol_id id -- * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume -+ * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume - * and saves it in @req->vol_id. Returns zero in case of success and a negative -- * error code in case of failure. -+ * error code in case of failure. Note, the caller has to have the -+ * @ubi->volumes_mutex locked. - */ - int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) - { -- int i, err, vol_id = req->vol_id; -+ int i, err, vol_id = req->vol_id, dont_free = 0; - struct ubi_volume *vol; - struct ubi_vtbl_record vtbl_rec; - uint64_t bytes; -+ dev_t dev; - - if (ubi->ro_mode) - return -EROFS; -@@ -199,7 +215,6 @@ - return -ENOMEM; - - spin_lock(&ubi->volumes_lock); -- - if (vol_id == UBI_VOL_NUM_AUTO) { - /* Find unused volume ID */ - dbg_msg("search for vacant volume ID"); -@@ -252,6 +267,7 @@ - } - ubi->avail_pebs -= vol->reserved_pebs; - ubi->rsvd_pebs += vol->reserved_pebs; -+ spin_unlock(&ubi->volumes_lock); - - vol->vol_id = vol_id; - vol->alignment = req->alignment; -@@ -259,10 +275,7 @@ - vol->vol_type = req->vol_type; - vol->name_len = req->name_len; - memcpy(vol->name, req->name, vol->name_len + 1); -- vol->exclusive = 1; - vol->ubi = ubi; -- ubi->volumes[vol_id] = vol; -- spin_unlock(&ubi->volumes_lock); - - /* - * Finish all pending erases because there may be some LEBs belonging -@@ -299,9 +312,10 @@ - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; -- err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1); -+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); -+ err = cdev_add(&vol->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device for volume %d", vol_id); -+ ubi_err("cannot add character device"); - goto out_mapping; - } - -@@ -311,12 +325,15 @@ - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; -- vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); -+ vol->dev.devt = dev; - vol->dev.class = ubi_class; -+ - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); -- if (err) -+ if (err) { -+ ubi_err("cannot register device"); - goto out_gluebi; -+ } - - err = volume_sysfs_init(ubi, vol); - if (err) -@@ -339,15 +356,29 @@ - goto out_sysfs; - - spin_lock(&ubi->volumes_lock); -+ ubi->volumes[vol_id] = vol; - ubi->vol_count += 1; -- vol->exclusive = 0; - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); - return 0; - -+out_sysfs: -+ /* -+ * We have registered our device, we should not free the volume* -+ * description object in this function in case of an error - it is -+ * freed by the release function. -+ * -+ * Get device reference to prevent the release function from being -+ * called just after sysfs has been closed. -+ */ -+ dont_free = 1; -+ get_device(&vol->dev); -+ volume_sysfs_close(vol); - out_gluebi: -- err = ubi_destroy_gluebi(vol); -+ if (ubi_destroy_gluebi(vol)) -+ dbg_err("cannot destroy gluebi for volume %d:%d", -+ ubi->ubi_num, vol_id); - out_cdev: - cdev_del(&vol->cdev); - out_mapping: -@@ -356,26 +387,13 @@ - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= vol->reserved_pebs; - ubi->avail_pebs += vol->reserved_pebs; -- ubi->volumes[vol_id] = NULL; - out_unlock: - spin_unlock(&ubi->volumes_lock); -- kfree(vol); -- return err; -- -- /* -- * We are registered, so @vol is destroyed in the release function and -- * we have to de-initialize differently. -- */ --out_sysfs: -- err = ubi_destroy_gluebi(vol); -- cdev_del(&vol->cdev); -- kfree(vol->eba_tbl); -- spin_lock(&ubi->volumes_lock); -- ubi->rsvd_pebs -= vol->reserved_pebs; -- ubi->avail_pebs += vol->reserved_pebs; -- ubi->volumes[vol_id] = NULL; -- spin_unlock(&ubi->volumes_lock); -- volume_sysfs_close(vol); -+ if (dont_free) -+ put_device(&vol->dev); -+ else -+ kfree(vol); -+ ubi_err("cannot create volume %d, error %d", vol_id, err); - return err; - } - -@@ -385,7 +403,8 @@ - * - * This function removes volume described by @desc. The volume has to be opened - * in "exclusive" mode. Returns zero in case of success and a negative error -- * code in case of failure. -+ * code in case of failure. The caller has to have the @ubi->volumes_mutex -+ * locked. - */ - int ubi_remove_volume(struct ubi_volume_desc *desc) - { -@@ -400,30 +419,36 @@ - if (ubi->ro_mode) - return -EROFS; - -+ spin_lock(&ubi->volumes_lock); -+ if (vol->ref_count > 1) { -+ /* -+ * The volume is busy, probably someone is reading one of its -+ * sysfs files. -+ */ -+ err = -EBUSY; -+ goto out_unlock; -+ } -+ ubi->volumes[vol_id] = NULL; -+ spin_unlock(&ubi->volumes_lock); -+ - err = ubi_destroy_gluebi(vol); - if (err) -- return err; -+ goto out_err; - - err = ubi_change_vtbl_record(ubi, vol_id, NULL); - if (err) -- return err; -+ goto out_err; - - for (i = 0; i < vol->reserved_pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, i); -+ err = ubi_eba_unmap_leb(ubi, vol, i); - if (err) -- return err; -+ goto out_err; - } - -- spin_lock(&ubi->volumes_lock); -- vol->removed = 1; -- ubi->volumes[vol_id] = NULL; -- spin_unlock(&ubi->volumes_lock); -- - kfree(vol->eba_tbl); - vol->eba_tbl = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); -- kfree(desc); - - spin_lock(&ubi->volumes_lock); - ubi->rsvd_pebs -= reserved_pebs; -@@ -441,8 +466,15 @@ - spin_unlock(&ubi->volumes_lock); - - paranoid_check_volumes(ubi); -- module_put(THIS_MODULE); - return 0; -+ -+out_err: -+ ubi_err("cannot remove volume %d, error %d", vol_id, err); -+ spin_lock(&ubi->volumes_lock); -+ ubi->volumes[vol_id] = vol; -+out_unlock: -+ spin_unlock(&ubi->volumes_lock); -+ return err; - } - - /** -@@ -450,8 +482,9 @@ - * @desc: volume descriptor - * @reserved_pebs: new size in physical eraseblocks - * -- * This function returns zero in case of success, and a negative error code in -- * case of failure. -+ * This function re-sizes the volume and returns zero in case of success, and a -+ * negative error code in case of failure. The caller has to have the -+ * @ubi->volumes_mutex locked. - */ - int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) - { -@@ -466,8 +499,6 @@ - - dbg_msg("re-size volume %d to from %d to %d PEBs", - vol_id, vol->reserved_pebs, reserved_pebs); -- ubi_assert(desc->mode == UBI_EXCLUSIVE); -- ubi_assert(vol == ubi->volumes[vol_id]); - - if (vol->vol_type == UBI_STATIC_VOLUME && - reserved_pebs < vol->used_ebs) { -@@ -487,6 +518,14 @@ - for (i = 0; i < reserved_pebs; i++) - new_mapping[i] = UBI_LEB_UNMAPPED; - -+ spin_lock(&ubi->volumes_lock); -+ if (vol->ref_count > 1) { -+ spin_unlock(&ubi->volumes_lock); -+ err = -EBUSY; -+ goto out_free; -+ } -+ spin_unlock(&ubi->volumes_lock); -+ - /* Reserve physical eraseblocks */ - pebs = reserved_pebs - vol->reserved_pebs; - if (pebs > 0) { -@@ -516,7 +555,7 @@ - - if (pebs < 0) { - for (i = 0; i < -pebs; i++) { -- err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i); -+ err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); - if (err) - goto out_acc; - } -@@ -565,27 +604,28 @@ - /** - * ubi_add_volume - add volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function adds an existin volume and initializes all its data -- * structures. Returnes zero in case of success and a negative error code in -+ * This function adds an existing volume and initializes all its data -+ * structures. Returns zero in case of success and a negative error code in - * case of failure. - */ --int ubi_add_volume(struct ubi_device *ubi, int vol_id) -+int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) - { -- int err; -- struct ubi_volume *vol = ubi->volumes[vol_id]; -+ int err, vol_id = vol->vol_id; -+ dev_t dev; - - dbg_msg("add volume %d", vol_id); - ubi_dbg_dump_vol_info(vol); -- ubi_assert(vol); - - /* Register character device for the volume */ - cdev_init(&vol->cdev, &ubi_vol_cdev_operations); - vol->cdev.owner = THIS_MODULE; -- err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1); -+ dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); -+ err = cdev_add(&vol->cdev, dev, 1); - if (err) { -- ubi_err("cannot add character device for volume %d", vol_id); -+ ubi_err("cannot add character device for volume %d, error %d", -+ vol_id, err); - return err; - } - -@@ -595,7 +635,7 @@ - - vol->dev.release = vol_release; - vol->dev.parent = &ubi->dev; -- vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); -+ vol->dev.devt = dev; - vol->dev.class = ubi_class; - sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); - err = device_register(&vol->dev); -@@ -623,22 +663,19 @@ - /** - * ubi_free_volume - free volume. - * @ubi: UBI device description object -- * @vol_id: volume ID -+ * @vol: volume description object - * -- * This function frees all resources for volume @vol_id but does not remove it. -+ * This function frees all resources for volume @vol but does not remove it. - * Used only when the UBI device is detached. - */ --void ubi_free_volume(struct ubi_device *ubi, int vol_id) -+void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) - { - int err; -- struct ubi_volume *vol = ubi->volumes[vol_id]; - -- dbg_msg("free volume %d", vol_id); -- ubi_assert(vol); -+ dbg_msg("free volume %d", vol->vol_id); - -- vol->removed = 1; -+ ubi->volumes[vol->vol_id] = NULL; - err = ubi_destroy_gluebi(vol); -- ubi->volumes[vol_id] = NULL; - cdev_del(&vol->cdev); - volume_sysfs_close(vol); - } -@@ -708,11 +745,6 @@ - goto fail; - } - -- if (vol->upd_marker != 0 && vol->upd_marker != 1) { -- ubi_err("bad upd_marker"); -- goto fail; -- } -- - if (vol->upd_marker && vol->corrupted) { - dbg_err("update marker and corrupted simultaneously"); - goto fail; -@@ -747,7 +779,7 @@ - - n = (long long)vol->used_ebs * vol->usable_leb_size; - if (vol->vol_type == UBI_DYNAMIC_VOLUME) { -- if (vol->corrupted != 0) { -+ if (vol->corrupted) { - ubi_err("corrupted dynamic volume"); - goto fail; - } -@@ -764,10 +796,6 @@ - goto fail; - } - } else { -- if (vol->corrupted != 0 && vol->corrupted != 1) { -- ubi_err("bad corrupted"); -- goto fail; -- } - if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { - ubi_err("bad used_ebs"); - goto fail; -@@ -820,9 +848,7 @@ - { - int i; - -- mutex_lock(&ubi->vtbl_mutex); - for (i = 0; i < ubi->vtbl_slots; i++) - paranoid_check_volume(ubi, i); -- mutex_unlock(&ubi->vtbl_mutex); - } - #endif -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/vtbl.c linux-2.6.24.7/drivers/mtd/ubi/vtbl.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/vtbl.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/vtbl.c 2009-04-12 18:13:57.000000000 +0200 -@@ -86,8 +86,10 @@ - { - int i, err; - uint32_t crc; -+ struct ubi_volume *layout_vol; - - ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); -+ layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; - - if (!vtbl_rec) - vtbl_rec = &empty_vtbl_record; -@@ -96,31 +98,25 @@ - vtbl_rec->crc = cpu_to_be32(crc); - } - -- mutex_lock(&ubi->vtbl_mutex); - memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); - for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { -- err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i); -- if (err) { -- mutex_unlock(&ubi->vtbl_mutex); -+ err = ubi_eba_unmap_leb(ubi, layout_vol, i); -+ if (err) - return err; -- } -- err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0, -+ -+ err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, - ubi->vtbl_size, UBI_LONGTERM); -- if (err) { -- mutex_unlock(&ubi->vtbl_mutex); -+ if (err) - return err; -- } - } - - paranoid_vtbl_check(ubi); -- mutex_unlock(&ubi->vtbl_mutex); -- return ubi_wl_flush(ubi); -+ return 0; - } - - /** -- * vol_til_check - check if volume table is not corrupted and contains sensible -- * data. -- * -+ * vtbl_check - check if volume table is not corrupted and contains sensible -+ * data. - * @ubi: UBI device description object - * @vtbl: volume table - * -@@ -273,7 +269,7 @@ - * this volume table copy was found during scanning. It has to be wiped - * out. - */ -- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); -+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); - if (sv) - old_seb = ubi_scan_find_seb(sv, copy); - -@@ -285,7 +281,7 @@ - } - - vid_hdr->vol_type = UBI_VID_DYNAMIC; -- vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID); -+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); - vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; - vid_hdr->data_size = vid_hdr->used_ebs = - vid_hdr->data_pad = cpu_to_be32(0); -@@ -378,7 +374,11 @@ - - /* Read both LEB 0 and LEB 1 into memory */ - ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ leb[seb->lnum] = kmalloc(ubi->vtbl_size, GFP_KERNEL); -+#else - leb[seb->lnum] = vmalloc(ubi->vtbl_size); -+#endif - if (!leb[seb->lnum]) { - err = -ENOMEM; - goto out_free; -@@ -414,7 +414,11 @@ - } - - /* Both LEB 1 and LEB 2 are OK and consistent */ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[1]); -+#else - vfree(leb[1]); -+#endif - return leb[0]; - } else { - /* LEB 0 is corrupted or does not exist */ -@@ -434,14 +438,23 @@ - if (err) - goto out_free; - ubi_msg("volume table was restored"); -- -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[0]); -+#else - vfree(leb[0]); -+#endif - return leb[1]; - } - - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(leb[0]); -+ kfree(leb[1]); -+#else - vfree(leb[0]); - vfree(leb[1]); -+#endif -+ - return ERR_PTR(err); - } - -@@ -459,7 +472,11 @@ - int i; - struct ubi_vtbl_record *vtbl; - -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ vtbl = kmalloc(ubi->vtbl_size, GFP_KERNEL); -+#else - vtbl = vmalloc(ubi->vtbl_size); -+#endif - if (!vtbl) - return ERR_PTR(-ENOMEM); - memset(vtbl, 0, ubi->vtbl_size); -@@ -472,7 +489,11 @@ - - err = create_vtbl(ubi, si, i, vtbl); - if (err) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(vtbl); -+#else - vfree(vtbl); -+#endif - return ERR_PTR(err); - } - } -@@ -518,6 +539,18 @@ - vol->name[vol->name_len] = '\0'; - vol->vol_id = i; - -+ if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { -+ /* Auto re-size flag may be set only for one volume */ -+ if (ubi->autoresize_vol_id != -1) { -+ ubi_err("more then one auto-resize volume (%d " -+ "and %d)", ubi->autoresize_vol_id, i); -+ kfree(vol); -+ return -EINVAL; -+ } -+ -+ ubi->autoresize_vol_id = i; -+ } -+ - ubi_assert(!ubi->volumes[i]); - ubi->volumes[i] = vol; - ubi->vol_count += 1; -@@ -568,6 +601,7 @@ - vol->last_eb_bytes = sv->last_data_size; - } - -+ /* And add the layout volume */ - vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); - if (!vol) - return -ENOMEM; -@@ -582,7 +616,8 @@ - vol->last_eb_bytes = vol->reserved_pebs; - vol->used_bytes = - (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); -- vol->vol_id = UBI_LAYOUT_VOL_ID; -+ vol->vol_id = UBI_LAYOUT_VOLUME_ID; -+ vol->ref_count = 1; - - ubi_assert(!ubi->volumes[i]); - ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; -@@ -734,7 +769,7 @@ - ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; - ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); - -- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); -+ sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); - if (!sv) { - /* - * No logical eraseblocks belonging to the layout volume were -@@ -786,7 +821,11 @@ - return 0; - - out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ubi->vtbl); -+#else - vfree(ubi->vtbl); -+#endif - for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) - if (ubi->volumes[i]) { - kfree(ubi->volumes[i]); -diff -urN linux-2.6.24.7.old/drivers/mtd/ubi/wl.c linux-2.6.24.7/drivers/mtd/ubi/wl.c ---- linux-2.6.24.7.old/drivers/mtd/ubi/wl.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/mtd/ubi/wl.c 2009-04-12 18:13:57.000000000 +0200 -@@ -117,21 +117,6 @@ - #define WL_MAX_FAILURES 32 - - /** -- * struct ubi_wl_entry - wear-leveling entry. -- * @rb: link in the corresponding RB-tree -- * @ec: erase counter -- * @pnum: physical eraseblock number -- * -- * Each physical eraseblock has a corresponding &struct wl_entry object which -- * may be kept in different RB-trees. -- */ --struct ubi_wl_entry { -- struct rb_node rb; -- int ec; -- int pnum; --}; -- --/** - * struct ubi_wl_prot_entry - PEB protection entry. - * @rb_pnum: link in the @wl->prot.pnum RB-tree - * @rb_aec: link in the @wl->prot.aec RB-tree -@@ -216,9 +201,6 @@ - #define paranoid_check_in_wl_tree(e, root) - #endif - --/* Slab cache for wear-leveling entries */ --static struct kmem_cache *wl_entries_slab; -- - /** - * wl_tree_add - add a wear-leveling entry to a WL RB-tree. - * @e: the wear-leveling entry to add -@@ -267,15 +249,26 @@ - int err; - struct ubi_work *wrk; - -- spin_lock(&ubi->wl_lock); -+ cond_resched(); - -+ /* -+ * @ubi->work_sem is used to synchronize with the workers. Workers take -+ * it in read mode, so many of them may be doing works at a time. But -+ * the queue flush code has to be sure the whole queue of works is -+ * done, and it takes the mutex in write mode. -+ */ -+ down_read(&ubi->work_sem); -+ spin_lock(&ubi->wl_lock); - if (list_empty(&ubi->works)) { - spin_unlock(&ubi->wl_lock); -+ up_read(&ubi->work_sem); - return 0; - } - - wrk = list_entry(ubi->works.next, struct ubi_work, list); - list_del(&wrk->list); -+ ubi->works_count -= 1; -+ ubi_assert(ubi->works_count >= 0); - spin_unlock(&ubi->wl_lock); - - /* -@@ -286,11 +279,8 @@ - err = wrk->func(ubi, wrk, 0); - if (err) - ubi_err("work failed with error code %d", err); -+ up_read(&ubi->work_sem); - -- spin_lock(&ubi->wl_lock); -- ubi->works_count -= 1; -- ubi_assert(ubi->works_count >= 0); -- spin_unlock(&ubi->wl_lock); - return err; - } - -@@ -549,8 +539,12 @@ - * prot_tree_del - remove a physical eraseblock from the protection trees - * @ubi: UBI device description object - * @pnum: the physical eraseblock to remove -+ * -+ * This function returns PEB @pnum from the protection trees and returns zero -+ * in case of success and %-ENODEV if the PEB was not found in the protection -+ * trees. - */ --static void prot_tree_del(struct ubi_device *ubi, int pnum) -+static int prot_tree_del(struct ubi_device *ubi, int pnum) - { - struct rb_node *p; - struct ubi_wl_prot_entry *pe = NULL; -@@ -561,7 +555,7 @@ - pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); - - if (pnum == pe->e->pnum) -- break; -+ goto found; - - if (pnum < pe->e->pnum) - p = p->rb_left; -@@ -569,10 +563,14 @@ - p = p->rb_right; - } - -+ return -ENODEV; -+ -+found: - ubi_assert(pe->e->pnum == pnum); - rb_erase(&pe->rb_aec, &ubi->prot.aec); - rb_erase(&pe->rb_pnum, &ubi->prot.pnum); - kfree(pe); -+ return 0; - } - - /** -@@ -744,7 +742,8 @@ - static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, - int cancel) - { -- int err, put = 0; -+ int err, put = 0, scrubbing = 0, protect = 0; -+ struct ubi_wl_prot_entry *uninitialized_var(pe); - struct ubi_wl_entry *e1, *e2; - struct ubi_vid_hdr *vid_hdr; - -@@ -757,21 +756,17 @@ - if (!vid_hdr) - return -ENOMEM; - -+ mutex_lock(&ubi->move_mutex); - spin_lock(&ubi->wl_lock); -+ ubi_assert(!ubi->move_from && !ubi->move_to); -+ ubi_assert(!ubi->move_to_put); - -- /* -- * Only one WL worker at a time is supported at this implementation, so -- * make sure a PEB is not being moved already. -- */ -- if (ubi->move_to || !ubi->free.rb_node || -+ if (!ubi->free.rb_node || - (!ubi->used.rb_node && !ubi->scrub.rb_node)) { - /* -- * Only one WL worker at a time is supported at this -- * implementation, so if a LEB is already being moved, cancel. -- * -- * No free physical eraseblocks? Well, we cancel wear-leveling -- * then. It will be triggered again when a free physical -- * eraseblock appears. -+ * No free physical eraseblocks? Well, they must be waiting in -+ * the queue to be erased. Cancel movement - it will be -+ * triggered again when a free physical eraseblock appears. - * - * No used physical eraseblocks? They must be temporarily - * protected from being moved. They will be moved to the -@@ -780,10 +775,7 @@ - */ - dbg_wl("cancel WL, a list is empty: free %d, used %d", - !ubi->free.rb_node, !ubi->used.rb_node); -- ubi->wl_scheduled = 0; -- spin_unlock(&ubi->wl_lock); -- ubi_free_vid_hdr(ubi, vid_hdr); -- return 0; -+ goto out_cancel; - } - - if (!ubi->scrub.rb_node) { -@@ -798,27 +790,24 @@ - if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { - dbg_wl("no WL needed: min used EC %d, max free EC %d", - e1->ec, e2->ec); -- ubi->wl_scheduled = 0; -- spin_unlock(&ubi->wl_lock); -- ubi_free_vid_hdr(ubi, vid_hdr); -- return 0; -+ goto out_cancel; - } - paranoid_check_in_wl_tree(e1, &ubi->used); - rb_erase(&e1->rb, &ubi->used); - dbg_wl("move PEB %d EC %d to PEB %d EC %d", - e1->pnum, e1->ec, e2->pnum, e2->ec); - } else { -+ /* Perform scrubbing */ -+ scrubbing = 1; - e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); - e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); - paranoid_check_in_wl_tree(e1, &ubi->scrub); -- rb_erase(&e1->rb, &ubi->scrub); -+ rb_erase(&e1->rb, &ubi->scrub); - dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); - } - - paranoid_check_in_wl_tree(e2, &ubi->free); - rb_erase(&e2->rb, &ubi->free); -- ubi_assert(!ubi->move_from && !ubi->move_to); -- ubi_assert(!ubi->move_to_put && !ubi->move_from_put); - ubi->move_from = e1; - ubi->move_to = e2; - spin_unlock(&ubi->wl_lock); -@@ -828,6 +817,10 @@ - * We so far do not know which logical eraseblock our physical - * eraseblock (@e1) belongs to. We have to read the volume identifier - * header first. -+ * -+ * Note, we are protected from this PEB being unmapped and erased. The -+ * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB -+ * which is being moved was unmapped. - */ - - err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); -@@ -842,32 +835,51 @@ - * likely have the VID header in place. - */ - dbg_wl("PEB %d has no VID header", e1->pnum); -- err = 0; -- } else { -- ubi_err("error %d while reading VID header from PEB %d", -- err, e1->pnum); -- if (err > 0) -- err = -EIO; -+ goto out_not_moved; - } -- goto error; -+ -+ ubi_err("error %d while reading VID header from PEB %d", -+ err, e1->pnum); -+ if (err > 0) -+ err = -EIO; -+ goto out_error; - } - - err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); - if (err) { -- if (err == UBI_IO_BITFLIPS) -- err = 0; -- goto error; -+ -+ if (err < 0) -+ goto out_error; -+ if (err == 1) -+ goto out_not_moved; -+ -+ /* -+ * For some reason the LEB was not moved - it might be because -+ * the volume is being deleted. We should prevent this PEB from -+ * being selected for wear-levelling movement for some "time", -+ * so put it to the protection tree. -+ */ -+ -+ dbg_wl("cancelled moving PEB %d", e1->pnum); -+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); -+ if (!pe) { -+ err = -ENOMEM; -+ goto out_error; -+ } -+ -+ protect = 1; - } - - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); -+ if (protect) -+ prot_tree_add(ubi, e1, pe, protect); - if (!ubi->move_to_put) - wl_tree_add(e2, &ubi->used); - else - put = 1; - ubi->move_from = ubi->move_to = NULL; -- ubi->move_from_put = ubi->move_to_put = 0; -- ubi->wl_scheduled = 0; -+ ubi->move_to_put = ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - - if (put) { -@@ -877,62 +889,67 @@ - */ - dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); - err = schedule_erase(ubi, e2, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e2); -- ubi_ro_mode(ubi); -- } -+ if (err) -+ goto out_error; - } - -- err = schedule_erase(ubi, e1, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e1); -- ubi_ro_mode(ubi); -+ if (!protect) { -+ err = schedule_erase(ubi, e1, 0); -+ if (err) -+ goto out_error; - } - -+ - dbg_wl("done"); -- return err; -+ mutex_unlock(&ubi->move_mutex); -+ return 0; - - /* -- * Some error occurred. @e1 was not changed, so return it back. @e2 -- * might be changed, schedule it for erasure. -+ * For some reasons the LEB was not moved, might be an error, might be -+ * something else. @e1 was not changed, so return it back. @e2 might -+ * be changed, schedule it for erasure. - */ --error: -- if (err) -- dbg_wl("error %d occurred, cancel operation", err); -- ubi_assert(err <= 0); -- -+out_not_moved: - ubi_free_vid_hdr(ubi, vid_hdr); - spin_lock(&ubi->wl_lock); -- ubi->wl_scheduled = 0; -- if (ubi->move_from_put) -- put = 1; -+ if (scrubbing) -+ wl_tree_add(e1, &ubi->scrub); - else - wl_tree_add(e1, &ubi->used); - ubi->move_from = ubi->move_to = NULL; -- ubi->move_from_put = ubi->move_to_put = 0; -+ ubi->move_to_put = ubi->wl_scheduled = 0; - spin_unlock(&ubi->wl_lock); - -- if (put) { -- /* -- * Well, the target PEB was put meanwhile, schedule it for -- * erasure. -- */ -- dbg_wl("PEB %d was put meanwhile, erase", e1->pnum); -- err = schedule_erase(ubi, e1, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e1); -- ubi_ro_mode(ubi); -- } -- } -- - err = schedule_erase(ubi, e2, 0); -- if (err) { -- kmem_cache_free(wl_entries_slab, e2); -- ubi_ro_mode(ubi); -- } -+ if (err) -+ goto out_error; -+ -+ mutex_unlock(&ubi->move_mutex); -+ return 0; -+ -+out_error: -+ ubi_err("error %d while moving PEB %d to PEB %d", -+ err, e1->pnum, e2->pnum); -+ -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ spin_lock(&ubi->wl_lock); -+ ubi->move_from = ubi->move_to = NULL; -+ ubi->move_to_put = ubi->wl_scheduled = 0; -+ spin_unlock(&ubi->wl_lock); - -- yield(); -+ kmem_cache_free(ubi_wl_entry_slab, e1); -+ kmem_cache_free(ubi_wl_entry_slab, e2); -+ ubi_ro_mode(ubi); -+ -+ mutex_unlock(&ubi->move_mutex); - return err; -+ -+out_cancel: -+ ubi->wl_scheduled = 0; -+ spin_unlock(&ubi->wl_lock); -+ mutex_unlock(&ubi->move_mutex); -+ ubi_free_vid_hdr(ubi, vid_hdr); -+ return 0; - } - - /** -@@ -1020,7 +1037,7 @@ - if (cancel) { - dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); - kfree(wl_wrk); -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - return 0; - } - -@@ -1049,7 +1066,7 @@ - - ubi_err("failed to erase PEB %d, error %d", pnum, err); - kfree(wl_wrk); -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - - if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || - err == -EBUSY) { -@@ -1119,8 +1136,7 @@ - } - - /** -- * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling -- * unit. -+ * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit. - * @ubi: UBI device description object - * @pnum: physical eraseblock to return - * @torture: if this physical eraseblock has to be tortured -@@ -1128,7 +1144,7 @@ - * This function is called to return physical eraseblock @pnum to the pool of - * free physical eraseblocks. The @torture flag has to be set if an I/O error - * occurred to this @pnum and it has to be tested. This function returns zero -- * in case of success and a negative error code in case of failure. -+ * in case of success, and a negative error code in case of failure. - */ - int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) - { -@@ -1139,8 +1155,8 @@ - ubi_assert(pnum >= 0); - ubi_assert(pnum < ubi->peb_count); - -+retry: - spin_lock(&ubi->wl_lock); -- - e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from) { - /* -@@ -1148,17 +1164,22 @@ - * be moved. It will be scheduled for erasure in the - * wear-leveling worker. - */ -- dbg_wl("PEB %d is being moved", pnum); -- ubi_assert(!ubi->move_from_put); -- ubi->move_from_put = 1; -+ dbg_wl("PEB %d is being moved, wait", pnum); - spin_unlock(&ubi->wl_lock); -- return 0; -+ -+ /* Wait for the WL worker by taking the @ubi->move_mutex */ -+ mutex_lock(&ubi->move_mutex); -+ mutex_unlock(&ubi->move_mutex); -+ goto retry; - } else if (e == ubi->move_to) { - /* - * User is putting the physical eraseblock which was selected - * as the target the data is moved to. It may happen if the EBA -- * unit already re-mapped the LEB but the WL unit did has not -- * put the PEB to the "used" tree. -+ * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but -+ * the WL unit has not put the PEB to the "used" tree yet, but -+ * it is about to do this. So we just set a flag which will -+ * tell the WL worker that the PEB is not needed anymore and -+ * should be scheduled for erasure. - */ - dbg_wl("PEB %d is the target of data moving", pnum); - ubi_assert(!ubi->move_to_put); -@@ -1172,8 +1193,15 @@ - } else if (in_wl_tree(e, &ubi->scrub)) { - paranoid_check_in_wl_tree(e, &ubi->scrub); - rb_erase(&e->rb, &ubi->scrub); -- } else -- prot_tree_del(ubi, e->pnum); -+ } else { -+ err = prot_tree_del(ubi, e->pnum); -+ if (err) { -+ ubi_err("PEB %d not found", pnum); -+ ubi_ro_mode(ubi); -+ spin_unlock(&ubi->wl_lock); -+ return err; -+ } -+ } - } - spin_unlock(&ubi->wl_lock); - -@@ -1227,8 +1255,17 @@ - if (in_wl_tree(e, &ubi->used)) { - paranoid_check_in_wl_tree(e, &ubi->used); - rb_erase(&e->rb, &ubi->used); -- } else -- prot_tree_del(ubi, pnum); -+ } else { -+ int err; -+ -+ err = prot_tree_del(ubi, e->pnum); -+ if (err) { -+ ubi_err("PEB %d not found", pnum); -+ ubi_ro_mode(ubi); -+ spin_unlock(&ubi->wl_lock); -+ return err; -+ } -+ } - - wl_tree_add(e, &ubi->scrub); - spin_unlock(&ubi->wl_lock); -@@ -1249,17 +1286,32 @@ - */ - int ubi_wl_flush(struct ubi_device *ubi) - { -- int err, pending_count; -- -- pending_count = ubi->works_count; -- -- dbg_wl("flush (%d pending works)", pending_count); -+ int err; - - /* - * Erase while the pending works queue is not empty, but not more then - * the number of currently pending works. - */ -- while (pending_count-- > 0) { -+ dbg_wl("flush (%d pending works)", ubi->works_count); -+ while (ubi->works_count) { -+ err = do_work(ubi); -+ if (err) -+ return err; -+ } -+ -+ /* -+ * Make sure all the works which have been done in parallel are -+ * finished. -+ */ -+ down_write(&ubi->work_sem); -+ up_write(&ubi->work_sem); -+ -+ /* -+ * And in case last was the WL worker and it cancelled the LEB -+ * movement, flush again. -+ */ -+ while (ubi->works_count) { -+ dbg_wl("flush more (%d pending works)", ubi->works_count); - err = do_work(ubi); - if (err) - return err; -@@ -1294,7 +1346,7 @@ - rb->rb_right = NULL; - } - -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - } - } - } -@@ -1303,7 +1355,7 @@ - * ubi_thread - UBI background thread. - * @u: the UBI device description object pointer - */ --static int ubi_thread(void *u) -+int ubi_thread(void *u) - { - int failures = 0; - struct ubi_device *ubi = u; -@@ -1394,36 +1446,22 @@ - ubi->used = ubi->free = ubi->scrub = RB_ROOT; - ubi->prot.pnum = ubi->prot.aec = RB_ROOT; - spin_lock_init(&ubi->wl_lock); -+ mutex_init(&ubi->move_mutex); -+ init_rwsem(&ubi->work_sem); - ubi->max_ec = si->max_ec; - INIT_LIST_HEAD(&ubi->works); - - sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); - -- ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); -- if (IS_ERR(ubi->bgt_thread)) { -- err = PTR_ERR(ubi->bgt_thread); -- ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, -- err); -- return err; -- } -- -- if (ubi_devices_cnt == 0) { -- wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab", -- sizeof(struct ubi_wl_entry), -- 0, 0, NULL); -- if (!wl_entries_slab) -- return -ENOMEM; -- } -- - err = -ENOMEM; - ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); - if (!ubi->lookuptbl) -- goto out_free; -+ return err; - - list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1431,7 +1469,7 @@ - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - goto out_free; - } - } -@@ -1439,7 +1477,7 @@ - list_for_each_entry(seb, &si->free, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1453,7 +1491,7 @@ - list_for_each_entry(seb, &si->corr, u.list) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1461,7 +1499,7 @@ - e->ec = seb->ec; - ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, 0)) { -- kmem_cache_free(wl_entries_slab, e); -+ kmem_cache_free(ubi_wl_entry_slab, e); - goto out_free; - } - } -@@ -1470,7 +1508,7 @@ - ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { - cond_resched(); - -- e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); -+ e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) - goto out_free; - -@@ -1510,8 +1548,6 @@ - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); -- if (ubi_devices_cnt == 0) -- kmem_cache_destroy(wl_entries_slab); - return err; - } - -@@ -1541,7 +1577,7 @@ - rb->rb_right = NULL; - } - -- kmem_cache_free(wl_entries_slab, pe->e); -+ kmem_cache_free(ubi_wl_entry_slab, pe->e); - kfree(pe); - } - } -@@ -1553,10 +1589,6 @@ - */ - void ubi_wl_close(struct ubi_device *ubi) - { -- dbg_wl("disable \"%s\"", ubi->bgt_name); -- if (ubi->bgt_thread) -- kthread_stop(ubi->bgt_thread); -- - dbg_wl("close the UBI wear-leveling unit"); - - cancel_pending(ubi); -@@ -1565,8 +1597,6 @@ - tree_destroy(&ubi->free); - tree_destroy(&ubi->scrub); - kfree(ubi->lookuptbl); -- if (ubi_devices_cnt == 1) -- kmem_cache_destroy(wl_entries_slab); - } - - #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID -diff -urN linux-2.6.24.7.old/drivers/mtd/udc_cache.c linux-2.6.24.7/drivers/mtd/udc_cache.c ---- linux-2.6.24.7.old/drivers/mtd/udc_cache.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/mtd/udc_cache.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,531 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define CACHE_MAX_NUM 256 -+#define SECTOR_SIZE 512 -+ -+//#define UDC_CACHE_DEBUG -+ -+#ifdef UDC_CACHE_DEBUG -+#define dprintk(a...) printk(a) -+#else -+#define dprintk(a...) while(0){} -+#endif -+ -+typedef struct { -+ unsigned short CacheState; -+ unsigned short UseCount; -+ unsigned short CacheChange; -+ unsigned short CacheReserve; -+ unsigned int BlockId; -+ unsigned char *aBlockData; -+} SSFDC__LB_CACHE; -+ -+#define FREE_CACHE 0 -+#define PREWRITE_CACHE 2 -+#define OFTEN_USE_CACHE 3 -+#define SECTOR_SHIFT 9 -+ -+#define CACHE_TO_UNCATCH(x) ((unsigned int)x | 0xa0000000) -+static unsigned int __aBlockData[SECTOR_SIZE * CACHE_MAX_NUM / 4] __attribute__ ((aligned (32))); -+static SSFDC__LB_CACHE ssfdc_cache[CACHE_MAX_NUM]; -+static unsigned short Cur_CacheCount = 0; -+int FlushDataState = 0; -+static struct mtdblk_dev *g_udc_mtdblk; -+static struct mtd_info *g_udc_mtd; -+ -+extern int udc_mtdblock_readsect(struct mtdblk_dev *, unsigned long, char *, int); -+extern int udc_mtdblock_writesect(struct mtdblk_dev *, unsigned long, char *); -+extern struct mtdblk_dev *udc_get_mtdblk(void); -+extern struct mtd_info *udc_get_mtd(void); -+extern void udc_flush_cache(struct mtdblk_dev *mtdblk); -+ -+#define _NAND_LB_Write(pCache) udc_mtdblock_writesect(g_udc_mtdblk, pCache->BlockId,pCache->aBlockData) -+#define _NAND_LB_Read(Sector,pBuffer) udc_mtdblock_readsect(g_udc_mtdblk, Sector, pBuffer, SECTOR_SIZE); -+ -+#define DMA_ENABLE 0 -+ -+#if DMA_ENABLE -+#define DMA_CHANNEL 5 -+#define PHYSADDR(x) virt_to_phys((void *)x) -+#else -+#define lb_memcpy memcpy -+#endif -+ -+#if DMA_ENABLE -+static void lb_memcpy(void *target,void* source,unsigned int len) -+{ -+ int ch = DMA_CHANNEL; -+ if(((unsigned int)source < 0xa0000000) && len) -+ dma_cache_wback_inv((unsigned long)source, len); -+ if(((unsigned int)target < 0xa0000000) && len) -+ dma_cache_wback_inv((unsigned long)target, len); -+ -+ REG_DMAC_DSAR(ch) = PHYSADDR((unsigned long)source); -+ REG_DMAC_DTAR(ch) = PHYSADDR((unsigned long)target); -+ REG_DMAC_DTCR(ch) = len / 32; -+ REG_DMAC_DRSR(ch) = DMAC_DRSR_RS_AUTO; -+ REG_DMAC_DCMD(ch) = DMAC_DCMD_SAI| DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32|DMAC_DCMD_DS_32BYTE; -+ REG_DMAC_DCCSR(ch) = DMAC_DCCSR_EN | DMAC_DCCSR_NDES; -+ while ( REG_DMAC_DTCR(ch) ); -+} -+#endif -+ -+static void _NAND_LB_InitCache(void) -+{ -+ int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+#if DMA_ENABLE -+ unsigned char * ptr = (unsigned char *)CACHE_TO_UNCATCH(__aBlockData); -+#else -+ unsigned char * ptr = (unsigned char *)(__aBlockData); -+#endif -+ for(i = 0;i < CACHE_MAX_NUM;i++) -+ { -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ pCache->CacheChange = 0; -+ pCache->aBlockData = ptr; -+ ptr+=SECTOR_SIZE; -+ pCache++; -+ } -+ Cur_CacheCount = 0; -+} -+ -+static SSFDC__LB_CACHE * _NAND_LB_GetFreeCache(void) -+{ -+ int ret = 0; -+ SSFDC__LB_CACHE *pCacheInfo = &ssfdc_cache[Cur_CacheCount]; -+ while(1) -+ { -+ if(ret >= CACHE_MAX_NUM) -+ return 0; -+ if(pCacheInfo >= &ssfdc_cache[CACHE_MAX_NUM]) -+ { -+ pCacheInfo = ssfdc_cache; -+ Cur_CacheCount = 0; -+ } -+ -+ if(pCacheInfo->CacheState == FREE_CACHE) -+ { -+ return pCacheInfo; -+ } -+ pCacheInfo++; -+ Cur_CacheCount++; -+ ret++; -+ } -+ return 0; -+} -+ -+static void _NAND_LB_CloseCACHES(unsigned int sectorstart,unsigned int sectorend) -+{ -+ unsigned int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ for( i = 0;i < CACHE_MAX_NUM;i++){ -+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ -+ pCache->CacheChange = 0; -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ } -+ pCache++; -+ } -+} -+ -+static void _NAND_LB_FLUSHCACHES(unsigned int sectorstart,unsigned int sectorend) -+{ -+ unsigned int i; -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ for( i = 0;i < CACHE_MAX_NUM;i++){ -+ if((pCache->CacheState != FREE_CACHE) && (pCache->BlockId >= sectorstart) && (pCache->BlockId < sectorend)){ -+ if(pCache->CacheChange) -+ _NAND_LB_Write(pCache); -+ pCache->CacheChange = 0; -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ } -+ pCache++; -+ -+ } -+} -+ -+inline static int Get_NAND_CacheFreeCount(void) -+{ -+ SSFDC__LB_CACHE *pCache = ssfdc_cache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ unsigned int count = 0; -+ while(pCache < pEndCache) -+ { -+ if(pCache->CacheState == FREE_CACHE) -+ count++; -+ pCache++; -+ } -+ return count; -+ -+} -+ -+static unsigned int _NAND_LB_PreWiteToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) -+{ -+ SSFDC__LB_CACHE *pWriteCache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ unsigned int sector = -1; -+ unsigned int flag; -+ while(1) -+ { -+ sector = -1; -+ flag = 0; -+ pWriteCache = ssfdc_cache; -+ while(pWriteCache < pEndCache) -+ { -+ if(pWriteCache->CacheState == update) //PREWRITE_CACHE -+ { -+ if(pWriteCache->BlockId < sector) -+ { -+ sector = pWriteCache->BlockId; -+ pCache = pWriteCache; -+ } -+ }else -+ flag++; -+ pWriteCache++; -+ } -+ -+ if(flag < CACHE_MAX_NUM) -+ { -+ if(pCache->CacheChange) -+ { -+ _NAND_LB_Write(pCache); -+ pCache->CacheChange = 0; -+ } -+ pCache->CacheState = FREE_CACHE; -+ pCache->UseCount = 0; -+ (*count)++; -+ }else -+ break; -+ } -+ return 0; -+} -+ -+static void _NAND_LB_OftenToNand(SSFDC__LB_CACHE *pCache,unsigned short *count,unsigned int update) -+{ -+ SSFDC__LB_CACHE *pWriteCache = pCache; -+ SSFDC__LB_CACHE *pOldCache = pCache; -+ SSFDC__LB_CACHE *pEndCache = &ssfdc_cache[CACHE_MAX_NUM]; -+ -+ dprintk("%s!\n",__FUNCTION__); -+ while(pCache) -+ { -+ if(pCache->CacheState == OFTEN_USE_CACHE) -+ { -+ if(pWriteCache->CacheState != OFTEN_USE_CACHE) -+ pWriteCache = pCache; -+ else if(pWriteCache->UseCount > pCache->UseCount) -+ { -+ pWriteCache = pCache; -+ } -+ } -+ pCache++; -+ if(pCache >= pEndCache) -+ break; -+ } -+ if(pWriteCache->CacheState == OFTEN_USE_CACHE) -+ { -+ (*count)++; -+ if(pWriteCache->CacheChange) -+ _NAND_LB_Write(pWriteCache); -+ pWriteCache->CacheState = FREE_CACHE; -+ -+ pWriteCache->UseCount = 0; -+ pWriteCache->CacheChange = 0; -+ if(update != -1) -+ update--; -+ if(update != 0) -+ _NAND_LB_OftenToNand(pOldCache,count,update); -+ } -+} -+ -+static int _NAND_LB_FreeCache(unsigned int update) -+{ -+ unsigned short freecount = 0,totalfree = 0; -+ -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); -+ -+ totalfree += freecount; -+ dprintk("free count = %d\n",freecount); -+ if(freecount == 0) -+ { -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+ totalfree += freecount; -+ update = 0; -+ } -+ if(update) -+ { -+ if(Get_NAND_CacheFreeCount() < CACHE_MAX_NUM * 1 / 4) // because fat is 4 sector -+ { -+ freecount = 0; -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+ totalfree += freecount; -+ } -+ } -+ -+ dprintk("Free = %d\r\n",totalfree); -+ return totalfree; -+} -+ -+static int _NAND_LB_GetFromCache(unsigned int Sector, void *pBuffer) { -+ -+ SSFDC__LB_CACHE *pCache = &ssfdc_cache[Cur_CacheCount]; -+ SSFDC__LB_CACHE *pUseCache = 0; -+ unsigned short i; -+ dprintk("sector = %x pBuffer = %x\n",Sector,pBuffer); -+ if(pCache >= &ssfdc_cache[CACHE_MAX_NUM]) -+ pCache = ssfdc_cache; -+ -+ i = 0; -+ while (1) { -+ if(pCache->CacheState != FREE_CACHE) -+ { -+ if (Sector == pCache->BlockId) { -+ dprintk("Cache is use = %d\r\n",pCache->BlockId); -+ pUseCache = pCache; -+ pCache->UseCount++; -+ if(pCache->UseCount == 0) -+ pCache->UseCount = -1; -+ pCache->CacheState = OFTEN_USE_CACHE; -+ } -+ } -+ pCache--; -+ if(pCache < ssfdc_cache) -+ pCache = &ssfdc_cache[CACHE_MAX_NUM - 1]; -+ -+ i++; -+ if (i >= CACHE_MAX_NUM) { -+ break; /* Sector not in cache */ -+ } -+ } -+ if (pUseCache) { -+ dprintk("From Cache %d\r\n",Sector); -+ lb_memcpy(pBuffer, pUseCache->aBlockData, SECTOR_SIZE); -+ return 0; -+ } -+ return -1; -+} -+ -+static void _NAND_LB_ClearCache(void) { -+ -+ unsigned short freecount = 0; -+ dprintk("Clear Cache\r\n"); -+ -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,PREWRITE_CACHE); -+ _NAND_LB_PreWiteToNand(ssfdc_cache,&freecount,OFTEN_USE_CACHE); -+} -+ -+static void _NAND_LB_CopyToCache(unsigned int Sector, void *pBuffer,unsigned short rw) -+{ -+ SSFDC__LB_CACHE *pCache = _NAND_LB_GetFreeCache(); -+ dprintk("Copy to Cache = 0x%08x 0x%08x\r\n",pCache,ssfdc_cache); -+ -+ if(!pCache) -+ { -+ _NAND_LB_FreeCache(rw); -+ -+ pCache = _NAND_LB_GetFreeCache(); -+ } -+ pCache->BlockId = Sector; -+ pCache->CacheState = PREWRITE_CACHE; -+ pCache->UseCount = 0; -+ pCache->CacheChange = rw; -+ -+ lb_memcpy(pCache->aBlockData,pBuffer,SECTOR_SIZE); -+} -+ -+ -+static int _NAND_LB_UpdateInCache(unsigned int Sector, void *pBuffer) { -+ short i,ret = 0; -+ i = Cur_CacheCount; -+ if(Cur_CacheCount > CACHE_MAX_NUM) -+ i = 0; -+ while(1) -+ { -+ if(ret >= CACHE_MAX_NUM) -+ return -1; -+ if(ssfdc_cache[i].CacheState != FREE_CACHE) -+ { -+ -+ if(ssfdc_cache[i].BlockId == Sector) -+ { -+ dprintk("UpdateInCache = %d\r\n",Sector); -+ ssfdc_cache[i].CacheState = OFTEN_USE_CACHE; -+ ssfdc_cache[i].UseCount++; -+ ssfdc_cache[i].CacheChange = 1; -+ lb_memcpy(ssfdc_cache[i].aBlockData,pBuffer,SECTOR_SIZE); -+ return 0; -+ } -+ } -+ i--; -+ if(i < 0) -+ i = CACHE_MAX_NUM - 1; -+ ret++; -+ } -+ return -1; -+} -+ -+static int NAND_LB_MultiRead(unsigned int Sector, void *pBuffer,unsigned int SectorCount) -+{ -+ int i,ret,end; -+ void *p; -+ -+ dprintk("NAND_LB_MultiRead = %d %d \n",Sector,SectorCount); -+ end = Sector + SectorCount; -+ _NAND_LB_FLUSHCACHES(Sector,end); -+ -+ p = pBuffer; -+ for (i = Sector; i < end; i ++) -+ { -+ ret = udc_mtdblock_readsect(g_udc_mtdblk, i, p, SECTOR_SIZE); -+ p += SECTOR_SIZE; -+ } -+ return ret; -+} -+ -+static int NAND_LB_Read(unsigned int Sector, void *pBuffer) -+{ -+ int x; -+#if DMA_ENABLE -+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); -+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); -+#else -+ unsigned char *ptr = (unsigned char *)pBuffer; -+#endif -+ dprintk("LB_Read = %d \n",Sector); -+ if(_NAND_LB_GetFromCache(Sector,ptr)) -+ { -+ x = _NAND_LB_Read(Sector,ptr); -+ _NAND_LB_CopyToCache(Sector,ptr,0); -+ } -+ return 512; -+} -+ -+static int NAND_LB_MultiWrite(unsigned int Sector, void *pBuffer,unsigned int SectorCount) -+{ -+ int i,ret; -+ unsigned char *p; -+ -+ _NAND_LB_CloseCACHES(Sector,Sector + SectorCount); -+ p = (unsigned char *)pBuffer; -+ for (i = Sector; i < Sector + SectorCount; i ++) -+ { -+ ret = udc_mtdblock_writesect(g_udc_mtdblk, i, p); -+ p += 512; -+ } -+ return ret; -+} -+ -+static int NAND_LB_Write(unsigned int Sector, void *pBuffer) -+{ -+#if DMA_ENABLE -+ unsigned char *ptr = (unsigned char *)CACHE_TO_UNCATCH(pBuffer); -+ dma_cache_wback_inv(pBuffer,SECTOR_SIZE); -+#else -+ unsigned char *ptr = (unsigned char *)pBuffer; -+#endif -+ dprintk("LB_Write = %x %x\r\n",Sector,pBuffer); -+ if(_NAND_LB_UpdateInCache(Sector,ptr)) -+ { -+ _NAND_LB_CopyToCache(Sector,ptr,1); -+ } -+ return 512; -+} -+/********************************************************************* -+* -+* Global functions -+* -+***********************************************************************/ -+ -+int NAND_LB_Init(void) -+{ -+ dprintk("UDC CACHE Init \n"); -+ _NAND_LB_InitCache(); -+ g_udc_mtdblk = udc_get_mtdblk(); -+ g_udc_mtd = udc_get_mtd(); -+ return 0; -+} -+ -+int NAND_LB_FLASHCACHE(void) -+{ -+ dprintk("Flush lb cache !\n"); -+ _NAND_LB_ClearCache(); -+// dprintk("Flush mtd cache !\n"); -+// udc_flush_cache(g_udc_mtdblk); -+ return 0; -+} -+ -+int NAND_MTD_FLASHCACHE(void) -+{ -+ dprintk("Flush mtd cache !\n"); -+ udc_flush_cache(g_udc_mtdblk); -+ return 0; -+} -+ -+int udc_read(unsigned int offset, unsigned int len, unsigned char *buf) -+{ -+ unsigned long block,sector,i; -+ -+ block = offset >> SECTOR_SHIFT; -+ sector = len >> SECTOR_SHIFT; -+ dprintk("read dev = ia:%x, s:%d c:%d\r\n",buf,block,sector); -+ -+ if (sector <= 8) -+ { -+ for(i = 0;i < sector; i++) -+ { -+ NAND_LB_Read(block + i,(void *)(buf)); -+ buf += 512; -+ } -+ } -+ else -+ NAND_LB_MultiRead(block, buf, sector); -+ -+ return len; -+} -+ -+int udc_write(unsigned int offset, unsigned int len, unsigned char *buf) -+{ -+ unsigned long block,sector,i; -+ -+ block = offset >> SECTOR_SHIFT; -+ sector = len >> SECTOR_SHIFT; -+ dprintk("write dev s:%d c:%d\r\n",block,sector); -+ -+ if(sector <= 8) -+ { -+ for(i = 0;i < sector; i++) -+ { -+ NAND_LB_Write(block + i,(void *)(buf)); -+ buf += 512; -+ FlushDataState = 1; -+ } -+ }else -+ NAND_LB_MultiWrite(block,(void *)(buf),sector); -+ -+ return len; -+} -+ -+EXPORT_SYMBOL_GPL(udc_write); -+EXPORT_SYMBOL_GPL(udc_read); -+EXPORT_SYMBOL_GPL(NAND_LB_Init); -+EXPORT_SYMBOL_GPL(NAND_LB_FLASHCACHE); -+EXPORT_SYMBOL_GPL(FlushDataState); -+EXPORT_SYMBOL_GPL(NAND_MTD_FLASHCACHE); -diff -urN linux-2.6.24.7.old/drivers/net/Kconfig linux-2.6.24.7/drivers/net/Kconfig ---- linux-2.6.24.7.old/drivers/net/Kconfig 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/net/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -333,6 +333,24 @@ - or internal device. It is safe to say Y or M here even if your - ethernet card lack MII. - -+config JZ_ETH -+ tristate "JZ4730/JZ5730 On-Chip Ethernet support" -+ depends on NET_ETHERNET && (SOC_JZ4730 || SOC_JZ5730 || JZ_FPGA) -+ help -+ Say Y for support of JZ4730/JZ5730 On-Chip Ethernet interface. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called jz_eth. -+ -+config JZCS8900 -+ tristate "JZ CS8900A Ethernet support" -+ depends on NET_ETHERNET && (SOC_JZ4740 || SOC_JZ4750) -+ help -+ Say Y for support of JZ CS8900A Ethernet interface. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called jzcs8900a. -+ - config MACB - tristate "Atmel MACB support" - depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 -diff -urN linux-2.6.24.7.old/drivers/net/Kconfig.orig linux-2.6.24.7/drivers/net/Kconfig.orig ---- linux-2.6.24.7.old/drivers/net/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/net/Kconfig.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,3192 @@ -+ -+# -+# Network device configuration -+# -+ -+menuconfig NETDEVICES -+ default y if UML -+ depends on NET -+ bool "Network device support" -+ ---help--- -+ You can say N here if you don't intend to connect your Linux box to -+ any other computer at all. -+ -+ You'll have to say Y if your computer contains a network card that -+ you want to use under Linux. If you are going to run SLIP or PPP over -+ telephone line or null modem cable you need say Y here. Connecting -+ two machines with parallel ports using PLIP needs this, as well as -+ AX.25/KISS for sending Internet traffic over amateur radio links. -+ -+ See also "The Linux Network Administrator's Guide" by Olaf Kirch and -+ Terry Dawson. Available at . -+ -+ If unsure, say Y. -+ -+# All the following symbols are dependent on NETDEVICES - do not repeat -+# that for each of the symbols. -+if NETDEVICES -+ -+config NETDEVICES_MULTIQUEUE -+ bool "Netdevice multiple hardware queue support" -+ ---help--- -+ Say Y here if you want to allow the network stack to use multiple -+ hardware TX queues on an ethernet device. -+ -+ Most people will say N here. -+ -+config IFB -+ tristate "Intermediate Functional Block support" -+ depends on NET_CLS_ACT -+ ---help--- -+ This is an intermediate driver that allows sharing of -+ resources. -+ To compile this driver as a module, choose M here: the module -+ will be called ifb. If you want to use more than one ifb -+ device at a time, you need to compile this driver as a module. -+ Instead of 'ifb', the devices will then be called 'ifb0', -+ 'ifb1' etc. -+ Look at the iproute2 documentation directory for usage etc -+ -+config DUMMY -+ tristate "Dummy net driver support" -+ ---help--- -+ This is essentially a bit-bucket device (i.e. traffic you send to -+ this device is consigned into oblivion) with a configurable IP -+ address. It is most commonly used in order to make your currently -+ inactive SLIP address seem like a real address for local programs. -+ If you use SLIP or PPP, you might want to say Y here. Since this -+ thing often comes in handy, the default is Y. It won't enlarge your -+ kernel either. What a deal. Read about it in the Network -+ Administrator's Guide, available from -+ . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called dummy. If you want to use more than one dummy -+ device at a time, you need to compile this driver as a module. -+ Instead of 'dummy', the devices will then be called 'dummy0', -+ 'dummy1' etc. -+ -+config BONDING -+ tristate "Bonding driver support" -+ depends on INET -+ ---help--- -+ Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet -+ Channels together. This is called 'Etherchannel' by Cisco, -+ 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. -+ -+ The driver supports multiple bonding modes to allow for both high -+ performance and high availability operation. -+ -+ Refer to for more -+ information. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called bonding. -+ -+config MACVLAN -+ tristate "MAC-VLAN support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ ---help--- -+ This allows one to create virtual interfaces that map packets to -+ or from specific MAC addresses to a particular interface. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called macvlan. -+ -+config EQUALIZER -+ tristate "EQL (serial line load balancing) support" -+ ---help--- -+ If you have two serial connections to some other computer (this -+ usually requires two modems and two telephone lines) and you use -+ SLIP (the protocol for sending Internet traffic over telephone -+ lines) or PPP (a better SLIP) on them, you can make them behave like -+ one double speed connection using this driver. Naturally, this has -+ to be supported at the other end as well, either with a similar EQL -+ Linux driver or with a Livingston Portmaster 2e. -+ -+ Say Y if you want this and read -+ . You may also want to read -+ section 6.2 of the NET-3-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called eql. If unsure, say N. -+ -+config IMQ -+ tristate "IMQ (intermediate queueing device) support" -+ depends on NETDEVICES && NETFILTER -+ ---help--- -+ The IMQ device(s) is used as placeholder for QoS queueing -+ disciplines. Every packet entering/leaving the IP stack can be -+ directed through the IMQ device where it's enqueued/dequeued to the -+ attached qdisc. This allows you to treat network devices as classes -+ and distribute bandwidth among them. Iptables is used to specify -+ through which IMQ device, if any, packets travel. -+ -+ More information at: http://www.linuximq.net/ -+ -+ To compile this driver as a module, choose M here: the module -+ will be called imq. If unsure, say N. -+ -+choice -+ prompt "IMQ behavior (PRE/POSTROUTING)" -+ depends on IMQ -+ default IMQ_BEHAVIOR_BB -+ help -+ -+ This settings defines how IMQ behaves in respect to its -+ hooking in PREROUTING and POSTROUTING. -+ -+ IMQ can work in any of the following ways: -+ -+ PREROUTING | POSTROUTING -+ -----------------|------------------- -+ #1 After NAT | After NAT -+ #2 After NAT | Before NAT -+ #3 Before NAT | After NAT -+ #4 Before NAT | Before NAT -+ -+ The default behavior is to hook before NAT on PREROUTING -+ and after NAT on POSTROUTING (#3). -+ -+ This settings are specially usefull when trying to use IMQ -+ to shape NATed clients. -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+config IMQ_BEHAVIOR_AA -+ bool "IMQ AA" -+ help -+ This settings defines how IMQ behaves in respect to its -+ hooking in PREROUTING and POSTROUTING. -+ -+ Choosing this option will make IMQ hook like this: -+ -+ PREROUTING: After NAT -+ POSTROUTING: After NAT -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+config IMQ_BEHAVIOR_AB -+ bool "IMQ AB" -+ help -+ This settings defines how IMQ behaves in respect to its -+ hooking in PREROUTING and POSTROUTING. -+ -+ Choosing this option will make IMQ hook like this: -+ -+ PREROUTING: After NAT -+ POSTROUTING: Before NAT -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+config IMQ_BEHAVIOR_BA -+ bool "IMQ BA" -+ help -+ This settings defines how IMQ behaves in respect to its -+ hooking in PREROUTING and POSTROUTING. -+ -+ Choosing this option will make IMQ hook like this: -+ -+ PREROUTING: Before NAT -+ POSTROUTING: After NAT -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+config IMQ_BEHAVIOR_BB -+ bool "IMQ BB" -+ help -+ This settings defines how IMQ behaves in respect to its -+ hooking in PREROUTING and POSTROUTING. -+ -+ Choosing this option will make IMQ hook like this: -+ -+ PREROUTING: Before NAT -+ POSTROUTING: Before NAT -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+endchoice -+ -+config IMQ_NUM_DEVS -+ -+ int "Number of IMQ devices" -+ range 2 16 -+ depends on IMQ -+ default "16" -+ help -+ -+ This settings defines how many IMQ devices will be -+ created. -+ -+ The default value is 16. -+ -+ More information can be found at: www.linuximq.net -+ -+ If not sure leave the default settings alone. -+ -+config TUN -+ tristate "Universal TUN/TAP device driver support" -+ select CRC32 -+ ---help--- -+ TUN/TAP provides packet reception and transmission for user space -+ programs. It can be viewed as a simple Point-to-Point or Ethernet -+ device, which instead of receiving packets from a physical media, -+ receives them from user space program and instead of sending packets -+ via physical media writes them to the user space program. -+ -+ When a program opens /dev/net/tun, driver creates and registers -+ corresponding net device tunX or tapX. After a program closed above -+ devices, driver will automatically delete tunXX or tapXX device and -+ all routes corresponding to it. -+ -+ Please read for more -+ information. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called tun. -+ -+ If you don't know what to use this for, you don't need it. -+ -+config VETH -+ tristate "Virtual ethernet pair device" -+ ---help--- -+ This device is a local ethernet tunnel. Devices are created in pairs. -+ When one end receives the packet it appears on its pair and vice -+ versa. -+ -+config NET_SB1000 -+ tristate "General Instruments Surfboard 1000" -+ depends on PNP -+ ---help--- -+ This is a driver for the General Instrument (also known as -+ NextLevel) SURFboard 1000 internal -+ cable modem. This is an ISA card which is used by a number of cable -+ TV companies to provide cable modem access. It's a one-way -+ downstream-only cable modem, meaning that your upstream net link is -+ provided by your regular phone modem. -+ -+ At present this driver only compiles as a module, so say M here if -+ you have this card. The module will be called sb1000. Then read -+ for information on how -+ to use this module, as it needs special ppp scripts for establishing -+ a connection. Further documentation and the necessary scripts can be -+ found at: -+ -+ -+ -+ -+ -+ If you don't have this card, of course say N. -+ -+source "drivers/net/arcnet/Kconfig" -+ -+source "drivers/net/phy/Kconfig" -+ -+# -+# Ethernet -+# -+ -+menuconfig NET_ETHERNET -+ bool "Ethernet (10 or 100Mbit)" -+ depends on !UML -+ ---help--- -+ Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common -+ type of Local Area Network (LAN) in universities and companies. -+ -+ Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over -+ coaxial cable, linking computers in a chain), 10BASE-T or twisted -+ pair (10 Mbps over twisted pair cable, linking computers to central -+ hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs), -+ 100BASE-TX (100 Mbps over two twisted pair cables, using hubs), -+ 100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair -+ cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links) -+ [the 100BASE varieties are also known as Fast Ethernet], and Gigabit -+ Ethernet (1 Gbps over optical fiber or short copper links). -+ -+ If your Linux machine will be connected to an Ethernet and you have -+ an Ethernet network interface card (NIC) installed in your computer, -+ say Y here and read the Ethernet-HOWTO, available from -+ . You will then also have -+ to say Y to the driver for your particular NIC. -+ -+ Note that the answer to this question won't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about Ethernet network cards. If unsure, say N. -+ -+if NET_ETHERNET -+ -+config MII -+ tristate "Generic Media Independent Interface device support" -+ help -+ Most ethernet controllers have MII transceiver either as an external -+ or internal device. It is safe to say Y or M here even if your -+ ethernet card lack MII. -+ -+config MACB -+ tristate "Atmel MACB support" -+ depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 -+ select PHYLIB -+ help -+ The Atmel MACB ethernet interface is found on many AT32 and AT91 -+ parts. Say Y to include support for the MACB chip. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called macb. -+ -+source "drivers/net/arm/Kconfig" -+ -+config AX88796 -+ tristate "ASIX AX88796 NE2000 clone support" -+ depends on ARM || MIPS || SUPERH -+ select CRC32 -+ select MII -+ help -+ AX88796 driver, using platform bus to provide -+ chip detection and resources -+ -+config AX88796_93CX6 -+ bool "ASIX AX88796 external 93CX6 eeprom support" -+ depends on AX88796 -+ select EEPROM_93CX6 -+ help -+ Select this if your platform comes with an external 93CX6 eeprom. -+ -+config MACE -+ tristate "MACE (Power Mac ethernet) support" -+ depends on PPC_PMAC && PPC32 -+ select CRC32 -+ help -+ Power Macintoshes and clones with Ethernet built-in on the -+ motherboard will usually use a MACE (Medium Access Control for -+ Ethernet) interface. Say Y to include support for the MACE chip. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called mace. -+ -+config MACE_AAUI_PORT -+ bool "Use AAUI port instead of TP by default" -+ depends on MACE -+ help -+ Some Apple machines (notably the Apple Network Server) which use the -+ MACE ethernet chip have an Apple AUI port (small 15-pin connector), -+ instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say -+ Y here if you have such a machine. If unsure, say N. -+ The driver will default to AAUI on ANS anyway, and if you use it as -+ a module, you can provide the port_aaui=0|1 to force the driver. -+ -+config BMAC -+ tristate "BMAC (G3 ethernet) support" -+ depends on PPC_PMAC && PPC32 -+ select CRC32 -+ help -+ Say Y for support of BMAC Ethernet interfaces. These are used on G3 -+ computers. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called bmac. -+ -+config ARIADNE -+ tristate "Ariadne support" -+ depends on ZORRO -+ help -+ If you have a Village Tronic Ariadne Ethernet adapter, say Y. -+ Otherwise, say N. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called ariadne. -+ -+config A2065 -+ tristate "A2065 support" -+ depends on ZORRO -+ select CRC32 -+ help -+ If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise, -+ say N. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called a2065. -+ -+config HYDRA -+ tristate "Hydra support" -+ depends on ZORRO -+ select CRC32 -+ help -+ If you have a Hydra Ethernet adapter, say Y. Otherwise, say N. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called hydra. -+ -+config ZORRO8390 -+ tristate "Zorro NS8390-based Ethernet support" -+ depends on ZORRO -+ select CRC32 -+ help -+ This driver is for Zorro Ethernet cards using an NS8390-compatible -+ chipset, like the Village Tronic Ariadne II and the Individual -+ Computers X-Surf Ethernet cards. If you have such a card, say Y. -+ Otherwise, say N. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called zorro8390. -+ -+config APNE -+ tristate "PCMCIA NE2000 support" -+ depends on AMIGA_PCMCIA -+ select CRC32 -+ help -+ If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, -+ say N. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called apne. -+ -+config APOLLO_ELPLUS -+ tristate "Apollo 3c505 support" -+ depends on APOLLO -+ help -+ Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card. -+ If you don't have one made for Apollos, you can use one from a PC, -+ except that your Apollo won't be able to boot from it (because the -+ code in the ROM will be for a PC). -+ -+config MAC8390 -+ bool "Macintosh NS 8390 based ethernet cards" -+ depends on MAC -+ select CRC32 -+ help -+ If you want to include a driver to support Nubus or LC-PDS -+ Ethernet cards using an NS8390 chipset or its equivalent, say Y -+ and read the Ethernet-HOWTO, available from -+ . -+ -+config MAC89x0 -+ tristate "Macintosh CS89x0 based ethernet cards" -+ depends on MAC -+ ---help--- -+ Support for CS89x0 chipset based Ethernet cards. If you have a -+ Nubus or LC-PDS network (Ethernet) card of this type, say Y and -+ read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. This module will -+ be called mac89x0. -+ -+config MACSONIC -+ tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)" -+ depends on MAC -+ ---help--- -+ Support for NatSemi SONIC based Ethernet devices. This includes -+ the onboard Ethernet in many Quadras as well as some LC-PDS, -+ a few Nubus and all known Comm Slot Ethernet cards. If you have -+ one of these say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. This module will -+ be called macsonic. -+ -+config MACMACE -+ bool "Macintosh (AV) onboard MACE ethernet" -+ depends on MAC -+ select CRC32 -+ help -+ Support for the onboard AMD 79C940 MACE Ethernet controller used in -+ the 660AV and 840AV Macintosh. If you have one of these Macintoshes -+ say Y and read the Ethernet-HOWTO, available from -+ . -+ -+config MVME147_NET -+ tristate "MVME147 (Lance) Ethernet support" -+ depends on MVME147 -+ select CRC32 -+ help -+ Support for the on-board Ethernet interface on the Motorola MVME147 -+ single-board computer. Say Y here to include the -+ driver for this chip in your kernel. -+ To compile this driver as a module, choose M here. -+ -+config MVME16x_NET -+ tristate "MVME16x Ethernet support" -+ depends on MVME16x -+ help -+ This is the driver for the Ethernet interface on the Motorola -+ MVME162, 166, 167, 172 and 177 boards. Say Y here to include the -+ driver for this chip in your kernel. -+ To compile this driver as a module, choose M here. -+ -+config BVME6000_NET -+ tristate "BVME6000 Ethernet support" -+ depends on BVME6000 -+ help -+ This is the driver for the Ethernet interface on BVME4000 and -+ BVME6000 VME boards. Say Y here to include the driver for this chip -+ in your kernel. -+ To compile this driver as a module, choose M here. -+ -+config ATARILANCE -+ tristate "Atari Lance support" -+ depends on ATARI -+ help -+ Say Y to include support for several Atari Ethernet adapters based -+ on the AMD Lance chipset: RieblCard (with or without battery), or -+ PAMCard VME (also the version by Rhotron, with different addresses). -+ -+config SUN3LANCE -+ tristate "Sun3/Sun3x on-board LANCE support" -+ depends on SUN3 || SUN3X -+ help -+ Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80) -+ featured an AMD Lance 10Mbit Ethernet controller on board; say Y -+ here to compile in the Linux driver for this and enable Ethernet. -+ General Linux information on the Sun 3 and 3x series (now -+ discontinued) is at -+ . -+ -+ If you're not building a kernel for a Sun 3, say N. -+ -+config SUN3_82586 -+ bool "Sun3 on-board Intel 82586 support" -+ depends on SUN3 -+ help -+ This driver enables support for the on-board Intel 82586 based -+ Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note -+ that this driver does not support 82586-based adapters on additional -+ VME boards. -+ -+config HPLANCE -+ bool "HP on-board LANCE support" -+ depends on DIO -+ select CRC32 -+ help -+ If you want to use the builtin "LANCE" Ethernet controller on an -+ HP300 machine, say Y here. -+ -+config LASI_82596 -+ tristate "Lasi ethernet" -+ depends on GSC -+ help -+ Say Y here to support the builtin Intel 82596 ethernet controller -+ found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet. -+ -+config SNI_82596 -+ tristate "SNI RM ethernet" -+ depends on NET_ETHERNET && SNI_RM -+ help -+ Say Y here to support the on-board Intel 82596 ethernet controller -+ built into SNI RM machines. -+ -+config MIPS_JAZZ_SONIC -+ tristate "MIPS JAZZ onboard SONIC Ethernet support" -+ depends on MACH_JAZZ -+ help -+ This is the driver for the onboard card of MIPS Magnum 4000, -+ Acer PICA, Olivetti M700-10 and a few other identical OEM systems. -+ -+config MIPS_AU1X00_ENET -+ bool "MIPS AU1000 Ethernet support" -+ depends on SOC_AU1X00 -+ select PHYLIB -+ select CRC32 -+ help -+ If you have an Alchemy Semi AU1X00 based system -+ say Y. Otherwise, say N. -+ -+config SGI_IOC3_ETH -+ bool "SGI IOC3 Ethernet" -+ depends on PCI && SGI_IP27 -+ select CRC32 -+ select MII -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+config MIPS_SIM_NET -+ tristate "MIPS simulator Network device" -+ depends on MIPS_SIM -+ help -+ The MIPSNET device is a simple Ethernet network device which is -+ emulated by the MIPS Simulator. -+ If you are not using a MIPSsim or are unsure, say N. -+ -+config SGI_O2MACE_ETH -+ tristate "SGI O2 MACE Fast Ethernet support" -+ depends on SGI_IP32=y -+ -+config STNIC -+ tristate "National DP83902AV support" -+ depends on SUPERH -+ select CRC32 -+ help -+ Support for cards based on the National Semiconductor DP83902AV -+ ST-NIC Serial Network Interface Controller for Twisted Pair. This -+ is a 10Mbit/sec Ethernet controller. Product overview and specs at -+ . -+ -+ If unsure, say N. -+ -+config SUNLANCE -+ tristate "Sun LANCE support" -+ depends on SBUS -+ select CRC32 -+ help -+ This driver supports the "le" interface present on all 32-bit Sparc -+ systems, on some older Ultra systems and as an Sbus option. These -+ cards are based on the AMD Lance chipset, which is better known -+ via the NE2100 cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sunlance. -+ -+config HAPPYMEAL -+ tristate "Sun Happy Meal 10/100baseT support" -+ depends on SBUS || PCI -+ select CRC32 -+ help -+ This driver supports the "hme" interface present on most Ultra -+ systems and as an option on older Sbus systems. This driver supports -+ both PCI and Sbus devices. This driver also supports the "qfe" quad -+ 100baseT device available in both PCI and Sbus configurations. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sunhme. -+ -+config SUNBMAC -+ tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)" -+ depends on SBUS && EXPERIMENTAL -+ select CRC32 -+ help -+ This driver supports the "be" interface available as an Sbus option. -+ This is Sun's older 100baseT Ethernet device. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sunbmac. -+ -+config SUNQE -+ tristate "Sun QuadEthernet support" -+ depends on SBUS -+ select CRC32 -+ help -+ This driver supports the "qe" 10baseT Ethernet device, available as -+ an Sbus option. Note that this is not the same as Quad FastEthernet -+ "qfe" which is supported by the Happy Meal driver instead. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sunqe. -+ -+config SUNGEM -+ tristate "Sun GEM support" -+ depends on PCI -+ select CRC32 -+ help -+ Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also -+ . -+ -+config CASSINI -+ tristate "Sun Cassini support" -+ depends on PCI -+ select CRC32 -+ help -+ Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also -+ -+ -+config SUNVNET -+ tristate "Sun Virtual Network support" -+ depends on SUN_LDOMS -+ help -+ Support for virtual network devices under Sun Logical Domains. -+ -+config NET_VENDOR_3COM -+ bool "3COM cards" -+ depends on ISA || EISA || MCA || PCI -+ help -+ If you have a network (Ethernet) card belonging to this class, say Y -+ and read the Ethernet-HOWTO, available from -+ . -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about 3COM cards. If you say Y, you will be asked for -+ your specific card in the following questions. -+ -+config EL1 -+ tristate "3c501 \"EtherLink\" support" -+ depends on NET_VENDOR_3COM && ISA -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . Also, consider buying a -+ new card, since the 3c501 is slow, broken, and obsolete: you will -+ have problems. Some people suggest to ping ("man ping") a nearby -+ machine every minute ("man cron") when using this card. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c501. -+ -+config EL2 -+ tristate "3c503 \"EtherLink II\" support" -+ depends on NET_VENDOR_3COM && ISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c503. -+ -+config ELPLUS -+ tristate "3c505 \"EtherLink Plus\" support" -+ depends on NET_VENDOR_3COM && ISA && ISA_DMA_API -+ ---help--- -+ Information about this network (Ethernet) card can be found in -+ . If you have a card of -+ this type, say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c505. -+ -+config EL16 -+ tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)" -+ depends on NET_VENDOR_3COM && ISA && EXPERIMENTAL -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c507. -+ -+config EL3 -+ tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support" -+ depends on NET_VENDOR_3COM && (ISA || EISA || MCA) -+ ---help--- -+ If you have a network (Ethernet) card belonging to the 3Com -+ EtherLinkIII series, say Y and read the Ethernet-HOWTO, available -+ from . -+ -+ If your card is not working you may need to use the DOS -+ setup disk to disable Plug & Play mode, and to select the default -+ media type. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c509. -+ -+config 3C515 -+ tristate "3c515 ISA \"Fast EtherLink\"" -+ depends on NET_VENDOR_3COM && (ISA || EISA) && ISA_DMA_API -+ help -+ If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet -+ network card, say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c515. -+ -+config ELMC -+ tristate "3c523 \"EtherLink/MC\" support" -+ depends on NET_VENDOR_3COM && MCA_LEGACY -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c523. -+ -+config ELMC_II -+ tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)" -+ depends on NET_VENDOR_3COM && MCA && MCA_LEGACY -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called 3c527. -+ -+config VORTEX -+ tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" -+ depends on NET_VENDOR_3COM && (PCI || EISA) -+ select MII -+ ---help--- -+ This option enables driver support for a large number of 10Mbps and -+ 10/100Mbps EISA, PCI and PCMCIA 3Com network cards: -+ -+ "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI -+ "Boomerang" (EtherLink XL 3c900 or 3c905) PCI -+ "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus -+ "Tornado" (3c905) PCI -+ "Hurricane" (3c555/3cSOHO) PCI -+ -+ If you have such a card, say Y and read the Ethernet-HOWTO, -+ available from . More -+ specific information is in -+ and in the comments at -+ the beginning of . -+ -+ To compile this support as a module, choose M here. -+ -+config TYPHOON -+ tristate "3cr990 series \"Typhoon\" support" -+ depends on NET_VENDOR_3COM && PCI -+ select CRC32 -+ ---help--- -+ This option enables driver support for the 3cr990 series of cards: -+ -+ 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97, -+ 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server, -+ 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR -+ -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called typhoon. -+ -+config LANCE -+ tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" -+ depends on ISA && ISA_DMA_API -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . Some LinkSys cards are -+ of this type. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called lance. This is recommended. -+ -+config NET_VENDOR_SMC -+ bool "Western Digital/SMC cards" -+ depends on ISA || MCA || EISA || MAC -+ help -+ If you have a network (Ethernet) card belonging to this class, say Y -+ and read the Ethernet-HOWTO, available from -+ . -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about Western Digital cards. If you say Y, you will be -+ asked for your specific card in the following questions. -+ -+config WD80x3 -+ tristate "WD80*3 support" -+ depends on NET_VENDOR_SMC && ISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called wd. -+ -+config ULTRAMCA -+ tristate "SMC Ultra MCA support" -+ depends on NET_VENDOR_SMC && MCA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type and are running -+ an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, -+ available from . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called smc-mca. -+ -+config ULTRA -+ tristate "SMC Ultra support" -+ depends on NET_VENDOR_SMC && ISA -+ select CRC32 -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ Important: There have been many reports that, with some motherboards -+ mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, -+ such as some BusLogic models) causes corruption problems with many -+ operating systems. The Linux smc-ultra driver has a work-around for -+ this but keep it in mind if you have such a SCSI card and have -+ problems. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called smc-ultra. -+ -+config ULTRA32 -+ tristate "SMC Ultra32 EISA support" -+ depends on NET_VENDOR_SMC && EISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called smc-ultra32. -+ -+config BFIN_MAC -+ tristate "Blackfin 536/537 on-chip mac support" -+ depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H) -+ select CRC32 -+ select MII -+ select PHYLIB -+ select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE -+ help -+ This is the driver for blackfin on-chip mac device. Say Y if you want it -+ compiled into the kernel. This driver is also available as a module -+ ( = code which can be inserted in and removed from the running kernel -+ whenever you want). The module will be called bfin_mac. -+ -+config BFIN_MAC_USE_L1 -+ bool "Use L1 memory for rx/tx packets" -+ depends on BFIN_MAC && BF537 -+ default y -+ help -+ To get maximum network performance, you should use L1 memory as rx/tx buffers. -+ Say N here if you want to reserve L1 memory for other uses. -+ -+config BFIN_TX_DESC_NUM -+ int "Number of transmit buffer packets" -+ depends on BFIN_MAC -+ range 6 10 if BFIN_MAC_USE_L1 -+ range 10 100 -+ default "10" -+ help -+ Set the number of buffer packets used in driver. -+ -+config BFIN_RX_DESC_NUM -+ int "Number of receive buffer packets" -+ depends on BFIN_MAC -+ range 20 100 if BFIN_MAC_USE_L1 -+ range 20 800 -+ default "20" -+ help -+ Set the number of buffer packets used in driver. -+ -+config BFIN_MAC_RMII -+ bool "RMII PHY Interface (EXPERIMENTAL)" -+ depends on BFIN_MAC && EXPERIMENTAL -+ default n -+ help -+ Use Reduced PHY MII Interface -+ -+config SMC9194 -+ tristate "SMC 9194 support" -+ depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN) -+ select CRC32 -+ ---help--- -+ This is support for the SMC9xxx based Ethernet cards. Choose this -+ option if you have a DELL laptop with the docking station, or -+ another SMC9192/9194 based chipset. Say Y if you want it compiled -+ into the kernel, and read the file -+ and the Ethernet-HOWTO, -+ available from . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called smc9194. -+ -+config SMC91X -+ tristate "SMC 91C9x/91C1xxx support" -+ select CRC32 -+ select MII -+ depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BLACKFIN -+ help -+ This is a driver for SMC's 91x series of Ethernet chipsets, -+ including the SMC91C94 and the SMC91C111. Say Y if you want it -+ compiled into the kernel, and read the file -+ and the Ethernet-HOWTO, -+ available from . -+ -+ This driver is also available as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ The module will be called smc91x. If you want to compile it as a -+ module, say M here and read . -+ -+config NET_NETX -+ tristate "NetX Ethernet support" -+ select MII -+ depends on ARCH_NETX -+ help -+ This is support for the Hilscher netX builtin Ethernet ports -+ -+ To compile this driver as a module, choose M here. The module -+ will be called netx-eth. -+ -+config DM9000 -+ tristate "DM9000 support" -+ depends on ARM || BLACKFIN || MIPS -+ select CRC32 -+ select MII -+ ---help--- -+ Support for DM9000 chipset. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called dm9000. -+ -+config SMC911X -+ tristate "SMSC LAN911[5678] support" -+ select CRC32 -+ select MII -+ depends on ARCH_PXA || SH_MAGIC_PANEL_R2 -+ help -+ This is a driver for SMSC's LAN911x series of Ethernet chipsets -+ including the new LAN9115, LAN9116, LAN9117, and LAN9118. -+ Say Y if you want it compiled into the kernel, -+ and read the Ethernet-HOWTO, available from -+ . -+ -+ This driver is also available as a module. The module will be -+ called smc911x. If you want to compile it as a module, say M -+ here and read -+ -+config NET_VENDOR_RACAL -+ bool "Racal-Interlan (Micom) NI cards" -+ depends on ISA -+ help -+ If you have a network (Ethernet) card belonging to this class, such -+ as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, -+ available from . -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about NI cards. If you say Y, you will be asked for -+ your specific card in the following questions. -+ -+config NI5010 -+ tristate "NI5010 support (EXPERIMENTAL)" -+ depends on NET_VENDOR_RACAL && ISA && EXPERIMENTAL && BROKEN_ON_SMP -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . Note that this is still -+ experimental code. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ni5010. -+ -+config NI52 -+ tristate "NI5210 support" -+ depends on NET_VENDOR_RACAL && ISA -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ni52. -+ -+config NI65 -+ tristate "NI6510 support" -+ depends on NET_VENDOR_RACAL && ISA && ISA_DMA_API -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ni65. -+ -+source "drivers/net/tulip/Kconfig" -+ -+config AT1700 -+ tristate "AT1700/1720 support (EXPERIMENTAL)" -+ depends on (ISA || MCA_LEGACY) && EXPERIMENTAL -+ select CRC32 -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called at1700. -+ -+config DEPCA -+ tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support" -+ depends on ISA || EISA || MCA -+ select CRC32 -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ as well as -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called depca. -+ -+config HP100 -+ tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" -+ depends on ISA || EISA || PCI -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called hp100. -+ -+config NET_ISA -+ bool "Other ISA cards" -+ depends on ISA -+ ---help--- -+ If your network (Ethernet) card hasn't been mentioned yet and its -+ bus system (that's the way the cards talks to the other components -+ of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. -+ Make sure you know the name of your card. Read the Ethernet-HOWTO, -+ available from . -+ -+ If unsure, say Y. -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the remaining ISA network card questions. If you say Y, you will be -+ asked for your specific card in the following questions. -+ -+config E2100 -+ tristate "Cabletron E21xx support" -+ depends on NET_ISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called e2100. -+ -+config EWRK3 -+ tristate "EtherWORKS 3 (DE203, DE204, DE205) support" -+ depends on NET_ISA -+ select CRC32 -+ ---help--- -+ This driver supports the DE203, DE204 and DE205 network (Ethernet) -+ cards. If this is for you, say Y and read -+ in the kernel source as -+ well as the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ewrk3. -+ -+config EEXPRESS -+ tristate "EtherExpress 16 support" -+ depends on NET_ISA -+ ---help--- -+ If you have an EtherExpress16 network (Ethernet) card, say Y and -+ read the Ethernet-HOWTO, available from -+ . Note that the Intel -+ EtherExpress16 card used to be regarded as a very poor choice -+ because the driver was very unreliable. We now have a new driver -+ that should do better. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called eexpress. -+ -+config EEXPRESS_PRO -+ tristate "EtherExpressPro support/EtherExpress 10 (i82595) support" -+ depends on NET_ISA -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y. This -+ driver supports Intel i82595{FX,TX} based boards. Note however -+ that the EtherExpress PRO/100 Ethernet card has its own separate -+ driver. Please read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called eepro. -+ -+config HPLAN_PLUS -+ tristate "HP PCLAN+ (27247B and 27252A) support" -+ depends on NET_ISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called hp-plus. -+ -+config HPLAN -+ tristate "HP PCLAN (27245 and other 27xxx series) support" -+ depends on NET_ISA -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called hp. -+ -+config LP486E -+ tristate "LP486E on board Ethernet" -+ depends on NET_ISA -+ help -+ Say Y here to support the 82596-based on-board Ethernet controller -+ for the Panther motherboard, which is one of the two shipped in the -+ Intel Professional Workstation. -+ -+config ETH16I -+ tristate "ICL EtherTeam 16i/32 support" -+ depends on NET_ISA -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called eth16i. -+ -+config NE2000 -+ tristate "NE2000/NE1000 support" -+ depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938 -+ select CRC32 -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . Many Ethernet cards -+ without a specific driver are compatible with NE2000. -+ -+ If you have a PCI NE2000 card however, say N here and Y to "PCI -+ NE2000 and clone support" under "EISA, VLB, PCI and on board -+ controllers" below. If you have a NE2000 card and are running on -+ an MCA system (a bus system used on some IBM PS/2 computers and -+ laptops), say N here and Y to "NE/2 (ne2000 MCA version) support", -+ below. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ne. -+ -+config ZNET -+ tristate "Zenith Z-Note support (EXPERIMENTAL)" -+ depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API -+ help -+ The Zenith Z-Note notebook computer has a built-in network -+ (Ethernet) card, and this is the Linux driver for it. Note that the -+ IBM Thinkpad 300 is compatible with the Z-Note and is also supported -+ by this driver. Read the Ethernet-HOWTO, available from -+ . -+ -+config SEEQ8005 -+ tristate "SEEQ8005 support (EXPERIMENTAL)" -+ depends on NET_ISA && EXPERIMENTAL -+ help -+ This is a driver for the SEEQ 8005 network (Ethernet) card. If this -+ is for you, read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called seeq8005. -+ -+config NE2_MCA -+ tristate "NE/2 (ne2000 MCA version) support" -+ depends on MCA_LEGACY -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ne2. -+ -+config IBMLANA -+ tristate "IBM LAN Adapter/A support" -+ depends on MCA && MCA_LEGACY -+ ---help--- -+ This is a Micro Channel Ethernet adapter. You need to set -+ CONFIG_MCA to use this driver. It is both available as an in-kernel -+ driver and as a module. -+ -+ To compile this driver as a module, choose M here. The only -+ currently supported card is the IBM LAN Adapter/A for Ethernet. It -+ will both support 16K and 32K memory windows, however a 32K window -+ gives a better security against packet losses. Usage of multiple -+ boards with this driver should be possible, but has not been tested -+ up to now due to lack of hardware. -+ -+config IBMVETH -+ tristate "IBM LAN Virtual Ethernet support" -+ depends on PPC_PSERIES -+ ---help--- -+ This driver supports virtual ethernet adapters on newer IBM iSeries -+ and pSeries systems. -+ -+ To compile this driver as a module, choose M here. The module will -+ be called ibmveth. -+ -+source "drivers/net/ibm_emac/Kconfig" -+source "drivers/net/ibm_newemac/Kconfig" -+ -+config NET_PCI -+ bool "EISA, VLB, PCI and on board controllers" -+ depends on ISA || EISA || PCI -+ help -+ This is another class of network cards which attach directly to the -+ bus. If you have one of those, say Y and read the Ethernet-HOWTO, -+ available from . -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about this class of network cards. If you say Y, you -+ will be asked for your specific card in the following questions. If -+ you are unsure, say Y. -+ -+config PCNET32 -+ tristate "AMD PCnet32 PCI support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ If you have a PCnet32 or PCnetPCI based network (Ethernet) card, -+ answer Y here and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called pcnet32. -+ -+config PCNET32_NAPI -+ bool "Use RX polling (NAPI)" -+ depends on PCNET32 -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config AMD8111_ETH -+ tristate "AMD 8111 (new PCI lance) support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ If you have an AMD 8111-based PCI lance ethernet card, -+ answer Y here and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called amd8111e. -+ -+config AMD8111E_NAPI -+ bool "Use RX polling (NAPI)" -+ depends on AMD8111_ETH -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config ADAPTEC_STARFIRE -+ tristate "Adaptec Starfire/DuraLAN support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network -+ adapter. The DuraLAN chip is used on the 64 bit PCI boards from -+ Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip -+ driver. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called starfire. This is recommended. -+ -+config ADAPTEC_STARFIRE_NAPI -+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -+ depends on ADAPTEC_STARFIRE && EXPERIMENTAL -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config AC3200 -+ tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)" -+ depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ac3200. -+ -+config APRICOT -+ tristate "Apricot Xen-II on board Ethernet" -+ depends on NET_PCI && ISA -+ help -+ If you have a network (Ethernet) controller of this type, say Y and -+ read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called apricot. -+ -+config B44 -+ tristate "Broadcom 440x/47xx ethernet support" -+ depends on SSB_POSSIBLE -+ select SSB -+ select MII -+ help -+ If you have a network (Ethernet) controller of this type, say Y -+ or M and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called b44. -+ -+# Auto-select SSB PCI-HOST support, if possible -+config B44_PCI_AUTOSELECT -+ bool -+ depends on B44 && SSB_PCIHOST_POSSIBLE -+ select SSB_PCIHOST -+ default y -+ -+# Auto-select SSB PCICORE driver, if possible -+config B44_PCICORE_AUTOSELECT -+ bool -+ depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE -+ select SSB_DRIVER_PCICORE -+ default y -+ -+config B44_PCI -+ bool -+ depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT -+ default y -+ -+config FORCEDETH -+ tristate "nForce Ethernet support" -+ depends on NET_PCI && PCI -+ help -+ If you have a network (Ethernet) controller of this type, say Y and -+ read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called forcedeth. -+ -+config FORCEDETH_NAPI -+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -+ depends on FORCEDETH && EXPERIMENTAL -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config CS89x0 -+ tristate "CS89x0 support" -+ depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X) -+ ---help--- -+ Support for CS89x0 chipset based Ethernet cards. If you have a -+ network (Ethernet) card of this type, say Y and read the -+ Ethernet-HOWTO, available from -+ as well as -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called cs89x0. -+ -+config TC35815 -+ tristate "TOSHIBA TC35815 Ethernet support" -+ depends on NET_PCI && PCI && MIPS -+ select MII -+ -+config EEPRO100 -+ tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" -+ depends on NET_PCI && PCI -+ select MII -+ help -+ If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) -+ card, say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called eepro100. -+ -+ -+config E100 -+ tristate "Intel(R) PRO/100+ support" -+ depends on NET_PCI && PCI -+ select MII -+ ---help--- -+ This driver supports Intel(R) PRO/100 family of adapters. -+ To verify that your adapter is supported, find the board ID number -+ on the adapter. Look for a label that has a barcode and a number -+ in the format 123456-001 (six digits hyphen three digits). -+ -+ Use the above information and the Adapter & Driver ID Guide at: -+ -+ -+ -+ to identify the adapter. -+ -+ For the latest Intel PRO/100 network driver for Linux, see: -+ -+ -+ -+ More specific information on configuring the driver is in -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called e100. -+ -+config LNE390 -+ tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)" -+ depends on NET_PCI && EISA && EXPERIMENTAL -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called lne390. -+ -+config FEALNX -+ tristate "Myson MTD-8xx PCI Ethernet support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet -+ cards. Specifications and data at -+ . -+ -+config NATSEMI -+ tristate "National Semiconductor DP8381x series PCI Ethernet support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ help -+ This driver is for the National Semiconductor DP83810 series, -+ which is used in cards from PureData, NetGear, Linksys -+ and others, including the 83815 chip. -+ More specific information and updates are available from -+ . -+ -+config NE2K_PCI -+ tristate "PCI NE2000 and clones support (see help)" -+ depends on NET_PCI && PCI -+ select CRC32 -+ ---help--- -+ This driver is for NE2000 compatible PCI cards. It will not work -+ with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 -+ support" below). If you have a PCI NE2000 network (Ethernet) card, -+ say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ This driver also works for the following NE2000 clone cards: -+ RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 -+ NetVin NV5000SC Via 86C926 SureCom NE34 Winbond -+ Holtek HT80232 Holtek HT80229 -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ne2k-pci. -+ -+config NE3210 -+ tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)" -+ depends on NET_PCI && EISA && EXPERIMENTAL -+ select CRC32 -+ ---help--- -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . Note that this driver -+ will NOT WORK for NE3200 cards as they are completely different. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ne3210. -+ -+config ES3210 -+ tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)" -+ depends on NET_PCI && EISA && EXPERIMENTAL -+ select CRC32 -+ help -+ If you have a network (Ethernet) card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called es3210. -+ -+config 8139CP -+ tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)" -+ depends on NET_PCI && PCI && EXPERIMENTAL -+ select CRC32 -+ select MII -+ help -+ This is a driver for the Fast Ethernet PCI network cards based on -+ the RTL8139C+ chips. If you have one of those, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called 8139cp. This is recommended. -+ -+config 8139TOO -+ tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ ---help--- -+ This is a driver for the Fast Ethernet PCI network cards based on -+ the RTL 8129/8130/8139 chips. If you have one of those, say Y and -+ read the Ethernet-HOWTO . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called 8139too. This is recommended. -+ -+config 8139TOO_PIO -+ bool "Use PIO instead of MMIO" -+ default y -+ depends on 8139TOO -+ help -+ This instructs the driver to use programmed I/O ports (PIO) instead -+ of PCI shared memory (MMIO). This can possibly solve some problems -+ in case your mainboard has memory consistency issues. If unsure, -+ say N. -+ -+config 8139TOO_TUNE_TWISTER -+ bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)" -+ depends on 8139TOO -+ help -+ This implements a function which might come in handy in case you -+ are using low quality on long cabling. It is required for RealTek -+ RTL-8139 revision K boards, and totally unused otherwise. It tries -+ to match the transceiver to the cable characteristics. This is -+ experimental since hardly documented by the manufacturer. -+ If unsure, say Y. -+ -+config 8139TOO_8129 -+ bool "Support for older RTL-8129/8130 boards" -+ depends on 8139TOO -+ help -+ This enables support for the older and uncommon RTL-8129 and -+ RTL-8130 chips, which support MII via an external transceiver, -+ instead of an internal one. Disabling this option will save some -+ memory by making the code size smaller. If unsure, say Y. -+ -+config 8139_OLD_RX_RESET -+ bool "Use older RX-reset method" -+ depends on 8139TOO -+ help -+ The 8139too driver was recently updated to contain a more rapid -+ reset sequence, in the face of severe receive errors. This "new" -+ RX-reset method should be adequate for all boards. But if you -+ experience problems, you can enable this option to restore the -+ old RX-reset behavior. If unsure, say N. -+ -+config SIS900 -+ tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ ---help--- -+ This is a driver for the Fast Ethernet PCI network cards based on -+ the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in -+ SiS 630 and SiS 540 chipsets. -+ -+ This driver also supports AMD 79C901 HomePNA so that you can use -+ your phone line as a network cable. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sis900. This is recommended. -+ -+config EPIC100 -+ tristate "SMC EtherPower II" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, -+ which is based on the SMC83c17x (EPIC/100). -+ More specific information and updates are available from -+ . -+ -+config SUNDANCE -+ tristate "Sundance Alta support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ This driver is for the Sundance "Alta" chip. -+ More specific information and updates are available from -+ . -+ -+config SUNDANCE_MMIO -+ bool "Use MMIO instead of PIO" -+ depends on SUNDANCE -+ help -+ Enable memory-mapped I/O for interaction with Sundance NIC registers. -+ Do NOT enable this by default, PIO (enabled when MMIO is disabled) -+ is known to solve bugs on certain chips. -+ -+ If unsure, say N. -+ -+config TLAN -+ tristate "TI ThunderLAN support" -+ depends on NET_PCI && (PCI || EISA) && !64BIT -+ ---help--- -+ If you have a PCI Ethernet network card based on the ThunderLAN chip -+ which is supported by this driver, say Y and read the -+ Ethernet-HOWTO, available from -+ . -+ -+ Devices currently supported by this driver are Compaq Netelligent, -+ Compaq NetFlex and Olicom cards. Please read the file -+ for more details. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called tlan. -+ -+ Please email feedback to . -+ -+config VIA_RHINE -+ tristate "VIA Rhine support" -+ depends on NET_PCI && PCI -+ select CRC32 -+ select MII -+ help -+ If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A), -+ Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type -+ Ethernet functions can also be found integrated on South Bridges -+ (e.g. VT8235). -+ -+ To compile this driver as a module, choose M here. The module -+ will be called via-rhine. -+ -+config VIA_RHINE_MMIO -+ bool "Use MMIO instead of PIO" -+ depends on VIA_RHINE -+ help -+ This instructs the driver to use PCI shared memory (MMIO) instead of -+ programmed I/O ports (PIO). Enabling this gives an improvement in -+ processing time in parts of the driver. -+ -+ If unsure, say Y. -+ -+config VIA_RHINE_NAPI -+ bool "Use Rx Polling (NAPI)" -+ depends on VIA_RHINE -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+config LAN_SAA9730 -+ bool "Philips SAA9730 Ethernet support" -+ depends on NET_PCI && PCI && MIPS_ATLAS -+ help -+ The SAA9730 is a combined multimedia and peripheral controller used -+ in thin clients, Internet access terminals, and diskless -+ workstations. -+ See . -+ -+config SC92031 -+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" -+ depends on NET_PCI && PCI && EXPERIMENTAL -+ select CRC32 -+ ---help--- -+ This is a driver for the Fast Ethernet PCI network cards based on -+ the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you -+ have one of these, say Y here. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sc92031. This is recommended. -+ -+config CPMAC -+ tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" -+ depends on NET_ETHERNET && EXPERIMENTAL && AR7 -+ select PHYLIB -+ select FIXED_PHY -+ select FIXED_MII_100_FDX -+ help -+ TI AR7 CPMAC Ethernet support -+ -+config NET_POCKET -+ bool "Pocket and portable adapters" -+ depends on PARPORT -+ ---help--- -+ Cute little network (Ethernet) devices which attach to the parallel -+ port ("pocket adapters"), commonly used with laptops. If you have -+ one of those, say Y and read the Ethernet-HOWTO, available from -+ . -+ -+ If you want to plug a network (or some other) card into the PCMCIA -+ (or PC-card) slot of your laptop instead (PCMCIA is the standard for -+ credit card size extension cards used by all modern laptops), you -+ need the pcmcia-cs package (location contained in the file -+ ) and you can say N here. -+ -+ Laptop users should read the Linux Laptop home page at -+ or -+ Tuxmobil - Linux on Mobile Computers at . -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about this class of network devices. If you say Y, you -+ will be asked for your specific device in the following questions. -+ -+config ATP -+ tristate "AT-LAN-TEC/RealTek pocket adapter support" -+ depends on NET_POCKET && PARPORT && X86 -+ select CRC32 -+ ---help--- -+ This is a network (Ethernet) device which attaches to your parallel -+ port. Read as well as the Ethernet-HOWTO, -+ available from , if you -+ want to use this. If you intend to use this driver, you should have -+ said N to the "Parallel printer support", because the two drivers -+ don't like each other. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called atp. -+ -+config DE600 -+ tristate "D-Link DE600 pocket adapter support" -+ depends on NET_POCKET && PARPORT -+ ---help--- -+ This is a network (Ethernet) device which attaches to your parallel -+ port. Read as well as the -+ Ethernet-HOWTO, available from -+ , if you want to use -+ this. It is possible to have several devices share a single parallel -+ port and it is safe to compile the corresponding drivers into the -+ kernel. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called de600. -+ -+config DE620 -+ tristate "D-Link DE620 pocket adapter support" -+ depends on NET_POCKET && PARPORT -+ ---help--- -+ This is a network (Ethernet) device which attaches to your parallel -+ port. Read as well as the -+ Ethernet-HOWTO, available from -+ , if you want to use -+ this. It is possible to have several devices share a single parallel -+ port and it is safe to compile the corresponding drivers into the -+ kernel. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called de620. -+ -+config SGISEEQ -+ tristate "SGI Seeq ethernet controller support" -+ depends on SGI_IP22 -+ help -+ Say Y here if you have an Seeq based Ethernet network card. This is -+ used in many Silicon Graphics machines. -+ -+config DECLANCE -+ tristate "DEC LANCE ethernet controller support" -+ depends on MACH_DECSTATION -+ select CRC32 -+ help -+ This driver is for the series of Ethernet controllers produced by -+ DEC (now Compaq) based on the AMD Lance chipset, including the -+ DEPCA series. (This chipset is better known via the NE2100 cards.) -+ -+config 68360_ENET -+ bool "Motorola 68360 ethernet controller" -+ depends on M68360 -+ help -+ Say Y here if you want to use the built-in ethernet controller of -+ the Motorola 68360 processor. -+ -+config FEC -+ bool "FEC ethernet controller (of ColdFire CPUs)" -+ depends on M523x || M527x || M5272 || M528x || M520x -+ help -+ Say Y here if you want to use the built-in 10/100 Fast ethernet -+ controller on some Motorola ColdFire processors. -+ -+config FEC2 -+ bool "Second FEC ethernet controller (on some ColdFire CPUs)" -+ depends on FEC -+ help -+ Say Y here if you want to use the second built-in 10/100 Fast -+ ethernet controller on some Motorola ColdFire processors. -+ -+config FEC_MPC52xx -+ tristate "MPC52xx FEC driver" -+ depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC -+ select CRC32 -+ select PHYLIB -+ ---help--- -+ This option enables support for the MPC5200's on-chip -+ Fast Ethernet Controller -+ If compiled as module, it will be called 'fec_mpc52xx.ko'. -+ -+config FEC_MPC52xx_MDIO -+ bool "MPC52xx FEC MDIO bus driver" -+ depends on FEC_MPC52xx -+ default y -+ ---help--- -+ The MPC5200's FEC can connect to the Ethernet either with -+ an external MII PHY chip or 10 Mbps 7-wire interface -+ (Motorola? industry standard). -+ If your board uses an external PHY connected to FEC, enable this. -+ If not sure, enable. -+ If compiled as module, it will be called 'fec_mpc52xx_phy.ko'. -+ -+config NE_H8300 -+ tristate "NE2000 compatible support for H8/300" -+ depends on H8300 -+ help -+ Say Y here if you want to use the NE2000 compatible -+ controller on the Renesas H8/300 processor. -+ -+source "drivers/net/fec_8xx/Kconfig" -+source "drivers/net/fs_enet/Kconfig" -+ -+endif # NET_ETHERNET -+ -+# -+# Gigabit Ethernet -+# -+ -+menuconfig NETDEV_1000 -+ bool "Ethernet (1000 Mbit)" -+ depends on !UML -+ default y -+ ---help--- -+ Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common -+ type of Local Area Network (LAN) in universities and companies. -+ -+ Say Y here to get to see options for Gigabit Ethernet drivers. -+ This option alone does not add any kernel code. -+ Note that drivers supporting both 100 and 1000 MBit may be listed -+ under "Ethernet (10 or 100MBit)" instead. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if NETDEV_1000 -+ -+config ACENIC -+ tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support" -+ depends on PCI -+ ---help--- -+ Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear -+ GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet -+ adapter. The driver allows for using the Jumbo Frame option (9000 -+ bytes/frame) however it requires that your switches can handle this -+ as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig -+ line. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called acenic. -+ -+config ACENIC_OMIT_TIGON_I -+ bool "Omit support for old Tigon I based AceNICs" -+ depends on ACENIC -+ help -+ Say Y here if you only have Tigon II based AceNICs and want to leave -+ out support for the older Tigon I based cards which are no longer -+ being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B -+ version)). This will reduce the size of the driver object by -+ app. 100KB. If you are not sure whether your card is a Tigon I or a -+ Tigon II, say N here. -+ -+ The safe and default value for this is N. -+ -+config DL2K -+ tristate "DL2000/TC902x-based Gigabit Ethernet support" -+ depends on PCI -+ select CRC32 -+ help -+ This driver supports DL2000/TC902x-based Gigabit ethernet cards, -+ which includes -+ D-Link DGE-550T Gigabit Ethernet Adapter. -+ D-Link DL2000-based Gigabit Ethernet Adapter. -+ Sundance/Tamarack TC902x Gigabit Ethernet Adapter. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called dl2k. -+ -+config E1000 -+ tristate "Intel(R) PRO/1000 Gigabit Ethernet support" -+ depends on PCI -+ ---help--- -+ This driver supports Intel(R) PRO/1000 gigabit ethernet family of -+ adapters. For more information on how to identify your adapter, go -+ to the Adapter & Driver ID Guide at: -+ -+ -+ -+ For general information and support, go to the Intel support -+ website at: -+ -+ -+ -+ More specific information on configuring the driver is in -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called e1000. -+ -+config E1000_NAPI -+ bool "Use Rx Polling (NAPI)" -+ depends on E1000 -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config E1000_DISABLE_PACKET_SPLIT -+ bool "Disable Packet Split for PCI express adapters" -+ depends on E1000 -+ help -+ Say Y here if you want to use the legacy receive path for PCI express -+ hardware. -+ -+ If in doubt, say N. -+ -+config E1000E -+ tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" -+ depends on PCI -+ ---help--- -+ This driver supports the PCI-Express Intel(R) PRO/1000 gigabit -+ ethernet family of adapters. For PCI or PCI-X e1000 adapters, -+ use the regular e1000 driver For more information on how to -+ identify your adapter, go to the Adapter & Driver ID Guide at: -+ -+ -+ -+ For general information and support, go to the Intel support -+ website at: -+ -+ -+ -+ To compile this driver as a module, choose M here. The module -+ will be called e1000e. -+ -+config IP1000 -+ tristate "IP1000 Gigabit Ethernet support" -+ depends on PCI && EXPERIMENTAL -+ select MII -+ ---help--- -+ This driver supports IP1000 gigabit Ethernet cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called ipg. This is recommended. -+ -+source "drivers/net/ixp2000/Kconfig" -+ -+config MYRI_SBUS -+ tristate "MyriCOM Gigabit Ethernet support" -+ depends on SBUS -+ help -+ This driver supports MyriCOM Sbus gigabit Ethernet cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called myri_sbus. This is recommended. -+ -+config NS83820 -+ tristate "National Semiconductor DP83820 support" -+ depends on PCI -+ help -+ This is a driver for the National Semiconductor DP83820 series -+ of gigabit ethernet MACs. Cards using this chipset include -+ the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX, -+ SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of -+ zero copy. -+ -+config HAMACHI -+ tristate "Packet Engines Hamachi GNIC-II support" -+ depends on PCI -+ select MII -+ help -+ If you have a Gigabit Ethernet card of this type, say Y and read -+ the Ethernet-HOWTO, available from -+ . -+ -+ To compile this driver as a module, choose M here. The module will be -+ called hamachi. -+ -+config YELLOWFIN -+ tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)" -+ depends on PCI && EXPERIMENTAL -+ select CRC32 -+ ---help--- -+ Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet -+ adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is -+ used by the Beowulf Linux cluster project. See -+ for more -+ information about this driver in particular and Beowulf in general. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called yellowfin. This is recommended. -+ -+config R8169 -+ tristate "Realtek 8169 gigabit ethernet support" -+ depends on PCI -+ select CRC32 -+ ---help--- -+ Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called r8169. This is recommended. -+ -+config R8169_NAPI -+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -+ depends on R8169 && EXPERIMENTAL -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config R8169_VLAN -+ bool "VLAN support" -+ depends on R8169 && VLAN_8021Q -+ ---help--- -+ Say Y here for the r8169 driver to support the functions required -+ by the kernel 802.1Q code. -+ -+ If in doubt, say Y. -+ -+config SB1250_MAC -+ tristate "SB1250 Gigabit Ethernet support" -+ depends on SIBYTE_SB1xxx_SOC -+ select PHYLIB -+ ---help--- -+ This driver supports Gigabit Ethernet interfaces based on the -+ Broadcom SiByte family of System-On-a-Chip parts. They include -+ the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455 -+ and BCM1480 chips. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sb1250-mac. -+ -+config SIS190 -+ tristate "SiS190/SiS191 gigabit ethernet support" -+ depends on PCI -+ select CRC32 -+ select MII -+ ---help--- -+ Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or -+ a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to -+ appear in lan on motherboard designs which are based on SiS 965 -+ and SiS 966 south bridge. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sis190. This is recommended. -+ -+config SKGE -+ tristate "New SysKonnect GigaEthernet support" -+ depends on PCI -+ select CRC32 -+ ---help--- -+ This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx -+ and related Gigabit Ethernet adapters. It is a new smaller driver -+ with better performance and more complete ethtool support. -+ -+ It does not support the link failover and network management -+ features that "portable" vendor supplied sk98lin driver does. -+ -+ This driver supports adapters based on the original Yukon chipset: -+ Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T, -+ Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872. -+ -+ It does not support the newer Yukon2 chipset: a separate driver, -+ sky2, is provided for Yukon2-based adapters. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called skge. This is recommended. -+ -+config SKGE_DEBUG -+ bool "Debugging interface" -+ depends on SKGE && DEBUG_FS -+ help -+ This option adds the ability to dump driver state for debugging. -+ The file debugfs/skge/ethX displays the state of the internal -+ transmit and receive rings. -+ -+ If unsure, say N. -+ -+config SKY2 -+ tristate "SysKonnect Yukon2 support" -+ depends on PCI -+ select CRC32 -+ ---help--- -+ This driver supports Gigabit Ethernet adapters based on the -+ Marvell Yukon 2 chipset: -+ Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/ -+ 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21 -+ -+ There is companion driver for the older Marvell Yukon and -+ Genesis based adapters: skge. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called sky2. This is recommended. -+ -+config SKY2_DEBUG -+ bool "Debugging interface" -+ depends on SKY2 && DEBUG_FS -+ help -+ This option adds the ability to dump driver state for debugging. -+ The file debugfs/sky2/ethX displays the state of the internal -+ transmit and receive rings. -+ -+ If unsure, say N. -+ -+config SK98LIN -+ tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)" -+ depends on PCI -+ ---help--- -+ Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx -+ compliant Gigabit Ethernet Adapter. -+ -+ This driver supports the original Yukon chipset. This driver is -+ deprecated and will be removed from the kernel in the near future, -+ it has been replaced by the skge driver. skge is cleaner and -+ seems to work better. -+ -+ This driver does not support the newer Yukon2 chipset. A separate -+ driver, sky2, is provided to support Yukon2-based adapters. -+ -+ The following adapters are supported by this driver: -+ - 3Com 3C940 Gigabit LOM Ethernet Adapter -+ - 3Com 3C941 Gigabit LOM Ethernet Adapter -+ - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter -+ - Allied Telesyn AT-2971T Gigabit Ethernet Adapter -+ - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45 -+ - EG1032 v2 Instant Gigabit Network Adapter -+ - EG1064 v2 Instant Gigabit Network Adapter -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte) -+ - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill) -+ - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel) -+ - Marvell RDK-8001 Adapter -+ - Marvell RDK-8002 Adapter -+ - Marvell RDK-8003 Adapter -+ - Marvell RDK-8004 Adapter -+ - Marvell RDK-8006 Adapter -+ - Marvell RDK-8007 Adapter -+ - Marvell RDK-8008 Adapter -+ - Marvell RDK-8009 Adapter -+ - Marvell RDK-8010 Adapter -+ - Marvell RDK-8011 Adapter -+ - Marvell RDK-8012 Adapter -+ - Marvell RDK-8052 Adapter -+ - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit) -+ - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit) -+ - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L) -+ - SK-9521 10/100/1000Base-T Adapter -+ - SK-9521 V2.0 10/100/1000Base-T Adapter -+ - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T) -+ - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter -+ - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link) -+ - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX) -+ - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter -+ - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link) -+ - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX) -+ - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter -+ - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link) -+ - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter -+ - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition) -+ - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter -+ - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link) -+ - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX) -+ - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter -+ - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link) -+ - SMC EZ Card 1000 (SMC9452TXV.2) -+ -+ The adapters support Jumbo Frames. -+ The dual link adapters support link-failover and dual port features. -+ Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support -+ the scatter-gather functionality with sendfile(). Please refer to -+ for more information about -+ optional driver parameters. -+ Questions concerning this driver may be addressed to: -+ -+ -+ If you want to compile this driver as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want), -+ say M here and read . The module will -+ be called sk98lin. This is recommended. -+ -+config VIA_VELOCITY -+ tristate "VIA Velocity support" -+ depends on PCI -+ select CRC32 -+ select CRC_CCITT -+ select MII -+ help -+ If you have a VIA "Velocity" based network card say Y here. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called via-velocity. -+ -+config TIGON3 -+ tristate "Broadcom Tigon3 support" -+ depends on PCI -+ help -+ This driver supports Broadcom Tigon3 based gigabit Ethernet cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called tg3. This is recommended. -+ -+config BNX2 -+ tristate "Broadcom NetXtremeII support" -+ depends on PCI -+ select CRC32 -+ select ZLIB_INFLATE -+ help -+ This driver supports Broadcom NetXtremeII gigabit Ethernet cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called bnx2. This is recommended. -+ -+config SPIDER_NET -+ tristate "Spider Gigabit Ethernet driver" -+ depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) -+ select FW_LOADER -+ help -+ This driver supports the Gigabit Ethernet chips present on the -+ Cell Processor-Based Blades from IBM. -+ -+config TSI108_ETH -+ tristate "Tundra TSI108 gigabit Ethernet support" -+ depends on TSI108_BRIDGE -+ help -+ This driver supports Tundra TSI108 gigabit Ethernet ports. -+ To compile this driver as a module, choose M here: the module -+ will be called tsi108_eth. -+ -+config GELIC_NET -+ tristate "PS3 Gigabit Ethernet driver" -+ depends on PPC_PS3 -+ help -+ This driver supports the network device on the PS3 game -+ console. This driver has built-in support for Ethernet. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called ps3_gelic. -+ -+config GIANFAR -+ tristate "Gianfar Ethernet" -+ depends on 85xx || 83xx || PPC_86xx -+ select PHYLIB -+ select CRC32 -+ help -+ This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, -+ and MPC86xx family of chips, and the FEC on the 8540. -+ -+config GFAR_NAPI -+ bool "Use Rx Polling (NAPI)" -+ depends on GIANFAR -+ -+config UCC_GETH -+ tristate "Freescale QE Gigabit Ethernet" -+ depends on QUICC_ENGINE -+ select PHYLIB -+ help -+ This driver supports the Gigabit Ethernet mode of the QUICC Engine, -+ which is available on some Freescale SOCs. -+ -+config UGETH_NAPI -+ bool "Use Rx Polling (NAPI)" -+ depends on UCC_GETH -+ -+config UGETH_MAGIC_PACKET -+ bool "Magic Packet detection support" -+ depends on UCC_GETH -+ -+config UGETH_FILTERING -+ bool "Mac address filtering support" -+ depends on UCC_GETH -+ -+config UGETH_TX_ON_DEMAND -+ bool "Transmit on Demand support" -+ depends on UCC_GETH -+ -+config MV643XX_ETH -+ tristate "Marvell Discovery (643XX) and Orion ethernet support" -+ depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION -+ select MII -+ help -+ This driver supports the gigabit ethernet MACs in the -+ Marvell Discovery PPC/MIPS chipset family (MV643XX) and -+ in the Marvell Orion ARM SoC family. -+ -+ Some boards that use the Discovery chipset are the Momenco -+ Ocelot C and Jaguar ATX and Pegasos II. -+ -+config QLA3XXX -+ tristate "QLogic QLA3XXX Network Driver Support" -+ depends on PCI -+ help -+ This driver supports QLogic ISP3XXX gigabit Ethernet cards. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called qla3xxx. -+ -+config ATL1 -+ tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" -+ depends on PCI && EXPERIMENTAL -+ select CRC32 -+ select MII -+ help -+ This driver supports the Attansic L1 gigabit ethernet adapter. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called atl1. -+ -+endif # NETDEV_1000 -+ -+# -+# 10 Gigabit Ethernet -+# -+ -+menuconfig NETDEV_10000 -+ bool "Ethernet (10000 Mbit)" -+ depends on !UML -+ default y -+ ---help--- -+ Say Y here to get to see options for 10 Gigabit Ethernet drivers. -+ This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and disabled. -+ -+if NETDEV_10000 -+ -+config CHELSIO_T1 -+ tristate "Chelsio 10Gb Ethernet support" -+ depends on PCI -+ select CRC32 -+ help -+ This driver supports Chelsio gigabit and 10-gigabit -+ Ethernet cards. More information about adapter features and -+ performance tuning is in . -+ -+ For general information about Chelsio and our products, visit -+ our website at . -+ -+ For customer support, please visit our customer support page at -+ . -+ -+ Please send feedback to . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called cxgb. -+ -+config CHELSIO_T1_1G -+ bool "Chelsio gigabit Ethernet support" -+ depends on CHELSIO_T1 -+ help -+ Enables support for Chelsio's gigabit Ethernet PCI cards. If you -+ are using only 10G cards say 'N' here. -+ -+config CHELSIO_T1_NAPI -+ bool "Use Rx Polling (NAPI)" -+ depends on CHELSIO_T1 -+ default y -+ help -+ NAPI is a driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. -+ -+config CHELSIO_T3 -+ tristate "Chelsio Communications T3 10Gb Ethernet support" -+ depends on PCI -+ select FW_LOADER -+ help -+ This driver supports Chelsio T3-based gigabit and 10Gb Ethernet -+ adapters. -+ -+ For general information about Chelsio and our products, visit -+ our website at . -+ -+ For customer support, please visit our customer support page at -+ . -+ -+ Please send feedback to . -+ -+ To compile this driver as a module, choose M here: the module -+ will be called cxgb3. -+ -+config EHEA -+ tristate "eHEA Ethernet support" -+ depends on IBMEBUS && INET -+ select INET_LRO -+ ---help--- -+ This driver supports the IBM pSeries eHEA ethernet adapter. -+ -+ To compile the driver as a module, choose M here. The module -+ will be called ehea. -+ -+config IXGBE -+ tristate "Intel(R) 10GbE PCI Express adapters support" -+ depends on PCI -+ ---help--- -+ This driver supports Intel(R) 10GbE PCI Express family of -+ adapters. For more information on how to identify your adapter, go -+ to the Adapter & Driver ID Guide at: -+ -+ -+ -+ For general information and support, go to the Intel support -+ website at: -+ -+ -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ixgbe. -+ -+config IXGB -+ tristate "Intel(R) PRO/10GbE support" -+ depends on PCI -+ ---help--- -+ This driver supports Intel(R) PRO/10GbE family of adapters for -+ PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver -+ instead. For more information on how to identify your adapter, go -+ to the Adapter & Driver ID Guide at: -+ -+ -+ -+ For general information and support, go to the Intel support -+ website at: -+ -+ -+ -+ More specific information on configuring the driver is in -+ . -+ -+ To compile this driver as a module, choose M here. The module -+ will be called ixgb. -+ -+config IXGB_NAPI -+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -+ depends on IXGB && EXPERIMENTAL -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config S2IO -+ tristate "S2IO 10Gbe XFrame NIC" -+ depends on PCI -+ ---help--- -+ This driver supports the 10Gbe XFrame NIC of S2IO. -+ More specific information on configuring the driver is in -+ . -+ -+config S2IO_NAPI -+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)" -+ depends on S2IO && EXPERIMENTAL -+ help -+ NAPI is a new driver API designed to reduce CPU and interrupt load -+ when the driver is receiving lots of packets from the card. It is -+ still somewhat experimental and thus not yet enabled by default. -+ -+ If your estimated Rx load is 10kpps or more, or if the card will be -+ deployed on potentially unfriendly networks (e.g. in a firewall), -+ then say Y here. -+ -+ If in doubt, say N. -+ -+config MYRI10GE -+ tristate "Myricom Myri-10G Ethernet support" -+ depends on PCI && INET -+ select FW_LOADER -+ select CRC32 -+ select INET_LRO -+ ---help--- -+ This driver supports Myricom Myri-10G Dual Protocol interface in -+ Ethernet mode. If the eeprom on your board is not recent enough, -+ you will need a newer firmware image. -+ You may get this image or more information, at: -+ -+ -+ -+ To compile this driver as a module, choose M here. The module -+ will be called myri10ge. -+ -+config NETXEN_NIC -+ tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" -+ depends on PCI -+ help -+ This enables the support for NetXen's Gigabit Ethernet card. -+ -+config NIU -+ tristate "Sun Neptune 10Gbit Ethernet support" -+ depends on PCI -+ help -+ This enables support for cards based upon Sun's -+ Neptune chipset. -+ -+config PASEMI_MAC -+ tristate "PA Semi 1/10Gbit MAC" -+ depends on PPC64 && PCI -+ select PHYLIB -+ help -+ This driver supports the on-chip 1/10Gbit Ethernet controller on -+ PA Semi's PWRficient line of chips. -+ -+config MLX4_CORE -+ tristate -+ depends on PCI -+ default n -+ -+config MLX4_DEBUG -+ bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED) -+ depends on MLX4_CORE -+ default y -+ ---help--- -+ This option causes debugging code to be compiled into the -+ mlx4_core driver. The output can be turned on via the -+ debug_level module parameter (which can also be set after -+ the driver is loaded through sysfs). -+ -+config TEHUTI -+ tristate "Tehuti Networks 10G Ethernet" -+ depends on PCI -+ help -+ Tehuti Networks 10G Ethernet NIC -+ -+endif # NETDEV_10000 -+ -+source "drivers/net/tokenring/Kconfig" -+ -+source "drivers/net/wireless/Kconfig" -+ -+source "drivers/net/usb/Kconfig" -+ -+source "drivers/net/pcmcia/Kconfig" -+ -+source "drivers/net/wan/Kconfig" -+ -+source "drivers/atm/Kconfig" -+ -+source "drivers/s390/net/Kconfig" -+ -+config XEN_NETDEV_FRONTEND -+ tristate "Xen network device frontend driver" -+ depends on XEN -+ default y -+ help -+ The network device frontend driver allows the kernel to -+ access network devices exported exported by a virtual -+ machine containing a physical network device driver. The -+ frontend driver is intended for unprivileged guest domains; -+ if you are compiling a kernel for a Xen guest, you almost -+ certainly want to enable this. -+ -+config ISERIES_VETH -+ tristate "iSeries Virtual Ethernet driver support" -+ depends on PPC_ISERIES -+ -+config RIONET -+ tristate "RapidIO Ethernet over messaging driver support" -+ depends on RAPIDIO -+ -+config RIONET_TX_SIZE -+ int "Number of outbound queue entries" -+ depends on RIONET -+ default "128" -+ -+config RIONET_RX_SIZE -+ int "Number of inbound queue entries" -+ depends on RIONET -+ default "128" -+ -+config FDDI -+ bool "FDDI driver support" -+ depends on (PCI || EISA || TC) -+ help -+ Fiber Distributed Data Interface is a high speed local area network -+ design; essentially a replacement for high speed Ethernet. FDDI can -+ run over copper or fiber. If you are connected to such a network and -+ want a driver for the FDDI card in your computer, say Y here (and -+ then also Y to the driver for your FDDI card, below). Most people -+ will say N. -+ -+config DEFXX -+ tristate "Digital DEFTA/DEFEA/DEFPA adapter support" -+ depends on FDDI && (PCI || EISA || TC) -+ ---help--- -+ This is support for the DIGITAL series of TURBOchannel (DEFTA), -+ EISA (DEFEA) and PCI (DEFPA) controllers which can connect you -+ to a local FDDI network. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called defxx. If unsure, say N. -+ -+config DEFXX_MMIO -+ bool -+ prompt "Use MMIO instead of PIO" if PCI || EISA -+ depends on DEFXX -+ default n if PCI || EISA -+ default y -+ ---help--- -+ This instructs the driver to use EISA or PCI memory-mapped I/O -+ (MMIO) as appropriate instead of programmed I/O ports (PIO). -+ Enabling this gives an improvement in processing time in parts -+ of the driver, but it may cause problems with EISA (DEFEA) -+ adapters. TURBOchannel does not have the concept of I/O ports, -+ so MMIO is always used for these (DEFTA) adapters. -+ -+ If unsure, say N. -+ -+config SKFP -+ tristate "SysKonnect FDDI PCI support" -+ depends on FDDI && PCI -+ select BITREVERSE -+ ---help--- -+ Say Y here if you have a SysKonnect FDDI PCI adapter. -+ The following adapters are supported by this driver: -+ - SK-5521 (SK-NET FDDI-UP) -+ - SK-5522 (SK-NET FDDI-UP DAS) -+ - SK-5541 (SK-NET FDDI-FP) -+ - SK-5543 (SK-NET FDDI-LP) -+ - SK-5544 (SK-NET FDDI-LP DAS) -+ - SK-5821 (SK-NET FDDI-UP64) -+ - SK-5822 (SK-NET FDDI-UP64 DAS) -+ - SK-5841 (SK-NET FDDI-FP64) -+ - SK-5843 (SK-NET FDDI-LP64) -+ - SK-5844 (SK-NET FDDI-LP64 DAS) -+ - Netelligent 100 FDDI DAS Fibre SC -+ - Netelligent 100 FDDI SAS Fibre SC -+ - Netelligent 100 FDDI DAS UTP -+ - Netelligent 100 FDDI SAS UTP -+ - Netelligent 100 FDDI SAS Fibre MIC -+ -+ Read for information about -+ the driver. -+ -+ Questions concerning this driver can be addressed to: -+ -+ -+ To compile this driver as a module, choose M here: the module -+ will be called skfp. This is recommended. -+ -+config HIPPI -+ bool "HIPPI driver support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && INET && PCI -+ help -+ HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and -+ 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI -+ can run over copper (25m) or fiber (300m on multi-mode or 10km on -+ single-mode). HIPPI networks are commonly used for clusters and to -+ connect to super computers. If you are connected to a HIPPI network -+ and have a HIPPI network card in your computer that you want to use -+ under Linux, say Y here (you must also remember to enable the driver -+ for your HIPPI card below). Most people will say N here. -+ -+config ROADRUNNER -+ tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)" -+ depends on HIPPI && PCI -+ help -+ Say Y here if this is your PCI HIPPI network card. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called rrunner. If unsure, say N. -+ -+config ROADRUNNER_LARGE_RINGS -+ bool "Use large TX/RX rings (EXPERIMENTAL)" -+ depends on ROADRUNNER -+ help -+ If you say Y here, the RoadRunner driver will preallocate up to 2 MB -+ of additional memory to allow for fastest operation, both for -+ transmitting and receiving. This memory cannot be used by any other -+ kernel code or by user space programs. Say Y here only if you have -+ the memory. -+ -+config PLIP -+ tristate "PLIP (parallel port) support" -+ depends on PARPORT -+ ---help--- -+ PLIP (Parallel Line Internet Protocol) is used to create a -+ reasonably fast mini network consisting of two (or, rarely, more) -+ local machines. A PLIP link from a Linux box is a popular means to -+ install a Linux distribution on a machine which doesn't have a -+ CD-ROM drive (a minimal system has to be transferred with floppies -+ first). The kernels on both machines need to have this PLIP option -+ enabled for this to work. -+ -+ The PLIP driver has two modes, mode 0 and mode 1. The parallel -+ ports (the connectors at the computers with 25 holes) are connected -+ with "null printer" or "Turbo Laplink" cables which can transmit 4 -+ bits at a time (mode 0) or with special PLIP cables, to be used on -+ bidirectional parallel ports only, which can transmit 8 bits at a -+ time (mode 1); you can find the wiring of these cables in -+ . The cables can be up to -+ 15m long. Mode 0 works also if one of the machines runs DOS/Windows -+ and has some PLIP software installed, e.g. the Crynwr PLIP packet -+ driver () -+ and winsock or NCSA's telnet. -+ -+ If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well -+ as the NET-3-HOWTO, both available from -+ . Note that the PLIP -+ protocol has been changed and this PLIP driver won't work together -+ with the PLIP support in Linux versions 1.0.x. This option enlarges -+ your kernel by about 8 KB. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called plip. If unsure, say Y or M, in case you buy -+ a laptop later. -+ -+config PPP -+ tristate "PPP (point-to-point protocol) support" -+ select SLHC -+ ---help--- -+ PPP (Point to Point Protocol) is a newer and better SLIP. It serves -+ the same purpose: sending Internet traffic over telephone (and other -+ serial) lines. Ask your access provider if they support it, because -+ otherwise you can't use it; most Internet access providers these -+ days support PPP rather than SLIP. -+ -+ To use PPP, you need an additional program called pppd as described -+ in the PPP-HOWTO, available at -+ . Make sure that you have -+ the version of pppd recommended in . -+ The PPP option enlarges your kernel by about 16 KB. -+ -+ There are actually two versions of PPP: the traditional PPP for -+ asynchronous lines, such as regular analog phone lines, and -+ synchronous PPP which can be used over digital ISDN lines for -+ example. If you want to use PPP over phone lines or other -+ asynchronous serial lines, you need to say Y (or M) here and also to -+ the next option, "PPP support for async serial ports". For PPP over -+ synchronous lines, you should say Y (or M) here and to "Support -+ synchronous PPP", below. -+ -+ If you said Y to "Version information on all symbols" above, then -+ you cannot compile the PPP driver into the kernel; you can then only -+ compile it as a module. To compile this driver as a module, choose M -+ here. The module will be called ppp_generic. -+ -+config PPP_MULTILINK -+ bool "PPP multilink support (EXPERIMENTAL)" -+ depends on PPP && EXPERIMENTAL -+ help -+ PPP multilink is a protocol (defined in RFC 1990) which allows you -+ to combine several (logical or physical) lines into one logical PPP -+ connection, so that you can utilize your full bandwidth. -+ -+ This has to be supported at the other end as well and you need a -+ version of the pppd daemon which understands the multilink protocol. -+ -+ If unsure, say N. -+ -+config PPP_FILTER -+ bool "PPP filtering" -+ depends on PPP -+ help -+ Say Y here if you want to be able to filter the packets passing over -+ PPP interfaces. This allows you to control which packets count as -+ activity (i.e. which packets will reset the idle timer or bring up -+ a demand-dialed link) and which packets are to be dropped entirely. -+ You need to say Y here if you wish to use the pass-filter and -+ active-filter options to pppd. -+ -+ If unsure, say N. -+ -+config PPP_ASYNC -+ tristate "PPP support for async serial ports" -+ depends on PPP -+ select CRC_CCITT -+ ---help--- -+ Say Y (or M) here if you want to be able to use PPP over standard -+ asynchronous serial ports, such as COM1 or COM2 on a PC. If you use -+ a modem (not a synchronous or ISDN modem) to contact your ISP, you -+ need this option. -+ -+ To compile this driver as a module, choose M here. -+ -+ If unsure, say Y. -+ -+config PPP_SYNC_TTY -+ tristate "PPP support for sync tty ports" -+ depends on PPP -+ help -+ Say Y (or M) here if you want to be able to use PPP over synchronous -+ (HDLC) tty devices, such as the SyncLink adapter. These devices -+ are often used for high-speed leased lines like T1/E1. -+ -+ To compile this driver as a module, choose M here. -+ -+config PPP_DEFLATE -+ tristate "PPP Deflate compression" -+ depends on PPP -+ select ZLIB_INFLATE -+ select ZLIB_DEFLATE -+ ---help--- -+ Support for the Deflate compression method for PPP, which uses the -+ Deflate algorithm (the same algorithm that gzip uses) to compress -+ each PPP packet before it is sent over the wire. The machine at the -+ other end of the PPP link (usually your ISP) has to support the -+ Deflate compression method as well for this to be useful. Even if -+ they don't support it, it is safe to say Y here. -+ -+ To compile this driver as a module, choose M here. -+ -+config PPP_BSDCOMP -+ tristate "PPP BSD-Compress compression" -+ depends on PPP -+ ---help--- -+ Support for the BSD-Compress compression method for PPP, which uses -+ the LZW compression method to compress each PPP packet before it is -+ sent over the wire. The machine at the other end of the PPP link -+ (usually your ISP) has to support the BSD-Compress compression -+ method as well for this to be useful. Even if they don't support it, -+ it is safe to say Y here. -+ -+ The PPP Deflate compression method ("PPP Deflate compression", -+ above) is preferable to BSD-Compress, because it compresses better -+ and is patent-free. -+ -+ Note that the BSD compression code will always be compiled as a -+ module; it is called bsd_comp and will show up in the directory -+ modules once you have said "make modules". If unsure, say N. -+ -+config PPP_MPPE -+ tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" -+ depends on PPP && EXPERIMENTAL -+ select CRYPTO -+ select CRYPTO_SHA1 -+ select CRYPTO_ARC4 -+ select CRYPTO_ECB -+ ---help--- -+ Support for the MPPE Encryption protocol, as employed by the -+ Microsoft Point-to-Point Tunneling Protocol. -+ -+ See http://pptpclient.sourceforge.net/ for information on -+ configuring PPTP clients and servers to utilize this method. -+ -+config PPPOE -+ tristate "PPP over Ethernet (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && PPP -+ help -+ Support for PPP over Ethernet. -+ -+ This driver requires the latest version of pppd from the CVS -+ repository at cvs.samba.org. Alternatively, see the -+ RoaringPenguin package () -+ which contains instruction on how to use this driver (under -+ the heading "Kernel mode PPPoE"). -+ -+config PPPOATM -+ tristate "PPP over ATM" -+ depends on ATM && PPP -+ help -+ Support PPP (Point to Point Protocol) encapsulated in ATM frames. -+ This implementation does not yet comply with section 8 of RFC2364, -+ which can lead to bad results if the ATM peer loses state and -+ changes its encapsulation unilaterally. -+ -+config PPPOL2TP -+ tristate "PPP over L2TP (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && PPP && INET -+ help -+ Support for PPP-over-L2TP socket family. L2TP is a protocol -+ used by ISPs and enterprises to tunnel PPP traffic over UDP -+ tunnels. L2TP is replacing PPTP for VPN uses. -+ -+ This kernel component handles only L2TP data packets: a -+ userland daemon handles L2TP the control protocol (tunnel -+ and session setup). One such daemon is OpenL2TP -+ (http://openl2tp.sourceforge.net/). -+ -+config SLIP -+ tristate "SLIP (serial line) support" -+ ---help--- -+ Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to -+ connect to your Internet service provider or to connect to some -+ other local Unix box or if you want to configure your Linux box as a -+ Slip/CSlip server for other people to dial in. SLIP (Serial Line -+ Internet Protocol) is a protocol used to send Internet traffic over -+ serial connections such as telephone lines or null modem cables; -+ nowadays, the protocol PPP is more commonly used for this same -+ purpose. -+ -+ Normally, your access provider has to support SLIP in order for you -+ to be able to use it, but there is now a SLIP emulator called SLiRP -+ around (available from -+ ) which -+ allows you to use SLIP over a regular dial up shell connection. If -+ you plan to use SLiRP, make sure to say Y to CSLIP, below. The -+ NET-3-HOWTO, available from -+ , explains how to -+ configure SLIP. Note that you don't need this option if you just -+ want to run term (term is a program which gives you almost full -+ Internet connectivity if you have a regular dial up shell account on -+ some Internet connected Unix computer. Read -+ ). SLIP -+ support will enlarge your kernel by about 4 KB. If unsure, say N. -+ -+ To compile this driver as a module, choose M here. The module -+ will be called slip. -+ -+config SLIP_COMPRESSED -+ bool "CSLIP compressed headers" -+ depends on SLIP -+ select SLHC -+ ---help--- -+ This protocol is faster than SLIP because it uses compression on the -+ TCP/IP headers (not on the data itself), but it has to be supported -+ on both ends. Ask your access provider if you are not sure and -+ answer Y, just in case. You will still be able to use plain SLIP. If -+ you plan to use SLiRP, the SLIP emulator (available from -+ ) which -+ allows you to use SLIP over a regular dial up shell connection, you -+ definitely want to say Y here. The NET-3-HOWTO, available from -+ , explains how to configure -+ CSLIP. This won't enlarge your kernel. -+ -+config SLHC -+ tristate -+ help -+ This option enables Van Jacobsen serial line header compression -+ routines. -+ -+config SLIP_SMART -+ bool "Keepalive and linefill" -+ depends on SLIP -+ help -+ Adds additional capabilities to the SLIP driver to support the -+ RELCOM line fill and keepalive monitoring. Ideal on poor quality -+ analogue lines. -+ -+config SLIP_MODE_SLIP6 -+ bool "Six bit SLIP encapsulation" -+ depends on SLIP -+ help -+ Just occasionally you may need to run IP over hostile serial -+ networks that don't pass all control characters or are only seven -+ bit. Saying Y here adds an extra mode you can use with SLIP: -+ "slip6". In this mode, SLIP will only send normal ASCII symbols over -+ the serial device. Naturally, this has to be supported at the other -+ end of the link as well. It's good enough, for example, to run IP -+ over the async ports of a Camtec JNT Pad. If unsure, say N. -+ -+config NET_FC -+ bool "Fibre Channel driver support" -+ depends on SCSI && PCI -+ help -+ Fibre Channel is a high speed serial protocol mainly used to connect -+ large storage devices to the computer; it is compatible with and -+ intended to replace SCSI. -+ -+ If you intend to use Fibre Channel, you need to have a Fibre channel -+ adaptor card in your computer; say Y here and to the driver for your -+ adaptor below. You also should have said Y to "SCSI support" and -+ "SCSI generic support". -+ -+config SHAPER -+ tristate "Traffic Shaper (OBSOLETE)" -+ depends on EXPERIMENTAL -+ ---help--- -+ The traffic shaper is a virtual network device that allows you to -+ limit the rate of outgoing data flow over some other network device. -+ The traffic that you want to slow down can then be routed through -+ these virtual devices. See -+ for more information. -+ -+ An alternative to this traffic shaper are traffic schedulers which -+ you'll get if you say Y to "QoS and/or fair queuing" in -+ "Networking options". -+ -+ To compile this driver as a module, choose M here: the module -+ will be called shaper. If unsure, say N. -+ -+config NETCONSOLE -+ tristate "Network console logging support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ ---help--- -+ If you want to log kernel messages over the network, enable this. -+ See for details. -+ -+config NETCONSOLE_DYNAMIC -+ bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)" -+ depends on NETCONSOLE && SYSFS && EXPERIMENTAL -+ select CONFIGFS_FS -+ help -+ This option enables the ability to dynamically reconfigure target -+ parameters (interface, IP addresses, port numbers, MAC addresses) -+ at runtime through a userspace interface exported using configfs. -+ See for details. -+ -+config NETPOLL -+ def_bool NETCONSOLE -+ -+config NETPOLL_TRAP -+ bool "Netpoll traffic trapping" -+ default n -+ depends on NETPOLL -+ -+config NET_POLL_CONTROLLER -+ def_bool NETPOLL -+ -+config VIRTIO_NET -+ tristate "Virtio network driver (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && VIRTIO -+ ---help--- -+ This is the virtual network driver for lguest. Say Y or M. -+ -+endif # NETDEVICES -diff -urN linux-2.6.24.7.old/drivers/net/Makefile linux-2.6.24.7/drivers/net/Makefile ---- linux-2.6.24.7.old/drivers/net/Makefile 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/drivers/net/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -84,6 +84,8 @@ - obj-$(CONFIG_MII) += mii.o - obj-$(CONFIG_PHYLIB) += phy/ - -+obj-$(CONFIG_JZ_ETH) += jz_eth.o -+obj-$(CONFIG_JZCS8900) += jzcs8900a.o - obj-$(CONFIG_SUNDANCE) += sundance.o - obj-$(CONFIG_HAMACHI) += hamachi.o - obj-$(CONFIG_NET) += Space.o loopback.o -diff -urN linux-2.6.24.7.old/drivers/net/jz_eth.c linux-2.6.24.7/drivers/net/jz_eth.c ---- linux-2.6.24.7.old/drivers/net/jz_eth.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/net/jz_eth.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1290 @@ -+/* -+ * linux/drivers/net/jz_eth.c -+ * -+ * Jz4730/Jz5730 On-Chip ethernet driver. -+ * -+ * Copyright (C) 2005 - 2007 Ingenic 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz_eth.h" -+ -+#define P2ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0xa0000000) -+#define P1ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0x80000000) -+ -+//#define DEBUG -+#ifdef DEBUG -+# define DBPRINTK(fmt,args...) printk(KERN_DEBUG fmt,##args) -+#else -+# define DBPRINTK(fmt,args...) do {} while(0) -+#endif -+ -+#define errprintk(fmt,args...) printk(KERN_ERR fmt,##args); -+#define infoprintk(fmt,args...) printk(KERN_INFO fmt,##args); -+ -+#define DRV_NAME "jz_eth" -+#define DRV_VERSION "1.2" -+#define DRV_AUTHOR "Peter Wei " -+#define DRV_DESC "JzSOC On-chip Ethernet driver" -+ -+MODULE_AUTHOR(DRV_AUTHOR); -+MODULE_DESCRIPTION(DRV_DESC); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * Local variables -+ */ -+static struct net_device *netdev; -+static char * hwaddr = NULL; -+static int debug = -1; -+static struct mii_if_info mii_info; -+ -+MODULE_PARM_DESC(debug, "i"); -+MODULE_PARM_DESC(hwaddr,"s"); -+ -+/* -+ * Local routines -+ */ -+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id); -+ -+static int link_check_thread (void *data); -+ -+/* -+ * Get MAC address -+ */ -+ -+#define I2C_DEVICE 0x57 -+#define MAC_OFFSET 64 -+ -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+ -+static inline unsigned char str2hexnum(unsigned char c) -+{ -+ if (c >= '0' && c <= '9') -+ return c - '0'; -+ if (c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if (c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+static inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for (i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+static int ethaddr_cmd = 0; -+static unsigned char ethaddr_hex[6]; -+ -+static int __init ethernet_addr_setup(char *str) -+{ -+ if (!str) { -+ printk("ethaddr not set in command line\n"); -+ return -1; -+ } -+ ethaddr_cmd = 1; -+ str2eaddr(ethaddr_hex, str); -+ -+ return 0; -+} -+ -+__setup("ethaddr=", ethernet_addr_setup); -+ -+static int get_mac_address(struct net_device *dev) -+{ -+ int i; -+ unsigned char flag0=0; -+ unsigned char flag1=0xff; -+ -+ dev->dev_addr[0] = 0xff; -+ if (hwaddr != NULL) { -+ /* insmod jz-ethc.o hwaddr=00:ef:a3:c1:00:10 */ -+ str2eaddr(dev->dev_addr, hwaddr); -+ } else if (ethaddr_cmd) { -+ /* linux command line: ethaddr=00:ef:a3:c1:00:10 */ -+ for (i=0; i<6; i++) -+ dev->dev_addr[i] = ethaddr_hex[i]; -+ } else { -+#if 0 -+ /* mac address in eeprom: byte 0x40-0x45 */ -+ i2c_open(); -+ i2c_read(I2C_DEVICE, dev->dev_addr, MAC_OFFSET, 6); -+ i2c_close(); -+#endif -+ } -+ -+ /* check whether valid MAC address */ -+ for (i=0; i<6; i++) { -+ flag0 |= dev->dev_addr[i]; -+ flag1 &= dev->dev_addr[i]; -+ } -+ if ((dev->dev_addr[0] & 0xC0) || (flag0 == 0) || (flag1 == 0xff)) { -+ printk("WARNING: There is not MAC address, use default ..\n"); -+ dev->dev_addr[0] = 0x00; -+ dev->dev_addr[1] = 0xef; -+ dev->dev_addr[2] = 0xa3; -+ dev->dev_addr[3] = 0xc1; -+ dev->dev_addr[4] = 0x00; -+ dev->dev_addr[5] = 0x10; -+ dev->dev_addr[5] = 0x03; -+ } -+ return 0; -+} -+ -+/*---------------------------------------------------------------------*/ -+ -+static u32 jz_eth_curr_mode(struct net_device *dev); -+ -+/* -+ * Ethernet START/STOP routines -+ */ -+#define START_ETH { \ -+ s32 val; \ -+ val = readl(DMA_OMR); \ -+ val |= OMR_ST | OMR_SR; \ -+ writel(val, DMA_OMR); \ -+} -+ -+#define STOP_ETH { \ -+ s32 val; \ -+ val = readl(DMA_OMR); \ -+ val &= ~(OMR_ST|OMR_SR); \ -+ writel(val, DMA_OMR); \ -+} -+ -+/* -+ * Link check routines -+ */ -+static void start_check(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ -+ np->thread_die = 0; -+ init_waitqueue_head(&np->thr_wait); -+ init_completion (&np->thr_exited); -+ np->thr_pid = kernel_thread (link_check_thread,(void *)dev, -+ CLONE_FS | CLONE_FILES); -+ if (np->thr_pid < 0) -+ errprintk("%s: unable to start kernel thread\n",dev->name); -+} -+ -+static int close_check(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int ret = 0; -+ -+ if (np->thr_pid >= 0) { -+ np->thread_die = 1; -+ wmb(); -+ ret = kill_proc (np->thr_pid, SIGTERM, 1); -+ if (ret) { -+ errprintk("%s: unable to signal thread\n", dev->name); -+ return 1; -+ } -+ wait_for_completion (&np->thr_exited); -+ } -+ return 0; -+} -+ -+static int link_check_thread(void *data) -+{ -+ struct net_device *dev=(struct net_device *)data; -+ struct jz_eth_private *np = (struct jz_eth_private *)netdev->priv; -+ unsigned char current_link; -+ unsigned long timeout; -+ -+ daemonize("%s", dev->name); -+ spin_lock_irq(¤t->sighand->siglock); -+ sigemptyset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ strncpy (current->comm, dev->name, sizeof(current->comm) - 1); -+ current->comm[sizeof(current->comm) - 1] = '\0'; -+ -+ while (1) { -+ timeout = 3*HZ; -+ do { -+ timeout = interruptible_sleep_on_timeout (&np->thr_wait, timeout); -+ /* make swsusp happy with our thread */ -+// if (current->flags & PF_FREEZE) -+// refrigerator(PF_FREEZE); -+ } while (!signal_pending (current) && (timeout > 0)); -+ -+ if (signal_pending (current)) { -+ spin_lock_irq(¤t->sighand->siglock); -+ flush_signals(current); -+ spin_unlock_irq(¤t->sighand->siglock); -+ } -+ -+ if (np->thread_die) -+ break; -+ -+ current_link=mii_link_ok(&mii_info); -+ if (np->link_state!=current_link) { -+ if (current_link) { -+ infoprintk("%s: Ethernet Link OK!\n",dev->name); -+ jz_eth_curr_mode(dev); -+ netif_carrier_on(dev); -+ } -+ else { -+ errprintk("%s: Ethernet Link offline!\n",dev->name); -+ netif_carrier_off(dev); -+ } -+ } -+ np->link_state=current_link; -+ -+ } -+ complete_and_exit (&np->thr_exited, 0); -+} -+ -+#ifdef DEBUG -+/* -+ * Display ethernet packet header -+ * This routine is used for test function -+ */ -+static void eth_dbg_rx(struct sk_buff *skb, int len) -+{ -+ -+ int i, j; -+ -+ printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", -+ (u8)skb->data[0], -+ (u8)skb->data[1], -+ (u8)skb->data[2], -+ (u8)skb->data[3], -+ (u8)skb->data[4], -+ (u8)skb->data[5], -+ (u8)skb->data[6], -+ (u8)skb->data[7], -+ (u8)skb->data[8], -+ (u8)skb->data[9], -+ (u8)skb->data[10], -+ (u8)skb->data[11], -+ (u8)skb->data[12], -+ (u8)skb->data[13], -+ len); -+ for (j=0; len>0; j+=16, len-=16) { -+ printk(" %03x: ",j); -+ for (i=0; i<16 && idata[i+j]); -+ } -+ printk("\n"); -+ } -+ return; -+ } -+#endif -+ -+/* -+ * Reset ethernet device -+ */ -+static inline void jz_eth_reset(void) -+{ -+ u32 i; -+ i = readl(DMA_BMR); -+ writel(i | BMR_SWR, DMA_BMR); -+ for(i = 0; i < 1000; i++) { -+ if(!(readl(DMA_BMR) & BMR_SWR)) break; -+ mdelay(1); -+ } -+} -+ -+/* -+ * MII operation routines -+ */ -+static inline void mii_wait(void) -+{ -+ int i; -+ for(i = 0; i < 10000; i++) { -+ if(!(readl(MAC_MIIA) & 0x1)) -+ break; -+ mdelay(1); -+ } -+ if (i >= 10000) -+ printk("MII wait timeout : %d.\n", i); -+} -+ -+static int mdio_read(struct net_device *dev,int phy_id, int location) -+{ -+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 1; -+ int retval = 0; -+ -+ writel(mii_cmd, MAC_MIIA); -+ mii_wait(); -+ retval = readl(MAC_MIID) & 0x0000ffff; -+ -+ return retval; -+ -+} -+ -+static void mdio_write(struct net_device *dev,int phy_id, int location, int data) -+{ -+ u32 mii_cmd = (phy_id << 11) | (location << 6) | 0x2 | 1; -+ -+ writel(mii_cmd, MAC_MIIA); -+ writel(data & 0x0000ffff, MAC_MIID); -+ mii_wait(); -+} -+ -+ -+/* -+ * Search MII phy -+ */ -+static int jz_search_mii_phy(struct net_device *dev) -+{ -+ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int phy, phy_idx = 0; -+ -+ np->valid_phy = 0xff; -+ for (phy = 0; phy < 32; phy++) { -+ int mii_status = mdio_read(dev,phy, 1); -+ if (mii_status != 0xffff && mii_status != 0x0000) { -+ np->phys[phy_idx] = phy; -+ np->ecmds[phy_idx].speed=SPEED_100; -+ np->ecmds[phy_idx].duplex=DUPLEX_FULL; -+ np->ecmds[phy_idx].port=PORT_MII; -+ np->ecmds[phy_idx].transceiver=XCVR_INTERNAL; -+ np->ecmds[phy_idx].phy_address=np->phys[phy_idx]; -+ np->ecmds[phy_idx].autoneg=AUTONEG_ENABLE; -+ np->ecmds[phy_idx].advertising=(ADVERTISED_10baseT_Half | -+ ADVERTISED_10baseT_Full | -+ ADVERTISED_100baseT_Half | -+ ADVERTISED_100baseT_Full); -+ phy_idx++; -+ } -+ } -+ if (phy_idx == 1) { -+ np->valid_phy = np->phys[0]; -+ np->phy_type = 0; -+ } -+ if (phy_idx != 0) { -+ phy = np->valid_phy; -+ np->advertising = mdio_read(dev,phy, 4); -+ } -+ return phy_idx; -+} -+ -+/* -+ * CRC calc for Destination Address for gets hashtable index -+ */ -+ -+#define POLYNOMIAL 0x04c11db7UL -+static u16 jz_hashtable_index(u8 *addr) -+{ -+#if 1 -+ u32 crc = 0xffffffff, msb; -+ int i, j; -+ u32 byte; -+ for (i = 0; i < 6; i++) { -+ byte = *addr++; -+ for (j = 0; j < 8; j++) { -+ msb = crc >> 31; -+ crc <<= 1; -+ if (msb ^ (byte & 1)) crc ^= POLYNOMIAL; -+ byte >>= 1; -+ } -+ } -+ return ((int)(crc >> 26)); -+#endif -+#if 0 -+ int crc = -1; -+ int length=6; -+ int bit; -+ unsigned char current_octet; -+ while (--length >= 0) { -+ current_octet = *addr++; -+ for (bit = 0; bit < 8; bit++, current_octet >>= 1) -+ crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? -+ POLYNOMIAL : 0); -+ } -+ return ((int)(crc >> 26)); -+#endif -+} -+ -+/* -+ * Multicast filter and config multicast hash table -+ */ -+#define MULTICAST_FILTER_LIMIT 64 -+ -+static void jz_set_multicast_list(struct net_device *dev) -+{ -+ int i, hash_index; -+ u32 mcr, hash_h, hash_l, hash_bit; -+ -+ mcr = readl(MAC_MCR); -+ mcr &= ~(MCR_PR | MCR_PM | MCR_HP); -+ -+ if (dev->flags & IFF_PROMISC) { -+ /* Accept any kinds of packets */ -+ mcr |= MCR_PR; -+ hash_h = 0xffffffff; -+ hash_l = 0xffffffff; -+ DBPRINTK("%s: enter promisc mode!\n",dev->name); -+ } -+ else if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MULTICAST_FILTER_LIMIT)){ -+ /* Accept all multicast packets */ -+ mcr |= MCR_PM; -+ hash_h = 0xffffffff; -+ hash_l = 0xffffffff; -+ DBPRINTK("%s: enter allmulticast mode! %d \n",dev->name,dev->mc_count); -+ } -+ else if (dev->flags & IFF_MULTICAST) -+ { -+ /* Update multicast hash table */ -+ struct dev_mc_list *mclist; -+ hash_h = readl(MAC_HTH); -+ hash_l = readl(MAC_HTL); -+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; -+ i++, mclist = mclist->next) -+ { -+ hash_index = jz_hashtable_index(mclist->dmi_addr); -+ hash_bit=0x00000001; -+ hash_bit <<= (hash_index & 0x1f); -+ if (hash_index > 0x1f) -+ hash_h |= hash_bit; -+ else -+ hash_l |= hash_bit; -+ DBPRINTK("----------------------------\n"); -+#ifdef DEBUG -+ int j; -+ for (j=0;jdmi_addrlen;j++) -+ printk("%2.2x:",mclist->dmi_addr[j]); -+ printk("\n"); -+#endif -+ DBPRINTK("dmi.addrlen => %d\n",mclist->dmi_addrlen); -+ DBPRINTK("dmi.users => %d\n",mclist->dmi_users); -+ DBPRINTK("dmi.gusers => %d\n",mclist->dmi_users); -+ } -+ writel(hash_h,MAC_HTH); -+ writel(hash_l,MAC_HTL); -+ mcr |= MCR_HP; -+ DBPRINTK("This is multicast hash table high bits [%4.4x]\n",readl(MAC_HTH)); -+ DBPRINTK("This is multicast hash table low bits [%4.4x]\n",readl(MAC_HTL)); -+ DBPRINTK("%s: enter multicast mode!\n",dev->name); -+ } -+ writel(mcr,MAC_MCR); -+} -+ -+static inline int jz_phy_reset(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ unsigned int mii_reg0; -+ unsigned int count; -+ -+ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); -+ mii_reg0 |=MII_CR_RST; -+ mdio_write(dev,np->valid_phy,MII_BMCR,mii_reg0); //reset phy -+ for ( count = 0; count < 1000; count++) { -+ mdelay(1); -+ mii_reg0 = mdio_read(dev,np->valid_phy,MII_BMCR); -+ if (!(mii_reg0 & MII_CR_RST)) break; //reset completed -+ } -+ if (count>=100) -+ return 1; //phy error -+ else -+ return 0; -+} -+ -+/* -+ * Show all mii registers - this routine is used for test -+ */ -+#ifdef DEBUG -+static void mii_db_out(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ unsigned int mii_test; -+ -+ mii_test = mdio_read(dev,np->valid_phy,MII_BMCR); -+ DBPRINTK("BMCR ====> 0x%4.4x \n",mii_test); -+ -+ mii_test = mdio_read(dev,np->valid_phy,MII_BMSR); -+ DBPRINTK("BMSR ====> 0x%4.4x \n",mii_test); -+ -+ mii_test = mdio_read(dev,np->valid_phy,MII_ANAR); -+ DBPRINTK("ANAR ====> 0x%4.4x \n",mii_test); -+ -+ mii_test = mdio_read(dev,np->valid_phy,MII_ANLPAR); -+ DBPRINTK("ANLPAR ====> 0x%4.4x \n",mii_test); -+ -+ mii_test = mdio_read(dev,np->valid_phy,16); -+ DBPRINTK("REG16 ====> 0x%4.4x \n",mii_test); -+ -+ mii_test = mdio_read(dev,np->valid_phy,17); -+ DBPRINTK("REG17 ====> 0x%4.4x \n",mii_test); -+} -+#endif -+ -+/* -+ * Start Auto-Negotiation function for PHY -+ */ -+static int jz_autonet_complete(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int count; -+ u32 mii_reg1, timeout = 3000; -+ -+ for (count = 0; count < timeout; count++) { -+ mdelay(1); -+ mii_reg1 = mdio_read(dev,np->valid_phy,MII_BMSR); -+ if (mii_reg1 & 0x0020) break; -+ } -+ //mii_db_out(dev); //for debug to display all register of MII -+ if (count >= timeout) -+ return 1; //auto negotiation error -+ else -+ return 0; -+} -+ -+/* -+ * Get current mode of eth phy -+ */ -+static u32 jz_eth_curr_mode(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ unsigned int mii_reg17; -+ u32 flag = 0; -+ -+ mii_reg17 = mdio_read(dev,np->valid_phy,MII_DSCSR); -+ np->media = mii_reg17>>12; -+ if (np->media==8) { -+ infoprintk("%s: Current Operation Mode is [100M Full Duplex]",dev->name); -+ flag = 0; -+ np->full_duplex=1; -+ } -+ if (np->media==4) { -+ infoprintk("%s: Current Operation Mode is [100M Half Duplex]",dev->name); -+ flag = 0; -+ np->full_duplex=0; -+ } -+ if (np->media==2) { -+ infoprintk("%s: Current Operation Mode is [10M Full Duplex]",dev->name); -+ flag = OMR_TTM; -+ np->full_duplex=1; -+ } -+ if (np->media==1) { -+ infoprintk("%s: Current Operation Mode is [10M Half Duplex]",dev->name); -+ flag = OMR_TTM; -+ np->full_duplex=0; -+ } -+ printk("\n"); -+ return flag; -+} -+ -+/* -+ * Ethernet device hardware init -+ * This routine initializes the ethernet device hardware and PHY -+ */ -+static int jz_init_hw(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ struct ethtool_cmd ecmd; -+ u32 mcr, omr; -+ u32 sts, flag = 0; -+ int i; -+ -+ jz_eth_reset(); -+ STOP_ETH; -+#if 0 -+ /* mii operation */ -+ if (jz_phy_reset(dev)) { -+ errprintk("PHY device do not reset!\n"); -+ return -EPERM; // return operation not permitted -+ } -+#endif -+ /* Set MAC address */ -+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[0]), MAC_MAL); -+ writel(le32_to_cpu(*(unsigned long *)&dev->dev_addr[4]), MAC_MAH); -+ printk("%s: JZ On-Chip ethernet (MAC ", dev->name); -+ for (i = 0; i < 5; i++) { -+ printk("%2.2x:", dev->dev_addr[i]); -+ } -+ printk("%2.2x, IRQ %d)\n", dev->dev_addr[i], dev->irq); -+ -+ np->mii_phy_cnt = jz_search_mii_phy(dev); -+ printk("%s: Found %d PHY on JZ MAC\n", dev->name, np->mii_phy_cnt); -+ -+ mii_info.phy_id = np->valid_phy; -+ mii_info.dev = dev; -+ mii_info.mdio_read = &mdio_read; -+ mii_info.mdio_write = &mdio_write; -+ -+ ecmd.speed = SPEED_100; -+ ecmd.duplex = DUPLEX_FULL; -+ ecmd.port = PORT_MII; -+ ecmd.transceiver = XCVR_INTERNAL; -+ ecmd.phy_address = np->valid_phy; -+ ecmd.autoneg = AUTONEG_ENABLE; -+ -+ mii_ethtool_sset(&mii_info,&ecmd); -+ if (jz_autonet_complete(dev)) -+ errprintk("%s: Ethernet Module AutoNegotiation failed\n",dev->name); -+ mii_ethtool_gset(&mii_info,&ecmd); -+ -+ infoprintk("%s: Provide Modes: ",dev->name); -+ for (i = 0; i < 5;i++) -+ if (ecmd.advertising & (1<full_duplex) -+ mcr |= MCR_FDX; -+ mcr |= MCR_BFD | MCR_TE | MCR_RE | MCR_OWD|MCR_HBD; -+ writel(mcr, MAC_MCR); -+// mcr &= (readl(MAC_MCR) & ~(MCR_PM | MCR_PR | MCR_IF | MCR_HO | MCR_HP)); -+// mcr &= 0xffdf; -+// mcr |= 0x0020; -+// writel(mcr, MAC_MCR); -+ -+ /* Set base address of TX and RX descriptors */ -+ writel(np->dma_rx_ring, DMA_RRBA); -+ writel(np->dma_tx_ring, DMA_TRBA); -+ -+ START_ETH; -+ -+ /* set interrupt mask */ -+ writel(IMR_DEFAULT | IMR_ENABLE, DMA_IMR); -+ -+ /* Reset any pending (stale) interrupts */ -+ sts = readl(DMA_STS); -+ writel(sts, DMA_STS); -+ -+ return 0; -+} -+ -+static int jz_eth_open(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int retval, i; -+ -+ retval = request_irq(dev->irq, jz_eth_interrupt, 0, dev->name, dev); -+ if (retval) { -+ errprintk("%s: unable to get IRQ %d .\n", dev->name, dev->irq); -+ return -EAGAIN; -+ } -+ -+ for (i = 0; i < NUM_RX_DESCS; i++) { -+ np->rx_ring[i].status = cpu_to_le32(R_OWN); -+ np->rx_ring[i].desc1 = cpu_to_le32(RX_BUF_SIZE | RD_RCH); -+ np->rx_ring[i].buf1_addr = cpu_to_le32(np->dma_rx_buf + i*RX_BUF_SIZE); -+ np->rx_ring[i].next_addr = cpu_to_le32(np->dma_rx_ring + (i+1) * sizeof (jz_desc_t)); -+ } -+ np->rx_ring[NUM_RX_DESCS - 1].next_addr = cpu_to_le32(np->dma_rx_ring); -+ -+ for (i = 0; i < NUM_TX_DESCS; i++) { -+ np->tx_ring[i].status = cpu_to_le32(0); -+ np->tx_ring[i].desc1 = cpu_to_le32(TD_TCH); -+ np->tx_ring[i].buf1_addr = 0; -+ np->tx_ring[i].next_addr = cpu_to_le32(np->dma_tx_ring + (i+1) * sizeof (jz_desc_t)); -+ } -+ np->tx_ring[NUM_TX_DESCS - 1].next_addr = cpu_to_le32(np->dma_tx_ring); -+ -+ np->rx_head = 0; -+ np->tx_head = np->tx_tail = 0; -+ -+ jz_init_hw(dev); -+ -+ dev->trans_start = jiffies; -+ netif_start_queue(dev); -+ start_check(dev); -+ -+ return 0; -+} -+ -+static int jz_eth_close(struct net_device *dev) -+{ -+ netif_stop_queue(dev); -+ close_check(dev); -+ STOP_ETH; -+ free_irq(dev->irq, dev); -+ return 0; -+} -+ -+/* -+ * Get the current statistics. -+ * This may be called with the device open or closed. -+ */ -+static struct net_device_stats * jz_eth_get_stats(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int tmp; -+ -+ tmp = readl(DMA_MFC); // After read clear to zero -+ np->stats.rx_missed_errors += (tmp & MFC_CNT2) + ((tmp & MFC_CNT1) >> 16); -+ -+ return &np->stats; -+} -+ -+/* -+ * ethtool routines -+ */ -+static int jz_ethtool_ioctl(struct net_device *dev, void *useraddr) -+{ -+ struct jz_eth_private *np = dev->priv; -+ u32 ethcmd; -+ -+ /* dev_ioctl() in ../../net/core/dev.c has already checked -+ capable(CAP_NET_ADMIN), so don't bother with that here. */ -+ -+ if (get_user(ethcmd, (u32 *)useraddr)) -+ return -EFAULT; -+ -+ switch (ethcmd) { -+ -+ case ETHTOOL_GDRVINFO: { -+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; -+ strcpy (info.driver, DRV_NAME); -+ strcpy (info.version, DRV_VERSION); -+ strcpy (info.bus_info, "OCS"); -+ if (copy_to_user (useraddr, &info, sizeof (info))) -+ return -EFAULT; -+ return 0; -+ } -+ -+ /* get settings */ -+ case ETHTOOL_GSET: { -+ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; -+ spin_lock_irq(&np->lock); -+ mii_ethtool_gset(&mii_info, &ecmd); -+ spin_unlock_irq(&np->lock); -+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) -+ return -EFAULT; -+ return 0; -+ } -+ /* set settings */ -+ case ETHTOOL_SSET: { -+ int r; -+ struct ethtool_cmd ecmd; -+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) -+ return -EFAULT; -+ spin_lock_irq(&np->lock); -+ r = mii_ethtool_sset(&mii_info, &ecmd); -+ spin_unlock_irq(&np->lock); -+ return r; -+ } -+ /* restart autonegotiation */ -+ case ETHTOOL_NWAY_RST: { -+ return mii_nway_restart(&mii_info); -+ } -+ /* get link status */ -+ case ETHTOOL_GLINK: { -+ struct ethtool_value edata = {ETHTOOL_GLINK}; -+ edata.data = mii_link_ok(&mii_info); -+ if (copy_to_user(useraddr, &edata, sizeof(edata))) -+ return -EFAULT; -+ return 0; -+ } -+ -+ /* get message-level */ -+ case ETHTOOL_GMSGLVL: { -+ struct ethtool_value edata = {ETHTOOL_GMSGLVL}; -+ edata.data = debug; -+ if (copy_to_user(useraddr, &edata, sizeof(edata))) -+ return -EFAULT; -+ return 0; -+ } -+ /* set message-level */ -+ case ETHTOOL_SMSGLVL: { -+ struct ethtool_value edata; -+ if (copy_from_user(&edata, useraddr, sizeof(edata))) -+ return -EFAULT; -+ debug = edata.data; -+ return 0; -+ } -+ -+ -+ default: -+ break; -+ } -+ -+ return -EOPNOTSUPP; -+ -+} -+ -+/* -+ * Config device -+ */ -+static int jz_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ struct jz_eth_private *np =(struct jz_eth_private *)dev->priv; -+ struct mii_ioctl_data *data, rdata; -+ -+ switch (cmd) { -+ case SIOCETHTOOL: -+ return jz_ethtool_ioctl(dev, (void *) rq->ifr_data); -+ case SIOCGMIIPHY: -+ case SIOCDEVPRIVATE: -+ data = (struct mii_ioctl_data *)&rq->ifr_data; -+ data->phy_id = np->valid_phy; -+ case SIOCGMIIREG: -+ case SIOCDEVPRIVATE+1: -+ data = (struct mii_ioctl_data *)&rq->ifr_data; -+ data->val_out = mdio_read(dev,np->valid_phy, data->reg_num & 0x1f); -+ return 0; -+ case SIOCSMIIREG: -+ case SIOCDEVPRIVATE+2: -+ data = (struct mii_ioctl_data *)&rq->ifr_data; -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ mdio_write(dev,np->valid_phy, data->reg_num & 0x1f, data->val_in); -+ return 0; -+ case READ_COMMAND: -+ data = (struct mii_ioctl_data *)rq->ifr_data; -+ if (copy_from_user(&rdata,data,sizeof(rdata))) -+ return -EFAULT; -+ rdata.val_out = mdio_read(dev,rdata.phy_id, rdata.reg_num & 0x1f); -+ if (copy_to_user(data,&rdata,sizeof(rdata))) -+ return -EFAULT; -+ return 0; -+ case WRITE_COMMAND: -+ if (np->phy_type==1) { -+ data = (struct mii_ioctl_data *)rq->ifr_data; -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ if (copy_from_user(&rdata,data,sizeof(rdata))) -+ return -EFAULT; -+ mdio_write(dev,rdata.phy_id, rdata.reg_num & 0x1f, rdata.val_in); -+ } -+ return 0; -+ case GETDRIVERINFO: -+ if (np->phy_type==1) { -+ data = (struct mii_ioctl_data *)rq->ifr_data; -+ if (copy_from_user(&rdata,data,sizeof(rdata))) -+ return -EFAULT; -+ rdata.val_in = 0x1; -+ rdata.val_out = 0x00d0; -+ if (copy_to_user(data,&rdata,sizeof(rdata))) -+ return -EFAULT; -+ } -+ return 0; -+ default: -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+/* -+ * Received one packet -+ */ -+static void eth_rxready(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private*)dev->priv; -+ struct sk_buff *skb; -+ unsigned char *pkt_ptr; -+ u32 pkt_len; -+ u32 status; -+ -+ status = le32_to_cpu(np->rx_ring[np->rx_head].status); -+ while (!(status & R_OWN)) { /* owner bit = 0 */ -+ if (status & RD_ES) { /* error summary */ -+ np->stats.rx_errors++; /* Update the error stats. */ -+ if (status & (RD_RF | RD_TL)) -+ np->stats.rx_frame_errors++; -+ if (status & RD_CE) -+ np->stats.rx_crc_errors++; -+ if (status & RD_TL) -+ np->stats.rx_length_errors++; -+ } else { -+ pkt_ptr = bus_to_virt(le32_to_cpu(np->rx_ring[np->rx_head].buf1_addr)); -+ pkt_len = ((status & RD_FL) >> 16) - 4; -+ -+ skb = dev_alloc_skb(pkt_len + 2); -+ if (skb == NULL) { -+ printk("%s: Memory squeeze, dropping.\n", -+ dev->name); -+ np->stats.rx_dropped++; -+ break; -+ } -+ skb->dev = dev; -+ skb_reserve(skb, 2); /* 16 byte align */ -+ -+ //pkt_ptr = P1ADDR(pkt_ptr); -+ //dma_cache_inv(pkt_ptr, pkt_len); -+ memcpy(skb->data, pkt_ptr, pkt_len); -+ skb_put(skb, pkt_len); -+ -+ //eth_dbg_rx(skb, pkt_len); -+ skb->protocol = eth_type_trans(skb,dev); -+ netif_rx(skb); /* pass the packet to upper layers */ -+ dev->last_rx = jiffies; -+ np->stats.rx_packets++; -+ np->stats.rx_bytes += pkt_len; -+ } -+ np->rx_ring[np->rx_head].status = cpu_to_le32(R_OWN); -+ -+ np->rx_head ++; -+ if (np->rx_head >= NUM_RX_DESCS) -+ np->rx_head = 0; -+ status = le32_to_cpu(np->rx_ring[np->rx_head].status); -+ } -+} -+ -+/* -+ * Tx timeout routine -+ */ -+static void jz_eth_tx_timeout(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ -+ jz_init_hw(dev); -+ np->stats.tx_errors ++; -+ netif_wake_queue(dev); -+} -+ -+/* -+ * One packet was transmitted -+ */ -+static void eth_txdone(struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private*)dev->priv; -+ int tx_tail = np->tx_tail; -+ -+ while (tx_tail != np->tx_head) { -+ int entry = tx_tail % NUM_TX_DESCS; -+ s32 status = le32_to_cpu(np->tx_ring[entry].status); -+ if(status < 0) break; -+ if (status & TD_ES ) { /* Error summary */ -+ np->stats.tx_errors++; -+ if (status & TD_NC) np->stats.tx_carrier_errors++; -+ if (status & TD_LC) np->stats.tx_window_errors++; -+ if (status & TD_UF) np->stats.tx_fifo_errors++; -+ if (status & TD_DE) np->stats.tx_aborted_errors++; -+ if (np->tx_head != np->tx_tail) -+ writel(1, DMA_TPD); /* Restart a stalled TX */ -+ } else -+ np->stats.tx_packets++; -+ /* Update the collision counter */ -+ np->stats.collisions += ((status & TD_EC) ? 16 : ((status & TD_CC) >> 3)); -+ /* Free the original skb */ -+ if (np->tx_skb[entry]) { -+ dev_kfree_skb_irq(np->tx_skb[entry]); -+ np->tx_skb[entry] = 0; -+ } -+ tx_tail++; -+ } -+ if (np->tx_full && (tx_tail + NUM_TX_DESCS > np->tx_head + 1)) { -+ /* The ring is no longer full */ -+ np->tx_full = 0; -+ netif_start_queue(dev); -+ } -+ np->tx_tail = tx_tail; -+} -+ -+/* -+ * Update the tx descriptor -+ */ -+static void load_tx_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ int entry = np->tx_head % NUM_TX_DESCS; -+ -+ np->tx_ring[entry].buf1_addr = cpu_to_le32(virt_to_bus(buf)); -+ np->tx_ring[entry].desc1 &= cpu_to_le32((TD_TER | TD_TCH)); -+ np->tx_ring[entry].desc1 |= cpu_to_le32(flags); -+ np->tx_ring[entry].status = cpu_to_le32(T_OWN); -+ np->tx_skb[entry] = skb; -+} -+ -+/* -+ * Transmit one packet -+ */ -+static int jz_eth_send_packet(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct jz_eth_private *np = (struct jz_eth_private *)dev->priv; -+ u32 length; -+ -+ if (np->tx_full) { -+ return 0; -+ } -+#ifdef CONFIG_FPGA -+ mdelay(10); -+#else -+ udelay(500); /* FIXME: can we remove this delay ? */ -+#endif -+ length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; -+ dma_cache_wback((unsigned long)skb->data, length); -+ load_tx_packet(dev, (char *)skb->data, TD_IC | TD_LS | TD_FS | length, skb); -+ spin_lock_irq(&np->lock); -+ np->tx_head ++; -+ np->stats.tx_bytes += length; -+ writel(1, DMA_TPD); /* Start the TX */ -+ dev->trans_start = jiffies; /* for timeout */ -+ if (np->tx_tail + NUM_TX_DESCS > np->tx_head + 1) { -+ np->tx_full = 0; -+ } -+ else { -+ np->tx_full = 1; -+ netif_stop_queue(dev); -+ } -+ spin_unlock_irq(&np->lock); -+ -+ return 0; -+} -+ -+/* -+ * Interrupt service routine -+ */ -+static irqreturn_t jz_eth_interrupt(int irq, void *dev_id) -+{ -+ struct net_device *dev = (struct net_device *)dev_id; -+ struct jz_eth_private *np = dev->priv; -+ u32 sts; -+ int i; -+ -+ spin_lock(&np->lock); -+ -+ writel((readl(DMA_IMR) & ~IMR_ENABLE), DMA_IMR); /* Disable interrupt */ -+ -+ for (i = 0; i < 100; i++) { -+ sts = readl(DMA_STS); -+ writel(sts, DMA_STS); /* clear status */ -+ -+ if (!(sts & IMR_DEFAULT)) break; -+ -+ if (sts & (DMA_INT_RI | DMA_INT_RU)) /* Rx IRQ */ -+ eth_rxready(dev); -+ if (sts & (DMA_INT_TI | DMA_INT_TU)) /* Tx IRQ */ -+ eth_txdone(dev); -+ -+ /* check error conditions */ -+ if (sts & DMA_INT_FB){ /* fatal bus error */ -+ STOP_ETH; -+ errprintk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",dev->name, sts); -+ break; -+ } -+ -+ if (sts & DMA_INT_UN) { /* Transmit underrun */ -+ u32 omr; -+ omr = readl(DMA_OMR); -+ if (!(omr & OMR_SF)) { -+ omr &= ~(OMR_ST | OMR_SR); -+ writel(omr, DMA_OMR); -+ while (readl(DMA_STS) & STS_TS); /* wait for stop */ -+ if ((omr & OMR_TR) < OMR_TR) { /* ? */ -+ omr += TR_24; -+ } else { -+ omr |= OMR_SF; -+ } -+ writel(omr | OMR_ST | OMR_SR, DMA_OMR); -+ } -+ } -+ } -+ -+ writel(readl(DMA_IMR) | IMR_ENABLE, DMA_IMR); /* enable interrupt */ -+ -+ spin_unlock(&np->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+#if 0 //def CONFIG_PM -+/* -+ * Suspend the ETH interface. -+ */ -+static int jz_eth_suspend(struct net_device *dev, int state) -+{ -+ struct jz_eth_private *jep = (struct jz_eth_private *)dev->priv; -+ unsigned long flags, tmp; -+ -+ printk("ETH suspend.\n"); -+ -+ if (!netif_running(dev)) { -+ return 0; -+ } -+ -+ netif_device_detach(dev); -+ -+ spin_lock_irqsave(&jep->lock, flags); -+ -+ /* Disable interrupts, stop Tx and Rx. */ -+ REG32(DMA_IMR) = 0; -+ STOP_ETH; -+ -+ /* Update the error counts. */ -+ tmp = REG32(DMA_MFC); -+ jep->stats.rx_missed_errors += (tmp & 0x1ffff); -+ jep->stats.rx_fifo_errors += ((tmp >> 17) & 0x7ff); -+ -+ spin_unlock_irqrestore(&jep->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * Resume the ETH interface. -+ */ -+static int jz_eth_resume(struct net_device *dev) -+{ -+ printk("ETH resume.\n"); -+ -+ if (!netif_running(dev)) -+ return 0; -+ -+ jz_init_hw(dev); -+ -+ netif_device_attach(dev); -+ jz_eth_tx_timeout(dev); -+ netif_wake_queue(dev); -+ -+ return 0; -+} -+ -+static int jz_eth_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -+{ -+ int ret; -+ -+ if (!dev->data) -+ return -EINVAL; -+ -+ switch (rqst) { -+ case PM_SUSPEND: -+ ret = jz_eth_suspend((struct net_device *)dev->data, -+ (int)data); -+ break; -+ -+ case PM_RESUME: -+ ret = jz_eth_resume((struct net_device *)dev->data); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+#endif /* CONFIG_PM */ -+ -+static int __init jz_eth_init(void) -+{ -+ struct net_device *dev; -+ struct jz_eth_private *np; -+ int err; -+ -+ dev = alloc_etherdev(sizeof(struct jz_eth_private)); -+ if (!dev) { -+ printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME); -+ return -ENOMEM; -+ } -+ netdev = dev; -+ -+ np = (struct jz_eth_private *)P2ADDR(dev->priv); -+ dev->priv = np; -+ memset(np, 0, sizeof(struct jz_eth_private)); -+ -+ np->vaddr_rx_buf = (u32)dma_alloc_noncoherent(NULL, NUM_RX_DESCS*RX_BUF_SIZE, -+ &np->dma_rx_buf, 0); -+ -+ if (!np->vaddr_rx_buf) { -+ printk(KERN_ERR "%s: Cannot alloc dma buffers\n", DRV_NAME); -+ unregister_netdev(dev); -+ free_netdev(dev); -+ return -ENOMEM; -+ } -+ -+ np->dma_rx_ring = virt_to_bus(np->rx_ring); -+ np->dma_tx_ring = virt_to_bus(np->tx_ring); -+ np->full_duplex = 1; -+ np->link_state = 1; -+ -+ spin_lock_init(&np->lock); -+ -+ ether_setup(dev); -+ dev->irq = IRQ_ETH; -+ dev->open = jz_eth_open; -+ dev->stop = jz_eth_close; -+ dev->hard_start_xmit = jz_eth_send_packet; -+ dev->get_stats = jz_eth_get_stats; -+ dev->set_multicast_list = jz_set_multicast_list; -+ dev->do_ioctl = jz_eth_ioctl; -+ dev->tx_timeout = jz_eth_tx_timeout; -+ dev->watchdog_timeo = ETH_TX_TIMEOUT; -+ -+ /* configure MAC address */ -+ get_mac_address(dev); -+ -+ if ((err = register_netdev(dev)) != 0) { -+ printk(KERN_ERR "%s: Cannot register net device, error %d\n", -+ DRV_NAME, err); -+ free_netdev(dev); -+ return -ENOMEM; -+ } -+ -+//#ifdef 0 //CONFIG_PM -+// np->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, jz_eth_pm_callback); -+// if (np->pmdev) -+// np->pmdev->data = dev; -+//#endif -+ -+ return 0; -+} -+ -+static void __exit jz_eth_exit(void) -+{ -+ struct net_device *dev = netdev; -+ struct jz_eth_private *np = dev->priv; -+ -+ unregister_netdev(dev); -+ dma_free_noncoherent(NULL, NUM_RX_DESCS * RX_BUF_SIZE, -+ (void *)np->vaddr_rx_buf, np->dma_rx_buf); -+ free_netdev(dev); -+} -+ -+module_init(jz_eth_init); -+module_exit(jz_eth_exit); -diff -urN linux-2.6.24.7.old/drivers/net/jz_eth.h linux-2.6.24.7/drivers/net/jz_eth.h ---- linux-2.6.24.7.old/drivers/net/jz_eth.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/net/jz_eth.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,403 @@ -+/* -+ * linux/drivers/net/jz_eth.h -+ * -+ * Jz4730/Jz5730 On-Chip ethernet driver. -+ * -+ * Copyright (C) 2005 - 2007 Ingenic 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 __JZ_ETH_H__ -+#define __JZ_ETH_H__ -+ -+/* DMA control and status registers */ -+#define DMA_BMR (ETH_BASE + 0x1000) // Bus mode -+#define DMA_TPD (ETH_BASE + 0x1004) // Transmit poll demand register -+#define DMA_RPD (ETH_BASE + 0x1008) // Receieve poll demand register -+#define DMA_RRBA (ETH_BASE + 0x100C) // Receieve descriptor base address -+#define DMA_TRBA (ETH_BASE + 0x1010) // Transmit descriptor base address -+#define DMA_STS (ETH_BASE + 0x1014) // Status register -+#define DMA_OMR (ETH_BASE + 0x1018) // Command register -+#define DMA_IMR (ETH_BASE + 0x101C) -+#define DMA_MFC (ETH_BASE + 0x1020) -+ -+/* DMA CSR8-CSR19 reserved */ -+#define DMA_CTA (ETH_BASE + 0x1050) -+#define DMA_CRA (ETH_BASE + 0x1054) -+ -+/* Mac control and status registers */ -+#define MAC_MCR (ETH_BASE + 0x0000) -+#define MAC_MAH (ETH_BASE + 0x0004) -+#define MAC_MAL (ETH_BASE + 0x0008) -+#define MAC_HTH (ETH_BASE + 0x000C) -+#define MAC_HTL (ETH_BASE + 0x0010) -+#define MAC_MIIA (ETH_BASE + 0x0014) -+#define MAC_MIID (ETH_BASE + 0x0018) -+#define MAC_FCR (ETH_BASE + 0x001C) -+#define MAC_VTR1 (ETH_BASE + 0x0020) -+#define MAC_VTR2 (ETH_BASE + 0x0024) -+ -+/* -+ * Bus Mode Register (DMA_BMR) -+ */ -+#define BMR_PBL 0x00003f00 /* Programmable Burst Length */ -+#define BMR_DSL 0x0000007c /* Descriptor Skip Length */ -+#define BMR_BAR 0x00000002 /* Bus ARbitration */ -+#define BMR_SWR 0x00000001 /* Software Reset */ -+ -+#define PBL_0 0x00000000 /* DMA burst length = amount in RX FIFO */ -+#define PBL_1 0x00000100 /* 1 longword DMA burst length */ -+#define PBL_2 0x00000200 /* 2 longwords DMA burst length */ -+#define PBL_4 0x00000400 /* 4 longwords DMA burst length */ -+#define PBL_8 0x00000800 /* 8 longwords DMA burst length */ -+#define PBL_16 0x00001000 /* 16 longwords DMA burst length */ -+#define PBL_32 0x00002000 /* 32 longwords DMA burst length */ -+ -+#define DSL_0 0x00000000 /* 0 longword / descriptor */ -+#define DSL_1 0x00000004 /* 1 longword / descriptor */ -+#define DSL_2 0x00000008 /* 2 longwords / descriptor */ -+#define DSL_4 0x00000010 /* 4 longwords / descriptor */ -+#define DSL_8 0x00000020 /* 8 longwords / descriptor */ -+#define DSL_16 0x00000040 /* 16 longwords / descriptor */ -+#define DSL_32 0x00000080 /* 32 longwords / descriptor */ -+ -+/* -+ * Status Register (DMA_STS) -+ */ -+#define STS_BE 0x03800000 /* Bus Error Bits */ -+#define STS_TS 0x00700000 /* Transmit Process State */ -+#define STS_RS 0x000e0000 /* Receive Process State */ -+ -+#define TS_STOP 0x00000000 /* Stopped */ -+#define TS_FTD 0x00100000 /* Running Fetch Transmit Descriptor */ -+#define TS_WEOT 0x00200000 /* Running Wait for End Of Transmission */ -+#define TS_QDAT 0x00300000 /* Running Queue skb data into TX FIFO */ -+#define TS_RES 0x00400000 /* Reserved */ -+#define TS_SPKT 0x00500000 /* Reserved */ -+#define TS_SUSP 0x00600000 /* Suspended */ -+#define TS_CLTD 0x00700000 /* Running Close Transmit Descriptor */ -+ -+#define RS_STOP 0x00000000 /* Stopped */ -+#define RS_FRD 0x00020000 /* Running Fetch Receive Descriptor */ -+#define RS_CEOR 0x00040000 /* Running Check for End of Receive Packet */ -+#define RS_WFRP 0x00060000 /* Running Wait for Receive Packet */ -+#define RS_SUSP 0x00080000 /* Suspended */ -+#define RS_CLRD 0x000a0000 /* Running Close Receive Descriptor */ -+#define RS_FLUSH 0x000c0000 /* Running Flush RX FIFO */ -+#define RS_QRFS 0x000e0000 /* Running Queue RX FIFO into RX Skb */ -+ -+/* -+ * Operation Mode Register (DMA_OMR) -+ */ -+#define OMR_TTM 0x00400000 /* Transmit Threshold Mode */ -+#define OMR_SF 0x00200000 /* Store and Forward */ -+#define OMR_TR 0x0000c000 /* Threshold Control Bits */ -+#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */ -+#define OMR_OSF 0x00000004 /* Operate on Second Frame */ -+#define OMR_SR 0x00000002 /* Start/Stop Receive */ -+ -+#define TR_18 0x00000000 /* Threshold set to 18 (32) bytes */ -+#define TR_24 0x00004000 /* Threshold set to 24 (64) bytes */ -+#define TR_32 0x00008000 /* Threshold set to 32 (128) bytes */ -+#define TR_40 0x0000c000 /* Threshold set to 40 (256) bytes */ -+ -+/* -+ * Missed Frames Counters (DMA_MFC) -+ */ -+//#define MFC_CNT1 0xffff0000 /* Missed Frames Counter Bits by application */ -+#define MFC_CNT1 0x0ffe0000 /* Missed Frames Counter Bits by application */ -+#define MFC_CNT2 0x0000ffff /* Missed Frames Counter Bits by controller */ -+ -+/* -+ * Mac control Register (MAC_MCR) -+ */ -+#define MCR_RA 0x80000000 /* Receive All */ -+#define MCR_HBD 0x10000000 /* HeartBeat Disable */ -+#define MCR_PS 0x08000000 /* Port Select */ -+#define MCR_OWD 0x00800000 /* Receive own Disable */ -+#define MCR_OM 0x00600000 /* Operating(loopback) Mode */ -+#define MCR_FDX 0x00100000 /* Full Duplex Mode */ -+#define MCR_PM 0x00080000 /* Pass All Multicast */ -+#define MCR_PR 0x00040000 /* Promiscuous Mode */ -+#define MCR_IF 0x00020000 /* Inverse Filtering */ -+#define MCR_PB 0x00010000 /* Pass Bad Frames */ -+#define MCR_HO 0x00008000 /* Hash Only Filtering Mode */ -+#define MCR_HP 0x00002000 /* Hash/Perfect Receive Filtering Mode */ -+#define MCR_FC 0x00001000 /* Late Collision control */ -+#define MCR_BFD 0x00000800 /* Boardcast frame Disable */ -+#define MCR_RED 0x00000400 /* Retry Disable */ -+#define MCR_APS 0x00000100 /* Automatic pad stripping */ -+#define MCR_BL 0x000000c0 /* Back off Limit */ -+#define MCR_DC 0x00000020 /* Deferral check */ -+#define MCR_TE 0x00000008 /* Transmitter enable */ -+#define MCR_RE 0x00000004 /* Receiver enable */ -+ -+#define MCR_MII_10 ( OMR_TTM | MCR_PS) -+#define MCR_MII_100 ( MCR_HBD | MCR_PS) -+ -+/* Flow control Register (MAC_FCR) */ -+#define FCR_PT 0xffff0000 /* Pause time */ -+#define FCR_PCF 0x00000004 /* Pass control frames */ -+#define FCR_FCE 0x00000002 /* Flow control enable */ -+#define FCR_FCB 0x00000001 /* Flow control busy */ -+ -+ -+/* Constants for the interrupt mask and -+ * interrupt status registers. (DMA_SIS and DMA_IMR) -+ */ -+#define DMA_INT_NI 0x00010000 // Normal interrupt summary -+#define DMA_INT_AI 0x00008000 // Abnormal interrupt summary -+#define DMA_INT_ER 0x00004000 // Early receive interrupt -+#define DMA_INT_FB 0x00002000 // Fatal bus error -+#define DMA_INT_ET 0x00000400 // Early transmit interrupt -+#define DMA_INT_RW 0x00000200 // Receive watchdog timeout -+#define DMA_INT_RS 0x00000100 // Receive stop -+#define DMA_INT_RU 0x00000080 // Receive buffer unavailble -+#define DMA_INT_RI 0x00000040 // Receive interrupt -+#define DMA_INT_UN 0x00000020 // Underflow -+#define DMA_INT_TJ 0x00000008 // Transmit jabber timeout -+#define DMA_INT_TU 0x00000004 // Transmit buffer unavailble -+#define DMA_INT_TS 0x00000002 // Transmit stop -+#define DMA_INT_TI 0x00000001 // Transmit interrupt -+ -+/* -+ * Receive Descriptor Bit Summary -+ */ -+#define R_OWN 0x80000000 /* Own Bit */ -+#define RD_FF 0x40000000 /* Filtering Fail */ -+#define RD_FL 0x3fff0000 /* Frame Length */ -+#define RD_ES 0x00008000 /* Error Summary */ -+#define RD_DE 0x00004000 /* Descriptor Error */ -+#define RD_LE 0x00001000 /* Length Error */ -+#define RD_RF 0x00000800 /* Runt Frame */ -+#define RD_MF 0x00000400 /* Multicast Frame */ -+#define RD_FS 0x00000200 /* First Descriptor */ -+#define RD_LS 0x00000100 /* Last Descriptor */ -+#define RD_TL 0x00000080 /* Frame Too Long */ -+#define RD_CS 0x00000040 /* Collision Seen */ -+#define RD_FT 0x00000020 /* Frame Type */ -+#define RD_RJ 0x00000010 /* Receive Watchdog timeout*/ -+#define RD_RE 0x00000008 /* Report on MII Error */ -+#define RD_DB 0x00000004 /* Dribbling Bit */ -+#define RD_CE 0x00000002 /* CRC Error */ -+ -+#define RD_RER 0x02000000 /* Receive End Of Ring */ -+#define RD_RCH 0x01000000 /* Second Address Chained */ -+#define RD_RBS2 0x003ff800 /* Buffer 2 Size */ -+#define RD_RBS1 0x000007ff /* Buffer 1 Size */ -+ -+/* -+ * Transmit Descriptor Bit Summary -+ */ -+#define T_OWN 0x80000000 /* Own Bit */ -+#define TD_ES 0x00008000 /* Frame Aborted (error summary)*/ -+#define TD_LO 0x00000800 /* Loss Of Carrier */ -+#define TD_NC 0x00000400 /* No Carrier */ -+#define TD_LC 0x00000200 /* Late Collision */ -+#define TD_EC 0x00000100 /* Excessive Collisions */ -+#define TD_HF 0x00000080 /* Heartbeat Fail */ -+#define TD_CC 0x0000003c /* Collision Counter */ -+#define TD_UF 0x00000002 /* Underflow Error */ -+#define TD_DE 0x00000001 /* Deferred */ -+ -+#define TD_IC 0x80000000 /* Interrupt On Completion */ -+#define TD_LS 0x40000000 /* Last Segment */ -+#define TD_FS 0x20000000 /* First Segment */ -+#define TD_FT1 0x10000000 /* Filtering Type */ -+#define TD_SET 0x08000000 /* Setup Packet */ -+#define TD_AC 0x04000000 /* Add CRC Disable */ -+#define TD_TER 0x02000000 /* Transmit End Of Ring */ -+#define TD_TCH 0x01000000 /* Second Address Chained */ -+#define TD_DPD 0x00800000 /* Disabled Padding */ -+#define TD_FT0 0x00400000 /* Filtering Type */ -+#define TD_TBS2 0x003ff800 /* Buffer 2 Size */ -+#define TD_TBS1 0x000007ff /* Buffer 1 Size */ -+ -+#define PERFECT_F 0x00000000 -+#define HASH_F TD_FT0 -+#define INVERSE_F TD_FT1 -+#define HASH_O_F (TD_FT1 | TD_F0) -+ -+/* -+ * Constant setting -+ */ -+ -+#define IMR_DEFAULT ( DMA_INT_TI | DMA_INT_RI | \ -+ DMA_INT_TS | DMA_INT_RS | \ -+ DMA_INT_TU | DMA_INT_RU | \ -+ DMA_INT_FB ) -+ -+#define IMR_ENABLE (DMA_INT_NI | DMA_INT_AI) -+ -+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */ -+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ -+ -+#define HASH_TABLE_LEN 512 /* Bits */ -+#define HASH_BITS 0x01ff /* 9 LS bits */ -+ -+#define SETUP_FRAME_LEN 192 /* Bytes */ -+#define IMPERF_PA_OFFSET 156 /* Bytes */ -+ -+/* -+ * Address Filtering Modes -+ */ -+#define PERFECT 0 /* 16 perfect physical addresses */ -+#define HASH_PERF 1 /* 1 perfect, 512 multicast addresses */ -+#define PERFECT_REJ 2 /* Reject 16 perfect physical addresses */ -+#define ALL_HASH 3 /* Hashes all physical & multicast addrs */ -+ -+#define ALL 0 /* Clear out all the setup frame */ -+#define PHYS_ADDR_ONLY 1 /* Update the physical address only */ -+ -+/* MII register */ -+#define MII_BMCR 0x00 /* MII Basic Mode Control Register */ -+#define MII_BMSR 0x01 /* MII Basic Mode Status Register */ -+#define MII_ID1 0x02 /* PHY Identifier Register 1 */ -+#define MII_ID2 0x03 /* PHY Identifier Register 2 */ -+#define MII_ANAR 0x04 /* Auto Negotiation Advertisement Register */ -+#define MII_ANLPAR 0x05 /* Auto Negotiation Link Partner Ability */ -+#define MII_ANER 0x06 /* Auto Negotiation Expansion */ -+#define MII_DSCR 0x10 /* Davicom Specified Configration Register */ -+#define MII_DSCSR 0x11 /* Davicom Specified Configration/Status Register */ -+#define MII_10BTCSR 0x12 /* 10base-T Specified Configration/Status Register */ -+ -+ -+#define MII_PREAMBLE 0xffffffff /* MII Management Preamble */ -+#define MII_TEST 0xaaaaaaaa /* MII Test Signal */ -+#define MII_STRD 0x06 /* Start of Frame+Op Code: use low nibble */ -+#define MII_STWR 0x0a /* Start of Frame+Op Code: use low nibble */ -+ -+/* -+ * MII Management Control Register -+ */ -+#define MII_CR_RST 0x8000 /* RESET the PHY chip */ -+#define MII_CR_LPBK 0x4000 /* Loopback enable */ -+#define MII_CR_SPD 0x2000 /* 0: 10Mb/s; 1: 100Mb/s */ -+#define MII_CR_ASSE 0x1000 /* Auto Speed Select Enable */ -+#define MII_CR_PD 0x0800 /* Power Down */ -+#define MII_CR_ISOL 0x0400 /* Isolate Mode */ -+#define MII_CR_RAN 0x0200 /* Restart Auto Negotiation */ -+#define MII_CR_FDM 0x0100 /* Full Duplex Mode */ -+#define MII_CR_CTE 0x0080 /* Collision Test Enable */ -+ -+/* -+ * MII Management Status Register -+ */ -+#define MII_SR_T4C 0x8000 /* 100BASE-T4 capable */ -+#define MII_SR_TXFD 0x4000 /* 100BASE-TX Full Duplex capable */ -+#define MII_SR_TXHD 0x2000 /* 100BASE-TX Half Duplex capable */ -+#define MII_SR_TFD 0x1000 /* 10BASE-T Full Duplex capable */ -+#define MII_SR_THD 0x0800 /* 10BASE-T Half Duplex capable */ -+#define MII_SR_ASSC 0x0020 /* Auto Speed Selection Complete*/ -+#define MII_SR_RFD 0x0010 /* Remote Fault Detected */ -+#define MII_SR_ANC 0x0008 /* Auto Negotiation capable */ -+#define MII_SR_LKS 0x0004 /* Link Status */ -+#define MII_SR_JABD 0x0002 /* Jabber Detect */ -+#define MII_SR_XC 0x0001 /* Extended Capabilities */ -+ -+/* -+ * MII Management Auto Negotiation Advertisement Register -+ */ -+#define MII_ANA_TAF 0x03e0 /* Technology Ability Field */ -+#define MII_ANA_T4AM 0x0200 /* T4 Technology Ability Mask */ -+#define MII_ANA_TXAM 0x0180 /* TX Technology Ability Mask */ -+#define MII_ANA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ -+#define MII_ANA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ -+#define MII_ANA_100M 0x0380 /* 100Mb Technology Ability Mask */ -+#define MII_ANA_10M 0x0060 /* 10Mb Technology Ability Mask */ -+#define MII_ANA_CSMA 0x0001 /* CSMA-CD Capable */ -+ -+/* -+ * MII Management Auto Negotiation Remote End Register -+ */ -+#define MII_ANLPA_NP 0x8000 /* Next Page (Enable) */ -+#define MII_ANLPA_ACK 0x4000 /* Remote Acknowledge */ -+#define MII_ANLPA_RF 0x2000 /* Remote Fault */ -+#define MII_ANLPA_TAF 0x03e0 /* Technology Ability Field */ -+#define MII_ANLPA_T4AM 0x0200 /* T4 Technology Ability Mask */ -+#define MII_ANLPA_TXAM 0x0180 /* TX Technology Ability Mask */ -+#define MII_ANLPA_FDAM 0x0140 /* Full Duplex Technology Ability Mask */ -+#define MII_ANLPA_HDAM 0x02a0 /* Half Duplex Technology Ability Mask */ -+#define MII_ANLPA_100M 0x0380 /* 100Mb Technology Ability Mask */ -+#define MII_ANLPA_10M 0x0060 /* 10Mb Technology Ability Mask */ -+#define MII_ANLPA_CSMA 0x0001 /* CSMA-CD Capable */ -+ -+/* -+ * MII Management DAVICOM Specified Configuration And Status Register -+ */ -+#define MII_DSCSR_100FDX 0x8000 /* 100M Full Duplex Operation Mode */ -+#define MII_DSCSR_100HDX 0x4000 /* 100M Half Duplex Operation Mode */ -+#define MII_DSCSR_10FDX 0x2000 /* 10M Full Duplex Operation Mode */ -+#define MII_DSCSR_10HDX 0x1000 /* 10M Half Duplex Operation Mode */ -+#define MII_DSCSR_ANMB 0x000f /* Auto-Negotiation Monitor Bits */ -+ -+ -+/* -+ * Used by IOCTL -+ */ -+#define READ_COMMAND (SIOCDEVPRIVATE+4) -+#define WRITE_COMMAND (SIOCDEVPRIVATE+5) -+#define GETDRIVERINFO (SIOCDEVPRIVATE+6) -+ -+/* -+ * Device data and structure -+ */ -+ -+#define ETH_TX_TIMEOUT (6*HZ) -+ -+#define RX_BUF_SIZE 1536 -+ -+#define NUM_RX_DESCS 32 -+#define NUM_TX_DESCS 16 -+ -+static const char *media_types[] = { -+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ", -+ "100baseTx-FD", "100baseT4", 0 -+}; -+ -+typedef struct { -+ unsigned int status; -+ unsigned int desc1; -+ unsigned int buf1_addr; -+ unsigned int next_addr; -+} jz_desc_t; -+ -+struct jz_eth_private { -+ jz_desc_t tx_ring[NUM_TX_DESCS]; /* transmit descriptors */ -+ jz_desc_t rx_ring[NUM_RX_DESCS]; /* receive descriptors */ -+ dma_addr_t dma_tx_ring; /* bus address of tx ring */ -+ dma_addr_t dma_rx_ring; /* bus address of rx ring */ -+ dma_addr_t dma_rx_buf; /* DMA address of rx buffer */ -+ unsigned int vaddr_rx_buf; /* virtual address of rx buffer */ -+ -+ unsigned int rx_head; /* first rx descriptor */ -+ unsigned int tx_head; /* first tx descriptor */ -+ unsigned int tx_tail; /* last unacked transmit packet */ -+ unsigned int tx_full; /* transmit buffers are full */ -+ struct sk_buff *tx_skb[NUM_TX_DESCS]; /* skbuffs for packets to transmit */ -+ -+ struct net_device_stats stats; -+ spinlock_t lock; -+ -+ int media; /* Media (eg TP), mode (eg 100B)*/ -+ int full_duplex; /* Current duplex setting. */ -+ int link_state; -+ char phys[32]; /* List of attached PHY devices */ -+ char valid_phy; /* Current linked phy-id with MAC */ -+ int mii_phy_cnt; -+ int phy_type; /* 1-RTL8309,0-DVCOM */ -+ struct ethtool_cmd ecmds[32]; -+ u16 advertising; /* NWay media advertisement */ -+ -+ pid_t thr_pid; /* Link cheak thread ID */ -+ int thread_die; -+ struct completion thr_exited; -+ wait_queue_head_t thr_wait; -+ -+ struct pm_dev *pmdev; -+}; -+ -+#endif /* __JZ_ETH_H__ */ -diff -urN linux-2.6.24.7.old/drivers/net/jzcs8900a.c linux-2.6.24.7/drivers/net/jzcs8900a.c ---- linux-2.6.24.7.old/drivers/net/jzcs8900a.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/net/jzcs8900a.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,649 @@ -+ -+/* -+ * linux/drivers/net/jzcs8900a.c -+ * -+ * Author: Lucifer -+ * -+ * A Cirrus Logic CS8900A driver for Linux -+ * based on the cs89x0 driver written by Russell Nelson, -+ * Donald Becker, and others. -+ * -+ * This source code 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. -+ */ -+ -+/* -+ * At the moment the driver does not support memory mode operation. -+ * It is trivial to implement this, but not worth the effort. -+ */ -+ -+/* -+ * TODO: -+ * -+ * 1. If !ready in send_start(), queue buffer and send it in interrupt handler -+ * when we receive a BufEvent with Rdy4Tx, send it again. dangerous! -+ * 2. how do we prevent interrupt handler destroying integrity of get_stats()? -+ * 3. Change reset code to check status. -+ * 4. Implement set_mac_address and remove fake mac address -+ * 5. Link status detection stuff -+ * 6. Write utility to write EEPROM, do self testing, etc. -+ * 7. Implement DMA routines (I need a board w/ DMA support for that) -+ * 8. Power management -+ * 9. Add support for multiple ethernet chips -+ * 10. Add support for other cs89xx chips (need hardware for that) -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jzcs8900a.h" -+ -+#define FULL_DUPLEX -+#define INT_PIN 0 -+#ifdef CONFIG_SOC_JZ4740 -+#define CIRRUS_DEFAULT_IO 0xa8000000 -+#define CIRRUS_DEFAULT_IRQ 107 -+ -+#elif CONFIG_SOC_JZ4750 -+#define CIRRUS_DEFAULT_IO 0xac000000 -+ -+#ifdef CONFIG_JZ4750_FUWA -+#define CIRRUS_DEFAULT_IRQ (32*4+20+48) -+#else -+#define CIRRUS_DEFAULT_IRQ (32*2 +6+48) -+#endif -+ -+ -+#endif -+ -+typedef struct { -+ struct net_device_stats stats; -+ u16 txlen; -+} cirrus_t; -+ -+static int ethaddr_cmd = 0; -+static unsigned char ethaddr_hex[6]; -+static struct net_device *dev; -+ -+/* -+ * I/O routines -+ */ -+static void gpio_init_cs8900(void) -+{ -+#ifdef CONFIG_SOC_JZ4740 -+ __gpio_as_func0(60); //CS4# -+ __gpio_as_func0(61); //RD# -+ __gpio_as_func0(62); //WR# -+ __gpio_as_irq_high_level(59); //irq -+ __gpio_disable_pull(59); //disable pull -+ REG_EMC_SMCR4 |= (1 << 6); //16bit -+#elif CONFIG_SOC_JZ4750 -+ __gpio_as_func0(32*2+23); //CS3# -+ __gpio_as_func0(32*2+25); //RD# -+ __gpio_as_func0(32*2+26); //WR# -+ -+#ifdef CONFIG_JZ4750_FUWA -+ __gpio_as_irq_high_level(32*4+20); //irq -+ __gpio_disable_pull(32*4+20); //disable pull -+#else -+ __gpio_as_irq_high_level(32*2 +6); //irq -+ __gpio_disable_pull(32*2 +6); //disable pull -+#endif -+ -+ REG_EMC_SMCR3 |= (1 << 6); //16bit -+#endif -+ udelay(1); -+} -+ -+static inline u16 cirrus_read (struct net_device *dev,u16 reg) -+{ -+ outw (reg,dev->base_addr + PP_Address); -+ return (inw (dev->base_addr + PP_Data)); -+} -+ -+static inline void cirrus_write (struct net_device *dev,u16 reg,u16 value) -+{ -+ outw (reg,dev->base_addr + PP_Address); -+ outw (value,dev->base_addr + PP_Data); -+} -+ -+static inline void cirrus_set (struct net_device *dev,u16 reg,u16 value) -+{ -+ cirrus_write (dev,reg,cirrus_read (dev,reg) | value); -+} -+ -+static inline void cirrus_clear (struct net_device *dev,u16 reg,u16 value) -+{ -+ cirrus_write (dev,reg,cirrus_read (dev,reg) & ~value); -+} -+ -+static inline void cirrus_frame_read (struct net_device *dev,struct sk_buff *skb,u16 length) -+{ -+ insw (dev->base_addr,skb_put (skb,length),(length + 1) / 2); -+} -+ -+static inline void cirrus_frame_write (struct net_device *dev,struct sk_buff *skb) -+{ -+ outsw (dev->base_addr,skb->data,(skb->len + 1) / 2); -+} -+ -+/* -+ * Debugging functions -+ */ -+ -+#ifdef DEBUG -+static inline int printable (int c) -+{ -+ return ((c >= 32 && c <= 126) || -+ (c >= 174 && c <= 223) || -+ (c >= 242 && c <= 243) || -+ (c >= 252 && c <= 253)); -+} -+ -+static void dump16 (struct net_device *dev,const u8 *s,size_t len) -+{ -+ int i; -+ char str[128]; -+ -+ if (!len) return; -+ -+ *str = '\0'; -+ -+ for (i = 0; i < len; i++) { -+ if (i && !(i % 4)) strcat (str," "); -+ sprintf (str,"%s%.2x ",str,s[i]); -+ } -+ -+ for ( ; i < 16; i++) { -+ if (i && !(i % 4)) strcat (str," "); -+ strcat (str," "); -+ } -+ -+ strcat (str," "); -+ for (i = 0; i < len; i++) sprintf (str,"%s%c",str,printable (s[i]) ? s[i] : '.'); -+ -+ printk (KERN_DEBUG "%s: %s\n",dev->name,str); -+} -+ -+static void hexdump (struct net_device *dev,const void *ptr,size_t size) -+{ -+ const u8 *s = (u8 *) ptr; -+ int i; -+ for (i = 0; i < size / 16; i++, s += 16) dump16 (dev,s,16); -+ dump16 (dev,s,size % 16); -+} -+ -+static void dump_packet (struct net_device *dev,struct sk_buff *skb,const char *type) -+{ -+ printk (KERN_INFO "%s: %s %d byte frame %.2x:%.2x:%.2x:%.2x:%.2x:%.2x to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x type %.4x\n", -+ dev->name, -+ type, -+ skb->len, -+ skb->data[0],skb->data[1],skb->data[2],skb->data[3],skb->data[4],skb->data[5], -+ skb->data[6],skb->data[7],skb->data[8],skb->data[9],skb->data[10],skb->data[11], -+ (skb->data[12] << 8) | skb->data[13]); -+ if (skb->len < 0x100) hexdump (dev,skb->data,skb->len); -+} -+#endif /* #ifdef DEBUG */ -+ -+/* -+ * Driver functions -+ */ -+ -+static void cirrus_receive (struct net_device *dev) -+{ -+ cirrus_t *priv = (cirrus_t *) dev->priv; -+ struct sk_buff *skb; -+ u16 status,length; -+ -+ status = cirrus_read (dev,PP_RxStatus); -+ length = cirrus_read (dev,PP_RxLength); -+ -+ if (!(status & RxOK)) { -+ priv->stats.rx_errors++; -+ if ((status & (Runt | Extradata))) priv->stats.rx_length_errors++; -+ if ((status & CRCerror)) priv->stats.rx_crc_errors++; -+ return; -+ } -+ -+ if ((skb = dev_alloc_skb (length + 4)) == NULL) { -+ priv->stats.rx_dropped++; -+ return; -+ } -+ -+ skb->dev = dev; -+ skb_reserve (skb,2); -+ -+ cirrus_frame_read (dev,skb,length); -+ skb->protocol = eth_type_trans (skb,dev); -+ -+ netif_rx (skb); -+ dev->last_rx = jiffies; -+ -+ priv->stats.rx_packets++; -+ priv->stats.rx_bytes += length; -+} -+ -+static int cirrus_send_start (struct sk_buff *skb,struct net_device *dev) -+{ -+ cirrus_t *priv = (cirrus_t *) dev->priv; -+ u16 status; -+ -+ mdelay(10); -+ netif_stop_queue (dev); -+ -+ cirrus_write (dev,PP_TxCMD,TxStart (After5)); -+ cirrus_write (dev,PP_TxLength,skb->len); -+ -+ status = cirrus_read (dev,PP_BusST); -+ -+ if ((status & TxBidErr)) { -+ printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len); -+ priv->stats.tx_errors++; -+ priv->stats.tx_aborted_errors++; -+ priv->txlen = 0; -+ return (1); -+ } -+ -+ if (!(status & Rdy4TxNOW)) { -+ //printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name); -+ priv->stats.tx_errors++; -+ priv->txlen = 0; -+ /* FIXME: store skb and send it in interrupt handler */ -+ return (1); -+ } -+ -+ cirrus_frame_write (dev,skb); -+ dev->trans_start = jiffies; -+ -+ dev_kfree_skb (skb); -+ -+ priv->txlen = skb->len; -+ -+ return (0); -+} -+ -+static irqreturn_t cirrus_interrupt(int irq, void *id) -+{ -+ struct net_device *dev = (struct net_device *) id; -+ cirrus_t *priv; -+ u16 status; -+ -+ if (dev->priv == NULL) { -+ return IRQ_NONE; -+ } -+ -+ priv = (cirrus_t *) dev->priv; -+ -+ while ((status = cirrus_read (dev,PP_ISQ))) { -+ switch (RegNum (status)) { -+ case RxEvent: -+ cirrus_receive (dev); -+ break; -+ -+ case TxEvent: -+ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL)); -+ if (!(RegContent (status) & TxOK)) { -+ priv->stats.tx_errors++; -+ if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++; -+ if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++; -+ break; -+ } else if (priv->txlen) { -+ priv->stats.tx_packets++; -+ priv->stats.tx_bytes += priv->txlen; -+ } -+ priv->txlen = 0; -+ netif_wake_queue (dev); -+ break; -+ -+ case BufEvent: -+ if ((RegContent (status) & RxMiss)) { -+ u16 missed = MissCount (cirrus_read (dev,PP_RxMISS)); -+ priv->stats.rx_errors += missed; -+ priv->stats.rx_missed_errors += missed; -+ } -+ if ((RegContent (status) & TxUnderrun)) { -+ priv->stats.tx_errors++; -+ priv->stats.tx_fifo_errors++; -+ } -+ /* FIXME: if Rdy4Tx, transmit last sent packet (if any) */ -+ priv->txlen = 0; -+ netif_wake_queue (dev); -+ break; -+ -+ case TxCOL: -+ priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL)); -+ break; -+ -+ case RxMISS: -+ status = MissCount (cirrus_read (dev,PP_RxMISS)); -+ priv->stats.rx_errors += status; -+ priv->stats.rx_missed_errors += status; -+ break; -+ default: -+ return IRQ_HANDLED; -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void cirrus_transmit_timeout (struct net_device *dev) -+{ -+ cirrus_t *priv = (cirrus_t *) dev->priv; -+ priv->stats.tx_errors++; -+ priv->stats.tx_heartbeat_errors++; -+ priv->txlen = 0; -+ netif_wake_queue (dev); -+} -+ -+static int cirrus_start (struct net_device *dev) -+{ -+ int result; -+ -+ /* valid ethernet address? */ -+ if (!is_valid_ether_addr(dev->dev_addr)) { -+ printk(KERN_ERR "%s: invalid ethernet MAC address\n",dev->name); -+ return (-EINVAL); -+ } -+ -+ /* install interrupt handler */ -+ if ((result = request_irq (dev->irq, &cirrus_interrupt, IRQF_DISABLED, dev->name, dev)) < 0) { -+ printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq); -+ return (result); -+ } -+ -+ /* enable the ethernet controller */ -+ cirrus_set (dev,PP_RxCFG,RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE); -+ cirrus_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA); -+ cirrus_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE); -+ cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE); -+ cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON); -+ cirrus_set (dev,PP_BusCTL,EnableRQ); -+ -+#ifdef FULL_DUPLEX -+ cirrus_set (dev,PP_TestCTL,FDX); -+#endif /* #ifdef FULL_DUPLEX */ -+ -+ /* start the queue */ -+ netif_start_queue (dev); -+ __gpio_unmask_irq(59); -+ -+ //MOD_INC_USE_COUNT; -+ return (0); -+} -+ -+static int cirrus_stop (struct net_device *dev) -+{ -+ /* disable ethernet controller */ -+ cirrus_write (dev,PP_BusCTL,0); -+ cirrus_write (dev,PP_TestCTL,0); -+ cirrus_write (dev,PP_SelfCTL,0); -+ cirrus_write (dev,PP_LineCTL,0); -+ cirrus_write (dev,PP_BufCFG,0); -+ cirrus_write (dev,PP_TxCFG,0); -+ cirrus_write (dev,PP_RxCTL,0); -+ cirrus_write (dev,PP_RxCFG,0); -+ -+ /* uninstall interrupt handler */ -+ free_irq (dev->irq,dev); -+ -+ /* stop the queue */ -+ netif_stop_queue (dev); -+ -+ //MOD_DEC_USE_COUNT; -+ -+ return (0); -+} -+ -+static int cirrus_set_mac_address (struct net_device *dev, void *p) -+{ -+ struct sockaddr *addr = (struct sockaddr *)p; -+ int i; -+ -+ if (netif_running(dev)) -+ return -EBUSY; -+ -+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -+ -+ /* configure MAC address */ -+ for (i = 0; i < ETH_ALEN; i += 2) -+ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); -+ -+ return 0; -+} -+ -+static struct net_device_stats *cirrus_get_stats (struct net_device *dev) -+{ -+ cirrus_t *priv = (cirrus_t *) dev->priv; -+ return (&priv->stats); -+} -+ -+static void cirrus_set_receive_mode (struct net_device *dev) -+{ -+ if ((dev->flags & IFF_PROMISC)) -+ cirrus_set (dev,PP_RxCTL,PromiscuousA); -+ else -+ cirrus_clear (dev,PP_RxCTL,PromiscuousA); -+ -+ if ((dev->flags & IFF_ALLMULTI) && dev->mc_list) -+ cirrus_set (dev,PP_RxCTL,MulticastA); -+ else -+ cirrus_clear (dev,PP_RxCTL,MulticastA); -+} -+ -+/* -+ * Architecture dependant code -+ */ -+ -+/* -+ * Driver initialization routines -+ */ -+ -+int __init cirrus_probe(void) -+{ -+ static cirrus_t priv; -+ int i; -+ u16 value; -+ -+ printk ("Jz CS8900A driver for Linux (V0.02)\n"); -+ -+ /* Init hardware for PAVO board */ -+ gpio_init_cs8900(); -+ -+ /* Allocate ethernet device */ -+ dev = alloc_etherdev(sizeof(struct net_device)); -+ -+ memset (&priv,0,sizeof (cirrus_t)); -+ -+ ether_setup (dev); -+ -+ dev->open = cirrus_start; -+ dev->stop = cirrus_stop; -+ dev->hard_start_xmit = cirrus_send_start; -+ dev->get_stats = cirrus_get_stats; -+ dev->set_multicast_list = cirrus_set_receive_mode; -+ dev->set_mac_address = cirrus_set_mac_address; -+ dev->tx_timeout = cirrus_transmit_timeout; -+ dev->watchdog_timeo = HZ; -+ -+ if (ethaddr_cmd==1) -+ { -+ dev->dev_addr[0] = ethaddr_hex[0]; -+ dev->dev_addr[1] = ethaddr_hex[1]; -+ dev->dev_addr[2] = ethaddr_hex[2]; -+ dev->dev_addr[3] = ethaddr_hex[3]; -+ dev->dev_addr[4] = ethaddr_hex[4]; -+ dev->dev_addr[5] = ethaddr_hex[5]; -+ } -+ else //default mac address 00:2a:cc:2a:af:fe -+ { -+ dev->dev_addr[0] = 0x00; -+ dev->dev_addr[1] = 0x62; -+ dev->dev_addr[2] = 0x9c; -+ dev->dev_addr[3] = 0x61; -+ dev->dev_addr[4] = 0xcf; -+ dev->dev_addr[5] = 0x16; -+ } -+ dev->if_port = IF_PORT_10BASET; -+ dev->priv = (void *) &priv; -+ -+ dev->base_addr = CIRRUS_DEFAULT_IO; -+ dev->irq = CIRRUS_DEFAULT_IRQ; -+ -+ -+ /* module parameters override everything */ -+ if (!dev->base_addr) { -+ printk (KERN_ERR -+ "%s: No default I/O base address defined. Use io=... or\n" -+ "%s: define CIRRUS_DEFAULT_IO for your platform\n", -+ dev->name,dev->name); -+ return (-EINVAL); -+ } -+ -+ if (!dev->irq) { -+ printk (KERN_ERR -+ "%s: No default IRQ number defined. Use irq=... or\n" -+ "%s: define CIRRUS_DEFAULT_IRQ for your platform\n", -+ dev->name,dev->name); -+ return (-EINVAL); -+ } -+#if 0 -+ if ((result = check_region (dev->base_addr,16))) { -+ printk (KERN_ERR "%s: can't get I/O port address 0x%lx\n",dev->name,dev->base_addr); -+ return (result); -+ } -+#endif -+ if (!request_region (dev->base_addr,16,dev->name)) -+ return -EBUSY; -+#if 0 -+ /* verify EISA registration number for Cirrus Logic */ -+ if ((value = cirrus_read (dev,PP_ProductID)) != EISA_REG_CODE) { -+ printk (KERN_ERR "%s: incorrect signature 0x%.4x\n",dev->name,value); -+ return (-ENXIO); -+ } -+#endif -+ -+ /* verify chip version */ -+ value = cirrus_read (dev,PP_ProductID + 2); -+ if (VERSION (value) != CS8900A) { -+ printk (KERN_ERR "%s: unknown chip version 0x%.8x\n",dev->name,VERSION (value)); -+ return (-ENXIO); -+ } -+ printk (KERN_INFO "%s: CS8900A rev %c detected\n",dev->name,'B' + REVISION (value) - REV_B); -+ -+ /* setup interrupt number */ -+ cirrus_write (dev,PP_IntNum,INT_PIN); -+ -+ /* configure MAC address */ -+ for (i = 0; i < ETH_ALEN; i += 2) -+ { -+ //printk(" %x",dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); -+ cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8)); -+ } -+ -+ if (register_netdev(dev) != 0) { -+ printk(KERN_ERR " Cannot register net device\n"); -+ free_netdev(dev); -+ return -ENOMEM; -+ } -+ -+ return (0); -+} -+ -+static inline unsigned char str2hexnum(unsigned char c) -+{ -+ if(c >= '0' && c <= '9') -+ return c - '0'; -+ if(c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ if(c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ return 0; /* foo */ -+} -+ -+static inline void str2eaddr(unsigned char *ea, unsigned char *str) -+{ -+ int i; -+ -+ for(i = 0; i < 6; i++) { -+ unsigned char num; -+ -+ if((*str == '.') || (*str == ':')) -+ str++; -+ num = str2hexnum(*str++) << 4; -+ num |= (str2hexnum(*str++)); -+ ea[i] = num; -+ } -+} -+ -+static int __init ethernet_addr_setup(char *str) -+{ -+ if (!str) { -+ printk("ethaddr not set in command line\n"); -+ return -1; -+ } -+ ethaddr_cmd = 1; -+ str2eaddr(ethaddr_hex, str); -+ return 0; -+} -+ -+__setup("ethaddr=", ethernet_addr_setup); -+ -+//EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR ("Lucifer "); -+MODULE_DESCRIPTION ("Jz CS8900A driver for Linux (V0.02)"); -+MODULE_LICENSE ("GPL"); -+ -+//#ifdef MODULE -+ -+ -+#if 0 -+static int io = 0; -+static int irq = 0; -+ -+module_param(io, int, 0); -+MODULE_PARM_DESC (io,"I/O Base Address"); -+//MODULE_PARM (io,"i"); -+ -+module_param(irq, int, 0); -+MODULE_PARM_DESC (irq,"IRQ Number"); -+//MODULE_PARM (irq,"i"); -+#endif -+ -+static int __init jzcs8900_init(void) -+{ -+ if (cirrus_probe()) { -+ printk(KERN_WARNING "jzcs8900: No cs8900a found\n"); -+ } -+ -+ return 0; -+} -+ -+static void __exit jzcs8900_exit(void) -+{ -+ release_region(dev->base_addr,16); -+ unregister_netdev(dev); -+ free_netdev(dev); -+} -+ -+module_init(jzcs8900_init); -+module_exit(jzcs8900_exit); -diff -urN linux-2.6.24.7.old/drivers/net/jzcs8900a.h linux-2.6.24.7/drivers/net/jzcs8900a.h ---- linux-2.6.24.7.old/drivers/net/jzcs8900a.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/net/jzcs8900a.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,235 @@ -+#ifndef JZCS8900A_H -+#define JZCS8900A_H -+ -+/* -+ * linux/drivers/net/jzcs8900a.h -+ * -+ * Author: Lucifer -+ * -+ * A Cirrus Logic CS8900A driver for Linux -+ * based on the cs89x0 driver written by Russell Nelson, -+ * Donald Becker, and others. -+ * -+ * This source code 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. -+ */ -+ -+/* -+ * Ports -+ */ -+ -+#define PP_Address 0x0a /* PacketPage Pointer Port (Section 4.10.10) */ -+#define PP_Data 0x0c /* PacketPage Data Port (Section 4.10.10) */ -+ -+/* -+ * Registers -+ */ -+ -+#define PP_ProductID 0x0000 /* Section 4.3.1 Product Identification Code */ -+#define PP_MemBase 0x002c /* Section 4.9.2 Memory Base Address Register */ -+#define PP_IntNum 0x0022 /* Section 3.2.3 Interrupt Number */ -+#define PP_EEPROMCommand 0x0040 /* Section 4.3.11 EEPROM Command */ -+#define PP_EEPROMData 0x0042 /* Section 4.3.12 EEPROM Data */ -+#define PP_RxCFG 0x0102 /* Section 4.4.6 Receiver Configuration */ -+#define PP_RxCTL 0x0104 /* Section 4.4.8 Receiver Control */ -+#define PP_TxCFG 0x0106 /* Section 4.4.9 Transmit Configuration */ -+#define PP_BufCFG 0x010a /* Section 4.4.12 Buffer Configuration */ -+#define PP_LineCTL 0x0112 /* Section 4.4.16 Line Control */ -+#define PP_SelfCTL 0x0114 /* Section 4.4.18 Self Control */ -+#define PP_BusCTL 0x0116 /* Section 4.4.20 Bus Control */ -+#define PP_TestCTL 0x0118 /* Section 4.4.22 Test Control */ -+#define PP_ISQ 0x0120 /* Section 4.4.5 Interrupt Status Queue */ -+#define PP_TxEvent 0x0128 /* Section 4.4.10 Transmitter Event */ -+#define PP_BufEvent 0x012c /* Section 4.4.13 Buffer Event */ -+#define PP_RxMISS 0x0130 /* Section 4.4.14 Receiver Miss Counter */ -+#define PP_TxCOL 0x0132 /* Section 4.4.15 Transmit Collision Counter */ -+#define PP_SelfST 0x0136 /* Section 4.4.19 Self Status */ -+#define PP_BusST 0x0138 /* Section 4.4.21 Bus Status */ -+#define PP_TxCMD 0x0144 /* Section 4.4.11 Transmit Command */ -+#define PP_TxLength 0x0146 /* Section 4.5.2 Transmit Length */ -+#define PP_IA 0x0158 /* Section 4.6.2 Individual Address (IEEE Address) */ -+#define PP_RxStatus 0x0400 /* Section 4.7.1 Receive Status */ -+#define PP_RxLength 0x0402 /* Section 4.7.1 Receive Length (in bytes) */ -+#define PP_RxFrame 0x0404 /* Section 4.7.2 Receive Frame Location */ -+#define PP_TxFrame 0x0a00 /* Section 4.7.2 Transmit Frame Location */ -+ -+/* -+ * Values -+ */ -+ -+/* PP_IntNum */ -+#define INTRQ0 0x0000 -+#define INTRQ1 0x0001 -+#define INTRQ2 0x0002 -+#define INTRQ3 0x0003 -+ -+/* PP_ProductID */ -+#define EISA_REG_CODE 0x630e -+#define REVISION(x) (((x) & 0x1f00) >> 8) -+#define VERSION(x) ((x) & ~0x1f00) -+ -+#define CS8900A 0x0000 -+#define REV_B 7 -+#define REV_C 8 -+#define REV_D 9 -+ -+/* PP_RxCFG */ -+#define Skip_1 0x0040 -+#define StreamE 0x0080 -+#define RxOKiE 0x0100 -+#define RxDMAonly 0x0200 -+#define AutoRxDMAE 0x0400 -+#define BufferCRC 0x0800 -+#define CRCerroriE 0x1000 -+#define RuntiE 0x2000 -+#define ExtradataiE 0x4000 -+ -+/* PP_RxCTL */ -+#define IAHashA 0x0040 -+#define PromiscuousA 0x0080 -+#define RxOKA 0x0100 -+#define MulticastA 0x0200 -+#define IndividualA 0x0400 -+#define BroadcastA 0x0800 -+#define CRCerrorA 0x1000 -+#define RuntA 0x2000 -+#define ExtradataA 0x4000 -+ -+/* PP_TxCFG */ -+#define Loss_of_CRSiE 0x0040 -+#define SQErroriE 0x0080 -+#define TxOKiE 0x0100 -+#define Out_of_windowiE 0x0200 -+#define JabberiE 0x0400 -+#define AnycolliE 0x0800 -+#define T16colliE 0x8000 -+ -+/* PP_BufCFG */ -+#define SWint_X 0x0040 -+#define RxDMAiE 0x0080 -+#define Rdy4TxiE 0x0100 -+#define TxUnderruniE 0x0200 -+#define RxMissiE 0x0400 -+#define Rx128iE 0x0800 -+#define TxColOvfiE 0x1000 -+#define MissOvfloiE 0x2000 -+#define RxDestiE 0x8000 -+ -+/* PP_LineCTL */ -+#define SerRxON 0x0040 -+#define SerTxON 0x0080 -+#define AUIonly 0x0100 -+#define AutoAUI_10BT 0x0200 -+#define ModBackoffE 0x0800 -+#define PolarityDis 0x1000 -+#define L2_partDefDis 0x2000 -+#define LoRxSquelch 0x4000 -+ -+/* PP_SelfCTL */ -+#define RESET 0x0040 -+#define SWSuspend 0x0100 -+#define HWSleepE 0x0200 -+#define HWStandbyE 0x0400 -+#define HC0E 0x1000 -+#define HC1E 0x2000 -+#define HCB0 0x4000 -+#define HCB1 0x8000 -+ -+/* PP_BusCTL */ -+#define ResetRxDMA 0x0040 -+#define DMAextend 0x0100 -+#define UseSA 0x0200 -+#define MemoryE 0x0400 -+#define DMABurst 0x0800 -+#define IOCHRDYE 0x1000 -+#define RxDMAsize 0x2000 -+#define EnableRQ 0x8000 -+ -+/* PP_TestCTL */ -+#define DisableLT 0x0080 -+#define ENDECloop 0x0200 -+#define AUIloop 0x0400 -+#define DisableBackoff 0x0800 -+#define FDX 0x4000 -+ -+/* PP_ISQ */ -+#define RegNum(x) ((x) & 0x3f) -+#define RegContent(x) ((x) & ~0x3d) -+ -+#define RxEvent 0x0004 -+#define TxEvent 0x0008 -+#define BufEvent 0x000c -+#define RxMISS 0x0010 -+#define TxCOL 0x0012 -+ -+/* PP_RxStatus */ -+#define IAHash 0x0040 -+#define Dribblebits 0x0080 -+#define RxOK 0x0100 -+#define Hashed 0x0200 -+#define IndividualAdr 0x0400 -+#define Broadcast 0x0800 -+#define CRCerror 0x1000 -+#define Runt 0x2000 -+#define Extradata 0x4000 -+ -+#define HashTableIndex(x) ((x) >> 0xa) -+ -+/* PP_TxCMD */ -+#define After5 0 -+#define After381 1 -+#define After1021 2 -+#define AfterAll 3 -+#define TxStart(x) ((x) << 6) -+ -+#define Force 0x0100 -+#define Onecoll 0x0200 -+#define InhibitCRC 0x1000 -+#define TxPadDis 0x2000 -+ -+/* PP_BusST */ -+#define TxBidErr 0x0080 -+#define Rdy4TxNOW 0x0100 -+ -+/* PP_TxEvent */ -+#define Loss_of_CRS 0x0040 -+#define SQEerror 0x0080 -+#define TxOK 0x0100 -+#define Out_of_window 0x0200 -+#define Jabber 0x0400 -+#define T16coll 0x8000 -+ -+#define TX_collisions(x) (((x) >> 0xb) & ~0x8000) -+ -+/* PP_BufEvent */ -+#define SWint 0x0040 -+#define RxDMAFrame 0x0080 -+#define Rdy4Tx 0x0100 -+#define TxUnderrun 0x0200 -+#define RxMiss 0x0400 -+#define Rx128 0x0800 -+#define RxDest 0x8000 -+ -+/* PP_RxMISS */ -+#define MissCount(x) ((x) >> 6) -+ -+/* PP_TxCOL */ -+#define ColCount(x) ((x) >> 6) -+ -+/* PP_SelfST */ -+#define T3VActive 0x0040 -+#define INITD 0x0080 -+#define SIBUSY 0x0100 -+#define EEPROMpresent 0x0200 -+#define EEPROMOK 0x0400 -+#define ELpresent 0x0800 -+#define EEsize 0x1000 -+ -+/* PP_EEPROMCommand */ -+#define EEWriteRegister 0x0100 -+#define EEReadRegister 0x0200 -+#define EEEraseRegister 0x0300 -+#define ELSEL 0x0400 -+ -+#endif /* #ifndef CIRRUS_H */ -diff -urN linux-2.6.24.7.old/drivers/pnp/Kconfig linux-2.6.24.7/drivers/pnp/Kconfig ---- linux-2.6.24.7.old/drivers/pnp/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/pnp/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -5,7 +5,7 @@ - menuconfig PNP - bool "Plug and Play support" - depends on HAS_IOMEM -- depends on ISA || ACPI -+# depends on ISA || ACPI - ---help--- - Plug and Play (PnP) is a standard for peripherals which allows those - peripherals to be configured by software, e.g. assign IRQ's or other -diff -urN linux-2.6.24.7.old/drivers/pnp/core.c linux-2.6.24.7/drivers/pnp/core.c ---- linux-2.6.24.7.old/drivers/pnp/core.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/pnp/core.c 2009-04-12 18:13:57.000000000 +0200 -@@ -74,6 +74,8 @@ - return device_register(&protocol->dev); - } - -+EXPORT_SYMBOL(pnp_register_protocol); -+ - /** - * pnp_protocol_unregister - removes a pnp protocol from the pnp layer - * @protocol: pointer to the corresponding pnp_protocol structure -@@ -86,6 +88,8 @@ - device_unregister(&protocol->dev); - } - -+EXPORT_SYMBOL(pnp_unregister_protocol); -+ - static void pnp_free_ids(struct pnp_dev *dev) - { - struct pnp_id *id; -@@ -166,6 +170,8 @@ - return 0; - } - -+EXPORT_SYMBOL(pnp_add_device); -+ - void __pnp_remove_device(struct pnp_dev *dev) - { - spin_lock(&pnp_lock); -@@ -175,6 +181,21 @@ - device_unregister(&dev->dev); - } - -+/** -+ * pnp_remove_device - removes a pnp device from the pnp layer -+ * @dev: pointer to dev to add -+ * -+ * this function will free all mem used by dev -+ */ -+void pnp_remove_device(struct pnp_dev *dev) -+{ -+ if (!dev || dev->card) -+ return; -+ __pnp_remove_device(dev); -+} -+ -+EXPORT_SYMBOL(pnp_remove_device); -+ - static int __init pnp_init(void) - { - printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n"); -diff -urN linux-2.6.24.7.old/drivers/pnp/driver.c linux-2.6.24.7/drivers/pnp/driver.c ---- linux-2.6.24.7.old/drivers/pnp/driver.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/pnp/driver.c 2009-04-12 18:13:57.000000000 +0200 -@@ -246,3 +246,4 @@ - EXPORT_SYMBOL(pnp_unregister_driver); - EXPORT_SYMBOL(pnp_device_attach); - EXPORT_SYMBOL(pnp_device_detach); -+EXPORT_SYMBOL(pnp_add_id); -diff -urN linux-2.6.24.7.old/drivers/pnp/resource.c linux-2.6.24.7/drivers/pnp/resource.c ---- linux-2.6.24.7.old/drivers/pnp/resource.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/pnp/resource.c 2009-04-12 18:13:57.000000000 +0200 -@@ -404,6 +404,10 @@ - - int pnp_check_dma(struct pnp_dev *dev, int idx) - { -+ printk("*********** %s, %s, line[%d]: Fix me, this should update in the future *********\n", -+ __FILE__, __FUNCTION__, __LINE__); -+ return 0; /* should be update in the future. Wolfgang ???*/ -+ - #ifndef CONFIG_IA64 - int tmp; - struct pnp_dev *tdev; -diff -urN linux-2.6.24.7.old/drivers/serial/8250.c linux-2.6.24.7/drivers/serial/8250.c ---- linux-2.6.24.7.old/drivers/serial/8250.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/serial/8250.c 2009-04-12 18:13:57.000000000 +0200 -@@ -12,7 +12,7 @@ - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * -- * $Id: 8250.c,v 1.90 2002/07/28 10:03:27 rmk Exp $ -+ * $Id: 8250.c,v 1.5 2008-07-14 06:40:28 lhhuang Exp $ - * - * A note about mapbase / membase - * -@@ -181,7 +181,7 @@ - [PORT_16550A] = { - .name = "16550A", - .fifo_size = 16, -- .tx_loadsz = 16, -+ .tx_loadsz = 8, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, -@@ -400,6 +400,10 @@ - break; - - case UPIO_MEM: -+#if defined(CONFIG_JZSOC) -+ if (offset == (UART_FCR << up->port.regshift)) -+ value |= 0x10; /* set FCR.UUE */ -+#endif - writeb(value, up->port.membase + offset); - break; - -@@ -1981,6 +1985,83 @@ - serial_unlink_irq_chain(up); - } - -+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) -+static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */ -+static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud) -+{ -+ int err, sum, i, j; -+ int a[12], b[12]; -+ unsigned short div, umr, uacr; -+ unsigned short umr_best, div_best, uacr_best; -+ long long t0, t1, t2, t3; -+ -+ sum = 0; -+ umr_best = div_best = uacr_best = 0; -+ div = 1; -+ -+ if ((port->uartclk % (16 * baud)) == 0) { -+ quot1[0] = port->uartclk / (16 * baud); -+ quot1[1] = 16; -+ quot1[2] = 0; -+ return quot1; -+ } -+ -+ while (1) { -+ umr = port->uartclk / (baud * div); -+ if (umr > 32) { -+ div++; -+ continue; -+ } -+ if (umr < 4) { -+ break; -+ } -+ for (i = 0; i < 12; i++) { -+ a[i] = umr; -+ b[i] = 0; -+ sum = 0; -+ for (j = 0; j <= i; j++) { -+ sum += a[j]; -+ } -+ -+ /* the precision could be 1/2^(36) due to the value of t0 */ -+ t0 = 0x1000000000LL; -+ t1 = (i + 1) * t0; -+ t2 = (sum * div) * t0; -+ t3 = div * t0; -+ do_div(t1, baud); -+ do_div(t2, port->uartclk); -+ do_div(t3, (2 * port->uartclk)); -+ err = t1 - t2 - t3; -+ -+ if (err > 0) { -+ a[i] += 1; -+ b[i] = 1; -+ } -+ } -+ -+ uacr = 0; -+ for (i = 0; i < 12; i++) { -+ if (b[i] == 1) { -+ uacr |= 1 << i; -+ } -+ } -+ -+ /* the best value of umr should be near 16, and the value of uacr should better be smaller */ -+ if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) { -+ div_best = div; -+ umr_best = umr; -+ uacr_best = uacr; -+ } -+ div++; -+ } -+ -+ quot1[0] = div_best; -+ quot1[1] = umr_best; -+ quot1[2] = uacr_best; -+ -+ return quot1; -+} -+#else - static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud) - { - unsigned int quot; -@@ -2000,6 +2081,7 @@ - - return quot; - } -+#endif - - static void - serial8250_set_termios(struct uart_port *port, struct ktermios *termios, -@@ -2009,6 +2091,9 @@ - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; -+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) -+ unsigned short *quot1; -+#endif - - switch (termios->c_cflag & CSIZE) { - case CS5: -@@ -2041,7 +2126,12 @@ - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); -+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) -+ quot1 = serial8250_get_divisor(port, baud); -+ quot = quot1[0]; /* not usefull, just let gcc happy */ -+#else - quot = serial8250_get_divisor(port, baud); -+#endif - - /* - * Oxford Semi 952 rev B workaround -@@ -2119,6 +2209,10 @@ - if (up->capabilities & UART_CAP_UUE) - up->ier |= UART_IER_UUE | UART_IER_RTOIE; - -+#ifdef CONFIG_JZSOC -+ up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */ -+#endif -+ - serial_out(up, UART_IER, up->ier); - - if (up->capabilities & UART_CAP_EFR) { -@@ -2153,7 +2247,15 @@ - serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - } - -+#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730) -+#define UART_UMR 9 -+#define UART_UACR 10 -+ serial_dl_write(up, quot1[0]); -+ serial_outp(up, UART_UMR, quot1[1]); -+ serial_outp(up, UART_UACR, quot1[2]); -+#else - serial_dl_write(up, quot); -+#endif - - /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR -@@ -2866,7 +2968,7 @@ - if (nr_uarts > UART_NR) - nr_uarts = UART_NR; - -- printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ " -+ printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.5 $ " - "%d ports, IRQ sharing %sabled\n", nr_uarts, - share_irqs ? "en" : "dis"); - -@@ -2927,7 +3029,7 @@ - EXPORT_SYMBOL(serial8250_resume_port); - - MODULE_LICENSE("GPL"); --MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.90 $"); -+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.5 $"); - - module_param(share_irqs, uint, 0644); - MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" -diff -urN linux-2.6.24.7.old/drivers/usb/Kconfig linux-2.6.24.7/drivers/usb/Kconfig ---- linux-2.6.24.7.old/drivers/usb/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -41,6 +41,7 @@ - default y if PPC_MPC52xx - # MIPS: - default y if SOC_AU1X00 -+ default y if JZSOC - # more: - default PCI - -diff -urN linux-2.6.24.7.old/drivers/usb/core/hub.c linux-2.6.24.7/drivers/usb/core/hub.c ---- linux-2.6.24.7.old/drivers/usb/core/hub.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/core/hub.c 2009-04-12 18:13:57.000000000 +0200 -@@ -2484,11 +2484,35 @@ - struct device *hub_dev = hub->intfdev; - u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - int status, i; -- -+#ifdef CONFIG_JZSOC -+ static char jzhub = 1; /* the hub first to be initialized is jzsoc on-chip hub */ -+#endif -+ - dev_dbg (hub_dev, - "port %d, status %04x, change %04x, %s\n", - port1, portstatus, portchange, portspeed (portstatus)); - -+#ifdef CONFIG_SOC_JZ4730 -+ /* -+ * On Jz4730, we assume that the first USB port was used as device. -+ * If not, please comment next lines. -+ */ -+ if ((port1 == 1) && (jzhub)) { -+ jzhub = 0; -+ return; -+ } -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) -+ /* -+ * On Jz4740 and Jz4750, the second USB port was used as device. -+ */ -+ if ((port1 == 2) && (jzhub)) { -+ jzhub = 0; -+ return; -+ } -+#endif -+ - if (hub->has_indicators) { - set_port_led(hub, port1, HUB_LED_AUTO); - hub->indicator[port1-1] = INDICATOR_AUTO; -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/Kconfig linux-2.6.24.7/drivers/usb/gadget/Kconfig ---- linux-2.6.24.7.old/drivers/usb/gadget/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/gadget/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -93,6 +93,47 @@ - Many controller drivers are platform-specific; these - often need board-specific hooks. - -+config USB_GADGET_JZ4740 -+ boolean "JZ4740 UDC" -+ depends on SOC_JZ4740 -+ select USB_GADGET_DUALSPEED -+ help -+ Select this to support the Ingenic JZ4740 processor -+ high speed USB device controller. -+ -+config USB_JZ4740 -+ tristate -+ depends on USB_GADGET_JZ4740 -+ default USB_GADGET -+ select USB_GADGET_SELECTED -+ -+config USB_GADGET_JZ4750 -+ boolean "JZ4750 UDC" -+ depends on SOC_JZ4750 -+ select USB_GADGET_DUALSPEED -+ help -+ Select this to support the Ingenic JZ4750 processor -+ high speed USB device controller. -+ -+config USB_JZ4750 -+ tristate -+ depends on USB_GADGET_JZ4750 -+ default USB_GADGET -+ select USB_GADGET_SELECTED -+ -+config USB_GADGET_JZ4730 -+ boolean "JZ4730 UDC" -+ depends on SOC_JZ4730 -+ help -+ Select this to support the Ingenic JZ4730 processor -+ full speed USB device controller. -+ -+config USB_JZ4730 -+ tristate -+ depends on USB_GADGET_JZ4730 -+ default USB_GADGET -+ select USB_GADGET_SELECTED -+ - config USB_GADGET_AMD5536UDC - boolean "AMD5536 UDC" - depends on PCI -@@ -509,6 +550,14 @@ - behavior of USB Mass Storage hosts. Not needed for - normal operation. - -+config UDC_USE_LB_CACHE -+ bool "enable lb cache" -+ depends on USB_FILE_STORAGE && (SOC_JZ4740 || SOC_JZ4750) -+ default y -+ help -+ say "y" to enable lb cache and UDC work in faster speed. -+ say "n" to disable lb cache and UDC work in normal speed. -+ - config USB_G_SERIAL - tristate "Serial Gadget (with CDC ACM support)" - help -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/Makefile linux-2.6.24.7/drivers/usb/gadget/Makefile ---- linux-2.6.24.7.old/drivers/usb/gadget/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/gadget/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -17,6 +17,9 @@ - obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o - obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o - obj-$(CONFIG_USB_M66592) += m66592-udc.o -+obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o -+obj-$(CONFIG_USB_JZ4730) += jz4730_udc.o -+obj-$(CONFIG_USB_JZ4750) += jz4740_udc.o - - # - # USB gadget drivers -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/file_storage.c linux-2.6.24.7/drivers/usb/gadget/file_storage.c ---- linux-2.6.24.7.old/drivers/usb/gadget/file_storage.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/gadget/file_storage.c 2009-04-12 18:13:57.000000000 +0200 -@@ -274,6 +274,18 @@ - - - /*-------------------------------------------------------------------------*/ -+#if defined(CONFIG_UDC_USE_LB_CACHE) -+#define GHOST -+#endif -+ -+#ifdef GHOST -+extern unsigned long udc_read(unsigned int offset, unsigned int len, unsigned char *); -+extern unsigned long udc_write(unsigned int offset, unsigned int len, unsigned char *); -+extern int NAND_LB_Init(void); -+extern int NAND_LB_FLASHCACHE(void); -+extern int NAND_MTD_FLASHCACHE(void); -+extern int FlushDataState; -+#endif - - #ifdef DEBUG - #define LDBG(lun,fmt,args...) \ -@@ -349,8 +361,8 @@ - } mod_data = { // Default values - .transport_parm = "BBB", - .protocol_parm = "SCSI", -- .removable = 0, -- .can_stall = 1, -+ .removable = 1, -+ .can_stall = 0, - .vendor = DRIVER_VENDOR_ID, - .product = DRIVER_PRODUCT_ID, - .release = 0xffff, // Use controller chip type -@@ -810,6 +822,7 @@ - #define STRING_SERIAL 3 - #define STRING_CONFIG 4 - #define STRING_INTERFACE 5 -+#define STRING_MS_OS 0xee - - /* There is only one configuration. */ - #define CONFIG_VALUE 1 -@@ -997,6 +1010,7 @@ - {STRING_SERIAL, serial}, - {STRING_CONFIG, "Self-powered"}, - {STRING_INTERFACE, "Mass Storage"}, -+ {STRING_MS_OS, "Microsoft"}, - {} - }; - -@@ -1618,9 +1632,14 @@ - - /* Perform the read */ - file_offset_tmp = file_offset; -+#ifdef GHOST -+ nread = udc_read(file_offset_tmp, amount, bh->buf); -+#else - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); -+#endif -+ - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); -@@ -1799,9 +1818,13 @@ - - /* Perform the write */ - file_offset_tmp = file_offset; -+#ifdef GHOST -+ nwritten = udc_write(file_offset_tmp, amount, bh->buf); -+#else - nwritten = vfs_write(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); -+#endif - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nwritten); -@@ -1976,9 +1999,19 @@ - - /* Perform the read */ - file_offset_tmp = file_offset; -+#ifdef GHOST -+ nread = udc_read(file_offset_tmp, amount, bh->buf); -+#else - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); -+#endif -+ -+#if 0 -+ nread = vfs_read(curlun->filp, -+ (char __user *) bh->buf, -+ amount, &file_offset_tmp); -+#endif - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); -@@ -2013,7 +2046,7 @@ - { - u8 *buf = (u8 *) bh->buf; - -- static char vendor_id[] = "Linux "; -+ static char vendor_id[] = "Ingenic "; - static char product_id[] = "File-Stor Gadget"; - - if (!fsg->curlun) { // Unsupported LUNs are okay -@@ -2857,6 +2890,15 @@ - reply = check_command(fsg, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); -+#ifdef GHOST -+ if( FlushDataState >= 1) -+ FlushDataState++; -+ if(FlushDataState > 6) -+ { -+ NAND_LB_FLASHCACHE(); -+ FlushDataState = 0; -+ } -+#endif - break; - - /* Although optional, this command is used by MS-Windows. We -@@ -3404,6 +3446,13 @@ - - /* The main loop */ - while (fsg->state != FSG_STATE_TERMINATED) { -+#ifdef GHOST -+ if ((fsg->atomic_bitflags & SUSPENDED)) -+ { -+ NAND_LB_FLASHCACHE(); -+ NAND_MTD_FLASHCACHE(); -+ } -+#endif - if (exception_in_progress(fsg) || signal_pending(current)) { - handle_exception(fsg); - continue; -@@ -3525,6 +3574,9 @@ - curlun->num_sectors = num_sectors; - LDBG(curlun, "open backing file: %s\n", filename); - rc = 0; -+#ifdef GHOST -+ NAND_LB_Init(); -+#endif - - out: - filp_close(filp, current->files); -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/gadget_chips.h linux-2.6.24.7/drivers/usb/gadget/gadget_chips.h ---- linux-2.6.24.7.old/drivers/usb/gadget/gadget_chips.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/gadget/gadget_chips.h 2009-04-12 18:13:57.000000000 +0200 -@@ -11,6 +11,18 @@ - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ -+#ifdef CONFIG_USB_GADGET_JZ4740 -+#define gadget_is_jz4740(g) !strcmp("jz4740_udc", (g)->name) -+#else -+#define gadget_is_jz4740(g) 0 -+#endif -+ -+#ifdef CONFIG_USB_GADGET_JZ4730 -+#define gadget_is_jz4730(g) !strcmp("jz4730_udc", (g)->name) -+#else -+#define gadget_is_jz4730(g) 0 -+#endif -+ - #ifdef CONFIG_USB_GADGET_NET2280 - #define gadget_is_net2280(g) !strcmp("net2280", (g)->name) - #else -@@ -212,5 +224,9 @@ - return 0x20; - else if (gadget_is_m66592(gadget)) - return 0x21; -+ else if (gadget_is_jz4730(gadget)) -+ return 0x22; -+ else if (gadget_is_jz4740(gadget)) -+ return 0x23; - return -ENOENT; - } -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/jz4730_udc.c linux-2.6.24.7/drivers/usb/gadget/jz4730_udc.c ---- linux-2.6.24.7.old/drivers/usb/gadget/jz4730_udc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/usb/gadget/jz4730_udc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1403 @@ -+/* -+ * JZ4730 USB Device Controller driver -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+/* -+ * This device has ep0 and six bulk/interrupt/iso endpoints. -+ * -+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep3in-bulk, -+ * ep4in-iso, ep5out-bulk, ep6out-bulk, ep7out-iso. -+ * - Gadget drivers can choose ep maxpacket (8/16/32/64). -+ * - Just PIO mode currently. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "jz4730_udc.h" -+ -+//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args) -+//#define DEBUG_EP0(fmt,args...) printk(KERN_DEBUG fmt , ## args) -+ -+#ifndef DEBUG -+# define DEBUG(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_EP0 -+# define DEBUG_EP0(fmt,args...) do {} while(0) -+#endif -+ -+#define DRIVER_DESC "JZ4730 USB Device Controller" -+#define DRIVER_VERSION "20 Sep 2007" -+ -+static const char driver_name [] = "jz4730_udc"; -+static const char driver_desc [] = DRIVER_DESC; -+ -+static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */ -+ -+module_param(udc_debug, int, 0); -+MODULE_PARM_DESC(udc_debug, "test udc cable type"); -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+extern int jz_udc_active; /* 0: No actions; 1: Have actions */ -+#endif -+ -+/* -+ * Local declarations. -+ */ -+static void nuke(struct jz4730_ep *, int status); -+static inline void pio_irq_enable(struct jz4730_ep *ep); -+static inline void pio_irq_disable(struct jz4730_ep *ep); -+static void jz4730_udc_release (struct device *dev) {} -+/*-------------------------------------------------------------------------*/ -+ -+static int jz4730_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct jz4730_udc *dev; -+ struct jz4730_ep *ep; -+ unsigned long flags; -+ u32 max; -+ -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ if (!_ep || !desc || ep->desc -+ || desc->bDescriptorType != USB_DT_ENDPOINT) -+ return -EINVAL; -+ dev = ep->dev; -+ if (ep == &dev->ep[0]) -+ return -EINVAL; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) -+ return -ESHUTDOWN; -+ if (ep->index != (desc->bEndpointAddress & 0x0f)) -+ return -EINVAL; -+ -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ case USB_ENDPOINT_XFER_INT: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+// max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); -+ max = 64; -+ ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ ep->stopped = 0; -+ ep->desc = desc; -+ ep->ep.maxpacket = max; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ DEBUG("enable %s %s maxpacket %u\n", ep->ep.name, -+ ep->is_in ? "IN" : "OUT", max); -+ -+ return 0; -+} -+ -+static int jz4730_ep_disable(struct usb_ep *_ep) -+{ -+ struct jz4730_ep *ep; -+ struct jz4730_udc *dev; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ if (!_ep || !ep->desc) -+ return -ENODEV; -+ dev = ep->dev; -+ if (dev->ep0state == EP0_SUSPEND) -+ return -EBUSY; -+ -+ DEBUG("disable %s\n", _ep->name); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ /* Nuke all pending requests */ -+ nuke(ep, -ESHUTDOWN); -+ -+ /* Disable ep IRQ */ -+ pio_irq_disable(ep); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ return 0; -+} -+ -+static struct usb_request *jz4730_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -+{ -+ struct jz4730_request *req; -+ -+ req = kzalloc(sizeof *req, gfp_flags); -+ if (!req) -+ return 0; -+ -+ INIT_LIST_HEAD(&req->queue); -+ return &req->req; -+} -+ -+static void jz4730_free_request(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct jz4730_request *req; -+ -+ req = container_of(_req, struct jz4730_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ kfree(req); -+} -+ -+static void *jz4730_alloc_buffer(struct usb_ep *_ep, unsigned bytes, -+ dma_addr_t *dma, gfp_t gfp_flags) -+{ -+ void *retval; -+ -+ retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM)); -+ if (retval) -+ *dma = virt_to_phys(retval); -+ return retval; -+} -+ -+static void jz4730_free_buffer(struct usb_ep *_ep, void *buf, -+ dma_addr_t dma, unsigned bytes) -+{ -+ kfree(buf); -+} -+ -+/* -+ * done - retire a request; caller blocked irqs -+ */ -+static void done(struct jz4730_ep *ep, struct jz4730_request *req, int status) -+{ -+ struct jz4730_udc *dev; -+ unsigned stopped = ep->stopped; -+ -+ list_del_init(&req->queue); -+ -+ if (likely(req->req.status == -EINPROGRESS)) -+ req->req.status = status; -+ else -+ status = req->req.status; -+ -+ if (status && status != -ESHUTDOWN) -+ DEBUG("complete %s req %p stat %d len %u/%u\n", -+ ep->ep.name, &req->req, status, -+ req->req.actual, req->req.length); -+ -+ dev = ep->dev; -+ -+ /* don't modify queue heads during completion callback */ -+ ep->stopped = 1; -+ spin_unlock(&dev->lock); -+ req->req.complete(&ep->ep, &req->req); -+ spin_lock(&dev->lock); -+ ep->stopped = stopped; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static __inline__ int write_packet(struct jz4730_ep *ep, -+ struct jz4730_request *req, int max) -+{ -+ u8 *buf; -+ int length, nlong, nbyte; -+ volatile u32 *fifo = (volatile u32 *)ep->fifo; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetch(buf); -+ -+ length = req->req.length - req->req.actual; -+ length = min(length, max); -+ req->req.actual += length; -+ -+ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); -+ -+ if (!length) { -+ /* Send ZLP */ -+ writel(0, (unsigned int *)UDC_TXZLP); -+ writel(0x12345678, (unsigned int *)fifo); -+ } -+ else { -+ nlong = length >> 2; -+ nbyte = length & 0x3; -+ while (nlong--) { -+ *fifo = *((u32 *)buf); -+ buf += 4; -+ } -+ while (nbyte--) { -+ *((volatile u8 *)fifo) = *buf++; -+ } -+ } -+ -+ writel(0, (unsigned int *)UDC_TXCONFIRM); -+ -+ return length; -+} -+ -+static __inline__ int read_packet(struct jz4730_ep *ep, -+ struct jz4730_request *req, int count) -+{ -+ u8 *buf; -+ int length, nlong, nbyte; -+ volatile u32 *fifo = (volatile u32 *)ep->fifo; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetchw(buf); -+ -+ length = req->req.length - req->req.actual; -+ length = min(length, count); -+ req->req.actual += length; -+ -+ DEBUG("Read %d, fifo %p\n", length, fifo); -+ -+ nlong = length >> 2; -+ nbyte = length & 0x3; -+ while (nlong--) { -+ *((u32 *)buf) = *fifo; -+ buf += 4; -+ } -+ if (nbyte) { -+ u32 data = *fifo; -+ while (nbyte--) { -+ *buf++ = data & 0x0ff; -+ data >>= 8; -+ } -+ } -+ -+ REG32(UDC_RXCONFIRM); -+ -+ return length; -+} -+ -+/** Write request to FIFO (max write == maxp size) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ */ -+static int write_fifo(struct jz4730_ep *ep, struct jz4730_request *req) -+{ -+ u32 max, count; -+ int is_last; -+ -+ max = ep->ep.maxpacket; -+ -+ count = write_packet(ep, req, max); -+ -+ /* last packet often short (sometimes a zlp, especially on ep0) */ -+ if (unlikely(count != max)) { -+ is_last = 1; -+ } else { -+ if (likely(req->req.length != req->req.actual) -+ || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ } -+ -+ DEBUG("write %s (%d)(IN) %d bytes%s req %p %d/%d is_last %d\n", -+ ep->ep.name, ep->index, count, -+ (count != ep->ep.maxpacket) ? " (short)" : "", -+ req, req->req.actual, req->req.length, is_last); -+ -+ /* requests complete when all IN data is in the FIFO, -+ * or sometimes later, if a zlp was needed. -+ */ -+ if (is_last) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/** Read to request from FIFO (max read == bytes in fifo) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ */ -+static int read_fifo(struct jz4730_ep *ep, struct jz4730_request *req, u32 count) -+{ -+ int is_short; -+ -+ is_short = (count < ep->ep.maxpacket); -+ -+ count = read_packet(ep, req, count); -+ -+ DEBUG("read %s %u bytes%s OUT req %p %u/%u is_short %d\n", -+ ep->ep.name, count, (count < ep->ep.maxpacket) ? "(short)" : "", -+ req, req->req.actual, req->req.length, is_short); -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+static inline void pio_irq_enable(struct jz4730_ep *ep) -+{ -+ switch (ep->index) { -+ case 0: -+ REG_UDC_EPIntMR &= ~0x1; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ REG_UDC_EPIntMR &= ~(1 << ep->index); -+ break; -+ case 5: -+ case 6: -+ case 7: -+ REG_UDC_EPIntMR &= ~(1 << (ep->index + 16)); -+ break; -+ } -+} -+ -+static inline void pio_irq_disable(struct jz4730_ep *ep) -+{ -+ switch (ep->index) { -+ case 0: -+ REG_UDC_EPIntMR |= 0x1; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ REG_UDC_EPIntMR |= (1 << ep->index); -+ break; -+ case 5: -+ case 6: -+ case 7: -+ REG_UDC_EPIntMR |= (1 << (ep->index + 16)); -+ break; -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int -+jz4730_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -+{ -+ struct jz4730_request *req; -+ struct jz4730_ep *ep; -+ struct jz4730_udc *dev; -+ unsigned long flags; -+ int status; -+ -+ /* always require a cpu-view buffer so pio works */ -+ req = container_of(_req, struct jz4730_request, req); -+ if (unlikely(!_req || !_req->complete -+ || !_req->buf || !list_empty(&req->queue))) -+ return -EINVAL; -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->index != 0))) -+ return -EINVAL; -+ dev = ep->dev; -+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) -+ return -ESHUTDOWN; -+ -+ DEBUG("%s queue req %p, len %u buf %p\n", -+ _ep->name, _req, _req->length, _req->buf); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ /* for ep0 IN without premature status, zlp is required and -+ * writing EOP starts the status stage (OUT). -+ */ -+ if (unlikely(ep->index == 0 && ep->is_in)) -+ _req->zero = 1; -+ -+ /* kickstart this i/o queue? */ -+ status = 0; -+ if (list_empty(&ep->queue) && likely(!ep->stopped)) { -+ if (unlikely(ep->index == 0)) { -+ pio_irq_enable(ep); -+ if (ep->irq_pending || -+ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0)) { -+ u32 stats, count; -+ -+ stats = REG_UDC_EP0OutSR; -+ if (stats & UDC_EPSR_OUT_RCVDATA) { -+ ep->irq_pending = 0; -+ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; -+ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP0) -+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; -+ -+ count = OUT_COUNT(stats); -+ if (read_fifo(ep, req, count) == 1) -+ req = 0; -+ } -+ } -+ -+ } else if (ep->is_in) { -+ /* EP1 ~ EP4 */ -+ if (ep->irq_pending || -+ (REG_UDC_EPIntR & UDC_EPIntR_INEP2)) { -+ if (REG_UDC_EP2InSR & UDC_EPSR_IN) { -+ ep->irq_pending = 0; -+ REG_UDC_EP2InSR &= ~UDC_EPSR_IN; -+ if (REG_UDC_EPIntR & UDC_EPIntR_INEP2) -+ REG_UDC_EPIntR = UDC_EPIntR_INEP2; -+ -+ if (write_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } -+ pio_irq_enable(ep); -+ } else { -+ /* EP5 ~ EP7 */ -+ pio_irq_enable(ep); -+ -+ if (ep->irq_pending || -+ (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5)) { -+ u32 stats, count; -+ -+ stats = REG_UDC_EP5OutSR; -+ if (stats & UDC_EPSR_OUT_RCVDATA) { -+ ep->irq_pending = 0; -+ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; -+ if (REG_UDC_EPIntR & UDC_EPIntR_OUTEP5) -+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; -+ -+ count = OUT_COUNT(stats); -+ if (read_fifo(ep, req, count) == 1) -+ req = 0; -+ } -+ } -+ } -+ } -+ -+ /* pio or dma irq handler advances the queue. */ -+ if (likely(req != 0)) { -+ list_add_tail(&req->queue, &ep->queue); -+ } -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ return status; -+} -+ -+/* dequeue ALL requests */ -+static void nuke(struct jz4730_ep *ep, int status) -+{ -+ struct jz4730_request *req; -+ -+ if (list_empty(&ep->queue)) -+ return; -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct jz4730_request, queue); -+ done(ep, req, status); -+ } -+} -+ -+/* dequeue JUST ONE request */ -+static int jz4730_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct jz4730_request *req; -+ struct jz4730_ep *ep; -+ struct jz4730_udc *dev; -+ unsigned long flags; -+ int stopped; -+ -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ if (!_ep || !_req || (!ep->desc && ep->index != 0)) -+ return -EINVAL; -+ dev = ep->dev; -+ if (!dev->driver) -+ return -ESHUTDOWN; -+ -+ DEBUG("%s %s %p\n", __FUNCTION__, _ep->name,_req); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ stopped = ep->stopped; -+ ep->stopped = 1; -+ -+ /* make sure it's actually queued on this endpoint */ -+ list_for_each_entry (req, &ep->queue, queue) { -+ if (&req->req == _req) -+ break; -+ } -+ if (&req->req != _req) { -+ spin_unlock_irqrestore (&dev->lock, flags); -+ return -EINVAL; -+ } -+ -+ /* queue head may be partially complete. */ -+ if (ep->queue.next == &req->queue) { -+ done (ep, req, -ECONNRESET); -+ req = 0; -+ } -+ -+ if (req) -+ done (ep, req, -ECONNRESET); -+ ep->stopped = stopped; -+ -+ spin_unlock_irqrestore (&ep->dev->lock, flags); -+ return req ? 0 : -EOPNOTSUPP; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz4730_clear_halt(struct jz4730_ep *ep) -+{ -+ if (ep->stopped) { -+ ep->stopped = 0; -+ } -+} -+ -+static int jz4730_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct jz4730_ep *ep; -+ unsigned long flags; -+ int retval = 0; -+ -+ if (!_ep) -+ return -ENODEV; -+ ep = container_of (_ep, struct jz4730_ep, ep); -+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) -+ return -ESHUTDOWN; -+ if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) -+ == USB_ENDPOINT_XFER_ISOC) -+ return -EINVAL; -+ -+ if (ep->index == 0) { -+ if (value) { -+ ep->dev->ep0state = EP0_STALL; -+ ep->dev->ep[0].stopped = 1; -+ } else -+ return -EINVAL; -+ -+ /* don't change EPxSTATUS_EP_INVALID to READY */ -+ } else if (!ep->desc) { -+ DEBUG("%s %s inactive?\n", __FUNCTION__, ep->ep.name); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ if (!list_empty(&ep->queue)) -+ retval = -EAGAIN; -+ else if (!value) -+ jz4730_clear_halt(ep); -+ else { -+ ep->stopped = 1; -+ } -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return retval; -+} -+ -+static int jz4730_fifo_status(struct usb_ep *_ep) -+{ -+ struct jz4730_ep *ep; -+ u32 size = 0; -+ -+ if (!_ep) -+ return -ENODEV; -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ -+ /* size is only reported sanely for OUT */ -+ if (ep->is_in) -+ return -EOPNOTSUPP; -+ -+ return size; -+} -+ -+static void jz4730_fifo_flush(struct usb_ep *_ep) -+{ -+ struct jz4730_ep *ep; -+ -+ if (!_ep) -+ return; -+ ep = container_of(_ep, struct jz4730_ep, ep); -+ -+ /* don't change EPxSTATUS_EP_INVALID to READY */ -+ if (!ep->desc && ep->index != 0) { -+ return; -+ } -+} -+ -+static struct usb_ep_ops jz4730_ep_ops = { -+ .enable = jz4730_ep_enable, -+ .disable = jz4730_ep_disable, -+ -+ .alloc_request = jz4730_alloc_request, -+ .free_request = jz4730_free_request, -+#if 0 -+ .alloc_buffer = jz4730_alloc_buffer, -+ .free_buffer = jz4730_free_buffer, -+#endif -+ .queue = jz4730_queue, -+ .dequeue = jz4730_dequeue, -+ -+ .set_halt = jz4730_set_halt, -+ .fifo_status = jz4730_fifo_status, -+ .fifo_flush = jz4730_fifo_flush, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int jz4730_get_frame(struct usb_gadget *_gadget) -+{ -+ return -EOPNOTSUPP; -+} -+ -+static const struct usb_gadget_ops jz4730_ops = { -+ .get_frame = jz4730_get_frame, -+ // no remote wakeup -+ // not selfpowered -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void udc_reinit(struct jz4730_udc *dev) -+{ -+ static char *names [] = { "ep0", "ep1in-int", "ep2in-bulk", "ep3in-bulk", -+ "ep4in-iso", "ep5out-bulk", "ep6out-bulk", -+ "ep7out-iso" }; -+ int i; -+ -+ INIT_LIST_HEAD (&dev->gadget.ep_list); -+ dev->gadget.ep0 = &dev->ep[0].ep; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ dev->ep0state = EP0_DISCONNECT; -+ -+ for (i = 0; i < MAX_EP_NUM; i++) { -+ struct jz4730_ep *ep = &dev->ep[i]; -+ -+ ep->index = i; -+ ep->ep.name = names[i]; -+ ep->fifo = ep_fifo[i]; -+ ep->ep.maxpacket = 64; -+ -+ ep->ep.ops = &jz4730_ep_ops; -+ list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); -+ ep->dev = dev; -+ INIT_LIST_HEAD(&ep->queue); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ ep->irq_pending = 0; -+ } -+ -+ dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; -+ list_del_init(&dev->ep[0].ep.ep_list); -+} -+ -+/* Reset udc registers */ -+static void udc_reset(struct jz4730_udc *dev) -+{ -+ REG_UDC_DevIntMR = 0x32; /* Enable RESET and SC interrupts */ -+ REG_UDC_EPIntMR = 0x0; /* Enable all EP interrupts */ -+ REG_UDC_DevCFGR = 0x17; -+ REG_UDC_DevCR = 0x0; -+ -+ REG_UDC_EP0InCR = (0 << 4) | (1 << 1); -+ REG_UDC_EP0InCR = (0 << 4); -+ REG_UDC_EP1InCR = (3 << 4) | (1 << 1); -+ REG_UDC_EP1InCR = (3 << 4); -+ REG_UDC_EP2InCR = (2 << 4) | (1 << 1); -+ REG_UDC_EP2InCR = (2 << 4); -+ REG_UDC_EP3InCR = (2 << 4) | (1 << 1); -+ REG_UDC_EP3InCR = (2 << 4); -+ REG_UDC_EP4InCR = (1 << 4) | (1 << 1); -+ REG_UDC_EP4InCR = (1 << 4); -+ -+ REG_UDC_EP0OutCR = (0 << 4); -+ REG_UDC_EP5OutCR = (2 << 4); -+ REG_UDC_EP6OutCR = (2 << 4); -+ REG_UDC_EP7OutCR = (1 << 4); -+ -+ REG_UDC_EP0InSR = 0; -+ REG_UDC_EP1InSR = 0; -+ REG_UDC_EP2InSR = 0; -+ REG_UDC_EP3InSR = 0; -+ REG_UDC_EP4InSR = 0; -+ REG_UDC_EP5OutSR = 0; -+ REG_UDC_EP6OutSR = 0; -+ REG_UDC_EP7OutSR = 0; -+ -+ REG_UDC_EP0InBSR = MAX_EP0_SIZE/4; -+ REG_UDC_EP1InBSR = MAX_EP1_SIZE/4; -+ REG_UDC_EP2InBSR = MAX_EP2_SIZE/4; -+ REG_UDC_EP3InBSR = MAX_EP3_SIZE/4; -+ REG_UDC_EP4InBSR = MAX_EP4_SIZE/4; -+ -+ REG_UDC_EP0InMPSR = MAX_EP0_SIZE; -+ REG_UDC_EP1InMPSR = MAX_EP1_SIZE; -+ REG_UDC_EP2InMPSR = MAX_EP2_SIZE; -+ REG_UDC_EP3InMPSR = MAX_EP3_SIZE; -+ REG_UDC_EP4InMPSR = MAX_EP4_SIZE; -+ -+ REG_UDC_EP0OutMPSR = MAX_EP0_SIZE; -+ REG_UDC_EP5OutMPSR = MAX_EP5_SIZE; -+ REG_UDC_EP6OutMPSR = MAX_EP6_SIZE; -+ REG_UDC_EP7OutMPSR = MAX_EP7_SIZE; -+ -+ REG_UDC_EP0InfR = (MAX_EP0_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (0 << 5) | (0 << 4) | (0 << 0); -+ REG_UDC_EP1InfR = (MAX_EP1_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (3 << 5) | (1 << 4) | (1 << 0); -+ REG_UDC_EP2InfR = (MAX_EP2_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (2 << 0); -+ REG_UDC_EP3InfR = (MAX_EP3_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (1 << 4) | (3 << 0); -+ REG_UDC_EP4InfR = (MAX_EP4_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (1 << 4) | (4 << 0); -+ REG_UDC_EP5InfR = (MAX_EP5_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (5 << 0); -+ REG_UDC_EP6InfR = (MAX_EP6_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (2 << 5) | (0 << 4) | (6 << 0); -+ REG_UDC_EP7InfR = (MAX_EP7_SIZE << 19) | (0 << 15) | (0 << 11) | (0x1 << 7) | (1 << 5) | (0 << 4) | (7 << 0); -+ -+ REG_UDC_STCMAR = 0xffff; -+} -+ -+static void ep0_start(struct jz4730_udc *dev) -+{ -+ udc_reset(dev); -+ udc_reinit(dev); -+ -+ /* expect ep0 requests when the host drops reset */ -+ dev->gadget.speed = USB_SPEED_FULL; -+ dev->ep0state = EP0_IDLE; -+} -+ -+static void udc_enable(struct jz4730_udc *dev) -+{ -+ /* Enable udc and enable all interrupts */ -+ __intc_unmask_irq(IRQ_UDC); -+ __harb_usb0_udc(); -+ -+ /* start enumeration now, or after power detect irq */ -+ ep0_start(dev); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* keeping it simple: -+ * - one bus driver, initted first; -+ * - one function driver, initted second -+ */ -+ -+static struct jz4730_udc *the_controller; -+ -+/* when a driver is successfully registered, it will receive -+ * control requests including set_configuration(), which enables -+ * non-control requests. then usb traffic follows until a -+ * disconnect is reported. then a host may connect again, or -+ * the driver might get unbound. -+ */ -+int usb_gadget_register_driver(struct usb_gadget_driver *driver) -+{ -+ struct jz4730_udc *dev = the_controller; -+ int retval; -+ -+ if (!driver -+// || driver->speed != USB_SPEED_FULL -+ || !driver->bind -+ || !driver->unbind -+ || !driver->disconnect -+ || !driver->setup) -+ { -+ printk("\n -EINVAL"); -+ return -EINVAL; -+ } -+ if (!dev) -+ return -ENODEV; -+ -+ if (dev->driver) -+ return -EBUSY; -+ -+ /* hook up the driver */ -+ dev->driver = driver; -+ retval = driver->bind(&dev->gadget); -+ if (retval) { -+ DEBUG("bind to driver %s --> error %d\n", -+ driver->driver.name, retval); -+ dev->driver = 0; -+ return retval; -+ } -+ /* then enable host detection and ep0; and we're ready -+ * for set_configuration as well as eventual disconnect. -+ */ -+ udc_enable(dev); -+ -+ DEBUG("registered gadget driver '%s'\n", driver->driver.name); -+ return 0; -+} -+EXPORT_SYMBOL(usb_gadget_register_driver); -+ -+static void -+stop_activity(struct jz4730_udc *dev, struct usb_gadget_driver *driver) -+{ -+ unsigned i; -+ -+ DEBUG("%s\n", __FUNCTION__); -+ -+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = 0; -+ -+ /* disconnect gadget driver after quiesceing hw and the driver */ -+ udc_reset (dev); -+ for (i = 0; i < MAX_EP_NUM; i++) -+ nuke(&dev->ep [i], -ESHUTDOWN); -+ if (driver) { -+ spin_unlock(&dev->lock); -+ driver->disconnect(&dev->gadget); -+ spin_lock(&dev->lock); -+ } -+ -+ if (dev->driver) -+ udc_enable(dev); -+} -+ -+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -+{ -+ struct jz4730_udc *dev = the_controller; -+ unsigned long flags; -+ -+ /* disable UDC irq */ -+ __intc_mask_irq(IRQ_UDC); -+ __harb_usb0_uhc(); -+ -+ if (!dev) -+ return -ENODEV; -+ if (!driver || driver != dev->driver) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ dev->driver = 0; -+ stop_activity(dev, driver); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ driver->unbind(&dev->gadget); -+ -+ DEBUG("unregistered driver '%s'\n", driver->driver.name); -+ return 0; -+} -+EXPORT_SYMBOL(usb_gadget_unregister_driver); -+ -+static void jz4730_epn_out(struct jz4730_udc *dev, int ep_idx, u32 count) -+{ -+ struct jz4730_request *req; -+ struct jz4730_ep *ep = &dev->ep[ep_idx]; -+ -+ req = list_entry(ep->queue.next, struct jz4730_request, queue); -+ read_fifo(ep, req, count); -+} -+ -+static void jz4730_epn_in(struct jz4730_udc *dev, int ep_idx) -+{ -+ struct jz4730_request *req; -+ struct jz4730_ep *ep = &dev->ep[ep_idx]; -+ -+ req = list_entry(ep->queue.next, struct jz4730_request, queue); -+ write_fifo(ep, req); -+} -+ -+/****************************************************************/ -+/* End Point 0 related functions */ -+/****************************************************************/ -+ -+/* return: 0 = still running, 1 = completed, negative = errno */ -+static int write_fifo_ep0(struct jz4730_ep *ep, struct jz4730_request *req) -+{ -+ u32 max, count; -+ int is_last; -+ -+ max = ep->ep.maxpacket; -+ -+ count = write_packet(ep, req, max); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ } -+ -+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Simulate a USB_REQ_SET_CONFIGURATION to the function driver, -+ * this is required to enable the endpoints of the function driver. -+ * UDC should let software have the chance to handle this standard -+ * request, unfortunately UDC can't do that. -+ */ -+static void psudo_set_config(void) -+{ -+ struct jz4730_udc *dev = (struct jz4730_udc *) the_controller; -+ struct usb_ctrlrequest ctrl; -+ int tmp; -+ -+ /* SETUP packet */ -+ ctrl.bRequestType = 0x00; -+ ctrl.bRequest = USB_REQ_SET_CONFIGURATION; -+ ctrl.wValue = 1; -+ ctrl.wIndex = 0; -+ ctrl.wLength = 0; -+ -+ nuke(&dev->ep[0], 0); -+ dev->ep[0].stopped = 0; -+ -+ if (likely(ctrl.bRequestType & USB_DIR_IN)) { -+ dev->ep[0].is_in = 1; -+ dev->ep0state = EP0_IN; -+ } else { -+ dev->ep[0].is_in = 0; -+ dev->ep0state = EP0_OUT; -+ } -+ -+ /* delegate everything to the gadget driver. -+ * it may respond after this irq handler returns. -+ */ -+ spin_unlock (&dev->lock); -+ tmp = dev->driver->setup(&dev->gadget, &ctrl); -+ spin_lock (&dev->lock); -+ if (unlikely(tmp < 0)) { -+ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", -+ ctrl.bRequestType, ctrl.bRequest, tmp); -+ dev->ep[0].stopped = 1; -+ dev->ep0state = EP0_STALL; -+ } -+} -+ -+/* -+ * Read 8 bytes setup packet from EP0 RX buffer -+ */ -+static void read_setup_packet(u8 *buf) -+{ -+ u32 *tmp = (u32 *)buf; -+ -+ *tmp++ = readl((unsigned int *)RXFIFO); -+ *tmp++ = readl((unsigned int *)RXFIFO); -+ -+ REG32(UDC_RXCONFIRM); -+} -+ -+static void jz4730_ep0_setup(struct jz4730_udc *dev) -+{ -+ struct jz4730_ep *ep = &dev->ep[0]; -+ struct usb_ctrlrequest ctrl; -+ int tmp; -+ -+ /* read control req from fifo (8 bytes) */ -+ read_setup_packet((unsigned char *) &ctrl); -+ -+ DEBUG_EP0("SETUP %02x.%02x v%04x i%04x l%04x\n", -+ ctrl.bRequestType, ctrl.bRequest, -+ ctrl.wValue, ctrl.wIndex, ctrl.wLength); -+ -+ /* Set direction of EP0 */ -+ if (likely(ctrl.bRequestType & USB_DIR_IN)) { -+ ep->is_in = 1; -+ dev->ep0state = EP0_IN; -+ } else { -+ ep->is_in = 0; -+ dev->ep0state = EP0_OUT; -+ } -+ -+ /* Nuke all previous transfers */ -+ nuke(ep, 0); -+ ep->stopped = 0; -+ -+ /* delegate everything to the gadget driver. -+ * it may respond after this irq handler returns. -+ */ -+ if (likely((u32)dev->driver)) { -+ /* device-2-host (IN) or no data setup command, process immediately */ -+ spin_unlock(&dev->lock); -+ tmp = dev->driver->setup(&dev->gadget, &ctrl); -+ spin_lock(&dev->lock); -+ -+ if (unlikely(tmp < 0)) { -+ /* setup processing failed, force stall */ -+ DEBUG_EP0("req %02x.%02x protocol STALL; err %d\n", -+ ctrl.bRequestType, ctrl.bRequest, tmp); -+ dev->ep0state = EP0_STALL; -+ } -+ } -+} -+ -+static int jz4730_ep0_in(struct jz4730_udc *dev) -+{ -+ struct jz4730_request *req; -+ struct jz4730_ep *ep = &dev->ep[0]; -+ int ret; -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4730_request, queue); -+ -+ if (!req) { -+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); -+ return 0; -+ } -+ -+ ret = write_fifo_ep0(ep, req); -+ -+ return ret; -+} -+ -+static void jz4730_ep0_out(struct jz4730_udc *dev) -+{ -+ u32 epsr; -+ struct jz4730_ep *ep = &dev->ep[0]; -+ -+ epsr = REG_UDC_EP0OutSR; -+ REG_UDC_EP0OutSR &= ~UDC_EPSR_OUT_MASK; -+ -+ if (epsr & UDC_EPSR_OUT_RCVSETUP) { -+ jz4730_ep0_setup(dev); -+ } -+ else if (epsr & UDC_EPSR_OUT_RCVDATA) { -+ u32 count = __udc_ep0out_packet_size(); -+ if (count == 0) { -+ readl((unsigned int *)UDC_RXCONFIRM); // ack zero packet -+ } -+ else { -+ /* EP0 OUT Data */ -+ if (list_empty(&ep->queue)) { -+ ep->irq_pending = 1; -+ pio_irq_disable(ep); -+ } -+ else -+ jz4730_epn_out(dev, 0, count); -+ -+ } -+ } -+} -+ -+static void handle_reset_irq(struct jz4730_udc *dev) -+{ -+ int i; -+ -+ /* clear any status */ -+ REG_UDC_EPIntR = 0xffffffff; -+ REG_UDC_DevIntR = 0xffffffff; -+ -+ /* reset udc */ -+ udc_reset(dev); -+ -+ /* reset driver status */ -+ for (i = 0; i < MAX_EP_NUM; i++) { -+ struct jz4730_ep *ep = &dev->ep[i]; -+ -+ ep->irq_pending = 0; -+// nuke(ep, 0); -+ nuke(ep, -ESHUTDOWN); -+ } -+} -+ -+static irqreturn_t jz4730_udc_irq(int irq, void *_dev) -+{ -+ struct jz4730_udc *dev = _dev; -+ struct jz4730_ep *ep; -+ -+ u32 intr_dev, intr_ep, stats, count; -+ -+ spin_lock(&dev->lock); -+ -+ intr_dev = REG_UDC_DevIntR; -+ intr_ep = REG_UDC_EPIntR; -+ -+ DEBUG("*** udc irq intr_dev=0x%x intr_ep=0x%x\n", intr_dev, intr_ep); -+ -+ if (!intr_dev && !intr_ep) { -+ spin_unlock(&dev->lock); -+ return IRQ_HANDLED; -+ } -+ -+ if (udc_debug) { -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ jz_udc_active = 1; -+#endif -+ REG_UDC_DevIntR = intr_dev; -+ REG_UDC_EPIntR = intr_ep; -+ __harb_usb0_uhc(); -+ __intc_mask_irq(IRQ_UDC); -+ spin_unlock(&dev->lock); -+ return IRQ_HANDLED; -+ } -+ -+ if (intr_dev) { -+ if (intr_dev & UDC_DevIntR_SC) { -+ psudo_set_config(); -+ udelay(100); -+ } -+ -+ if (intr_dev & UDC_DevIntR_UR) { -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ jz_udc_active = 1; -+#endif -+ handle_reset_irq(dev); -+ } -+ -+ REG_UDC_DevIntR = intr_dev; -+ } -+ -+ if (intr_ep & UDC_EPIntR_OUTEP0) { -+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP0; -+ jz4730_ep0_out(dev); -+ } -+ -+ if (intr_ep & UDC_EPIntR_INEP0) { -+ ep = &dev->ep[0]; -+ if (list_empty(&ep->queue)) { -+ pio_irq_disable(ep); -+ } -+ else { -+ stats = REG_UDC_EP0InSR; -+ if (stats & UDC_EPSR_IN) { -+ REG_UDC_EPIntR = UDC_EPIntR_INEP0; -+ REG_UDC_EP0InSR &= ~UDC_EPSR_IN; -+ -+ jz4730_ep0_in(dev); -+ } -+ } -+ } -+ -+ if (intr_ep & UDC_EPIntR_OUTEP5) { -+ REG_UDC_EPIntR = UDC_EPIntR_OUTEP5; -+ ep = &dev->ep[5]; -+ if (list_empty(&ep->queue)) { -+ ep->irq_pending = 1; -+ pio_irq_disable(ep); -+ } -+ else { -+ stats = REG_UDC_EP5OutSR; -+ if (stats & UDC_EPSR_OUT_RCVDATA) { -+ REG_UDC_EP5OutSR &= ~UDC_EPSR_OUT_MASK; -+ -+ count = OUT_COUNT(stats); -+ jz4730_epn_out(dev, 5, count); -+ } -+ } -+ } -+ -+ if (intr_ep & UDC_EPIntR_INEP2) { -+ ep = &dev->ep[2]; -+ if (list_empty(&ep->queue)) { -+ ep->irq_pending = 1; -+ pio_irq_disable(ep); -+ } -+ else { -+ stats = REG_UDC_EP2InSR; -+ if (stats & UDC_EPSR_IN) { -+ REG_UDC_EP2InSR &= ~UDC_EPSR_IN; -+ jz4730_epn_in(dev, 2); -+ } -+ } -+ -+ REG_UDC_EPIntR = UDC_EPIntR_INEP2; -+ } -+ -+ if (intr_ep & UDC_EPIntR_INEP1) { -+ ep = &dev->ep[1]; -+ if (list_empty(&ep->queue)) { -+ ep->irq_pending = 1; -+ pio_irq_disable(ep); -+ } -+ else { -+ stats = REG_UDC_EP1InSR; -+ if (stats & UDC_EPSR_IN) { -+ REG_UDC_EP1InSR &= ~UDC_EPSR_IN; -+ jz4730_epn_in(dev, 1); -+ } -+ } -+ -+ REG_UDC_EPIntR = UDC_EPIntR_INEP1; -+ } -+ -+ spin_unlock(&dev->lock); -+ return IRQ_HANDLED; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct jz4730_udc udc_dev = { -+ .usb_address = 0, -+ -+ .gadget = { -+ .ops = &jz4730_ops, -+ .ep0 = &udc_dev.ep[0].ep, -+ .name = driver_name, -+ .dev = { -+ .bus_id = "gadget", -+ }, -+ }, -+ /* control endpoint no need to init here!*/ -+ /* control endpoint */ -+}; -+ -+ -+/* tear down the binding between this driver and the pci device */ -+static int jz4730_udc_remove(struct platform_device *pdev) -+{ -+ struct jz4730_udc *dev = platform_get_drvdata(pdev); -+ -+ if (dev->driver) -+ return -EBUSY; -+ -+ /* USB port0 as UHC */ -+ __harb_usb0_uhc(); -+ -+ /* reset udc */ -+ udc_reset(dev); -+ -+ /* clear any status */ -+ REG_UDC_EPIntR = 0xffffffff; -+ REG_UDC_DevIntR = 0xffffffff; -+ -+ /* disable all UDC interrupts */ -+ REG_UDC_DevIntMR = 0xffffffff; -+ REG_UDC_EPIntMR = 0xffffffff; -+ -+ free_irq(IRQ_UDC, dev); -+ platform_set_drvdata(pdev, 0); -+ device_unregister(&dev->gadget.dev); -+ the_controller = 0; -+ -+ return 0; -+} -+ -+static int jz4730_udc_probe(struct platform_device *pdev) -+{ -+ struct jz4730_udc *dev = &udc_dev; -+ int retval,rc; -+ -+ /* if you want to support more than one controller in a system, -+ * usb_gadget_driver_{register,unregister}() must change. -+ */ -+ if (the_controller) { -+ printk("Check the_controller: %s\n", driver_name); -+ return -EBUSY; -+ } -+ -+ spin_lock_init(&dev->lock); -+ device_initialize(&dev->gadget.dev); -+ dev->gadget.dev.parent = &pdev->dev; //if no,can only insmod once!! -+ dev->gadget.dev.release = jz4730_udc_release; -+ rc = device_register (&dev->gadget.dev); -+ if (rc < 0) -+ return rc; -+ platform_set_drvdata(pdev, dev); -+ -+ /* -+ * Note: we just mask INTC irq but allow UDC irq. -+ * This avoid that we miss any UDC irqs. -+ */ -+ -+ /* To avoid any UDC irqs here, we call cli() first */ -+// cli(); -+ -+ /* disable INTC irq */ -+ __intc_mask_irq(IRQ_UDC); -+ -+ /* init to known state, then setup irqs */ -+ udc_reset(dev); -+ udc_reinit(dev); -+ -+ /* request UDC irq */ -+ if (request_irq(IRQ_UDC, jz4730_udc_irq, IRQF_DISABLED, // SA_INTERRUPT, -+ driver_name, dev) != 0) { -+ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); -+ retval = -EBUSY; -+ goto done; -+ } -+ -+ /* disable INTC irq again since request_irq has enabled it */ -+ __intc_mask_irq(IRQ_UDC); -+ __intc_ack_irq(IRQ_UDC); -+ -+ /* Re-enable irqs */ -+// sti(); -+ -+ printk(KERN_INFO "%s\n", driver_desc); -+ printk(KERN_INFO "version: " DRIVER_VERSION "\n"); -+ -+ /* done */ -+ the_controller = dev; -+ -+ return 0; -+ -+done: -+ if (dev) -+ jz4730_udc_remove (pdev); -+ return retval; -+} -+ -+static struct platform_driver udc_driver = { -+ .probe = jz4730_udc_probe, -+ .remove = jz4730_udc_remove, -+ .suspend = NULL, -+ .resume = NULL, -+ .driver = { -+ .name = (char *) driver_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+static struct platform_device the_udc_pdev = { -+ .name = (char *) driver_name, -+ .id = -1, -+ .dev = { -+ .release = jz4730_udc_release, -+ }, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init udc_init (void) -+{ -+ platform_driver_register(&udc_driver); -+ return platform_device_register (&the_udc_pdev); -+} -+ -+static void __exit udc_exit (void) -+{ -+ platform_driver_unregister(&udc_driver); -+ platform_device_unregister(&the_udc_pdev); -+} -+ -+module_init(udc_init); -+module_exit(udc_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR("Wei Jianli "); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/jz4730_udc.h linux-2.6.24.7/drivers/usb/gadget/jz4730_udc.h ---- linux-2.6.24.7.old/drivers/usb/gadget/jz4730_udc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/usb/gadget/jz4730_udc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,107 @@ -+/* -+ * JZ4730 USB Device Controller driver -+ * -+ * Copyright (C) 2005 by Wei Jianli -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#ifndef __JZ4730_UDC_H__ -+#define __JZ4730_UDC_H__ -+ -+/* DRIVER DATA STRUCTURES and UTILITIES */ -+#define MAX_EP_NUM 8 /* Number of endpoints on this UDC */ -+ -+#define MAX_EP0_SIZE 32 -+#define MAX_EP1_SIZE 64 -+#define MAX_EP2_SIZE 64 -+#define MAX_EP3_SIZE 64 -+#define MAX_EP4_SIZE 64 -+#define MAX_EP5_SIZE 64 -+#define MAX_EP6_SIZE 64 -+#define MAX_EP7_SIZE 64 -+ -+// UDC FIFO -+#define RXFIFO (UDC_RXFIFO) /* EP0 OUT, EP5-7 OUT */ -+#define TXFIFOEP0 (UDC_TXFIFOEP0) /* EP0 IN */ -+#define TXFIFOEP1 (TXFIFOEP0 + MAX_EP0_SIZE) /* EP1 IN */ -+#define TXFIFOEP2 (TXFIFOEP1 + MAX_EP1_SIZE) /* EP2 IN */ -+#define TXFIFOEP3 (TXFIFOEP2 + MAX_EP2_SIZE) /* EP3 IN */ -+#define TXFIFOEP4 (TXFIFOEP3 + MAX_EP3_SIZE) /* EP4 IN */ -+ -+static u32 ep_fifo[MAX_EP_NUM] = {TXFIFOEP0, TXFIFOEP1, TXFIFOEP2, -+ TXFIFOEP3, TXFIFOEP4, RXFIFO, RXFIFO, -+ RXFIFO}; -+ -+#define OUT_COUNT(stats) \ -+ ((stats&UDC_EPSR_RXPKTSIZE_MASK)>>UDC_EPSR_RXPKTSIZE_BIT) -+ -+struct jz4730_ep { -+ struct usb_ep ep; -+ struct jz4730_udc *dev; -+ -+ u8 index; -+ u8 is_in; -+ u8 stopped; -+ u8 irq_pending; -+ u32 fifo; -+ -+ struct list_head queue; -+ const struct usb_endpoint_descriptor *desc; -+}; -+ -+struct jz4730_request { -+ struct usb_request req; -+ struct list_head queue; -+}; -+ -+enum ep0state { -+ EP0_DISCONNECT, /* no host */ -+ EP0_IDLE, /* between STATUS ack and SETUP report */ -+ EP0_IN, EP0_OUT, /* data stage */ -+ EP0_STATUS, /* status stage */ -+ EP0_STALL, /* data or status stages */ -+ EP0_SUSPEND, /* usb suspend */ -+}; -+ -+struct jz4730_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ spinlock_t lock; -+ -+ struct jz4730_ep ep[MAX_EP_NUM]; -+ enum ep0state ep0state; -+ unsigned char usb_address; -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* 2.5 stuff that's sometimes missing in 2.4 */ -+ -+#ifndef container_of -+#define container_of list_entry -+#endif -+ -+#ifndef likely -+#define likely(x) (x) -+#define unlikely(x) (x) -+#endif -+ -+#ifndef BUG_ON -+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) -+#endif -+ -+#ifndef WARN_ON -+#define WARN_ON(x) do { } while (0) -+#endif -+ -+#ifndef IRQ_NONE -+typedef void irqreturn_t; -+#define IRQ_NONE -+#define IRQ_HANDLED -+#define IRQ_RETVAL(x) -+#endif -+ -+#endif /* __JZ4730_UDC_H__ */ -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/jz4740_udc.c linux-2.6.24.7/drivers/usb/gadget/jz4740_udc.c ---- linux-2.6.24.7.old/drivers/usb/gadget/jz4740_udc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/usb/gadget/jz4740_udc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2251 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.c -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+/* -+ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint. -+ * -+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk. -+ * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz4740_udc.h" -+ -+//#define DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args) -+//#define DEBUG(fmt,args...) printk(fmt , ## args) -+//#define DEBUG_EP0(fmt,args...) printk(fmt , ## args) -+//#define DEBUG_SETUP(fmt,args...) printk(fmt , ## args) -+ -+#ifndef DEBUG -+# define DEBUG(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_EP0 -+# define NO_STATES -+# define DEBUG_EP0(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_SETUP -+# define DEBUG_SETUP(fmt,args...) do {} while(0) -+#endif -+ -+static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */ -+ -+module_param(udc_debug, int, 0); -+MODULE_PARM_DESC(udc_debug, "test udc cable or power type"); -+ -+static unsigned int use_dma = 1; /* 1: use DMA, 0: use PIO */ -+ -+module_param(use_dma, int, 0); -+MODULE_PARM_DESC(use_dma, "DMA mode enable flag"); -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+extern int jz_udc_active; /* 0: No actions; 1: Have actions */ -+#endif -+ -+/* -+ * Local definintions. -+ */ -+ -+#define DRIVER_VERSION "13-Mar-2008" -+#define DRIVER_DESC "JZ4740 USB Device Controller" -+ -+static const char gadget_name [] = "jz4740_udc"; -+ -+struct jz4740_udc *the_controller; -+ -+static const char driver_name [] = "jz4740_udc"; -+static const char driver_desc [] = DRIVER_DESC; -+static const char ep0name[] = "ep0"; -+ -+#ifndef NO_STATES -+static char *state_names[] = { -+ "WAIT_FOR_SETUP", -+ "DATA_STATE_XMIT", -+ "DATA_STATE_NEED_ZLP", -+ "WAIT_FOR_OUT_STATUS", -+ "DATA_STATE_RECV" -+}; -+#endif -+ -+/* -+ * Local declarations. -+ */ -+static int jz4740_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc); -+static int jz4740_ep_disable(struct usb_ep *_ep); -+static struct usb_request *jz4740_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags); -+static void jz4740_free_request(struct usb_ep *_ep, struct usb_request *_req); -+ -+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); -+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req); -+static int jz4740_set_halt(struct usb_ep *_ep, int value); -+static int jz4740_fifo_status(struct usb_ep *_ep); -+static void jz4740_fifo_flush(struct usb_ep *_ep); -+ -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep); -+static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr); -+ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, -+ int status); -+static void pio_irq_enable(struct jz4740_ep *ep); -+static void pio_irq_disable(struct jz4740_ep *ep); -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver); -+static void nuke(struct jz4740_ep *ep, int status); -+static void flush(struct jz4740_ep *ep); -+static void udc_enable(struct jz4740_udc *dev); -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address); -+static void jz4740_udc_release (struct device *dev) {} -+ -+extern void *dma_alloc_noncoherent(struct device *dev, size_t size, -+ dma_addr_t *dma_handle, gfp_t flag); -+extern void dma_free_noncoherent(struct device *dev, size_t size, -+ void *vaddr, dma_addr_t dma_handle); -+ -+static struct usb_ep_ops jz4740_ep_ops = { -+ .enable = jz4740_ep_enable, -+ .disable = jz4740_ep_disable, -+ -+ .alloc_request = jz4740_alloc_request, -+ .free_request = jz4740_free_request, -+ -+ .queue = jz4740_queue, -+ .dequeue = jz4740_dequeue, -+ -+ .set_halt = jz4740_set_halt, -+ .fifo_status = jz4740_fifo_status, -+ .fifo_flush = jz4740_fifo_flush, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* inline functions of register read/write/set/clear */ -+ -+static __inline__ u8 usb_readb(u32 port) -+{ -+ return *(volatile u8 *)port; -+} -+ -+static __inline__ u16 usb_readw(u32 port) -+{ -+ return *(volatile u16 *)port; -+} -+ -+static __inline__ u32 usb_readl(u32 port) -+{ -+ return *(volatile u32 *)port; -+} -+ -+static __inline__ void usb_writeb(u32 port, u8 val) -+{ -+ *(volatile u8 *)port = val; -+} -+ -+static __inline__ void usb_writew(u32 port, u16 val) -+{ -+ *(volatile u16 *)port = val; -+} -+ -+static __inline__ void usb_writel(u32 port, u32 val) -+{ -+ *(volatile u32 *)port = val; -+} -+ -+static __inline__ void usb_setb(u32 port, u8 val) -+{ -+ volatile u8 *ioport = (volatile u8 *)(port); -+ *ioport = (*ioport) | val; -+} -+ -+static __inline__ void usb_setw(u32 port, u16 val) -+{ -+ volatile u16 *ioport = (volatile u16 *)(port); -+ *ioport = (*ioport) | val; -+} -+ -+static __inline__ void usb_setl(u32 port, u32 val) -+{ -+ volatile u32 *ioport = (volatile u32 *)(port); -+ *ioport = (*ioport) | val; -+} -+ -+static __inline__ void usb_clearb(u32 port, u8 val) -+{ -+ volatile u8 *ioport = (volatile u8 *)(port); -+ *ioport = (*ioport) & ~val; -+} -+ -+static __inline__ void usb_clearw(u32 port, u16 val) -+{ -+ volatile u16 *ioport = (volatile u16 *)(port); -+ *ioport = (*ioport) & ~val; -+} -+ -+static __inline__ void usb_clearl(u32 port, u32 val) -+{ -+ volatile u32 *ioport = (volatile u32 *)(port); -+ *ioport = (*ioport) & ~val; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static __inline__ int write_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, int max) -+{ -+ u8 *buf; -+ int length, nlong, nbyte; -+ volatile u32 *fifo = (volatile u32 *)ep->fifo; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetch(buf); -+ -+ length = req->req.length - req->req.actual; -+ length = min(length, max); -+ req->req.actual += length; -+ -+ DEBUG("Write %d (max %d), fifo %p\n", length, max, fifo); -+ -+ nlong = length >> 2; -+ nbyte = length & 0x3; -+ while (nlong--) { -+ *fifo = *((u32 *)buf); -+ buf += 4; -+ } -+ while (nbyte--) { -+ *((volatile u8 *)fifo) = *buf++; -+ } -+ -+ return length; -+} -+ -+static __inline__ int read_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, int count) -+{ -+ u8 *buf; -+ int length, nlong, nbyte; -+ volatile u32 *fifo = (volatile u32 *)ep->fifo; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetchw(buf); -+ -+ length = req->req.length - req->req.actual; -+ length = min(length, count); -+ req->req.actual += length; -+ -+ DEBUG("Read %d, fifo %p\n", length, fifo); -+ -+ nlong = length >> 2; -+ nbyte = length & 0x3; -+ while (nlong--) { -+ *((u32 *)buf) = *fifo; -+ buf += 4; -+ } -+ while (nbyte--) { -+ *buf++ = *((volatile u8 *)fifo); -+ } -+ -+ return length; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * udc_disable - disable USB device controller -+ */ -+static void udc_disable(struct jz4740_udc *dev) -+{ -+ DEBUG("%s, %p\n", __FUNCTION__, dev); -+ -+ udc_set_address(dev, 0); -+ -+ /* Disable interrupts */ -+ usb_writew(USB_REG_INTRINE, 0); -+ usb_writew(USB_REG_INTROUTE, 0); -+ usb_writeb(USB_REG_INTRUSBE, 0); -+ -+ /* Disable DMA */ -+ usb_writel(USB_REG_CNTL1, 0); -+ usb_writel(USB_REG_CNTL2, 0); -+ -+ /* Disconnect from usb */ -+ usb_clearb(USB_REG_POWER, USB_POWER_SOFTCONN); -+ -+ /* Disable the USB PHY */ -+#ifdef CONFIG_SOC_JZ4740 -+ REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; -+#elif CONFIG_SOC_JZ4750 -+ REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; -+#endif -+ -+ dev->ep0state = WAIT_FOR_SETUP; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+} -+ -+/* -+ * udc_reinit - initialize software state -+ */ -+static void udc_reinit(struct jz4740_udc *dev) -+{ -+ u32 i; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, dev); -+ -+ /* device/ep0 records init */ -+ INIT_LIST_HEAD(&dev->gadget.ep_list); -+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -+ dev->ep0state = WAIT_FOR_SETUP; -+ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ if (i != 0) -+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -+ -+ INIT_LIST_HEAD(&ep->queue); -+ ep->desc = 0; -+ ep->stopped = 0; -+ ep->pio_irqs = 0; -+ } -+} -+ -+/* until it's enabled, this UDC should be completely invisible -+ * to any USB host. -+ */ -+static void udc_enable(struct jz4740_udc *dev) -+{ -+ int i; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, dev); -+ -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* Flush FIFO for each */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ usb_set_index(ep_index(ep)); -+ flush(ep); -+ } -+ -+ /* Set this bit to allow the UDC entering low-power mode when -+ * there are no actions on the USB bus. -+ * UDC still works during this bit was set. -+ */ -+ __cpm_stop_udc(); -+ -+ /* Enable the USB PHY */ -+#ifdef CONFIG_SOC_JZ4740 -+ REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; -+#elif CONFIG_SOC_JZ4750 -+ REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; -+#endif -+ -+ /* Disable interrupts */ -+ usb_writew(USB_REG_INTRINE, 0); -+ usb_writew(USB_REG_INTROUTE, 0); -+ usb_writeb(USB_REG_INTRUSBE, 0); -+ -+ /* Enable interrupts */ -+ usb_setw(USB_REG_INTRINE, USB_INTR_EP0); -+ usb_setb(USB_REG_INTRUSBE, USB_INTR_RESET); -+ /* Don't enable rest of the interrupts */ -+ /* usb_setw(USB_REG_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2); -+ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1); */ -+ -+ /* Enable SUSPEND */ -+ /* usb_setb(USB_REG_POWER, USB_POWER_SUSPENDM); */ -+ -+ /* Enable HS Mode */ -+ usb_setb(USB_REG_POWER, USB_POWER_HSENAB); -+ -+ /* Let host detect UDC: -+ * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this -+ * transistor on and pull the USBDP pin HIGH. -+ */ -+ usb_setb(USB_REG_POWER, USB_POWER_SOFTCONN); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* keeping it simple: -+ * - one bus driver, initted first; -+ * - one function driver, initted second -+ */ -+ -+/* -+ * Register entry point for the peripheral controller driver. -+ */ -+ -+int usb_gadget_register_driver(struct usb_gadget_driver *driver) -+{ -+ struct jz4740_udc *dev = the_controller; -+ int retval; -+ -+ if (!driver -+ || !driver->bind -+ || !driver->unbind || !driver->disconnect || !driver->setup) -+ { -+ printk("\n-EINVAL"); -+ return -EINVAL; -+ } -+ if (!dev) -+ { -+ printk("\n-ENODEV"); -+ return -ENODEV; -+ } -+ if (dev->driver) -+ { -+ printk("\n-ENODEV"); -+ return -EBUSY; -+ } -+ -+ /* hook up the driver */ -+ dev->driver = driver; -+ retval = driver->bind(&dev->gadget); -+ if (retval) { -+ DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name, -+ driver->driver.name, retval); -+ dev->driver = 0; -+ return retval; -+ } -+ -+ /* then enable host detection and ep0; and we're ready -+ * for set_configuration as well as eventual disconnect. -+ */ -+ udc_enable(dev); -+ DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, -+ driver->driver.name); -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL(usb_gadget_register_driver); -+ -+ -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver) -+{ -+ int i; -+ -+ DEBUG("%s\n", __FUNCTION__); -+ -+ /* don't disconnect drivers more than once */ -+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = 0; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* prevent new request submissions, kill any outstanding requests */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ ep->stopped = 1; -+ -+ usb_set_index(ep_index(ep)); -+ nuke(ep, -ESHUTDOWN); -+ } -+ -+ /* report disconnect; the driver is already quiesced */ -+ if (driver) { -+ spin_unlock(&dev->lock); -+ driver->disconnect(&dev->gadget); -+ spin_lock(&dev->lock); -+ } -+ -+ /* re-init driver-visible data structures */ -+ udc_reinit(dev); -+} -+ -+ -+/* -+ * Unregister entry point for the peripheral controller driver. -+ */ -+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -+{ -+ struct jz4740_udc *dev = the_controller; -+ unsigned long flags; -+ -+ if (!dev) -+ return -ENODEV; -+ if (!driver || driver != dev->driver) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ dev->driver = 0; -+ stop_activity(dev, driver); -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ driver->unbind(&dev->gadget); -+ -+ udc_disable(dev); -+ -+ DEBUG("unregistered driver '%s'\n", driver->driver.name); -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL(usb_gadget_unregister_driver); -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * Starting DMA using mode 1 -+ */ -+static void kick_dma(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ u32 count = req->req.length; -+ u32 physaddr = virt_to_phys((void *)req->req.buf); -+ -+ usb_set_index(ep_index(ep)); -+ if (ep_is_in(ep)) { /* Bulk-IN transfer using DMA channel 1 */ -+ ep->reg_addr = USB_REG_ADDR1; -+ -+ dma_cache_wback_inv((unsigned long)req->req.buf, count); -+ -+ pio_irq_enable(ep); -+ -+ usb_writeb(USB_REG_INCSRH, -+ USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); -+ -+ usb_writel(USB_REG_ADDR1, physaddr); -+ usb_writel(USB_REG_COUNT1, count); -+ usb_writel(USB_REG_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | -+ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); -+ } -+ else { /* Bulk-OUT transfer using DMA channel 2 */ -+ ep->reg_addr = USB_REG_ADDR2; -+ -+ dma_cache_wback_inv((unsigned long)req->req.buf, count); -+ -+ pio_irq_enable(ep); -+ -+ usb_setb(USB_REG_OUTCSRH, -+ USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); -+ -+ usb_writel(USB_REG_ADDR2, physaddr); -+ usb_writel(USB_REG_COUNT2, count); -+ usb_writel(USB_REG_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | -+ USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); -+ } -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/** Write request to FIFO (max write == maxp size) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ u32 max, csr; -+ u32 physaddr = virt_to_phys((void *)req->req.buf); -+ -+ max = le16_to_cpu(ep->desc->wMaxPacketSize); -+ -+ if (use_dma) { -+ u32 dma_count; -+ -+ /* DMA interrupt generated due to the last packet loaded into the FIFO */ -+ -+ dma_count = usb_readl(ep->reg_addr) - physaddr; -+ req->req.actual += dma_count; -+ -+ if (dma_count % max) { -+ /* If the last packet is less than MAXP, set INPKTRDY manually */ -+ usb_setb(ep->csr, USB_INCSR_INPKTRDY); -+ } -+ -+ done(ep, req, 0); -+ if (list_empty(&ep->queue)) { -+ pio_irq_disable(ep); -+ return 1; -+ } -+ else { -+ /* advance the request queue */ -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ kick_dma(ep, req); -+ return 0; -+ } -+ } -+ -+ /* -+ * PIO mode handling starts here ... -+ */ -+ -+ csr = usb_readb(ep->csr); -+ -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ unsigned count; -+ int is_last, is_short; -+ -+ count = write_packet(ep, req, max); -+ usb_setb(ep->csr, USB_INCSR_INPKTRDY); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = is_short = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) -+ || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ /* interrupt/iso maxpacket may not fill the fifo */ -+ is_short = unlikely(max < ep_maxpacket(ep)); -+ } -+ -+ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", is_short ? "/S" : "", -+ req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ if (list_empty(&ep->queue)) { -+ pio_irq_disable(ep); -+ } -+ return 1; -+ } -+ } else { -+ DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); -+ } -+ -+ return 0; -+} -+ -+/** Read to request from FIFO (max read == bytes in fifo) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ u32 csr; -+ unsigned count, is_short; -+ u32 physaddr = virt_to_phys((void *)req->req.buf); -+ -+ if (use_dma) { -+ u32 dma_count; -+ -+ /* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */ -+ -+ dma_count = usb_readl(ep->reg_addr) - physaddr; -+ req->req.actual += dma_count; -+ -+ /* Disable interrupt and DMA */ -+ pio_irq_disable(ep); -+ usb_writel(USB_REG_CNTL2, 0); -+ -+ /* Read all bytes from this packet */ -+ count = usb_readw(USB_REG_OUTCOUNT); -+ count = read_packet(ep, req, count); -+ -+ if (count) { -+ /* If the last packet is greater than zero, clear OUTPKTRDY manually */ -+ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY); -+ } -+ -+ done(ep, req, 0); -+ -+ if (!list_empty(&ep->queue)) { -+ /* advance the request queue */ -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ kick_dma(ep, req); -+ } -+ -+ return 1; -+ } -+ -+ /* -+ * PIO mode handling starts here ... -+ */ -+ -+ /* make sure there's a packet in the FIFO. */ -+ csr = usb_readb(ep->csr); -+ if (!(csr & USB_OUTCSR_OUTPKTRDY)) { -+ DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* read all bytes from this packet */ -+ count = usb_readw(USB_REG_OUTCOUNT); -+ -+ is_short = (count < ep->ep.maxpacket); -+ -+ count = read_packet(ep, req, count); -+ -+ DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ /* Clear OutPktRdy */ -+ usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY); -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ -+ if (list_empty(&ep->queue)) -+ pio_irq_disable(ep); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/* -+ * done - retire a request; caller blocked irqs -+ * INDEX register is preserved to keep same -+ */ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status) -+{ -+ unsigned int stopped = ep->stopped; -+ u32 index; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ list_del_init(&req->queue); -+ -+ if (likely(req->req.status == -EINPROGRESS)) -+ req->req.status = status; -+ else -+ status = req->req.status; -+ -+ if (status && status != -ESHUTDOWN) -+ DEBUG("complete %s req %p stat %d len %u/%u\n", -+ ep->ep.name, &req->req, status, -+ req->req.actual, req->req.length); -+ -+ /* don't modify queue heads during completion callback */ -+ ep->stopped = 1; -+ /* Read current index (completion may modify it) */ -+ index = usb_readb(USB_REG_INDEX); -+ -+ spin_unlock(&ep->dev->lock); -+ req->req.complete(&ep->ep, &req->req); -+ spin_lock(&ep->dev->lock); -+ -+ /* Restore index */ -+ usb_set_index(index); -+ ep->stopped = stopped; -+} -+ -+/** Enable EP interrupt */ -+static void pio_irq_enable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ if (ep_is_in(ep)) { -+ switch (ep_index(ep)) { -+ case 1: -+ usb_setw(USB_REG_INTRINE, USB_INTR_INEP1); -+ break; -+ case 2: -+ usb_setw(USB_REG_INTRINE, USB_INTR_INEP2); -+ break; -+ default: -+ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); -+ break; -+ } -+ } -+ else { -+ switch (ep_index(ep)) { -+ case 1: -+ usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1); -+ break; -+ default: -+ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); -+ break; -+ } -+ } -+} -+ -+/** Disable EP interrupt */ -+static void pio_irq_disable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ if (ep_is_in(ep)) { -+ switch (ep_index(ep)) { -+ case 1: -+ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP1); -+ break; -+ case 2: -+ usb_clearw(USB_REG_INTRINE, USB_INTR_INEP2); -+ break; -+ default: -+ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); -+ break; -+ } -+ } -+ else { -+ switch (ep_index(ep)) { -+ case 1: -+ usb_clearw(USB_REG_INTROUTE, USB_INTR_OUTEP1); -+ break; -+ default: -+ DEBUG("Unknown endpoint: %d\n", ep_index(ep)); -+ break; -+ } -+ } -+} -+ -+/* -+ * nuke - dequeue ALL requests -+ */ -+static void nuke(struct jz4740_ep *ep, int status) -+{ -+ struct jz4740_request *req; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ /* Flush FIFO */ -+ flush(ep); -+ -+ /* called with irqs blocked */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ done(ep, req, status); -+ } -+ -+ /* Disable IRQ if EP is enabled (has descriptor) */ -+ if (ep->desc) -+ pio_irq_disable(ep); -+} -+ -+/** Flush EP FIFO -+ * NOTE: INDEX register must be set before this call -+ */ -+static void flush(struct jz4740_ep *ep) -+{ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ switch (ep->ep_type) { -+ case ep_control: -+ break; -+ -+ case ep_bulk_in: -+ case ep_interrupt: -+ usb_setb(ep->csr, USB_INCSR_FF); -+ break; -+ -+ case ep_bulk_out: -+ usb_setb(ep->csr, USB_OUTCSR_FF); -+ break; -+ } -+} -+ -+/** -+ * jz4740_in_epn - handle IN interrupt -+ */ -+static void jz4740_in_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr) -+{ -+ u32 csr; -+ struct jz4740_ep *ep = &dev->ep[ep_idx + 1]; -+ struct jz4740_request *req; -+ -+ usb_set_index(ep_index(ep)); -+ -+ csr = usb_readb(ep->csr); -+ DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); -+ -+ if (csr & USB_INCSR_SENTSTALL) { -+ DEBUG("USB_INCSR_SENTSTALL\n"); -+ usb_clearb(ep->csr, USB_INCSR_SENTSTALL); -+ return; -+ } -+ -+ if (!ep->desc) { -+ DEBUG("%s: NO EP DESC\n", __FUNCTION__); -+ return; -+ } -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ DEBUG("req: %p\n", req); -+ -+ if (!req) -+ return; -+ -+ write_fifo(ep, req); -+} -+ -+/* -+ * Bulk OUT (recv) -+ */ -+static void jz4740_out_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[ep_idx]; -+ struct jz4740_request *req; -+ -+ DEBUG("%s: %d\n", __FUNCTION__, ep_idx); -+ -+ usb_set_index(ep_index(ep)); -+ if (ep->desc) { -+ u32 csr; -+ -+ if (use_dma) { -+ /* DMA starts here ... */ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (req) -+ read_fifo(ep, req); -+ return; -+ } -+ -+ /* -+ * PIO mode starts here ... -+ */ -+ -+ while ((csr = usb_readb(ep->csr)) & -+ (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { -+ DEBUG("%s: %x\n", __FUNCTION__, csr); -+ -+ if (csr & USB_OUTCSR_SENTSTALL) { -+ DEBUG("%s: stall sent, flush fifo\n", -+ __FUNCTION__); -+ /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ -+ flush(ep); -+ } else if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = -+ list_entry(ep->queue.next, -+ struct jz4740_request, -+ queue); -+ -+ if (!req) { -+ DEBUG("%s: NULL REQ %d\n", -+ __FUNCTION__, ep_idx); -+ break; -+ } else { -+ read_fifo(ep, req); -+ } -+ } -+ } -+ } else { -+ /* Throw packet away.. */ -+ printk("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx); -+ flush(ep); -+ } -+} -+ -+static int jz4740_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ unsigned long flags; -+ u32 max, csrh = 0; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || !desc || ep->desc || _ep->name == ep0name -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || ep->bEndpointAddress != desc->bEndpointAddress) { -+ DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* xfer types must match, except that interrupt ~= bulk */ -+ if (ep->bmAttributes != desc->bmAttributes -+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK -+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { -+ DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { -+ DEBUG("%s, bogus device state\n", __FUNCTION__); -+ return -ESHUTDOWN; -+ } -+ -+ max = le16_to_cpu(desc->wMaxPacketSize); -+ -+ /* Configure the endpoint */ -+ usb_set_index(desc->bEndpointAddress & 0x0F); -+ if (ep_is_in(ep)) { -+ usb_writew(USB_REG_INMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_INCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_INCSRH_ISO; -+ break; -+ } -+ usb_writeb(USB_REG_INCSRH, csrh); -+ } -+ else { -+ usb_writew(USB_REG_OUTMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ csrh &= ~USB_OUTCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_OUTCSRH_ISO; -+ csrh |= USB_OUTCSRH_DNYT; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_OUTCSRH_ISO; -+ break; -+ } -+ usb_writeb(USB_REG_OUTCSRH, csrh); -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ ep->stopped = 0; -+ ep->desc = desc; -+ ep->pio_irqs = 0; -+ ep->ep.maxpacket = max; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ /* Reset halt state (does flush) */ -+ jz4740_set_halt(_ep, 0); -+ -+ DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); -+ -+ return 0; -+} -+ -+/** Disable EP -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_ep_disable(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || !ep->desc) { -+ DEBUG("%s, %s not enabled\n", __FUNCTION__, -+ _ep ? ep->ep.name : NULL); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ usb_set_index(ep_index(ep)); -+ -+ /* Nuke all pending requests (does flush) */ -+ nuke(ep, -ESHUTDOWN); -+ -+ /* Disable ep IRQ */ -+ pio_irq_disable(ep); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); -+ return 0; -+} -+ -+static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ req = kzalloc(sizeof(*req), gfp_flags); -+ if (!req) -+ return 0; -+ -+ INIT_LIST_HEAD(&req->queue); -+ -+ return &req->req; -+} -+ -+static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req) -+{ -+ struct jz4740_request *req; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ req = container_of(_req, struct jz4740_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ kfree(req); -+} -+ -+/*--------------------------------------------------------------------*/ -+ -+/** Queue one request -+ * Kickstart transfer if needed -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, -+ gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ req = container_of(_req, struct jz4740_request, req); -+ if (unlikely -+ (!_req || !_req->complete || !_req->buf -+ || !list_empty(&req->queue))) { -+ DEBUG("%s, bad params\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { -+ DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); -+ return -ESHUTDOWN; -+ } -+ -+ DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, -+ _req->buf); -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ /* kickstart this i/o queue? */ -+ DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), -+ ep->stopped); -+ if (list_empty(&ep->queue) && likely(!ep->stopped)) { -+ u32 csr; -+ -+ if (unlikely(ep_index(ep) == 0)) { -+ /* EP0 */ -+ list_add_tail(&req->queue, &ep->queue); -+ jz4740_ep0_kick(dev, ep); -+ req = 0; -+ } else if (use_dma) { -+ /* DMA */ -+ kick_dma(ep, req); -+ } -+ /* PIO */ -+ else if (ep_is_in(ep)) { -+ /* EP1 & EP2 */ -+ usb_set_index(ep_index(ep)); -+ csr = usb_readb(ep->csr); -+ pio_irq_enable(ep); -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ if (write_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } else { -+ /* EP1 */ -+ usb_set_index(ep_index(ep)); -+ csr = usb_readb(ep->csr); -+ pio_irq_enable(ep); -+ if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (read_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } -+ } -+ -+ /* pio or dma irq handler advances the queue. */ -+ if (likely(req != 0)) -+ list_add_tail(&req->queue, &ep->queue); -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ return 0; -+} -+ -+/* dequeue JUST ONE request */ -+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_request *req; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || ep->ep.name == ep0name) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ /* make sure it's actually queued on this endpoint */ -+ list_for_each_entry(req, &ep->queue, queue) { -+ if (&req->req == _req) -+ break; -+ } -+ if (&req->req != _req) { -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return -EINVAL; -+ } -+ -+ done(ep, req, -ECONNRESET); -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return 0; -+} -+ -+/** Halt specific EP -+ * Return 0 if success -+ * NOTE: Sets INDEX register to EP ! -+ */ -+static int jz4740_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ usb_set_index(ep_index(ep)); -+ -+ DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ if (ep_index(ep) == 0) { -+ /* EP0 */ -+ usb_setb(USB_REG_CSR0, USB_CSR0_SENDSTALL); -+ } else if (ep_is_in(ep)) { -+ u32 csr = usb_readb(ep->csr); -+ if (value && ((csr & USB_INCSR_FFNOTEMPT) -+ || !list_empty(&ep->queue))) { -+ /* -+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) -+ * if any transfer requests are still queued, or if the controller -+ * FIFO still holds bytes that the host hasnÂ’t collected. -+ */ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ DEBUG -+ ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", -+ (csr & USB_INCSR_FFNOTEMPT), -+ !list_empty(&ep->queue)); -+ return -EAGAIN; -+ } -+ flush(ep); -+ if (value) { -+ usb_setb(ep->csr, USB_INCSR_SENDSTALL); -+ } -+ else { -+ usb_clearb(ep->csr, USB_INCSR_SENDSTALL); -+ usb_setb(ep->csr, USB_INCSR_CDT); -+ } -+ } else { -+ -+ flush(ep); -+ if (value) { -+ usb_setb(ep->csr, USB_OUTCSR_SENDSTALL); -+ } -+ else { -+ usb_clearb(ep->csr, USB_OUTCSR_SENDSTALL); -+ usb_setb(ep->csr, USB_OUTCSR_CDT); -+ } -+ } -+ -+ if (value) { -+ ep->stopped = 1; -+ } else { -+ ep->stopped = 0; -+ } -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); -+ -+ return 0; -+} -+ -+/** Return bytes in EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static int jz4740_fifo_status(struct usb_ep *_ep) -+{ -+ u32 csr; -+ int count = 0; -+ struct jz4740_ep *ep; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -ENODEV; -+ } -+ -+ DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); -+ -+ /* LPD can't report unclaimed bytes from IN fifos */ -+ if (ep_is_in(ep)) -+ return -EOPNOTSUPP; -+ -+ usb_set_index(ep_index(ep)); -+ -+ csr = usb_readb(ep->csr); -+ if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || -+ csr & 0x1) { -+ count = usb_readw(USB_REG_OUTCOUNT); -+ } -+ -+ return count; -+} -+ -+/** Flush EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static void jz4740_fifo_flush(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return; -+ } -+ -+ usb_set_index(ep_index(ep)); -+ flush(ep); -+} -+ -+/****************************************************************/ -+/* End Point 0 related functions */ -+/****************************************************************/ -+ -+/* return: 0 = still running, 1 = completed, negative = errno */ -+static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ u32 max; -+ unsigned count; -+ int is_last; -+ -+ max = ep_maxpacket(ep); -+ -+ count = write_packet(ep, req, max); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ } -+ -+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static __inline__ int jz4740_fifo_read(struct jz4740_ep *ep, -+ unsigned char *cp, int max) -+{ -+ int bytes; -+ int count = usb_readw(USB_REG_OUTCOUNT); -+ volatile u8 *fifo = (volatile u8 *)ep->fifo; -+ -+ if (count > max) -+ count = max; -+ bytes = count; -+ while (count--) -+ *cp++ = *fifo; -+ return bytes; -+} -+ -+static __inline__ void jz4740_fifo_write(struct jz4740_ep *ep, -+ unsigned char *cp, int count) -+{ -+ volatile u8 *fifo = (volatile u8 *)ep->fifo; -+ DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count); -+ while (count--) -+ *fifo = *cp++; -+} -+ -+static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ u32 csr; -+ u8 *buf; -+ unsigned bufferspace, count, is_short; -+ volatile u8 *fifo = (volatile u8 *)ep->fifo; -+ -+ DEBUG_EP0("%s\n", __FUNCTION__); -+ -+ csr = usb_readb(USB_REG_CSR0); -+ if (!(csr & USB_CSR0_OUTPKTRDY)) -+ return 0; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetchw(buf); -+ bufferspace = req->req.length - req->req.actual; -+ -+ /* read all bytes from this packet */ -+ if (likely(csr & USB_CSR0_OUTPKTRDY)) { -+ count = usb_readw(USB_REG_OUTCOUNT); -+ req->req.actual += min(count, bufferspace); -+ } else /* zlp */ -+ count = 0; -+ -+ is_short = (count < ep->ep.maxpacket); -+ DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ while (likely(count-- != 0)) { -+ u8 byte = (u8) (*fifo & 0xff); -+ -+ if (unlikely(bufferspace == 0)) { -+ /* this happens when the driver's buffer -+ * is smaller than what the host sent. -+ * discard the extra data. -+ */ -+ if (req->req.status != -EOVERFLOW) -+ DEBUG_EP0("%s overflow %d\n", ep->ep.name, -+ count); -+ req->req.status = -EOVERFLOW; -+ } else { -+ *buf++ = byte; -+ bufferspace--; -+ } -+ } -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/** -+ * udc_set_address - set the USB address for this device -+ * @address: -+ * -+ * Called from control endpoint function after it decodes a set address setup packet. -+ */ -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address) -+{ -+ DEBUG_EP0("%s: %d\n", __FUNCTION__, address); -+ -+ dev->usb_address = address; -+ usb_writeb(USB_REG_FADDR, address); -+} -+ -+/* -+ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY bit -+ if last set USB_CSR0_DATAEND bit -+ */ -+static void jz4740_ep0_out(struct jz4740_udc *dev, u32 csr) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (req) { -+ if (req->req.length == 0) { -+ DEBUG_EP0("ZERO LENGTH OUT!\n"); -+/* usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); */ -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } -+ ret = read_fifo_ep0(ep, req); -+ if (ret) { -+ /* Done! */ -+ DEBUG_EP0("%s: finished, waiting for status\n", -+ __FUNCTION__); -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ /* Not done yet.. */ -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ } -+ } else { -+ DEBUG_EP0("NO REQ??!\n"); -+ } -+} -+ -+/* -+ * DATA_STATE_XMIT -+ */ -+static int jz4740_ep0_in(struct jz4740_udc *dev, u32 csr) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret, need_zlp = 0; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (!req) { -+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); -+ return 0; -+ } -+ -+ if (req->req.length == 0) { -+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return 1; -+ } -+ -+ if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) { -+ /* Next write will end with the packet size, */ -+ /* so we need zero-length-packet */ -+ need_zlp = 1; -+ } -+ -+ ret = write_fifo_ep0(ep, req); -+ -+ if (ret == 1 && !need_zlp) { -+ /* Last packet */ -+ DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); -+ -+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); -+ } -+ -+ if (need_zlp) { -+ DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); -+ usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); -+ dev->ep0state = DATA_STATE_NEED_ZLP; -+ } -+ -+ return 1; -+} -+ -+#if 0 -+static int jz4740_handle_get_status(struct jz4740_udc *dev, -+ struct usb_ctrlrequest *ctrl) -+{ -+ struct jz4740_ep *ep0 = &dev->ep[0]; -+ struct jz4740_ep *qep; -+ int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); -+ u16 val = 0; -+ -+ if (reqtype == USB_RECIP_INTERFACE) { -+ /* This is not supported. -+ * And according to the USB spec, this one does nothing.. -+ * Just return 0 -+ */ -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); -+ } else if (reqtype == USB_RECIP_DEVICE) { -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); -+ val |= (1 << 0); /* Self powered */ -+ /*val |= (1<<1); *//* Remote wakeup */ -+ } else if (reqtype == USB_RECIP_ENDPOINT) { -+ int ep_num = (ctrl->wIndex & ~USB_DIR_IN); -+ -+ DEBUG_SETUP -+ ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", -+ ep_num, ctrl->wLength); -+ -+ if (ctrl->wLength > 2 || ep_num > 3) -+ return -EOPNOTSUPP; -+ -+ qep = &dev->ep[ep_num]; -+ if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) -+ && ep_index(qep) != 0) { -+ return -EOPNOTSUPP; -+ } -+ -+ usb_set_index(ep_index(qep)); -+ -+ /* Return status on next IN token */ -+ switch (qep->ep_type) { -+ case ep_control: -+ val = -+ (usb_readb(qep->csr) & USB_CSR0_SENDSTALL) == -+ USB_CSR0_SENDSTALL; -+ break; -+ case ep_bulk_in: -+ case ep_interrupt: -+ val = -+ (usb_readb(qep->csr) & USB_INCSR_SENDSTALL) == -+ USB_INCSR_SENDSTALL; -+ break; -+ case ep_bulk_out: -+ val = -+ (usb_readb(qep->csr) & USB_OUTCSR_SENDSTALL) == -+ USB_OUTCSR_SENDSTALL; -+ break; -+ } -+ -+ /* Back to EP0 index */ -+ usb_set_index(0); -+ -+ DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, -+ ctrl->wIndex, val); -+ } else { -+ DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); -+ return -EOPNOTSUPP; -+ } -+ -+ /* Clear "out packet ready" */ -+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ /* Put status to FIFO */ -+ jz4740_fifo_write(ep0, (u8 *) & val, sizeof(val)); -+ /* Issue "In packet ready" */ -+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ -+ return 0; -+} -+#endif -+ -+/* -+ * WAIT_FOR_SETUP (OUTPKTRDY) -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits -+ */ -+static void jz4740_ep0_setup(struct jz4740_udc *dev, u32 csr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ struct usb_ctrlrequest ctrl; -+ int i; -+ -+ DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Nuke all previous transfers */ -+ nuke(ep, -EPROTO); -+ -+ /* read control req from fifo (8 bytes) */ -+ jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8); -+ -+ DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n", -+ ctrl.bRequestType, ctrl.bRequest, -+ ctrl.wValue, ctrl.wIndex, ctrl.wLength); -+ -+ /* Set direction of EP0 */ -+ if (likely(ctrl.bRequestType & USB_DIR_IN)) { -+ ep->bEndpointAddress |= USB_DIR_IN; -+ } else { -+ ep->bEndpointAddress &= ~USB_DIR_IN; -+ } -+ -+ /* Handle some SETUP packets ourselves */ -+ switch (ctrl.bRequest) { -+ case USB_REQ_SET_ADDRESS: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); -+ udc_set_address(dev, ctrl.wValue); -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ -+ case USB_REQ_SET_CONFIGURATION: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ -+ /* Enable RESUME and SUSPEND interrupts */ -+ usb_setb(USB_REG_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); -+ break; -+ -+ case USB_REQ_SET_INTERFACE: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ break; -+ -+// case USB_REQ_GET_STATUS: -+// if (jz4740_handle_get_status(dev, &ctrl) == 0) -+// return; -+ -+ case USB_REQ_CLEAR_FEATURE: -+ case USB_REQ_SET_FEATURE: -+ if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { -+ struct jz4740_ep *qep; -+ int ep_num = (ctrl.wIndex & 0x0f); -+ -+ /* Support only HALT feature */ -+ if (ctrl.wValue != 0 || ctrl.wLength != 0 -+ || ep_num > 3 || ep_num < 1) -+ break; -+ -+ qep = &dev->ep[ep_num]; -+ spin_unlock(&dev->lock); -+ if (ctrl.bRequest == USB_REQ_SET_FEATURE) { -+ DEBUG_SETUP("SET_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 1); -+ } else { -+ DEBUG_SETUP("CLR_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 0); -+ } -+ spin_lock(&dev->lock); -+ -+ usb_set_index(0); -+ -+ /* Reply with a ZLP on next IN token */ -+ usb_setb(USB_REG_CSR0, -+ (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ /* gadget drivers see class/vendor specific requests, -+ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, -+ * and more. -+ */ -+ if (likely((u32)dev->driver)) { -+ /* device-2-host (IN) or no data setup command, process immediately */ -+ spin_unlock(&dev->lock); -+ -+ i = dev->driver->setup(&dev->gadget, &ctrl); -+ spin_lock(&dev->lock); -+ -+ if (unlikely(i < 0)) { -+ /* setup processing failed, force stall */ -+ DEBUG_SETUP -+ (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", -+ i); -+ usb_set_index(0); -+ usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); -+ -+ /* ep->stopped = 1; */ -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ else { -+ DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); -+ if (!ctrl.wLength) { -+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ } -+ } -+ } -+} -+ -+/* -+ * DATA_STATE_NEED_ZLP -+ */ -+static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, u32 csr) -+{ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+} -+ -+/* -+ * handle ep0 interrupt -+ */ -+static void jz4740_handle_ep0(struct jz4740_udc *dev, u32 intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ u32 csr; -+ -+ /* Set index 0 */ -+ usb_set_index(0); -+ csr = usb_readb(USB_REG_CSR0); -+ -+ DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); -+ -+ /* -+ * if SENT_STALL is set -+ * - clear the SENT_STALL bit -+ */ -+ if (csr & USB_CSR0_SENTSTALL) { -+ DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); -+ usb_clearb(USB_REG_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); -+ nuke(ep, -ECONNABORTED); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } -+ -+ /* -+ * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear -+ * - fill EP0 FIFO -+ * - if last packet -+ * - set IN_PKT_RDY | DATA_END -+ * - else -+ * set IN_PKT_RDY -+ */ -+ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { -+ DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", -+ __FUNCTION__); -+ -+ switch (dev->ep0state) { -+ case DATA_STATE_XMIT: -+ DEBUG_EP0("continue with DATA_STATE_XMIT\n"); -+ jz4740_ep0_in(dev, csr); -+ return; -+ case DATA_STATE_NEED_ZLP: -+ DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); -+ jz4740_ep0_in_zlp(dev, csr); -+ return; -+ default: -+ /* Stall? */ -+// DEBUG_EP0("Odd state!! state = %s\n", -+// state_names[dev->ep0state]); -+ dev->ep0state = WAIT_FOR_SETUP; -+ /* nuke(ep, 0); */ -+ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */ -+// break; -+ return; -+ } -+ } -+ -+ /* -+ * if SETUPEND is set -+ * - abort the last transfer -+ * - set SERVICED_SETUP_END_BIT -+ */ -+ if (csr & USB_CSR0_SETUPEND) { -+ DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDSETUPEND); -+ nuke(ep, 0); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ -+ /* -+ * if USB_CSR0_OUTPKTRDY is set -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits -+ * - else -+ * set SVDOUTPKTRDY | DATAEND bits -+ */ -+ if (csr & USB_CSR0_OUTPKTRDY) { -+ -+ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, -+ csr); -+ -+ switch (dev->ep0state) { -+ case WAIT_FOR_SETUP: -+ DEBUG_EP0("WAIT_FOR_SETUP\n"); -+ jz4740_ep0_setup(dev, csr); -+ break; -+ -+ case DATA_STATE_RECV: -+ DEBUG_EP0("DATA_STATE_RECV\n"); -+ jz4740_ep0_out(dev, csr); -+ break; -+ -+ default: -+ /* send stall? */ -+ DEBUG_EP0("strange state!! 2. send stall? state = %d\n", -+ dev->ep0state); -+ break; -+ } -+ } -+} -+ -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep) -+{ -+ u32 csr; -+ -+ usb_set_index(0); -+ csr = usb_readb(USB_REG_CSR0); -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Clear "out packet ready" */ -+ usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ -+ if (ep_is_in(ep)) { -+ dev->ep0state = DATA_STATE_XMIT; -+ jz4740_ep0_in(dev, csr); -+ } else { -+ dev->ep0state = DATA_STATE_RECV; -+ jz4740_ep0_out(dev, csr); -+ } -+} -+ -+/** Handle USB RESET interrupt -+ */ -+static void jz4740_reset_irq(struct jz4740_udc *dev) -+{ -+ dev->gadget.speed = (usb_readb(USB_REG_POWER) & USB_POWER_HSMODE) ? -+ USB_SPEED_HIGH : USB_SPEED_FULL; -+ -+ DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address, -+ (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" ); -+} -+ -+/* -+ * jz4740 usb device interrupt handler. -+ */ -+static irqreturn_t jz4740_udc_irq(int irq, void *_dev) -+{ -+ struct jz4740_udc *dev = _dev; -+ -+ u32 intr_usb = usb_readb(USB_REG_INTRUSB) & 0x7; /* mask SOF */ -+ u32 intr_in = usb_readw(USB_REG_INTRIN); -+ u32 intr_out = usb_readw(USB_REG_INTROUT); -+ u32 intr_dma = usb_readb(USB_REG_INTR); -+ -+ if (!intr_usb && !intr_in && !intr_out && !intr_dma) -+ return IRQ_HANDLED; -+ -+ DEBUG("intr_out = %x intr_in=%x intr_usb=%x\n", -+ intr_out, intr_in, intr_usb); -+ -+ spin_lock(&dev->lock); -+ -+ /* Check for resume from suspend mode */ -+ if ((intr_usb & USB_INTR_RESUME) && -+ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_RESUME)) { -+ DEBUG("USB resume\n"); -+ } -+ -+ /* Check for system interrupts */ -+ if (intr_usb & USB_INTR_RESET) { -+ DEBUG("USB reset\n"); -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ jz_udc_active = 1; -+#endif -+ if (udc_debug) { -+ /* We have tested the cable type, disable module and -+ * disconnect from host right now. -+ */ -+ udc_disable(dev); -+ spin_unlock(&dev->lock); -+ return IRQ_HANDLED; -+ } -+ jz4740_reset_irq(dev); -+ } -+ -+ /* Check for endpoint 0 interrupt */ -+ if (intr_in & USB_INTR_EP0) { -+ DEBUG("USB_INTR_EP0 (control)\n"); -+ jz4740_handle_ep0(dev, intr_in); -+ } -+ -+ /* Check for Bulk-IN DMA interrupt */ -+ if (intr_dma & 0x1) { -+ int ep_num; -+ ep_num = (usb_readl(USB_REG_CNTL1) >> 4) & 0xf; -+ jz4740_in_epn(dev, ep_num, intr_in); -+ } -+ -+ /* Check for Bulk-OUT DMA interrupt */ -+ if (intr_dma & 0x2) { -+ int ep_num; -+ ep_num = (usb_readl(USB_REG_CNTL2) >> 4) & 0xf; -+ jz4740_out_epn(dev, ep_num, intr_out); -+ } -+ -+ /* Check for each configured endpoint interrupt */ -+ if (intr_in & USB_INTR_INEP1) { -+ DEBUG("USB_INTR_INEP1\n"); -+ jz4740_in_epn(dev, 1, intr_in); -+ } -+ -+ if (intr_in & USB_INTR_INEP2) { -+ DEBUG("USB_INTR_INEP2\n"); -+ jz4740_in_epn(dev, 2, intr_in); -+ } -+ -+ if (intr_out & USB_INTR_OUTEP1) { -+ DEBUG("USB_INTR_OUTEP1\n"); -+ jz4740_out_epn(dev, 1, intr_out); -+ } -+ -+ /* Check for suspend mode */ -+ if ((intr_usb & USB_INTR_SUSPEND) && -+ (usb_readb(USB_REG_INTRUSBE) & USB_INTR_SUSPEND)) { -+ DEBUG("USB suspend\n"); -+ dev->driver->suspend(&dev->gadget); -+ /* Host unloaded from us, can do something, such as flushing -+ the NAND block cache etc. */ -+ } -+ -+#ifdef CONFIG_JZ_UDC_HOTPLUG -+ jz_udc_active = 1; -+#endif -+ -+ spin_unlock(&dev->lock); -+ return IRQ_HANDLED; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int jz4740_udc_get_frame(struct usb_gadget *_gadget) -+{ -+ DEBUG("%s, %p\n", __FUNCTION__, _gadget); -+ return usb_readw(USB_REG_FRAME); -+} -+ -+static int jz4740_udc_wakeup(struct usb_gadget *_gadget) -+{ -+ /* host may not have enabled remote wakeup */ -+ /*if ((UDCCS0 & UDCCS0_DRWF) == 0) -+ return -EHOSTUNREACH; -+ udc_set_mask_UDCCR(UDCCR_RSM); */ -+ return -ENOTSUPP; -+} -+ -+static const struct usb_gadget_ops jz4740_udc_ops = { -+ .get_frame = jz4740_udc_get_frame, -+ .wakeup = jz4740_udc_wakeup, -+ /* current versions must always be self-powered */ -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct jz4740_udc udc_dev = { -+ .usb_address = 0, -+ -+ .gadget = { -+ .ops = &jz4740_udc_ops, -+ .ep0 = &udc_dev.ep[0].ep, -+ .name = driver_name, -+ .dev = { -+ .bus_id = "gadget", -+ }, -+ }, -+ -+ /* control endpoint */ -+ .ep[0] = { -+ .ep = { -+ .name = ep0name, -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EP0_MAXPACKETSIZE, -+ }, -+ .dev = &udc_dev, -+ -+ .bEndpointAddress = 0, -+ .bmAttributes = 0, -+ -+ .ep_type = ep_control, -+ .fifo = USB_FIFO_EP0, -+ .csr = USB_REG_CSR0, -+ }, -+ -+ /* bulk out endpoint */ -+ .ep[1] = { -+ .ep = { -+ .name = "ep1out-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &udc_dev, -+ -+ .bEndpointAddress = 1, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .ep_type = ep_bulk_out, -+ .fifo = USB_FIFO_EP1, -+ .csr = USB_REG_OUTCSR, -+ }, -+ -+ /* bulk in endpoint */ -+ .ep[2] = { -+ .ep = { -+ .name = "ep1in-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &udc_dev, -+ -+ .bEndpointAddress = USB_DIR_IN | 1, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .ep_type = ep_bulk_in, -+ .fifo = USB_FIFO_EP1, -+ .csr = USB_REG_INCSR, -+ }, -+ -+ /* interrupt in endpoint */ -+ .ep[3] = { -+ .ep = { -+ .name = "ep2in-int", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPINTR_MAXPACKETSIZE, -+ }, -+ .dev = &udc_dev, -+ -+ .bEndpointAddress = USB_DIR_IN | 2, -+ .bmAttributes = USB_ENDPOINT_XFER_INT, -+ -+ .ep_type = ep_interrupt, -+ .fifo = USB_FIFO_EP2, -+ .csr = USB_REG_INCSR, -+ }, -+}; -+ -+static int jz4740_udc_probe(struct platform_device *pdev) -+{ -+ struct jz4740_udc *dev = &udc_dev; -+ int rc; -+ -+ DEBUG("%s\n", __FUNCTION__); -+ -+ spin_lock_init(&dev->lock); -+ the_controller = dev; -+ -+ dev->dev = &pdev->dev; -+ device_initialize(&dev->gadget.dev); -+ dev->gadget.dev.parent = &pdev->dev; -+ -+// strcpy (dum->gadget.dev.bus_id, "gadget"); -+ dev->gadget.dev.release = jz4740_udc_release; -+ if ((rc = device_register (&dev->gadget.dev)) < 0) -+ return rc; -+ platform_set_drvdata(pdev, dev); -+ -+ udc_disable(dev); -+ udc_reinit(dev); -+ -+ /* irq setup */ -+ if (request_irq(IRQ_UDC, jz4740_udc_irq, IRQF_DISABLED,//SA_SHIRQ/*|SA_SAMPLE_RANDOM*/, -+ driver_name, dev) != 0) { -+ printk(KERN_INFO "request UDC interrupt %d failed\n", IRQ_UDC); -+ return -EBUSY; -+ } -+ -+ printk(KERN_INFO "%s\n", driver_desc); -+ printk(KERN_INFO "version: " DRIVER_VERSION "\n"); -+ -+ return 0; -+} -+ -+static int jz4740_udc_remove(struct platform_device *pdev) -+{ -+ struct jz4740_udc *dev = platform_get_drvdata(pdev); -+ DEBUG("%s: %p\n", __FUNCTION__, dev); -+ -+ if (dev->driver) -+ return -EBUSY; -+ -+ udc_disable(dev); -+#ifdef UDC_PROC_FILE -+ remove_proc_entry(proc_node_name, NULL); -+#endif -+ -+ free_irq(IRQ_UDC, dev); -+ platform_set_drvdata(pdev, 0); -+ device_unregister(&dev->gadget.dev); -+ the_controller = 0; -+ -+ return 0; -+} -+ -+static struct platform_driver udc_driver = { -+ .probe = jz4740_udc_probe, -+ .remove = jz4740_udc_remove, -+ .suspend = NULL, -+ .resume = NULL, -+ .driver = { -+ .name = (char *) driver_name, -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+ -+ -+static struct platform_device the_udc_pdev = { -+ .name = (char *) gadget_name, -+ .id = -1, -+ .dev = { -+ .release = jz4740_udc_release, -+ }, -+}; -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init udc_init (void) -+{ -+ platform_driver_register(&udc_driver); -+ return platform_device_register (&the_udc_pdev); -+} -+ -+static void __exit udc_exit (void) -+{ -+ platform_driver_unregister(&udc_driver); -+ platform_device_unregister(&the_udc_pdev); -+} -+ -+module_init(udc_init); -+module_exit(udc_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR("Wei Jianli "); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/usb/gadget/jz4740_udc.h linux-2.6.24.7/drivers/usb/gadget/jz4740_udc.h ---- linux-2.6.24.7.old/drivers/usb/gadget/jz4740_udc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/usb/gadget/jz4740_udc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,112 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.h -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#ifndef __USB_GADGET_JZ4740_H__ -+#define __USB_GADGET_JZ4740_H__ -+ -+/*-------------------------------------------------------------------------*/ -+ -+// Max packet size -+#define EP0_MAXPACKETSIZE 64 -+#define EPBULK_MAXPACKETSIZE 512 -+#define EPINTR_MAXPACKETSIZE 64 -+ -+#define UDC_MAX_ENDPOINTS 4 -+ -+/*-------------------------------------------------------------------------*/ -+ -+typedef enum ep_type { -+ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt -+} ep_type_t; -+ -+struct jz4740_ep { -+ struct usb_ep ep; -+ struct jz4740_udc *dev; -+ -+ const struct usb_endpoint_descriptor *desc; -+ struct list_head queue; -+ unsigned long pio_irqs; -+ -+ u8 stopped; -+ u8 bEndpointAddress; -+ u8 bmAttributes; -+ -+ ep_type_t ep_type; -+ u32 fifo; -+ u32 csr; -+ -+ u32 reg_addr; -+}; -+ -+struct jz4740_request { -+ struct usb_request req; -+ struct list_head queue; -+}; -+ -+enum ep0state { -+ WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */ -+ DATA_STATE_XMIT, /* data tx stage */ -+ DATA_STATE_NEED_ZLP, /* data tx zlp stage */ -+ WAIT_FOR_OUT_STATUS, /* status stages */ -+ DATA_STATE_RECV, /* data rx stage */ -+}; -+ -+struct jz4740_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ struct device *dev; -+ spinlock_t lock; -+ -+ enum ep0state ep0state; -+ struct jz4740_ep ep[UDC_MAX_ENDPOINTS]; -+ -+ unsigned char usb_address; -+}; -+ -+extern struct jz4740_udc *the_controller; -+ -+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) -+#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -+#define ep_index(EP) ((EP)->bEndpointAddress&0xF) -+#define usb_set_index(i) (REG8(USB_REG_INDEX) = (i)) -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* 2.5 stuff that's sometimes missing in 2.4 */ -+ -+#ifndef container_of -+#define container_of list_entry -+#endif -+ -+#ifndef likely -+#define likely(x) (x) -+#define unlikely(x) (x) -+#endif -+ -+#ifndef BUG_ON -+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) -+#endif -+ -+#ifndef WARN_ON -+#define WARN_ON(x) do { } while (0) -+#endif -+ -+#ifndef IRQ_NONE -+typedef void irqreturn_t; -+#define IRQ_NONE -+#define IRQ_HANDLED -+#define IRQ_RETVAL(x) -+#endif -+ -+#endif /* __USB_GADGET_JZ4740_H__ */ -diff -urN linux-2.6.24.7.old/drivers/usb/host/ohci-hcd.c linux-2.6.24.7/drivers/usb/host/ohci-hcd.c ---- linux-2.6.24.7.old/drivers/usb/host/ohci-hcd.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/usb/host/ohci-hcd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -977,6 +977,11 @@ - #define PCI_DRIVER ohci_pci_driver - #endif - -+#ifdef CONFIG_JZSOC -+#include "ohci-jz.c" -+#define PLATFORM_DRIVER ohci_hcd_jz_driver -+#endif -+ - #ifdef CONFIG_SA1111 - #include "ohci-sa1111.c" - #define SA1111_DRIVER ohci_hcd_sa1111_driver -diff -urN linux-2.6.24.7.old/drivers/usb/host/ohci-jz.c linux-2.6.24.7/drivers/usb/host/ohci-jz.c ---- linux-2.6.24.7.old/drivers/usb/host/ohci-jz.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/usb/host/ohci-jz.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,260 @@ -+/* -+ * OHCI HCD (Host Controller Driver) for USB. -+ * -+ * (C) Copyright 1999 Roman Weissgaerber -+ * (C) Copyright 2000-2002 David Brownell -+ * (C) Copyright 2002 Hewlett-Packard Company -+ * -+ * Bus Glue for Ingenic Jz47xx. -+ * -+ * Written by Christopher Hoover -+ * Based on fragments of previous driver by Rusell King et al. -+ * -+ * Modified for LH7A404 from ohci-sa1111.c -+ * by Durgesh Pattamatta -+ * Modified for AMD Alchemy Au1xxx -+ * by Matt Porter -+ * Modified for Jz47xx from ohci-au1xxx.c -+ * by Peter -+ * -+ * This file is licenced under the GPL. -+ */ -+ -+#include -+#include -+ -+#include -+ -+extern int usb_disabled(void); -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void jz_start_ohc(struct platform_device *dev) -+{ -+ printk(KERN_DEBUG __FILE__ -+ ": starting JZ OHCI USB Controller\n"); -+ -+ /* enable host controller */ -+ __cpm_start_uhc(); -+ -+#ifdef CONFIG_SOC_JZ4750 -+ __cpm_enable_uhcphy(); -+#endif -+ -+ printk(KERN_DEBUG __FILE__ -+ ": Clock to USB host has been enabled \n"); -+} -+ -+static void jz_stop_ohc(struct platform_device *dev) -+{ -+ printk(KERN_DEBUG __FILE__ -+ ": stopping JZ OHCI USB Controller\n"); -+ -+#ifdef CONFIG_SOC_JZ4750 -+ __cpm_suspend_uhcphy(); -+#endif -+ -+ __cpm_stop_uhc(); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* configure so an HC device and id are always provided */ -+/* always called with process context; sleeping is OK */ -+ -+ -+/** -+ * usb_ohci_jz_probe - initialize Jz-based HCDs -+ * Context: !in_interrupt() -+ * -+ * Allocates basic resources for this USB host controller, and -+ * then invokes the start() method for the HCD associated with it -+ * through the hotplug entry's driver_data. -+ * -+ */ -+static int usb_ohci_jz_probe(const struct hc_driver *driver, -+ struct platform_device *dev) -+{ -+ int retval; -+ struct usb_hcd *hcd; -+ -+ if (dev->resource[1].flags != IORESOURCE_IRQ) { -+ pr_debug("resource[1] is not IORESOURCE_IRQ\n"); -+ return -ENOMEM; -+ } -+ -+ hcd = usb_create_hcd(driver, &dev->dev, "jz"); -+ if (!hcd) -+ return -ENOMEM; -+ hcd->rsrc_start = dev->resource[0].start; -+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; -+ -+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -+ pr_debug("request_mem_region failed\n"); -+ retval = -EBUSY; -+ goto err1; -+ } -+ -+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -+ if (!hcd->regs) { -+ pr_debug("ioremap failed\n"); -+ retval = -ENOMEM; -+ goto err2; -+ } -+ -+ jz_start_ohc(dev); -+ ohci_hcd_init(hcd_to_ohci(hcd)); -+ -+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED); -+ if (retval == 0) -+ return retval; -+ -+ jz_stop_ohc(dev); -+ iounmap(hcd->regs); -+ err2: -+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ err1: -+ usb_put_hcd(hcd); -+ return retval; -+} -+ -+ -+/* may be called without controller electrically present */ -+/* may be called with controller, bus, and devices active */ -+ -+/** -+ * usb_hcd_jz_remove - shutdown processing for Jz-based HCDs -+ * @dev: USB Host Controller being removed -+ * Context: !in_interrupt() -+ * -+ * Reverses the effect of usb_hcd_jz_probe(), first invoking -+ * the HCD's stop() method. It is always called from a thread -+ * context, normally "rmmod", "apmd", or something similar. -+ * -+ */ -+static void usb_ohci_jz_remove(struct usb_hcd *hcd, struct platform_device *dev) -+{ -+ usb_remove_hcd(hcd); -+ jz_stop_ohc(dev); -+ iounmap(hcd->regs); -+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -+ usb_put_hcd(hcd); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __devinit -+ohci_jz_start (struct usb_hcd *hcd) -+{ -+ struct ohci_hcd *ohci = hcd_to_ohci (hcd); -+ int ret; -+ -+ ohci_dbg (ohci, "ohci_jz_start, ohci:%p", ohci); -+ -+ if ((ret = ohci_init (ohci)) < 0) -+ return ret; -+ -+ if ((ret = ohci_run (ohci)) < 0) { -+ err ("can't start %s", hcd->self.bus_name); -+ ohci_stop (hcd); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static const struct hc_driver ohci_jz_hc_driver = { -+ .description = hcd_name, -+ .product_desc = "JZ OHCI", -+ .hcd_priv_size = sizeof(struct ohci_hcd), -+ -+ /* -+ * generic hardware linkage -+ */ -+ .irq = ohci_irq, -+ .flags = HCD_USB11 | HCD_MEMORY, -+ -+ /* -+ * basic lifecycle operations -+ */ -+ .start = ohci_jz_start, -+ .stop = ohci_stop, -+ .shutdown = ohci_shutdown, -+ -+ /* -+ * managing i/o requests and associated device resources -+ */ -+ .urb_enqueue = ohci_urb_enqueue, -+ .urb_dequeue = ohci_urb_dequeue, -+ .endpoint_disable = ohci_endpoint_disable, -+ -+ /* -+ * scheduling support -+ */ -+ .get_frame_number = ohci_get_frame, -+ -+ /* -+ * root hub support -+ */ -+ .hub_status_data = ohci_hub_status_data, -+ .hub_control = ohci_hub_control, -+ .hub_irq_enable = ohci_rhsc_enable, -+#ifdef CONFIG_PM -+ .bus_suspend = ohci_bus_suspend, -+ .bus_resume = ohci_bus_resume, -+#endif -+ .start_port_reset = ohci_start_port_reset, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int ohci_hcd_jz_drv_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ pr_debug ("In ohci_hcd_jz_drv_probe"); -+ -+ if (usb_disabled()) -+ return -ENODEV; -+ -+ ret = usb_ohci_jz_probe(&ohci_jz_hc_driver, pdev); -+ return ret; -+} -+ -+static int ohci_hcd_jz_drv_remove(struct platform_device *pdev) -+{ -+ struct usb_hcd *hcd = platform_get_drvdata(pdev); -+ -+ usb_ohci_jz_remove(hcd, pdev); -+ return 0; -+} -+ /*TBD*/ -+/*static int ohci_hcd_jz_drv_suspend(struct platform_device *dev) -+{ -+ struct usb_hcd *hcd = platform_get_drvdata(dev); -+ -+ return 0; -+} -+static int ohci_hcd_jz_drv_resume(struct platform_device *dev) -+{ -+ struct usb_hcd *hcd = platform_get_drvdata(dev); -+ -+ return 0; -+} -+*/ -+ -+static struct platform_driver ohci_hcd_jz_driver = { -+ .probe = ohci_hcd_jz_drv_probe, -+ .remove = ohci_hcd_jz_drv_remove, -+ .shutdown = usb_hcd_platform_shutdown, -+ /*.suspend = ohci_hcd_jz_drv_suspend, */ -+ /*.resume = ohci_hcd_jz_drv_resume, */ -+ .driver = { -+ .name = "jz-ohci", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -diff -urN linux-2.6.24.7.old/drivers/video/Kconfig linux-2.6.24.7/drivers/video/Kconfig ---- linux-2.6.24.7.old/drivers/video/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/video/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -201,6 +201,222 @@ - comment "Frame buffer hardware drivers" - depends on FB - -+config FB_JZSOC -+ tristate "JZSOC LCD controller support" -+ depends on FB && JZSOC -+ select FB_CFB_FILLRECT -+ select FB_CFB_COPYAREA -+ select FB_CFB_IMAGEBLIT -+ ---help--- -+ JZSOC LCD Controller and Smart LCD Controller driver support. -+ -+config FB_JZ4740_SLCD -+ tristate "JZ4740 Smart LCD controller support" -+ depends on FB_JZSOC && SOC_JZ4740 -+ default n -+ ---help--- -+ This is the frame buffer device driver for the JZ4740 Smart LCD controller. -+ If select this, please set to . -+ -+choice -+ depends on FB_JZ4740_SLCD -+ prompt "SLCD Panel" -+ default JZ_SLCD_LGDP4551_8BUS -+ -+config JZ_SLCD_LGDP4551 -+ bool "LG LGDP4551 Smart LCD panel" -+ ---help--- -+ Driver for Smart LCD LGDP4551, 8-bit sytem interface, 16BPP. -+ -+config JZ_SLCD_SPFD5420A -+ bool "SPFD5420A Smart LCD panel" -+ ---help--- -+ Driver for Smart LCD SPFD5420A 18-bit sytem interface, 18BPP. -+ -+config JZ_SLCD_TRULY -+ bool "TRULY Smart LCD panel (MAX Pixels 400x240)" -+ ---help--- -+ -+endchoice -+ -+config FB_JZLCD_4730_4740 -+ tristate "JZ4730 JZ4740 LCD controller support" -+ depends on FB_JZSOC && (SOC_JZ4730 || SOC_JZ4740) -+ help -+ This is the frame buffer device driver for the JZ4730 and JZ4740 LCD controller. -+config JZLCD_FRAMEBUFFER_MAX -+ int "Default FrameBuffer num" -+ depends on FB_JZLCD_4730_4740 -+ default "1" -+ ---help--- -+ JZ LCD driver support multi-framebuffers for video applications. -+config JZLCD_FRAMEBUFFER_ROTATE_SUPPORT -+ bool "JZLCD FrameBuffer Rotate Support(For TEST)" -+ depends on FB_JZLCD_4730_4740 -+ default n -+ ---help--- -+ JZ LCD driver framebuffer rotate support. Rotate angle can be 0,90,180,270. -+ Note, this fearture is implemented by software, and will cost a lot of cpu capcity. -+ That is to say, if you select this function, you system will become slowly. -+ Rotate cost cpu about: -+ ratate angle 0'C: 0% cpu -+ ratate angle 90'C: 40% cpu -+ ratate angle 180'C: 20% cpu -+ ratate angle 270'C: 40% cpu -+ -+config JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE -+ int "FrameBuffer default rotate angle" -+ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT -+ default 0 -+ ---help--- -+ JZ LCD driver framebuffer angle value can be: -+ 0: 0'C -+ 1: 90'C -+ 2: 180'C -+ 3: 270'C -+config JZLCD_FRAMEBUFFER_BPP -+ int "FrameBuffer bit per pixel" -+ depends on JZLCD_FRAMEBUFFER_ROTATE_SUPPORT -+ default 32 -+ ---help--- -+ JZ LCD driver framebuffer support 8bpp, 16bpp, 32bpp -+choice -+ depends on FB_JZLCD_4730_4740 -+ prompt "LCD Panel" -+ default JZLCD_SAMSUNG_LTP400WQF01 -+ -+config JZLCD_SHARP_LQ035Q7 -+ bool "SHARP LQ035Q7 TFT panel (240x320)" -+ -+config JZLCD_SAMSUNG_LTS350Q1 -+ bool "SAMSUNG LTS350Q1 TFT panel (240x320)" -+ -+config JZLCD_SAMSUNG_LTV350QVF04 -+ bool "SAMSUNG LTV350QV_F04 TFT panel (320x240)" -+ -+config JZLCD_SAMSUNG_LTP400WQF01 -+ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)" -+ -+config JZLCD_SAMSUNG_LTP400WQF02 -+ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)" -+ -+config JZLCD_AUO_A030FL01_V1 -+ bool "AUO A030FL01_V1 TFT panel (480x272)" -+ -+config JZLCD_TRULY_TFTG320240DTSW -+ bool "TRULY TFTG320240DTSW TFT panel (320x240)" -+ -+config JZLCD_TRULY_TFTG320240DTSW_SERIAL -+ bool "TRULY TFTG320240DTSW TFT panel (320x240)(8bit-serial mode)" -+ -+config JZLCD_TRULY_TFTG240320UTSW_63W_E -+ bool "TRULY TFTG240320UTSW-63W-E TFT panel (240x320,2.5in)" -+ -+config JZLCD_FOXCONN_PT035TN01 -+ bool "FOXCONN PT035TN01 TFT panel (320x240)" -+ -+config JZLCD_INNOLUX_PT035TN01_SERIAL -+ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)" -+ -+config JZLCD_TOSHIBA_LTM084P363 -+ bool "Toshiba LTM084P363 TFT panel (800x600)" -+ -+config JZLCD_HYNIX_HT10X21 -+ bool "Hynix HT10X21_300 TFT panel (1024x768)" -+ -+config JZLCD_INNOLUX_AT080TN42 -+ bool "INNOLUX AT080TN42 TFT panel (800x600)" -+ -+config JZLCD_CSTN_800x600 -+ bool "800x600 colorDSTN panel" -+ -+config JZLCD_CSTN_320x240 -+ bool "320x240 colorSTN panel" -+ -+config JZLCD_MSTN_480x320 -+ bool "480x320 monoSTN panel" -+ -+config JZLCD_MSTN_320x240 -+ bool "320x240 monoSTN panel" -+ -+config JZLCD_MSTN_240x128 -+ bool "240x128 monoSTN panel" -+ -+config JZLCD_MSTN_INVERSE -+ bool "Use an inverse color display." -+ depends on (JZLCD_MSTN_480x320 || JZLCD_MSTN_240x128) -+ -+endchoice -+ -+ -+config FB_JZ4750_TVE -+ tristate -+ depends on FB_JZSOC && SOC_JZ4750 -+ default n -+ -+config IPU_JZ4750 -+ bool "Jz4750 ipu support" -+ depends on FB_JZSOC && SOC_JZ4750 -+ ---help--- -+ Use JZ4750 IPU, if need, please select this. -+ -+config FB_JZ4750_LCD -+ tristate "JZ4750 LCD Controller support" -+ depends on FB_JZSOC && SOC_JZ4750 -+ select FB_JZ4750_TVE -+ ---help--- -+ JZ4750 LCD Controller driver. -+ JZ4750 LCD Controller support OSD function(refer jz4750_lcdc_spec.pdf).JZ4750 LCD OSD implement 2 framebuffer layers: foreground0 and foreground1. JZ4750 LCD driver support only foreground0 default. -+ -+config FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER -+ bool "JZ4750 LCD driver 2 layers framebuffer support." -+ depends on FB_JZ4750_LCD -+ ---help--- -+ JZ4750 LCD driver support only foreground0 by default. -+ If you need both foreground0 and foreground1, please select this. -+ -+config FB_JZ4750_SLCD -+ bool -+ depends on FB_JZ4750_LCD -+ default n -+ -+choice -+ depends on FB_JZ4750_LCD -+ prompt "JZ4750 LCD Panels Support" -+ default JZ4750_LCD_SAMSUNG_LTP400WQF02 -+ ---help--- -+ Please select the lcd panel in you board -+ -+config JZ4750_LCD_SAMSUNG_LTP400WQF01 -+ bool "SAMSUNG LTP400WQF01 TFT panel (480x272)(16bits)" -+ -+config JZ4750_LCD_SAMSUNG_LTP400WQF02 -+ bool "SAMSUNG LTP400WQF02 TFT panel (480x272)(18bits)" -+ -+config JZ4750_LCD_AUO_A043FL01V2 -+ bool "AUO A043FL01V2 TFT panel (480x272)(24bits)" -+ -+config JZ4750_LCD_FOXCONN_PT035TN01 -+ bool "FOXCONN PT035TN01 TFT panel (320x240,3.5in)(18bit-parallel mode)" -+ -+config JZ4750_LCD_INNOLUX_PT035TN01_SERIAL -+ bool "INNOLUX PT035TN01 TFT panel (320x240,3.5in)(8bit-serial mode)" -+ -+config JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA -+ bool "TOPPOLY_TD025THEA7 TFT panel(320x240)(serial RGB delta mode)" -+ -+config JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT -+ bool "TRULY_TFTG320240DTSW TFT panel (320x240) (Parallel 18bit mode)" -+ -+config JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W -+ bool "TRULY_TFT_GG1P0319LTSW_W (240x320) (Smart LCD 16bit)" -+ -+config JZ4750_SLCD_KGM701A3_TFT_SPFD5420A -+ bool "KGM701A3_TFT_SPFD5420A (400x240) (Smart LCD 18bit)" -+ select FB_JZ4750_SLCD -+endchoice -+ -+ - config FB_CIRRUS - tristate "Cirrus Logic support" - depends on FB && (ZORRO || PCI) -diff -urN linux-2.6.24.7.old/drivers/video/Makefile linux-2.6.24.7/drivers/video/Makefile ---- linux-2.6.24.7.old/drivers/video/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/video/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -28,6 +28,10 @@ - obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o - - # Hardware specific drivers go first -+obj-$(CONFIG_FB_JZLCD_4730_4740) += jzlcd.o -+obj-$(CONFIG_FB_JZ4740_SLCD) += jz4740_slcd.o -+obj-$(CONFIG_FB_JZ4750_LCD) += jz4750_lcd.o -+obj-$(CONFIG_FB_JZ4750_TVE) += jz4750_tve.o - obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o - obj-$(CONFIG_FB_ARC) += arcfb.o - obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o -diff -urN linux-2.6.24.7.old/drivers/video/console/Kconfig linux-2.6.24.7/drivers/video/console/Kconfig ---- linux-2.6.24.7.old/drivers/video/console/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/video/console/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -134,6 +134,14 @@ - - If unsure, select n. - -+config FRAMEBUFFER_CONSOLE_CURSOR_FLASH -+ bool "Framebuffer Console Cursor flash" -+ depends on FRAMEBUFFER_CONSOLE -+ help -+ Enable cursor flush for the framebuffer console. This is done -+ in software and may be significantly slower than a normally oriented -+ display. -+ - config FRAMEBUFFER_CONSOLE_ROTATION - bool "Framebuffer Console Rotation" - depends on FRAMEBUFFER_CONSOLE -diff -urN linux-2.6.24.7.old/drivers/video/console/fbcon.c linux-2.6.24.7/drivers/video/console/fbcon.c ---- linux-2.6.24.7.old/drivers/video/console/fbcon.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/video/console/fbcon.c 2009-04-12 18:13:57.000000000 +0200 -@@ -399,6 +399,7 @@ - - static void fb_flashcursor(struct work_struct *work) - { -+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_CURSOR_FLASH - struct fb_info *info = container_of(work, struct fb_info, queue); - struct fbcon_ops *ops = info->fbcon_par; - struct display *p; -@@ -424,6 +425,7 @@ - ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - release_console_sem(); -+#endif - } - - #if defined(CONFIG_ATARI) || defined(CONFIG_MAC) -diff -urN linux-2.6.24.7.old/drivers/video/jz4740_slcd.c linux-2.6.24.7/drivers/video/jz4740_slcd.c ---- linux-2.6.24.7.old/drivers/video/jz4740_slcd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4740_slcd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1334 @@ -+/* -+ * linux/drivers/video/jzslcd.c -- Ingenic On-Chip Smart LCD frame buffer device -+ * -+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "console/fbcon.h" -+ -+#include "jz4740_slcd.h" -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) -+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) -+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) -+#ifdef DEBUG -+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) -+#else -+#define print_dbg(f, arg...) do {} while (0) -+#endif -+ -+static jz_dma_desc slcd_palette_desc __attribute__ ((aligned (16))); -+static jz_dma_desc slcd_frame_desc __attribute__ ((aligned (16))); -+ -+static int dma_chan; -+static dma_addr_t slcd_frame_desc_phys_addr, slcd_palette_desc_phys_addr; -+ -+static unsigned char non_link_desp = 0; -+static unsigned char is_set_reg = 0; -+struct lcd_cfb_info { -+ struct fb_info fb; -+ struct display_switch *dispsw; -+ signed int currcon; -+ int func_use_count; -+ -+ struct { -+ u16 red, green, blue; -+ } palette[NR_PALETTE]; -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+struct slcd_reg_info { -+ unsigned int cmd; -+ unsigned int data; -+}; -+static struct slcd_reg_info reg_buf; -+static struct lcd_cfb_info *jzslcd_info; -+ -+struct jzfb_info { -+ unsigned int cfg; /* panel mode and pin usage etc. */ -+ unsigned int w; -+ unsigned int h; -+ unsigned int bpp; /* bit per pixel */ -+ unsigned int bus; -+ unsigned int pclk; /* pixel clk */ -+ -+}; -+ -+static struct jzfb_info jzfb = { -+#ifdef CONFIG_JZ_SLCD_LGDP4551 -+ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL, -+ 400, 240, 16, 8, 16000000 /*16 bpp, 8 bus*/ -+// 240, 400, 18, 8, 16000000 /*18 bpp, 8 bus*/ -+// 400, 240, 18, 8, 16000000 /*18 bpp, 8 bus*/ -+#endif -+ -+#ifdef CONFIG_JZ_SLCD_SPFD5420A -+ SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_TYPE_PARALLEL, -+ 400, 240, 18, 18, 16000000 /*18 bpp, 18 bus*/ -+#endif -+}; -+ -+ -+static volatile unsigned char *slcd_palette; -+static volatile unsigned char *slcd_frame; -+ -+//extern struct display fb_display[MAX_NR_CONSOLES]; -+static irqreturn_t slcd_dma_irq(int irq, void *dev_id); -+ -+ -+static void Mcupanel_RegSet(UINT32 cmd, UINT32 data) -+{ -+ switch (jzfb.bus) { -+ case 8: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); -+ break; -+ case 9: -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; -+ break; -+ case 16: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); -+ break; -+ case 18: -+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); -+ break; -+ default: -+ printk("Don't support %d bit Bus\n", jzfb.bus ); -+ break; -+ } -+} -+ -+/* Sent a command withou data */ -+static void Mcupanel_Command(UINT32 cmd) { -+ switch (jzfb.bus) { -+ case 8: -+ case 9: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ break; -+ case 16: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); -+ break; -+ case 18: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); -+ break; -+ default: -+ printk("Don't support %d bit Bus\n", jzfb.bus ); -+ break; -+ } -+} -+ -+/* Set the start address of screen, for example (0, 0) */ -+#ifdef CONFIG_JZ_SLCD_LGDP4551 -+static void Mcupanel_SetAddr(UINT16 x, UINT16 y) -+{ -+ Mcupanel_RegSet(0x20,x) ; -+ udelay(1); -+ Mcupanel_RegSet(0x21,y) ; -+ udelay(1); -+ Mcupanel_Command(0x22); -+ -+} -+#endif -+#ifdef CONFIG_JZ_SLCD_SPFD5420A -+void Mcupanel_SetAddr(u32 x, u32 y) //u32 -+{ -+ Mcupanel_RegSet(0x200,x) ; -+ udelay(1); -+ Mcupanel_RegSet(0x201,y) ; -+ udelay(1); -+ Mcupanel_Command(0x202); -+ -+} -+ -+#endif -+ -+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, -+ u_int transp, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned short *ptr, ctmp; -+ -+ print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); -+ if (regno >= NR_PALETTE) -+ return 1; -+ -+ cfb->palette[regno].red = red ; -+ cfb->palette[regno].green = green; -+ cfb->palette[regno].blue = blue; -+ if (cfb->fb.var.bits_per_pixel <= 16) { -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ red &= 0xff; -+ green &= 0xff; -+ blue &= 0xff; -+ } -+ switch (cfb->fb.var.bits_per_pixel) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ /* RGB 565 */ -+ if (((red >> 3) == 0) && ((red >> 2) != 0)) -+ red = 1 << 3; -+ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) -+ blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) -+ | ((green >> 2) << 5) | (blue >> 3); -+ -+ ptr = (unsigned short *)slcd_palette; -+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); -+ ptr[regno] = ctmp; -+ -+ break; -+ -+ case 15: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | -+ ((green >> 3) << 5) | -+ (blue >> 3); -+ break; -+ case 16: -+ if (regno < 16) { -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | -+ ((green >> 2) << 5) | -+ (blue >> 3); -+ } -+ break; -+ case 18: -+ case 24: -+ case 32: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | -+ (green << 8) | -+ (blue << 0); -+ -+/* if (regno < 16) { -+ unsigned val; -+ val = chan_to_field(red, &cfb->fb.var.red); -+ val |= chan_to_field(green, &cfb->fb.var.green); -+ val |= chan_to_field(blue, &cfb->fb.var.blue); -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; -+ } -+*/ -+ -+ break; -+ } -+ return 0; -+} -+ -+static int jzfb_ioctl (struct fb_info *info, unsigned int cmd, unsigned long arg ) -+{ -+ int ret = 0; -+ void __user *argp = (void __user *)arg; -+ -+ switch (cmd) { -+ case FBIOSETBACKLIGHT: -+ __slcd_set_backlight_level(arg); /* We support 8 levels here. */ -+ break; -+ case FBIODISPON: -+ __slcd_display_on(); -+ break; -+ case FBIODISPOFF: -+ __slcd_display_off(); -+ break; -+ case FBIO_REFRESH_ALWAYS: -+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); -+ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK) -+ printk("The Smart LCD refreshes automatically. Option is omitted!\n"); -+ else { -+ dprintk("OPEN DMAC_DCMD_LINK \n"); -+ slcd_frame_desc.dcmd &= ~DMAC_DCMD_TIE; -+ slcd_frame_desc.dcmd |= DMAC_DCMD_LINK; -+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); -+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_TIE; -+ __dmac_channel_set_doorbell(dma_chan); -+ } -+ break; -+ case FBIO_REFRESH_EVENTS: -+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); -+ if (!(slcd_frame_desc.dcmd & DMAC_DCMD_LINK)) -+ printk("The Smart LCD is refreshed by envents. Option is omitted!\n"); -+ else { -+ non_link_desp = 1; -+ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE; -+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; -+ } -+ break; -+ case FBIO_DO_REFRESH: -+ -+ dprintk("slcd_frame_desc.dcmd = 0x%08x\n", slcd_frame_desc.dcmd); -+ if (slcd_frame_desc.dcmd & DMAC_DCMD_LINK) -+ printk("The Smart LCD can refresh automatically. Option is omitted!\n"); -+ else { -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ __dmac_channel_set_doorbell(dma_chan); -+ } -+ break; -+ case FBIO_SET_REG: -+ if (copy_from_user(®_buf, argp, sizeof(reg_buf))) -+ return -EFAULT; -+ is_set_reg = 1; -+ REG_DMAC_DCMD(dma_chan) |= DMAC_DCMD_TIE; -+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ -+static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned long start; -+ unsigned long off; -+ u32 len; -+ -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); -+ -+ /* frame buffer memory */ -+ start = cfb->fb.fix.smem_start; -+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); -+ start &= PAGE_MASK; -+ -+ if ((vma->vm_end - vma->vm_start + off) > len) -+ return -EINVAL; -+ off += start; -+ -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ vma->vm_flags |= VM_IO; -+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ -+ -+#if 1 -+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; -+// pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ -+ pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */ -+#endif -+ -+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+/* checks var and eventually tweaks it to something supported, -+ * DO NOT MODIFY PAR */ -+static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ print_dbg("jzfb_check_var"); -+ return 0; -+} -+ -+ -+/* -+ * set the video mode according to info->var -+ */ -+static int jzfb_set_par(struct fb_info *info) -+{ -+// print_dbg("jzfb_set_par"); -+ printk("jzfb_set_par"); -+ return 0; -+} -+ -+ -+/* -+ * (Un)Blank the display. -+ * Fix me: should we use VESA value? -+ */ -+static int jzfb_blank(int blank_mode, struct fb_info *info) -+{ -+ -+ dprintk("fb_blank %d %p", blank_mode, info); -+ -+ switch (blank_mode) { -+ -+ case FB_BLANK_UNBLANK: -+ /* Turn on panel */ -+ break; -+ -+ case FB_BLANK_NORMAL: -+ case FB_BLANK_VSYNC_SUSPEND: -+ case FB_BLANK_HSYNC_SUSPEND: -+ case FB_BLANK_POWERDOWN: -+ /* Turn off panel */ -+ break; -+ default: -+ break; -+ -+ } -+ return 0; -+} -+ -+/* -+ * pan display -+ */ -+static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ int dy; -+ -+ if (!var || !cfb) { -+ return -EINVAL; -+ } -+ -+ if (var->xoffset - cfb->fb.var.xoffset) { -+ /* No support for X panning for now! */ -+ return -EINVAL; -+ } -+ -+ dy = var->yoffset - cfb->fb.var.yoffset; -+ print_dbg("var.yoffset: %d", dy); -+ if (dy) { -+ -+ print_dbg("Panning screen of %d lines", dy); -+// slcd_frame_desc->databuf += (cfb->fb.fix.line_length * dy); -+// slcd_frame_desc->dsadr += (cfb->fb.fix.line_length * dy); -+ /* TODO: Wait for current frame to finished */ -+ } -+ -+ return 0; -+} -+ -+ -+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ -+static struct fb_ops jzfb_ops = { -+ .owner = THIS_MODULE, -+ .fb_setcolreg = jzfb_setcolreg, -+ .fb_check_var = jzfb_check_var, -+ .fb_set_par = jzfb_set_par, -+ .fb_blank = jzfb_blank, -+ .fb_pan_display = jzfb_pan_display, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+ .fb_mmap = jzfb_mmap, -+ .fb_ioctl = jzfb_ioctl, -+}; -+ -+static int jzfb_set_var(struct fb_var_screeninfo *var, int con, -+ struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ //struct display *display; -+ int chgvar = 0; -+ -+ var->height = jzfb.h ; -+ var->width = jzfb.w ; -+ var->bits_per_pixel = jzfb.bpp; -+ -+ var->vmode = FB_VMODE_NONINTERLACED; -+ var->activate = cfb->fb.var.activate; -+ var->xres = var->width; -+ var->yres = var->height; -+ var->xres_virtual = var->width; -+ var->yres_virtual = var->height; -+ var->xoffset = 0; -+ var->yoffset = 0; -+ var->pixclock = 0; -+ var->left_margin = 0; -+ var->right_margin = 0; -+ var->upper_margin = 0; -+ var->lower_margin = 0; -+ var->hsync_len = 0; -+ var->vsync_len = 0; -+ var->sync = 0; -+ var->activate &= ~FB_ACTIVATE_TEST; -+ -+ /* -+ * CONUPDATE and SMOOTH_XPAN are equal. However, -+ * SMOOTH_XPAN is only used internally by fbcon. -+ */ -+ if (var->vmode & FB_VMODE_CONUPDATE) { -+ var->vmode |= FB_VMODE_YWRAP; -+ var->xoffset = cfb->fb.var.xoffset; -+ var->yoffset = cfb->fb.var.yoffset; -+ } -+ -+ if (var->activate & FB_ACTIVATE_TEST) -+ return 0; -+ -+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) -+ return -EINVAL; -+ -+ if (cfb->fb.var.xres != var->xres) -+ chgvar = 1; -+ if (cfb->fb.var.yres != var->yres) -+ chgvar = 1; -+ if (cfb->fb.var.xres_virtual != var->xres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.yres_virtual != var->yres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) -+ chgvar = 1; -+ -+ //display = fb_display + con; -+ -+ var->red.msb_right = 0; -+ var->green.msb_right = 0; -+ var->blue.msb_right = 0; -+ -+ switch(var->bits_per_pixel){ -+ case 1: /* Mono */ -+ cfb->fb.fix.visual = FB_VISUAL_MONO01; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 2: /* Mono */ -+ var->red.offset = 0; -+ var->red.length = 2; -+ var->green.offset = 0; -+ var->green.length = 2; -+ var->blue.offset = 0; -+ var->blue.length = 2; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 4: /* PSEUDOCOLOUR*/ -+ var->red.offset = 0; -+ var->red.length = 4; -+ var->green.offset = 0; -+ var->green.length = 4; -+ var->blue.offset = 0; -+ var->blue.length = 4; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres / 2; -+ break; -+ case 8: /* PSEUDOCOLOUR, 256 */ -+ var->red.offset = 0; -+ var->red.length = 8; -+ var->green.offset = 0; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres ; -+ break; -+ case 15: /* DIRECTCOLOUR, 32k */ -+ var->bits_per_pixel = 15; -+ var->red.offset = 10; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 5; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 16: /* DIRECTCOLOUR, 64k */ -+ var->bits_per_pixel = 16; -+ var->red.offset = 11; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 6; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 18: -+ case 24: -+ case 32: -+ /* DIRECTCOLOUR, 256 */ -+ var->bits_per_pixel = 32; -+ -+ var->red.offset = 16; -+ var->red.length = 8; -+ var->green.offset = 8; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ var->transp.offset = 24; -+ var->transp.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 4; -+ break; -+ -+ default: /* in theory this should never happen */ -+ printk(KERN_WARNING "%s: don't support for %dbpp\n", -+ cfb->fb.fix.id, var->bits_per_pixel); -+ break; -+ } -+ -+ cfb->fb.var = *var; -+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; -+ -+ /* -+ * If we are setting all the virtual consoles, also set the -+ * defaults used to create new consoles. -+ */ -+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); -+ dprintk("jzfb_set_var: after fb_set_cmap...\n"); -+ -+ return 0; -+} -+ -+static struct lcd_cfb_info * jzfb_alloc_fb_info(void) -+{ -+ struct lcd_cfb_info *cfb; -+ -+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); -+ -+ if (!cfb) -+ return NULL; -+ -+ jzslcd_info = cfb; -+ -+ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); -+ -+ cfb->currcon = -1; -+ -+ -+ strcpy(cfb->fb.fix.id, "jz-slcd"); -+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; -+ cfb->fb.fix.type_aux = 0; -+ cfb->fb.fix.xpanstep = 1; -+ cfb->fb.fix.ypanstep = 1; -+ cfb->fb.fix.ywrapstep = 0; -+ cfb->fb.fix.accel = FB_ACCEL_NONE; -+ -+ cfb->fb.var.nonstd = 0; -+ cfb->fb.var.activate = FB_ACTIVATE_NOW; -+ cfb->fb.var.height = -1; -+ cfb->fb.var.width = -1; -+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; -+ -+ cfb->fb.fbops = &jzfb_ops; -+ cfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ -+ cfb->fb.pseudo_palette = (void *)(cfb + 1); -+ -+ switch (jzfb.bpp) { -+ case 1: -+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); -+ break; -+ case 2: -+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); -+ break; -+ case 4: -+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); -+ break; -+ case 8: -+ -+ default: -+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); -+ break; -+ } -+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); -+ -+ return cfb; -+} -+ -+/* -+ * Map screen memory -+ */ -+static int jzfb_map_smem(struct lcd_cfb_info *cfb) -+{ -+ struct page * map = NULL; -+ unsigned char *tmp; -+ unsigned int page_shift, needroom, t; -+ -+ t = jzfb.bpp; -+ if (jzfb.bpp == 15) -+ t = 16; -+ if (jzfb.bpp == 18 || jzfb.bpp == 24) -+ t = 32; -+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; -+ -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ -+ slcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); -+ slcd_frame = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ if ((!slcd_palette) || (!slcd_frame)) -+ return -ENOMEM; -+ -+ memset((void *)slcd_palette, 0, PAGE_SIZE); -+ memset((void *)slcd_frame, 0, PAGE_SIZE << page_shift); -+ -+ map = virt_to_page(slcd_palette); -+ set_bit(PG_reserved, &map->flags); -+ -+ for (tmp=(unsigned char *)slcd_frame; -+ tmp < slcd_frame + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ set_bit(PG_reserved, &map->flags); -+ } -+ -+ cfb->fb.fix.smem_start = virt_to_phys((void *)slcd_frame); -+ -+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); -+ -+ cfb->fb.screen_base = -+ (unsigned char *)(((unsigned int)slcd_frame & 0x1fffffff) | 0xa0000000); -+ -+ if (!cfb->fb.screen_base) { -+ printk("%s: unable to map screen memory\n", cfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void jzfb_free_fb_info(struct lcd_cfb_info *cfb) -+{ -+ if (cfb) { -+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); -+ kfree(cfb); -+ } -+} -+ -+static void jzfb_unmap_smem(struct lcd_cfb_info *cfb) -+{ -+ struct page * map = NULL; -+ unsigned char *tmp; -+ unsigned int page_shift, needroom, t; -+ -+ t = jzfb.bpp; -+ if (jzfb.bpp == 18 || jzfb.bpp == 24) -+ t = 32; -+ if (jzfb.bpp == 15) -+ t = 16; -+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ -+ if (cfb && cfb->fb.screen_base) { -+ iounmap(cfb->fb.screen_base); -+ cfb->fb.screen_base = NULL; -+ release_mem_region(cfb->fb.fix.smem_start, -+ cfb->fb.fix.smem_len); -+ } -+ -+ if (slcd_palette) { -+ map = virt_to_page(slcd_palette); -+ clear_bit(PG_reserved, &map->flags); -+ free_pages((int)slcd_palette, 0); -+ } -+ -+ if (slcd_frame) { -+ -+ for (tmp=(unsigned char *)slcd_frame; -+ tmp < slcd_frame + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ clear_bit(PG_reserved, &map->flags); -+ } -+ -+ free_pages((int)slcd_frame, page_shift); -+ } -+} -+ -+static void slcd_descriptor_init(void) -+{ -+ int i; -+ int frm_size, pal_size; -+ unsigned int next; -+ unsigned int slcd_frame_src_phys_addr, slcd_palette_src_phys_addr, slcd_dma_dst_phys_addr; -+ -+ i = jzfb.bpp; -+ if (i == 18 || i == 24) -+ i = 32; -+ if (i == 15) -+ i = 16; -+ -+ switch (jzfb.bpp) { -+ case 1: -+ pal_size = 4; -+ break; -+ case 2: -+ pal_size = 8; -+ break; -+ case 4: -+ pal_size = 32; -+ break; -+ case 8: -+ default: -+ pal_size = 512; -+ } -+ -+ frm_size = jzfb.w * jzfb.h * jzfb.bpp / 8; -+ -+ /*Offset of next descriptor*/ -+ slcd_frame_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_frame_desc)); -+ slcd_palette_desc_phys_addr = (dma_addr_t)CPHYSADDR((unsigned long)(&slcd_palette_desc)); -+ -+ /*Soure address and Target address*/ -+ slcd_palette_src_phys_addr = (unsigned int)virt_to_phys(slcd_palette); -+ slcd_frame_src_phys_addr = (unsigned int)virt_to_phys(slcd_frame); -+ slcd_dma_dst_phys_addr = (unsigned int)CPHYSADDR(SLCD_FIFO); -+ next = slcd_frame_desc_phys_addr >> 4; -+ -+ /* Prepare Palette Descriptor */ -+ slcd_palette_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 -+ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V -+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; -+ switch (slcd_palette_desc.dcmd & DMAC_DCMD_DS_MASK) { -+ case DMAC_DCMD_DS_32BYTE: -+ pal_size /= 32; -+ break; -+ case DMAC_DCMD_DS_16BYTE: -+ pal_size /= 16; -+ break; -+ case DMAC_DCMD_DS_32BIT: -+ pal_size /= 4; -+ break; -+ case DMAC_DCMD_DS_16BIT: -+ pal_size /= 2; -+ break; -+ case DMAC_DCMD_DS_8BIT: -+ default: -+ break; -+ } -+ -+ slcd_palette_desc.dsadr = (unsigned int)virt_to_phys(slcd_palette); /* DMA source address */ -+ slcd_palette_desc.dtadr = (unsigned int)CPHYSADDR(SLCD_FIFO); /* DMA target address */ -+ slcd_palette_desc.ddadr = (volatile unsigned int)((next << 24) | (pal_size & 0xffffff)); /* offset and size*/ -+ dma_cache_wback((unsigned long)(&slcd_palette_desc), 16); -+ -+ /*Prepare Frame Descriptor in memory*/ -+ switch (jzfb.bpp) { -+ case 8 ... 16: -+ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 -+ | DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V -+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; -+ break; -+ -+ case 17 ... 32: -+ slcd_frame_desc.dcmd = DMAC_DCMD_SAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 -+ | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V -+ | DMAC_DCMD_DES_VIE | DMAC_DCMD_LINK; -+ break; -+ } -+ switch (slcd_frame_desc.dcmd & DMAC_DCMD_DS_MASK) { -+ case DMAC_DCMD_DS_32BYTE: -+ frm_size /= 32; -+ break; -+ case DMAC_DCMD_DS_16BYTE: -+ frm_size /= 16; -+ break; -+ case DMAC_DCMD_DS_32BIT: -+ frm_size /= 4; -+ break; -+ case DMAC_DCMD_DS_16BIT: -+ frm_size /= 2; -+ break; -+ case DMAC_DCMD_DS_8BIT: -+ default: -+ break; -+ } -+ -+ slcd_frame_desc.dsadr = slcd_frame_src_phys_addr; /* DMA source address */ -+ slcd_frame_desc.dtadr = slcd_dma_dst_phys_addr; /* DMA target address */ -+ slcd_frame_desc.ddadr = (volatile unsigned int)((next << 24) | (frm_size & 0xffffff)); /* offset and size*/ -+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); -+} -+ -+void slcd_hw_init(void) -+{ -+ unsigned int val, pclk; -+ int pll_div; -+ -+ REG_LCD_CFG &= ~LCD_CFG_LCDPIN_MASK; -+ REG_LCD_CFG |= LCD_CFG_LCDPIN_SLCD; -+ -+ if ((jzfb.bpp == 18) | (jzfb.bpp == 24)) -+ jzfb.bpp = 32; -+ -+ /* Configure SLCD module for initialize smart lcd registers*/ -+ switch (jzfb.bus) { -+ case 8: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_8bit(); -+ break; -+ case 9: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_9bit(); -+ break; -+ case 16: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16 -+ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_16bit(); -+ break; -+ case 18: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18 -+ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_18bit(); -+ break; -+ default: -+ printk("Error: Don't support BUS %d!\n", jzfb.bus); -+ break; -+ } -+ -+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; -+ __cpm_stop_lcd(); -+ pclk = jzfb.pclk; -+ pll_div = ( REG_CPM_CPCCR & CPM_CPCCR_PCS ); /* clock source,0:pllout/2 1: pllout */ -+ pll_div = pll_div ? 1 : 2 ; -+ val = ( __cpm_get_pllout()/pll_div ) / pclk; -+ val--; -+ if ( val > 0x1ff ) { -+ printk("CPM_LPCDR too large, set it to 0x1ff\n"); -+ val = 0x1ff; -+ } -+ __cpm_set_pixdiv(val); -+ -+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ -+ -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ printk("SLCDC: PixClock:%d LcdClock:%d\n", -+ jz_clocks.pixclk, jz_clocks.lcdclk); -+ -+ __cpm_start_lcd(); -+ udelay(1000); -+ __slcd_display_pin_init(); -+ __slcd_special_on(); -+ -+ /* Configure SLCD module for transfer data to smart lcd GRAM*/ -+ switch (jzfb.bus) { -+ case 8: -+ switch (jzfb.bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15: -+ case 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 9: -+ switch (jzfb.bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15 ... 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 16: -+ switch (jzfb.bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15 ... 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 18: -+ switch (jzfb.bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15: -+ case 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ default: -+ printk("Error: The BUS %d is not supported\n", jzfb.bus); -+ break; -+ } -+ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG); -+} -+ -+static irqreturn_t slcd_dma_irq(int irq, void *dev_id) -+{ -+ -+ if (__dmac_channel_transmit_halt_detected(dma_chan)) { -+ dprintk("DMA HALT\n"); -+ __dmac_channel_clear_transmit_halt(dma_chan); -+ } -+ -+ if (__dmac_channel_address_error_detected(dma_chan)) { -+ dprintk("DMA ADDR ERROR\n"); -+ __dmac_channel_clear_address_error(dma_chan); -+ } -+ -+ if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { -+ dprintk("DMA DESC INVALID\n"); -+ __dmac_channel_clear_descriptor_invalid(dma_chan); -+ } -+ -+ if (__dmac_channel_count_terminated_detected(dma_chan)) { -+ dprintk("DMA CT\n"); -+ __dmac_channel_clear_count_terminated(dma_chan); -+ if(is_set_reg){ -+ printk("Close DMAC_DCMD_LINK \n"); -+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; -+ } -+ if (non_link_desp) { -+ printk("Close DMAC_DCMD_LINK \n"); -+ /*Set to Non-Link Descriptor*/ -+ REG_DMAC_DCMD(dma_chan) &= ~DMAC_DCMD_LINK; -+ } -+ } -+ -+ if (__dmac_channel_transmit_end_detected(dma_chan)) { -+ printk("DMA TT\n"); -+ __dmac_channel_clear_transmit_end(dma_chan); -+ if (non_link_desp) { -+ slcd_frame_desc.dcmd |= DMAC_DCMD_TIE; -+ slcd_frame_desc.dcmd &= ~DMAC_DCMD_LINK; -+ dma_cache_wback((unsigned long)(&slcd_frame_desc), 16); -+ non_link_desp = 0; -+ } -+ if (is_set_reg) { -+ is_set_reg = 0; -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE; /* disable DMA */ -+ REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ -+ REG_SLCD_CTRL = 0; -+ -+ /* -+ *add operation here -+ */ -+ Mcupanel_RegSet(reg_buf.cmd, reg_buf.data); -+ Mcupanel_Command(0x0022);/*Write Data to GRAM */ -+ mdelay(100); -+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; -+ __dmac_channel_set_doorbell(dma_chan); -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+static int slcd_dma_init(void) -+{ -+ /* Request DMA channel and setup irq handler */ -+ dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", slcd_dma_irq, 0, NULL); -+ if (dma_chan < 0) { -+ printk("Request DMA Failed\n"); -+ return -1; -+ } -+ printk("DMA channel %d is requested by SLCD!\n", dma_chan); -+ -+ /*Init the SLCD DMA and Enable*/ -+ REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_SLCD; -+ REG_DMAC_DMACR = DMAC_DMACR_DMAE; -+ REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /*Descriptor Transfer*/ -+ -+ if (jzfb.bpp <= 8) -+ REG_DMAC_DDA(dma_chan) = slcd_palette_desc_phys_addr; -+ else -+ REG_DMAC_DDA(dma_chan) = slcd_frame_desc_phys_addr; -+ -+ /* DMA doorbell set -- start DMA now ... */ -+ __dmac_channel_set_doorbell(dma_chan); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+/* -+ * Suspend the LCDC. -+ */ -+static int jzfb_suspend(void) -+{ -+ -+ __slcd_close_backlight(); -+ __dmac_disable_channel(dma_chan); -+ __slcd_dma_disable(); /* Quick Disable */ -+ __slcd_special_off(); -+ __cpm_stop_lcd(); -+ return 0; -+} -+ -+/* -+ * Resume the LCDC. -+ */ -+ -+static int jzfb_resume(void) -+{ -+ __cpm_start_lcd(); -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ switch (jzfb.bpp) { -+ case 8: -+ /* DATA 8-bit once*/ -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15: -+ case 16: -+ case 18: -+ case 24: -+ case 32: -+ /* DATA 8-bit twice*/ -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; -+ break; -+ default: -+ REG_SLCD_CFG = SLCD_CFG_DWIDTH_8_x2; -+ break; -+ } -+ __slcd_display_pin_init(); -+ __slcd_special_on(); -+ -+ if (jzfb.bpp == 32) { -+ /* DATA 8-bit three time*/ -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; -+ } -+ __slcd_dma_enable(); -+ udelay(100); -+ __dmac_enable_channel(dma_chan); -+ __dmac_channel_set_doorbell(dma_chan); -+ mdelay(200); -+ __slcd_set_backlight_level(80); -+ return 0; -+} -+ -+/* -+ * Power management hook. Note that we won't be called from IRQ context, -+ * unlike the blank functions above, so we may sleep. -+ */ -+static int jzslcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct lcd_cfb_info *cfb = pm_dev->data; -+ -+ if (!cfb) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jzfb_suspend(); -+ break; -+ -+ case PM_RESUME: -+ ret = jzfb_resume(); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#else -+#define jzfb_suspend NULL -+#define jzfb_resume NULL -+#endif /* CONFIG_PM */ -+static int __init jzslcd_fb_init(void) -+{ -+ -+ struct lcd_cfb_info *cfb; -+ int err = 0; -+ -+ /*the parameters of slcd*/ -+ cfb = jzfb_alloc_fb_info(); -+ if (!cfb) -+ goto failed; -+ -+ err = jzfb_map_smem(cfb); -+ if (err) -+ goto failed; -+ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb); -+ -+ slcd_hw_init(); -+ -+ err = register_framebuffer(&cfb->fb); -+ if (err < 0) { -+ printk("jzslcd_fb_init(): slcd register framebuffer err.\n"); -+ goto failed; -+ } -+ -+ printk("fb%d: %s frame buffer device, using %dK of video memory\n", -+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); -+ -+ slcd_descriptor_init(); -+ err = slcd_dma_init(); -+ if (err != 0) { -+ printk("SLCD Init DMA Fail!\n"); -+ return err; -+ } -+ mdelay(100); -+ __slcd_set_backlight_level(80); -+ -+#ifdef CONFIG_PM -+ /* -+ * Note that the console registers this as well, but we want to -+ * power down the display prior to sleeping. -+ */ -+//struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback); -+ -+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzslcd_pm_callback); -+ if (cfb->pm) -+ cfb->pm->data = cfb; -+ -+#endif -+ return 0; -+ -+failed: -+ jzfb_unmap_smem(cfb); -+ jzfb_free_fb_info(cfb); -+ -+ return err; -+} -+ -+#if 0 -+static int jzfb_remove(struct device *dev) -+{ -+ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); -+ jzfb_unmap_smem(cfb); -+ jzfb_free_fb_info(cfb); -+ return 0; -+} -+#endif -+ -+#if 0 -+static struct device_driver jzfb_driver = { -+ .name = "jz-slcd", -+ .bus = &platform_bus_type, -+ .probe = jzfb_probe, -+ .remove = jzfb_remove, -+ .suspend = jzfb_suspend, -+ .resume = jzfb_resume, -+}; -+#endif -+ -+static void __exit jzslcd_fb_cleanup(void) -+{ -+ //driver_unregister(&jzfb_driver); -+ //jzfb_remove(); -+} -+ -+module_init(jzslcd_fb_init); -+module_exit(jzslcd_fb_cleanup); -+ -+MODULE_DESCRIPTION("JzSOC SLCD Controller driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/video/jz4740_slcd.h linux-2.6.24.7/drivers/video/jz4740_slcd.h ---- linux-2.6.24.7.old/drivers/video/jz4740_slcd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4740_slcd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,376 @@ -+/* -+ * linux/drivers/video/jzslcd.h -- Ingenic On-Chip SLCD frame buffer device -+ * -+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. -+ * -+ * 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 __JZSLCD_H__ -+#define __JZSLCD_H__ -+ -+#define UINT16 unsigned short -+#define UINT32 unsigned int -+ -+#define NR_PALETTE 256 -+/* Jz LCDFB supported I/O controls. */ -+#define FBIOSETBACKLIGHT 0x4688 -+#define FBIODISPON 0x4689 -+#define FBIODISPOFF 0x468a -+#define FBIORESET 0x468b -+#define FBIOPRINT_REG 0x468c -+#define FBIO_REFRESH_ALWAYS 0x468d -+#define FBIO_REFRESH_EVENTS 0x468e -+#define FBIO_DO_REFRESH 0x468f -+#define FBIO_SET_REG 0x4690 -+ -+#ifdef CONFIG_JZ_SLCD_LGDP4551 -+#define PIN_CS_N (32*2+18) /* Chip select :SLCD_WR: GPC18 */ -+#define PIN_RESET_N (32*2+21) /* LCD reset :SLCD_RST: GPC21*/ -+#define PIN_RS_N (32*2+19) -+ -+#define __slcd_special_pin_init() \ -+do { \ -+ __gpio_as_output(PIN_CS_N); \ -+ __gpio_as_output(PIN_RESET_N); \ -+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */\ -+ mdelay(100); \ -+} while(0) -+ -+#define __slcd_special_on() \ -+do { /* RESET# */ \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_clear_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+ Mcupanel_RegSet(0x0015,0x0050); \ -+ Mcupanel_RegSet(0x0011,0x0000); \ -+ Mcupanel_RegSet(0x0010,0x3628); \ -+ Mcupanel_RegSet(0x0012,0x0002); \ -+ Mcupanel_RegSet(0x0013,0x0E47); \ -+ udelay(100); \ -+ Mcupanel_RegSet(0x0012,0x0012); \ -+ udelay(100); \ -+ Mcupanel_RegSet(0x0010,0x3620); \ -+ Mcupanel_RegSet(0x0013,0x2E47); \ -+ udelay(50); \ -+ Mcupanel_RegSet(0x0030,0x0000); \ -+ Mcupanel_RegSet(0x0031,0x0502); \ -+ Mcupanel_RegSet(0x0032,0x0307); \ -+ Mcupanel_RegSet(0x0033,0x0304); \ -+ Mcupanel_RegSet(0x0034,0x0004); \ -+ Mcupanel_RegSet(0x0035,0x0401); \ -+ Mcupanel_RegSet(0x0036,0x0707); \ -+ Mcupanel_RegSet(0x0037,0x0303); \ -+ Mcupanel_RegSet(0x0038,0x1E02); \ -+ Mcupanel_RegSet(0x0039,0x1E02); \ -+ Mcupanel_RegSet(0x0001,0x0000); \ -+ Mcupanel_RegSet(0x0002,0x0300); \ -+ if (jzfb.bpp == 16) \ -+ Mcupanel_RegSet(0x0003,0x10B8); /*8-bit system interface two transfers -+ up:0x10B8 down:0x1088 left:0x1090 right:0x10a0*/ \ -+ else \ -+ if (jzfb.bpp == 32)\ -+ Mcupanel_RegSet(0x0003,0xD0B8);/*8-bit system interface three transfers,666 -+ up:0xD0B8 down:0xD088 left:0xD090 right:0xD0A0*/ \ -+ Mcupanel_RegSet(0x0008,0x0204);\ -+ Mcupanel_RegSet(0x000A,0x0008);\ -+ Mcupanel_RegSet(0x0060,0x3100);\ -+ Mcupanel_RegSet(0x0061,0x0001);\ -+ Mcupanel_RegSet(0x0090,0x0052);\ -+ Mcupanel_RegSet(0x0092,0x000F);\ -+ Mcupanel_RegSet(0x0093,0x0001);\ -+ Mcupanel_RegSet(0x009A,0x0008);\ -+ Mcupanel_RegSet(0x00A3,0x0010);\ -+ Mcupanel_RegSet(0x0050,0x0000);\ -+ Mcupanel_RegSet(0x0051,0x00EF);\ -+ Mcupanel_RegSet(0x0052,0x0000);\ -+ Mcupanel_RegSet(0x0053,0x018F);\ -+ /*===Display_On_Function=== */ \ -+ Mcupanel_RegSet(0x0007,0x0001);\ -+ Mcupanel_RegSet(0x0007,0x0021);\ -+ Mcupanel_RegSet(0x0007,0x0023);\ -+ Mcupanel_RegSet(0x0007,0x0033);\ -+ Mcupanel_RegSet(0x0007,0x0133);\ -+ Mcupanel_Command(0x0022);/*Write Data to GRAM */ \ -+ udelay(1); \ -+ Mcupanel_SetAddr(0,0); \ -+ mdelay(100); \ -+} while (0) -+ -+#define __slcd_special_off() \ -+do { \ -+} while(0) -+#endif /*CONFIG_JZ_SLCD_LGDP4551_xxBUS*/ -+ -+#ifdef CONFIG_JZ_SLCD_SPFD5420A -+ -+ //#define PIN_CS_N (32*2+18) // Chip select //GPC18; -+#define PIN_CS_N (32*2+22) // Chip select //GPC18; -+#define PIN_RESET_N (32*1+18) // LCD reset //GPB18; -+#define PIN_RS_N (32*2+19) // LCD RS //GPC19; -+#define PIN_POWER_N (32*3+0) //Power off //GPD0; -+#define PIN_FMARK_N (32*3+1) //fmark //GPD1; -+ -+#define GAMMA() \ -+do { \ -+ Mcupanel_RegSet(0x0300,0x0101); \ -+ Mcupanel_RegSet(0x0301,0x0b27); \ -+ Mcupanel_RegSet(0x0302,0x132a); \ -+ Mcupanel_RegSet(0x0303,0x2a13); \ -+ Mcupanel_RegSet(0x0304,0x270b); \ -+ Mcupanel_RegSet(0x0305,0x0101); \ -+ Mcupanel_RegSet(0x0306,0x1205); \ -+ Mcupanel_RegSet(0x0307,0x0512); \ -+ Mcupanel_RegSet(0x0308,0x0005); \ -+ Mcupanel_RegSet(0x0309,0x0003); \ -+ Mcupanel_RegSet(0x030a,0x0f04); \ -+ Mcupanel_RegSet(0x030b,0x0f00); \ -+ Mcupanel_RegSet(0x030c,0x000f); \ -+ Mcupanel_RegSet(0x030d,0x040f); \ -+ Mcupanel_RegSet(0x030e,0x0300); \ -+ Mcupanel_RegSet(0x030f,0x0500); \ -+ /*** secorrect gamma2 ***/ \ -+ Mcupanel_RegSet(0x0400,0x3500); \ -+ Mcupanel_RegSet(0x0401,0x0001); \ -+ Mcupanel_RegSet(0x0404,0x0000); \ -+ Mcupanel_RegSet(0x0500,0x0000); \ -+ Mcupanel_RegSet(0x0501,0x0000); \ -+ Mcupanel_RegSet(0x0502,0x0000); \ -+ Mcupanel_RegSet(0x0503,0x0000); \ -+ Mcupanel_RegSet(0x0504,0x0000); \ -+ Mcupanel_RegSet(0x0505,0x0000); \ -+ Mcupanel_RegSet(0x0600,0x0000); \ -+ Mcupanel_RegSet(0x0606,0x0000); \ -+ Mcupanel_RegSet(0x06f0,0x0000); \ -+ Mcupanel_RegSet(0x07f0,0x5420); \ -+ Mcupanel_RegSet(0x07f3,0x288a); \ -+ Mcupanel_RegSet(0x07f4,0x0022); \ -+ Mcupanel_RegSet(0x07f5,0x0001); \ -+ Mcupanel_RegSet(0x07f0,0x0000); \ -+} while(0) -+ -+#define __slcd_special_on() \ -+do { \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_clear_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+ if (jzfb.bus == 18) {\ -+ Mcupanel_RegSet(0x0606,0x0000); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0007,0x0001); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0110,0x0001); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0100,0x17b0); \ -+ Mcupanel_RegSet(0x0101,0x0147); \ -+ Mcupanel_RegSet(0x0102,0x019d); \ -+ Mcupanel_RegSet(0x0103,0x8600); \ -+ Mcupanel_RegSet(0x0281,0x0010); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0102,0x01bd); \ -+ udelay(10); \ -+ /************initial************/\ -+ Mcupanel_RegSet(0x0000,0x0000); \ -+ Mcupanel_RegSet(0x0001,0x0000); \ -+ Mcupanel_RegSet(0x0002,0x0400); \ -+ Mcupanel_RegSet(0x0003,0x1288); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \ -+ Mcupanel_RegSet(0x0006,0x0000); \ -+ Mcupanel_RegSet(0x0008,0x0503); \ -+ Mcupanel_RegSet(0x0009,0x0001); \ -+ Mcupanel_RegSet(0x000b,0x0010); \ -+ Mcupanel_RegSet(0x000c,0x0000); \ -+ Mcupanel_RegSet(0x000f,0x0000); \ -+ Mcupanel_RegSet(0x0007,0x0001); \ -+ Mcupanel_RegSet(0x0010,0x0010); \ -+ Mcupanel_RegSet(0x0011,0x0202); \ -+ Mcupanel_RegSet(0x0012,0x0300); \ -+ Mcupanel_RegSet(0x0020,0x021e); \ -+ Mcupanel_RegSet(0x0021,0x0202); \ -+ Mcupanel_RegSet(0x0022,0x0100); \ -+ Mcupanel_RegSet(0x0090,0x0000); \ -+ Mcupanel_RegSet(0x0092,0x0000); \ -+ Mcupanel_RegSet(0x0100,0x16b0); \ -+ Mcupanel_RegSet(0x0101,0x0147); \ -+ Mcupanel_RegSet(0x0102,0x01bd); \ -+ Mcupanel_RegSet(0x0103,0x2c00); \ -+ Mcupanel_RegSet(0x0107,0x0000); \ -+ Mcupanel_RegSet(0x0110,0x0001); \ -+ Mcupanel_RegSet(0x0210,0x0000); \ -+ Mcupanel_RegSet(0x0211,0x00ef); \ -+ Mcupanel_RegSet(0x0212,0x0000); \ -+ Mcupanel_RegSet(0x0213,0x018f); \ -+ Mcupanel_RegSet(0x0280,0x0000); \ -+ Mcupanel_RegSet(0x0281,0x0001); \ -+ Mcupanel_RegSet(0x0282,0x0000); \ -+ GAMMA(); \ -+ Mcupanel_RegSet(0x0007,0x0173); \ -+ } else { \ -+ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0606, 0x0000); /*i80-i/F Endian Control*/ \ -+ /*===User setting=== */ \ -+ Mcupanel_RegSet(0x0001, 0x0000);/* Driver Output Control-----0x0100 SM(bit10) | 0x400*/ \ -+ Mcupanel_RegSet(0x0002, 0x0100); /*LCD Driving Wave Control 0x0100 */ \ -+ if (jzfb.bpp == 16) \ -+ Mcupanel_RegSet(0x0003, 0x50A8);/*Entry Mode 0x1030*/ \ -+ else /*bpp = 18*/ \ -+ Mcupanel_RegSet(0x0003, 0x1010 | 0xC8); /*Entry Mode 0x1030*/ \ -+ /*#endif */ \ -+ Mcupanel_RegSet(0x0006, 0x0000); /*Outline Sharpening Control*/\ -+ Mcupanel_RegSet(0x0008, 0x0808); /*Sets the number of lines for front/back porch period*/\ -+ Mcupanel_RegSet(0x0009, 0x0001); /*Display Control 3 */\ -+ Mcupanel_RegSet(0x000B, 0x0010); /*Low Power Control*/\ -+ Mcupanel_RegSet(0x000C, 0x0000); /*External Display Interface Control 1 /*0x0001*/\ -+ Mcupanel_RegSet(0x000F, 0x0000); /*External Display Interface Control 2 */\ -+ Mcupanel_RegSet(0x0400, 0xB104);/*Base Image Number of Line---GS(bit15) | 0x8000*/ \ -+ Mcupanel_RegSet(0x0401, 0x0001); /*Base Image Display 0x0001*/\ -+ Mcupanel_RegSet(0x0404, 0x0000); /*Base Image Vertical Scroll Control 0x0000*/\ -+ Mcupanel_RegSet(0x0500, 0x0000); /*Partial Image 1: Display Position*/\ -+ Mcupanel_RegSet(0x0501, 0x0000); /*RAM Address (Start Line Address) */\ -+ Mcupanel_RegSet(0x0502, 0x018f); /*RAM Address (End Line Address) */ \ -+ Mcupanel_RegSet(0x0503, 0x0000); /*Partial Image 2: Display Position RAM Address*/\ -+ Mcupanel_RegSet(0x0504, 0x0000); /*RAM Address (Start Line Address) */\ -+ Mcupanel_RegSet(0x0505, 0x0000); /*RAM Address (End Line Address)*/\ -+ /*Panel interface control===*/\ -+ Mcupanel_RegSet(0x0010, 0x0011); /*Division Ratio,Clocks per Line 14 */\ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0011, 0x0202); /*Division Ratio,Clocks per Line*/\ -+ Mcupanel_RegSet(0x0012, 0x0300); /*Sets low power VCOM drive period. */\ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0020, 0x021e); /*Panel Interface Control 4 */\ -+ Mcupanel_RegSet(0x0021, 0x0202); /*Panel Interface Control 5 */\ -+ Mcupanel_RegSet(0x0022, 0x0100); /*Panel Interface Control 6*/\ -+ Mcupanel_RegSet(0x0090, 0x0000); /*Frame Marker Control */\ -+ Mcupanel_RegSet(0x0092, 0x0000); /*MDDI Sub-display Control */\ -+ /*===Gamma setting=== */\ -+ Mcupanel_RegSet(0x0300, 0x0101); /*γ Control*/\ -+ Mcupanel_RegSet(0x0301, 0x0000); /*γ Control*/\ -+ Mcupanel_RegSet(0x0302, 0x0016); /*γ Control*/\ -+ Mcupanel_RegSet(0x0303, 0x2913); /*γ Control*/\ -+ Mcupanel_RegSet(0x0304, 0x260B); /*γ Control*/\ -+ Mcupanel_RegSet(0x0305, 0x0101); /*γ Control*/\ -+ Mcupanel_RegSet(0x0306, 0x1204); /*γ Control*/\ -+ Mcupanel_RegSet(0x0307, 0x0415); /*γ Control*/\ -+ Mcupanel_RegSet(0x0308, 0x0205); /*γ Control*/\ -+ Mcupanel_RegSet(0x0309, 0x0303); /*γ Control*/\ -+ Mcupanel_RegSet(0x030a, 0x0E05); /*γ Control*/\ -+ Mcupanel_RegSet(0x030b, 0x0D01); /*γ Control*/\ -+ Mcupanel_RegSet(0x030c, 0x010D); /*γ Control*/\ -+ Mcupanel_RegSet(0x030d, 0x050E); /*γ Control*/\ -+ Mcupanel_RegSet(0x030e, 0x0303); /*γ Control*/\ -+ Mcupanel_RegSet(0x030f, 0x0502); /*γ Control*/\ -+ /*===Power on sequence===*/\ -+ Mcupanel_RegSet(0x0007, 0x0001); /*Display Control 1*/\ -+ Mcupanel_RegSet(0x0110, 0x0001); /*Power supply startup enable bit*/\ -+ Mcupanel_RegSet(0x0112, 0x0060); /*Power Control 7*/\ -+ Mcupanel_RegSet(0x0100, 0x16B0); /*Power Control 1 */\ -+ Mcupanel_RegSet(0x0101, 0x0115); /*Power Control 2*/\ -+ Mcupanel_RegSet(0x0102, 0x0119); /*Starts VLOUT3,Sets the VREG1OUT.*/\ -+ mdelay(50); \ -+ Mcupanel_RegSet(0x0103, 0x2E00); /*set the amplitude of VCOM*/\ -+ mdelay(50);\ -+ Mcupanel_RegSet(0x0282, 0x0093);/*0x008E);/*0x0093); /*VCOMH voltage*/\ -+ Mcupanel_RegSet(0x0281, 0x000A); /*Selects the factor of VREG1OUT to generate VCOMH. */\ -+ Mcupanel_RegSet(0x0102, 0x01BE); /*Starts VLOUT3,Sets the VREG1OUT.*/\ -+ mdelay(10);\ -+ /*Address */\ -+ Mcupanel_RegSet(0x0210, 0x0000); /*Window Horizontal RAM Address Start*/\ -+ Mcupanel_RegSet(0x0211, 0x00ef); /*Window Horizontal RAM Address End*/\ -+ Mcupanel_RegSet(0x0212, 0x0000); /*Window Vertical RAM Address Start*/\ -+ Mcupanel_RegSet(0x0213, 0x018f); /*Window Vertical RAM Address End */\ -+ Mcupanel_RegSet(0x0200, 0x0000); /*RAM Address Set (Horizontal Address)*/\ -+ Mcupanel_RegSet(0x0201, 0x018f); /*RAM Address Set (Vertical Address)*/ \ -+ /*===Display_On_Function===*/\ -+ Mcupanel_RegSet(0x0007, 0x0021); /*Display Control 1 */\ -+ mdelay(50); /*40*/\ -+ Mcupanel_RegSet(0x0007, 0x0061); /*Display Control 1 */\ -+ mdelay(50); /*100*/\ -+ Mcupanel_RegSet(0x0007, 0x0173); /*Display Control 1 */\ -+ mdelay(50); /*300*/\ -+ }\ -+ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \ -+ udelay(10);\ -+ Mcupanel_SetAddr(0,0);\ -+ udelay(100);\ -+} while(0) -+ -+#define __slcd_special_pin_init() \ -+do { \ -+ __gpio_as_output(PIN_CS_N); \ -+ __gpio_as_output(PIN_RESET_N); \ -+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \ -+ __gpio_as_output(PIN_POWER_N); \ -+ mdelay(100); \ -+} while(0) -+ -+#endif /*CONFIG_JZ_SLCD_SPFD5420A*/ -+ -+#ifndef __slcd_special_pin_init -+#define __slcd_special_pin_init() -+#endif -+#ifndef __slcd_special_on -+#define __slcd_special_on() -+#endif -+#ifndef __slcd_special_off -+#define __slcd_special_off() -+#endif -+ -+/* -+ * Platform specific definition -+ */ -+#if defined(CONFIG_SOC_JZ4740) -+#if defined(CONFIG_JZ4740_PAVO) -+#define GPIO_PWM 123 /* GP_D27 */ -+#define PWM_CHN 4 /* pwm channel */ -+#define PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+#define __slcd_set_backlight_level(n)\ -+do { \ -+ __gpio_as_output(32*3+27); \ -+ __gpio_set_pin(32*3+27); \ -+} while (0) -+ -+#define __slcd_close_backlight() \ -+do { \ -+ __gpio_as_output(GPIO_PWM); \ -+ __gpio_clear_pin(GPIO_PWM); \ -+} while (0) -+ -+#else -+ -+#define __slcd_set_backlight_level(n) -+#define __slcd_close_backlight() -+ -+#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */ -+ -+#define __slcd_display_pin_init() \ -+do { \ -+ __slcd_special_pin_init(); \ -+} while (0) -+ -+#define __slcd_display_on() \ -+do { \ -+ __slcd_special_on(); \ -+ __slcd_set_backlight_level(80); \ -+} while (0) -+ -+#define __slcd_display_off() \ -+do { \ -+ __slcd_special_off(); \ -+ __slcd_close_backlight(); \ -+} while (0) -+ -+#endif /* CONFIG_SOC_JZ4740 */ -+#endif /*__JZSLCD_H__*/ -+ -diff -urN linux-2.6.24.7.old/drivers/video/jz4750_lcd.c linux-2.6.24.7/drivers/video/jz4750_lcd.c ---- linux-2.6.24.7.old/drivers/video/jz4750_lcd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4750_lcd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2139 @@ -+/* -+ * linux/drivers/video/jz4750_lcd.c -- Ingenic Jz4750 LCD frame buffer device -+ * -+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. -+ * -+ * 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. -+ * -+ * 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. -+ */ -+ -+/* -+ * -------------------------------- -+ * NOTE: -+ * This LCD driver support TFT16 TFT32 LCD, not support STN and Special TFT LCD -+ * now. -+ * It seems not necessory to support STN and Special TFT. -+ * If it's necessary, update this driver in the future. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "console/fbcon.h" -+ -+#include "jz4750_lcd.h" -+#include "jz4750_tve.h" -+ -+#ifdef CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A -+#include "jz_kgm_spfd5420a.h" -+#endif -+ -+MODULE_DESCRIPTION("Jz4750 LCD Controller driver"); -+MODULE_AUTHOR("Wolfgang Wang, "); -+MODULE_LICENSE("GPL"); -+ -+ -+//#define DEBUG -+#undef DEBUG -+ -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) -+#else -+#define dprintk(x...) -+#define print_dbg(f, arg...) do {} while (0) -+#endif -+ -+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) -+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) -+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) -+ -+struct lcd_cfb_info { -+ struct fb_info fb; -+ struct display_switch *dispsw; -+ signed int currcon; -+ int func_use_count; -+ -+ struct { -+ u16 red, green, blue; -+ } palette[NR_PALETTE]; -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+static struct lcd_cfb_info *jz4750fb_info; -+static struct jz4750_lcd_dma_desc *dma_desc_base; -+static struct jz4750_lcd_dma_desc *dma0_desc_palette, *dma0_desc0, *dma0_desc1, *dma1_desc0, *dma1_desc1; -+#define DMA_DESC_NUM 6 -+ -+static unsigned char *lcd_palette; -+static unsigned char *lcd_frame0; -+static unsigned char *lcd_frame1; -+ -+static struct jz4750_lcd_dma_desc *dma0_desc_cmd0, *dma0_desc_cmd; -+static unsigned char *lcd_cmdbuf ; -+ -+static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info ); -+static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ); -+ -+ -+ -+struct jz4750lcd_info jz4750_lcd_panel = { -+#if defined(CONFIG_JZ4750_LCD_SAMSUNG_LTP400WQF02) -+ .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ -+ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ -+ LCD_CFG_HSP | /* Hsync polarity: active low */ -+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ -+ .slcd_cfg = 0, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 480, 272, 60, 41, 10, 2, 2, 2, 2, -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ -+ }, -+#elif defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2) -+ .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ -+ LCD_CFG_MODE_TFT_24BIT | /* output 18bpp */ -+ LCD_CFG_HSP | /* Hsync polarity: active low */ -+ LCD_CFG_VSP, /* Vsync polarity: leading edge is falling edge */ -+ .slcd_cfg = 0, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 480, 272, 60, 41, 10, 8, 4, 4, 2, -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+// LCD_OSDC_F1EN | /* enable Foreground1 */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 480, 272}, /* bpp, x, y, w, h */ -+ }, -+#elif defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) -+ .panel = { -+// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ -+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ -+ .slcd_cfg = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 240, 320, 60, 0, 0, 0, 0, 0, 0, -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+// LCD_OSDC_F1EN | /* enable Foreground0 */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 240, 320}, /* bpp, x, y, w, h */ -+ }, -+ -+#elif defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) -+ .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_GENERIC_TFT | /* General TFT panel */ -+// LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ -+ LCD_CFG_MODE_TFT_24BIT | /* output 24bpp */ -+ LCD_CFG_HSP | /* Hsync polarity: active low */ -+ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */ -+ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */ -+ .slcd_cfg = 0, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 320, 240, 80, 1, 1, 10, 50, 10, 13 -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+// LCD_OSDC_F1EN | /* enable Foreground1 */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ -+ }, -+#elif defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) -+ .panel = { -+ .cfg = LCD_CFG_LCDPIN_LCD | LCD_CFG_RECOVER | /* Underrun recover */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_SERIAL_TFT | /* Serial TFT panel */ -+ LCD_CFG_MODE_TFT_18BIT | /* output 18bpp */ -+ LCD_CFG_HSP | /* Hsync polarity: active low */ -+ LCD_CFG_VSP | /* Vsync polarity: leading edge is falling edge */ -+ LCD_CFG_PCP, /* Pix-CLK polarity: data translations at falling edge */ -+ .slcd_cfg = 0, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 320, 240, 60, 1, 1, 10, 50, 10, 13 -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 320, 240}, /* bpp, x, y, w, h */ -+ }, -+#elif defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A) -+ .panel = { -+// .cfg = LCD_CFG_LCDPIN_SLCD | LCD_CFG_RECOVER | /* Underrun recover*/ -+ .cfg = LCD_CFG_LCDPIN_SLCD | /* Underrun recover*/ -+// LCD_CFG_DITHER | /* dither */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_MODE_SLCD, /* TFT Smart LCD panel */ -+ .slcd_cfg = SLCD_CFG_DWIDTH_18BIT | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL, -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst, enable out FIFO underrun irq */ -+ 400, 240, 60, 0, 0, 0, 0, 0, 0, -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+// LCD_OSDC_ALPHAMD | /* alpha blending mode */ -+// LCD_OSDC_F1EN | /* enable Foreground1 */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = 0, -+ .bgcolor = 0x000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80001000, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */ -+ .fg1 = {32, 0, 0, 400, 240}, /* bpp, x, y, w, h */ -+ }, -+#else -+#error "Select LCD panel first!!!" -+#endif -+}; -+ -+struct jz4750lcd_info jz4750_info_tve = { -+ .panel = { -+ .cfg = LCD_CFG_TVEN | /* output to tve */ -+ LCD_CFG_NEWDES | /* 8words descriptor */ -+ LCD_CFG_RECOVER | /* underrun protect */ -+ LCD_CFG_MODE_INTER_CCIR656, /* Interlace CCIR656 mode */ -+ .ctrl = LCD_CTRL_OFUM | LCD_CTRL_BST_16, /* 16words burst */ -+ TVE_WIDTH_PAL, TVE_HEIGHT_PAL, TVE_FREQ_PAL, 0, 0, 0, 0, 0, 0, -+ }, -+ .osd = { -+ .osd_cfg = LCD_OSDC_OSDEN | /* Use OSD mode */ -+// LCD_OSDC_ALPHAEN | /* enable alpha */ -+ LCD_OSDC_F0EN, /* enable Foreground0 */ -+ .osd_ctrl = 0, /* disable ipu, */ -+ .rgb_ctrl = LCD_RGBC_YCC, /* enable RGB => YUV */ -+ .bgcolor = 0x00000000, /* set background color Black */ -+ .colorkey0 = 0, /* disable colorkey */ -+ .colorkey1 = 0, /* disable colorkey */ -+ .alpha = 0xA0, /* alpha value */ -+ .ipu_restart = 0x80000100, /* ipu restart */ -+ .fg_change = FG_CHANGE_ALL, /* change all initially */ -+ .fg0 = {32,}, /* */ -+ .fg0 = {32,}, -+ }, -+}; -+ -+ -+struct jz4750lcd_info *jz4750_lcd_info = &jz4750_lcd_panel; /* default output to lcd panel */ -+ -+#ifdef DEBUG -+static void print_lcdc_registers(void) /* debug */ -+{ -+ /* LCD Controller Resgisters */ -+ printk("REG_LCD_CFG:\t0x%08x\n", REG_LCD_CFG); -+ printk("REG_LCD_CTRL:\t0x%08x\n", REG_LCD_CTRL); -+ printk("REG_LCD_STATE:\t0x%08x\n", REG_LCD_STATE); -+ printk("REG_LCD_OSDC:\t0x%08x\n", REG_LCD_OSDC); -+ printk("REG_LCD_OSDCTRL:\t0x%08x\n", REG_LCD_OSDCTRL); -+ printk("REG_LCD_OSDS:\t0x%08x\n", REG_LCD_OSDS); -+ printk("REG_LCD_BGC:\t0x%08x\n", REG_LCD_BGC); -+ printk("REG_LCD_KEK0:\t0x%08x\n", REG_LCD_KEY0); -+ printk("REG_LCD_KEY1:\t0x%08x\n", REG_LCD_KEY1); -+ printk("REG_LCD_ALPHA:\t0x%08x\n", REG_LCD_ALPHA); -+ printk("REG_LCD_IPUR:\t0x%08x\n", REG_LCD_IPUR); -+ printk("REG_LCD_VAT:\t0x%08x\n", REG_LCD_VAT); -+ printk("REG_LCD_DAH:\t0x%08x\n", REG_LCD_DAH); -+ printk("REG_LCD_DAV:\t0x%08x\n", REG_LCD_DAV); -+ printk("REG_LCD_XYP0:\t0x%08x\n", REG_LCD_XYP0); -+ printk("REG_LCD_XYP1:\t0x%08x\n", REG_LCD_XYP1); -+ printk("REG_LCD_SIZE0:\t0x%08x\n", REG_LCD_SIZE0); -+ printk("REG_LCD_SIZE1:\t0x%08x\n", REG_LCD_SIZE1); -+ printk("REG_LCD_RGBC\t0x%08x\n", REG_LCD_RGBC); -+ printk("REG_LCD_VSYNC:\t0x%08x\n", REG_LCD_VSYNC); -+ printk("REG_LCD_HSYNC:\t0x%08x\n", REG_LCD_HSYNC); -+ printk("REG_LCD_PS:\t0x%08x\n", REG_LCD_PS); -+ printk("REG_LCD_CLS:\t0x%08x\n", REG_LCD_CLS); -+ printk("REG_LCD_SPL:\t0x%08x\n", REG_LCD_SPL); -+ printk("REG_LCD_REV:\t0x%08x\n", REG_LCD_REV); -+ printk("REG_LCD_IID:\t0x%08x\n", REG_LCD_IID); -+ printk("REG_LCD_DA0:\t0x%08x\n", REG_LCD_DA0); -+ printk("REG_LCD_SA0:\t0x%08x\n", REG_LCD_SA0); -+ printk("REG_LCD_FID0:\t0x%08x\n", REG_LCD_FID0); -+ printk("REG_LCD_CMD0:\t0x%08x\n", REG_LCD_CMD0); -+ printk("REG_LCD_OFFS0:\t0x%08x\n", REG_LCD_OFFS0); -+ printk("REG_LCD_PW0:\t0x%08x\n", REG_LCD_PW0); -+ printk("REG_LCD_CNUM0:\t0x%08x\n", REG_LCD_CNUM0); -+ printk("REG_LCD_DESSIZE0:\t0x%08x\n", REG_LCD_DESSIZE0); -+ printk("REG_LCD_DA1:\t0x%08x\n", REG_LCD_DA1); -+ printk("REG_LCD_SA1:\t0x%08x\n", REG_LCD_SA1); -+ printk("REG_LCD_FID1:\t0x%08x\n", REG_LCD_FID1); -+ printk("REG_LCD_CMD1:\t0x%08x\n", REG_LCD_CMD1); -+ printk("REG_LCD_OFFS1:\t0x%08x\n", REG_LCD_OFFS1); -+ printk("REG_LCD_PW1:\t0x%08x\n", REG_LCD_PW1); -+ printk("REG_LCD_CNUM1:\t0x%08x\n", REG_LCD_CNUM1); -+ printk("REG_LCD_DESSIZE1:\t0x%08x\n", REG_LCD_DESSIZE1); -+ printk("==================================\n"); -+ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff); -+ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff); -+ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff); -+ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff); -+ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff); -+ printk("==================================\n"); -+ -+ /* Smart LCD Controller Resgisters */ -+ printk("REG_SLCD_CFG:\t0x%08x\n", REG_SLCD_CFG); -+ printk("REG_SLCD_CTRL:\t0x%08x\n", REG_SLCD_CTRL); -+ printk("REG_SLCD_STATE:\t0x%08x\n", REG_SLCD_STATE); -+ printk("==================================\n"); -+ -+ /* TVE Controller Resgisters */ -+ printk("REG_TVE_CTRL:\t0x%08x\n", REG_TVE_CTRL); -+ printk("REG_TVE_FRCFG:\t0x%08x\n", REG_TVE_FRCFG); -+ printk("REG_TVE_SLCFG1:\t0x%08x\n", REG_TVE_SLCFG1); -+ printk("REG_TVE_SLCFG2:\t0x%08x\n", REG_TVE_SLCFG2); -+ printk("REG_TVE_SLCFG3:\t0x%08x\n", REG_TVE_SLCFG3); -+ printk("REG_TVE_LTCFG1:\t0x%08x\n", REG_TVE_LTCFG1); -+ printk("REG_TVE_LTCFG2:\t0x%08x\n", REG_TVE_LTCFG2); -+ printk("REG_TVE_CFREQ:\t0x%08x\n", REG_TVE_CFREQ); -+ printk("REG_TVE_CPHASE:\t0x%08x\n", REG_TVE_CPHASE); -+ printk("REG_TVE_CBCRCFG:\t0x%08x\n", REG_TVE_CBCRCFG); -+ printk("REG_TVE_WSSCR:\t0x%08x\n", REG_TVE_WSSCR); -+ printk("REG_TVE_WSSCFG1:\t0x%08x\n", REG_TVE_WSSCFG1); -+ printk("REG_TVE_WSSCFG2:\t0x%08x\n", REG_TVE_WSSCFG2); -+ printk("REG_TVE_WSSCFG3:\t0x%08x\n", REG_TVE_WSSCFG3); -+ -+ printk("==================================\n"); -+ -+ if ( 1 ) { -+ unsigned int * pii = (unsigned int *)dma_desc_base; -+ int i, j; -+ for (j=0;j< DMA_DESC_NUM ; j++) { -+ printk("dma_desc%d(0x%08x):\n", j, (unsigned int)pii); -+ for (i =0; i<8; i++ ) { -+ printk("\t\t0x%08x\n", *pii++); -+ } -+ } -+ } -+} -+#else -+#define print_lcdc_registers() -+#endif -+ -+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int jz4750fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, -+ u_int transp, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned short *ptr, ctmp; -+ -+// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); -+ if (regno >= NR_PALETTE) -+ return 1; -+ -+ cfb->palette[regno].red = red ; -+ cfb->palette[regno].green = green; -+ cfb->palette[regno].blue = blue; -+ if (cfb->fb.var.bits_per_pixel <= 16) { -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ red &= 0xff; -+ green &= 0xff; -+ blue &= 0xff; -+ } -+ switch (cfb->fb.var.bits_per_pixel) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ if (((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_SINGLE_MSTN ) || -+ ((jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) == LCD_CFG_MODE_DUAL_MSTN )) { -+ ctmp = (77L * red + 150L * green + 29L * blue) >> 8; -+ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) | -+ (ctmp >> 3); -+ } else { -+ /* RGB 565 */ -+ if (((red >> 3) == 0) && ((red >> 2) != 0)) -+ red = 1 << 3; -+ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) -+ blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) -+ | ((green >> 2) << 5) | (blue >> 3); -+ } -+ -+ ptr = (unsigned short *)lcd_palette; -+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); -+ ptr[regno] = ctmp; -+ -+ break; -+ -+ case 15: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | -+ ((green >> 3) << 5) | -+ (blue >> 3); -+ break; -+ case 16: -+ if (regno < 16) { -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | -+ ((green >> 2) << 5) | -+ (blue >> 3); -+ } -+ break; -+ case 17 ... 32: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | -+ (green << 8) | -+ (blue << 0); -+ -+/* if (regno < 16) { -+ unsigned val; -+ val = chan_to_field(red, &cfb->fb.var.red); -+ val |= chan_to_field(green, &cfb->fb.var.green); -+ val |= chan_to_field(blue, &cfb->fb.var.blue); -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; -+ } -+*/ -+ -+ break; -+ } -+ return 0; -+} -+ -+ -+/* -+ * switch to tve mode from lcd mode -+ * mode: -+ * PANEL_MODE_TVE_PAL: switch to TVE_PAL mode -+ * PANEL_MODE_TVE_NTSC: switch to TVE_NTSC mode -+ */ -+static void jz4750lcd_info_switch_to_TVE(int mode) -+{ -+ struct jz4750lcd_info *info; -+ struct jz4750lcd_osd_t *osd_lcd; -+ int x, y, w, h; -+ -+ info = jz4750_lcd_info = &jz4750_info_tve; -+ osd_lcd = &jz4750_lcd_panel.osd; -+ -+ switch ( mode ) { -+ case PANEL_MODE_TVE_PAL: -+ info->panel.cfg |= LCD_CFG_TVEPEH; /* TVE PAL enable extra halfline signal */ -+ info->panel.w = TVE_WIDTH_PAL; -+ info->panel.h = TVE_HEIGHT_PAL; -+ info->panel.fclk = TVE_FREQ_PAL; -+ w = ( osd_lcd->fg0.w < TVE_WIDTH_PAL )? osd_lcd->fg0.w:TVE_WIDTH_PAL; -+ h = ( osd_lcd->fg0.h < TVE_HEIGHT_PAL )?osd_lcd->fg0.h:TVE_HEIGHT_PAL; -+ x = (TVE_WIDTH_PAL-w)/2; -+ y = (TVE_HEIGHT_PAL-h)/2; -+ info->osd.fg0.bpp = osd_lcd->fg0.bpp; -+ info->osd.fg0.x = x; -+ info->osd.fg0.y = y; -+ info->osd.fg0.w = w; -+ info->osd.fg0.h = h; -+ w = ( osd_lcd->fg1.w < TVE_WIDTH_PAL )? osd_lcd->fg1.w:TVE_WIDTH_PAL; -+ h = ( osd_lcd->fg1.h < TVE_HEIGHT_PAL )?osd_lcd->fg1.h:TVE_HEIGHT_PAL; -+ x = (TVE_WIDTH_PAL-w)/2; -+ y = (TVE_HEIGHT_PAL-h)/2; -+ info->osd.fg1.bpp = 32; /* use RGB888 in TVE mode*/ -+ info->osd.fg1.x = x; -+ info->osd.fg1.y = y; -+ info->osd.fg1.w = w; -+ info->osd.fg1.h = h; -+ break; -+ case PANEL_MODE_TVE_NTSC: -+ info->panel.cfg &= ~LCD_CFG_TVEPEH; /* TVE NTSC disable extra halfline signal */ -+ info->panel.w = TVE_WIDTH_NTSC; -+ info->panel.h = TVE_HEIGHT_NTSC; -+ info->panel.fclk = TVE_FREQ_NTSC; -+ w = ( osd_lcd->fg0.w < TVE_WIDTH_NTSC )? osd_lcd->fg0.w:TVE_WIDTH_NTSC; -+ h = ( osd_lcd->fg0.h < TVE_HEIGHT_NTSC)?osd_lcd->fg0.h:TVE_HEIGHT_NTSC; -+ x = (TVE_WIDTH_NTSC - w)/2; -+ y = (TVE_HEIGHT_NTSC - h)/2; -+ info->osd.fg0.bpp = osd_lcd->fg0.bpp; -+ info->osd.fg0.x = x; -+ info->osd.fg0.y = y; -+ info->osd.fg0.w = w; -+ info->osd.fg0.h = h; -+ w = ( osd_lcd->fg1.w < TVE_WIDTH_NTSC )? osd_lcd->fg1.w:TVE_WIDTH_NTSC; -+ h = ( osd_lcd->fg1.h < TVE_HEIGHT_NTSC)?osd_lcd->fg1.h:TVE_HEIGHT_NTSC; -+ x = (TVE_WIDTH_NTSC - w)/2; -+ y = (TVE_HEIGHT_NTSC - h)/2; -+ info->osd.fg1.bpp = 32; /* use RGB888 int TVE mode */ -+ info->osd.fg1.x = x; -+ info->osd.fg1.y = y; -+ info->osd.fg1.w = w; -+ info->osd.fg1.h = h; -+ break; -+ default: -+ printk("%s, %s: Unknown tve mode\n", __FILE__, __FUNCTION__); -+ } -+} -+ -+static int jz4750fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ -+ void __user *argp = (void __user *)arg; -+ -+// struct jz4750lcd_info *lcd_info = jz4750_lcd_info; -+ -+ -+ switch (cmd) { -+ case FBIOSETBACKLIGHT: -+ __lcd_set_backlight_level(arg); /* We support 8 levels here. */ -+ break; -+ case FBIODISPON: -+ REG_LCD_STATE = 0; /* clear lcdc status */ -+ __lcd_slcd_special_on(); -+ __lcd_clr_dis(); -+ __lcd_set_ena(); /* enable lcdc */ -+ __lcd_display_on(); -+ break; -+ case FBIODISPOFF: -+ __lcd_display_off(); -+ if ( jz4750_lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD || -+ jz4750_lcd_info->panel.cfg & LCD_CFG_TVEN ) /* */ -+ __lcd_clr_ena(); /* Smart lcd and TVE mode only support quick disable */ -+ else -+ __lcd_set_dis(); /* regular disable */ -+ break; -+ case FBIOPRINT_REG: -+ print_lcdc_registers(); -+ break; -+ case FBIO_GET_MODE: -+ print_dbg("fbio get mode\n"); -+ if (copy_to_user(argp, jz4750_lcd_info, sizeof(struct jz4750lcd_info))) -+ return -EFAULT; -+ break; -+ case FBIO_SET_MODE: -+ print_dbg("fbio set mode\n"); -+ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info))) -+ return -EFAULT; -+ /* set mode */ -+ jz4750fb_set_mode(jz4750_lcd_info); -+ break; -+ case FBIO_DEEP_SET_MODE: -+ print_dbg("fbio deep set mode\n"); -+ if (copy_from_user(jz4750_lcd_info, argp, sizeof(struct jz4750lcd_info))) -+ return -EFAULT; -+ jz4750fb_deep_set_mode(jz4750_lcd_info); -+ break; -+ case FBIO_MODE_SWITCH: -+ print_dbg("lcd mode switch between tve and lcd, arg=%lu\n", arg); -+ switch ( arg ) { -+ case PANEL_MODE_TVE_PAL: /* switch to TVE_PAL mode */ -+ case PANEL_MODE_TVE_NTSC: /* switch to TVE_NTSC mode */ -+ jz4750lcd_info_switch_to_TVE(arg); -+ jz4750tve_init(arg); /* tve controller init */ -+ jz4750tve_enable_tve(); -+ /* turn off lcd backlight */ -+ __lcd_display_off(); -+ break; -+ case PANEL_MODE_LCD_PANEL: /* switch to LCD mode */ -+ default : -+ /* turn off TVE, turn off DACn... */ -+ jz4750tve_disable_tve(); -+ jz4750_lcd_info = &jz4750_lcd_panel; -+ /* turn on lcd backlight */ -+ __lcd_display_on(); -+ break; -+ } -+ jz4750fb_deep_set_mode(jz4750_lcd_info); -+ break; -+ case FBIO_GET_TVE_MODE: -+ print_dbg("fbio get TVE mode\n"); -+ if (copy_to_user(argp, jz4750_tve_info, sizeof(struct jz4750tve_info))) -+ return -EFAULT; -+ break; -+ case FBIO_SET_TVE_MODE: -+ print_dbg("fbio set TVE mode\n"); -+ if (copy_from_user(jz4750_tve_info, argp, sizeof(struct jz4750tve_info))) -+ return -EFAULT; -+ /* set tve mode */ -+ jz4750tve_set_tve_mode(jz4750_tve_info); -+ break; -+ default: -+ printk("%s, unknown command(0x%x)", __FILE__, cmd); -+ break; -+ } -+ -+ return ret; -+} -+ -+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ -+static int jz4750fb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned long start; -+ unsigned long off; -+ u32 len; -+ dprintk("%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); -+ -+ /* frame buffer memory */ -+ start = cfb->fb.fix.smem_start; -+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); -+ start &= PAGE_MASK; -+ -+ if ((vma->vm_end - vma->vm_start + off) > len) -+ return -EINVAL; -+ off += start; -+ -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ vma->vm_flags |= VM_IO; -+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ -+ -+#if 1 -+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; -+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ -+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Back */ -+#endif -+ -+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+/* checks var and eventually tweaks it to something supported, -+ * DO NOT MODIFY PAR */ -+static int jz4750fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ printk("jz4750fb_check_var, not implement\n"); -+ return 0; -+} -+ -+ -+/* -+ * set the video mode according to info->var -+ */ -+static int jz4750fb_set_par(struct fb_info *info) -+{ -+ printk("jz4750fb_set_par, not implemented\n"); -+ return 0; -+} -+ -+ -+/* -+ * (Un)Blank the display. -+ * Fix me: should we use VESA value? -+ */ -+static int jz4750fb_blank(int blank_mode, struct fb_info *info) -+{ -+ dprintk("jz4750 fb_blank %d %p", blank_mode, info); -+ switch (blank_mode) { -+ case FB_BLANK_UNBLANK: -+ //case FB_BLANK_NORMAL: -+ /* Turn on panel */ -+ __lcd_set_ena(); -+ __lcd_display_on(); -+ break; -+ -+ case FB_BLANK_NORMAL: -+ case FB_BLANK_VSYNC_SUSPEND: -+ case FB_BLANK_HSYNC_SUSPEND: -+ case FB_BLANK_POWERDOWN: -+#if 0 -+ /* Turn off panel */ -+ __lcd_display_off(); -+ __lcd_set_dis(); -+#endif -+ break; -+ default: -+ break; -+ -+ } -+ return 0; -+} -+ -+/* -+ * pan display -+ */ -+static int jz4750fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ int dy; -+ -+ if (!var || !cfb) { -+ return -EINVAL; -+ } -+ -+ if (var->xoffset - cfb->fb.var.xoffset) { -+ /* No support for X panning for now! */ -+ return -EINVAL; -+ } -+ -+ dy = var->yoffset - cfb->fb.var.yoffset; -+ print_dbg("var.yoffset: %d", dy); -+ if (dy) { -+ print_dbg("Panning screen of %d lines", dy); -+ dma0_desc0->databuf += (cfb->fb.fix.line_length * dy); -+ /* TODO: Wait for current frame to finished */ -+ } -+ -+ return 0; -+} -+ -+ -+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ -+static struct fb_ops jz4750fb_ops = { -+ .owner = THIS_MODULE, -+ .fb_setcolreg = jz4750fb_setcolreg, -+ .fb_check_var = jz4750fb_check_var, -+ .fb_set_par = jz4750fb_set_par, -+ .fb_blank = jz4750fb_blank, -+ .fb_pan_display = jz4750fb_pan_display, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+ .fb_mmap = jz4750fb_mmap, -+ .fb_ioctl = jz4750fb_ioctl, -+}; -+ -+static int jz4750fb_set_var(struct fb_var_screeninfo *var, int con, -+ struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ struct jz4750lcd_info *lcd_info = jz4750_lcd_info; -+ int chgvar = 0; -+ -+ var->height = lcd_info->osd.fg0.h; /* tve mode */ -+ var->width = lcd_info->osd.fg0.w; -+ var->bits_per_pixel = lcd_info->osd.fg0.bpp; -+ -+ var->vmode = FB_VMODE_NONINTERLACED; -+ var->activate = cfb->fb.var.activate; -+ var->xres = var->width; -+ var->yres = var->height; -+ var->xres_virtual = var->width; -+ var->yres_virtual = var->height; -+ var->xoffset = 0; -+ var->yoffset = 0; -+ var->pixclock = 0; -+ var->left_margin = 0; -+ var->right_margin = 0; -+ var->upper_margin = 0; -+ var->lower_margin = 0; -+ var->hsync_len = 0; -+ var->vsync_len = 0; -+ var->sync = 0; -+ var->activate &= ~FB_ACTIVATE_TEST; -+ -+ /* -+ * CONUPDATE and SMOOTH_XPAN are equal. However, -+ * SMOOTH_XPAN is only used internally by fbcon. -+ */ -+ if (var->vmode & FB_VMODE_CONUPDATE) { -+ var->vmode |= FB_VMODE_YWRAP; -+ var->xoffset = cfb->fb.var.xoffset; -+ var->yoffset = cfb->fb.var.yoffset; -+ } -+ -+ if (var->activate & FB_ACTIVATE_TEST) -+ return 0; -+ -+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) -+ return -EINVAL; -+ -+ if (cfb->fb.var.xres != var->xres) -+ chgvar = 1; -+ if (cfb->fb.var.yres != var->yres) -+ chgvar = 1; -+ if (cfb->fb.var.xres_virtual != var->xres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.yres_virtual != var->yres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) -+ chgvar = 1; -+ -+ //display = fb_display + con; -+ -+ var->red.msb_right = 0; -+ var->green.msb_right = 0; -+ var->blue.msb_right = 0; -+ -+ switch(var->bits_per_pixel){ -+ case 1: /* Mono */ -+ cfb->fb.fix.visual = FB_VISUAL_MONO01; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 2: /* Mono */ -+ var->red.offset = 0; -+ var->red.length = 2; -+ var->green.offset = 0; -+ var->green.length = 2; -+ var->blue.offset = 0; -+ var->blue.length = 2; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 4: /* PSEUDOCOLOUR*/ -+ var->red.offset = 0; -+ var->red.length = 4; -+ var->green.offset = 0; -+ var->green.length = 4; -+ var->blue.offset = 0; -+ var->blue.length = 4; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres / 2; -+ break; -+ case 8: /* PSEUDOCOLOUR, 256 */ -+ var->red.offset = 0; -+ var->red.length = 8; -+ var->green.offset = 0; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres ; -+ break; -+ case 15: /* DIRECTCOLOUR, 32k */ -+ var->bits_per_pixel = 15; -+ var->red.offset = 10; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 5; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 16: /* DIRECTCOLOUR, 64k */ -+ var->bits_per_pixel = 16; -+ var->red.offset = 11; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 6; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 17 ... 32: -+ /* DIRECTCOLOUR, 256 */ -+ var->bits_per_pixel = 32; -+ -+ var->red.offset = 16; -+ var->red.length = 8; -+ var->green.offset = 8; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ var->transp.offset = 24; -+ var->transp.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 4; -+ break; -+ -+ default: /* in theory this should never happen */ -+ printk(KERN_WARNING "%s: don't support for %dbpp\n", -+ cfb->fb.fix.id, var->bits_per_pixel); -+ break; -+ } -+ -+ cfb->fb.var = *var; -+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; -+ -+ /* -+ * Update the old var. The fbcon drivers still use this. -+ * Once they are using cfb->fb.var, this can be dropped. -+ * --rmk -+ */ -+ //display->var = cfb->fb.var; -+ /* -+ * If we are setting all the virtual consoles, also set the -+ * defaults used to create new consoles. -+ */ -+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); -+ dprintk("jz4750fb_set_var: after fb_set_cmap...\n"); -+ -+ return 0; -+} -+ -+static struct lcd_cfb_info * jz4750fb_alloc_fb_info(void) -+{ -+ struct lcd_cfb_info *cfb; -+ -+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); -+ -+ if (!cfb) -+ return NULL; -+ -+ jz4750fb_info = cfb; -+ -+ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); -+ -+ cfb->currcon = -1; -+ -+ -+ strcpy(cfb->fb.fix.id, "jz-lcd"); -+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; -+ cfb->fb.fix.type_aux = 0; -+ cfb->fb.fix.xpanstep = 1; -+ cfb->fb.fix.ypanstep = 1; -+ cfb->fb.fix.ywrapstep = 0; -+ cfb->fb.fix.accel = FB_ACCEL_NONE; -+ -+ cfb->fb.var.nonstd = 0; -+ cfb->fb.var.activate = FB_ACTIVATE_NOW; -+ cfb->fb.var.height = -1; -+ cfb->fb.var.width = -1; -+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; -+ -+ cfb->fb.fbops = &jz4750fb_ops; -+ cfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ -+ cfb->fb.pseudo_palette = (void *)(cfb + 1); -+ -+ switch (jz4750_lcd_info->osd.fg0.bpp) { -+ case 1: -+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); -+ break; -+ case 2: -+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); -+ break; -+ case 4: -+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); -+ break; -+ case 8: -+ -+ default: -+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); -+ break; -+ } -+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); -+ -+ return cfb; -+} -+ -+/* -+ * Map screen memory -+ */ -+static int jz4750fb_map_smem(struct lcd_cfb_info *cfb) -+{ -+ unsigned long page; -+ unsigned int page_shift, needroom, needroom1, bpp, w, h; -+ -+ bpp = jz4750_lcd_info->osd.fg0.bpp; -+ if ( bpp == 18 || bpp == 24) -+ bpp = 32; -+ if ( bpp == 15 ) -+ bpp = 16; -+ w = jz4750_lcd_info->osd.fg0.w; -+ h = jz4750_lcd_info->osd.fg0.h; -+ needroom1 = needroom = ((w * bpp + 7) >> 3) * h; -+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) -+ bpp = jz4750_lcd_info->osd.fg1.bpp; -+ if ( bpp == 18 || bpp == 24) -+ bpp = 32; -+ if ( bpp == 15 ) -+ bpp = 16; -+ w = jz4750_lcd_info->osd.fg1.w; -+ h = jz4750_lcd_info->osd.fg1.h; -+ needroom += ((w * bpp + 7) >> 3) * h; -+#endif -+ -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); -+ lcd_frame0 = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ -+ if ((!lcd_palette) || (!lcd_frame0)) -+ return -ENOMEM; -+ memset((void *)lcd_palette, 0, PAGE_SIZE); -+ memset((void *)lcd_frame0, 0, PAGE_SIZE << page_shift); -+ -+ dma_desc_base = (struct jz4750_lcd_dma_desc *)((void*)lcd_palette + ((PALETTE_SIZE+3)/4)*4); -+ -+#if defined(CONFIG_FB_JZ4750_SLCD) -+ -+ lcd_cmdbuf = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); -+ memset((void *)lcd_cmdbuf, 0, PAGE_SIZE); -+ -+ { int data, i, *ptr; -+ ptr = (unsigned int *)lcd_cmdbuf; -+ data = WR_GRAM_CMD; -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ for(i = 0; i < 3; i++){ -+ ptr[i] = data; -+ } -+ } -+#endif -+ -+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) -+ lcd_frame1 = lcd_frame0 + needroom1; -+#endif -+ -+ /* -+ * Set page reserved so that mmap will work. This is necessary -+ * since we'll be remapping normal memory. -+ */ -+ page = (unsigned long)lcd_palette; -+ SetPageReserved(virt_to_page((void*)page)); -+ -+ for (page = (unsigned long)lcd_frame0; -+ page < PAGE_ALIGN((unsigned long)lcd_frame0 + (PAGE_SIZE<fb.fix.smem_start = virt_to_phys((void *)lcd_frame0); -+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); /* page_shift/2 ??? */ -+ cfb->fb.screen_base = -+ (unsigned char *)(((unsigned int)lcd_frame0&0x1fffffff) | 0xa0000000); -+ -+ if (!cfb->fb.screen_base) { -+ printk("jz4750fb, %s: unable to map screen memory\n", cfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void jz4750fb_free_fb_info(struct lcd_cfb_info *cfb) -+{ -+ if (cfb) { -+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); -+ kfree(cfb); -+ } -+} -+ -+static void jz4750fb_unmap_smem(struct lcd_cfb_info *cfb) -+{ -+ struct page * map = NULL; -+ unsigned char *tmp; -+ unsigned int page_shift, needroom, bpp, w, h; -+ -+ bpp = jz4750_lcd_info->osd.fg0.bpp; -+ if ( bpp == 18 || bpp == 24) -+ bpp = 32; -+ if ( bpp == 15 ) -+ bpp = 16; -+ w = jz4750_lcd_info->osd.fg0.w; -+ h = jz4750_lcd_info->osd.fg0.h; -+ needroom = ((w * bpp + 7) >> 3) * h; -+#if defined(CONFIG_FB_JZ4750_LCD_USE_2LAYER_FRAMEBUFFER) -+ bpp = jz4750_lcd_info->osd.fg1.bpp; -+ if ( bpp == 18 || bpp == 24) -+ bpp = 32; -+ if ( bpp == 15 ) -+ bpp = 16; -+ w = jz4750_lcd_info->osd.fg1.w; -+ h = jz4750_lcd_info->osd.fg1.h; -+ needroom += ((w * bpp + 7) >> 3) * h; -+#endif -+ -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ -+ if (cfb && cfb->fb.screen_base) { -+ iounmap(cfb->fb.screen_base); -+ cfb->fb.screen_base = NULL; -+ release_mem_region(cfb->fb.fix.smem_start, -+ cfb->fb.fix.smem_len); -+ } -+ -+ if (lcd_palette) { -+ map = virt_to_page(lcd_palette); -+ clear_bit(PG_reserved, &map->flags); -+ free_pages((int)lcd_palette, 0); -+ } -+ -+ if (lcd_frame0) { -+ for (tmp=(unsigned char *)lcd_frame0; -+ tmp < lcd_frame0 + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ clear_bit(PG_reserved, &map->flags); -+ } -+ free_pages((int)lcd_frame0, page_shift); -+ } -+} -+ -+/* initial dma descriptors */ -+static void jz4750fb_descriptor_init( struct jz4750lcd_info * lcd_info ) -+{ -+ unsigned int pal_size; -+ -+ switch ( lcd_info->osd.fg0.bpp ) { -+ case 1: -+ pal_size = 4; -+ break; -+ case 2: -+ pal_size = 8; -+ break; -+ case 4: -+ pal_size = 32; -+ break; -+ case 8: -+ default: -+ pal_size = 512; -+ } -+ -+ pal_size /= 4; -+ -+ dma0_desc_palette = dma_desc_base + 0; -+ dma0_desc0 = dma_desc_base + 1; -+ dma0_desc1 = dma_desc_base + 2; -+ dma0_desc_cmd0 = dma_desc_base + 3; /* use only once */ -+ dma0_desc_cmd = dma_desc_base + 4; -+ dma1_desc0 = dma_desc_base + 5; -+ dma1_desc1 = dma_desc_base + 6; -+ -+ /* -+ * Normal TFT panel's DMA Chan0: -+ * TO LCD Panel: -+ * no palette: dma0_desc0 <<==>> dma0_desc0 -+ * palette : dma0_desc_palette <<==>> dma0_desc0 -+ * TO TV Encoder: -+ * no palette: dma0_desc0 <<==>> dma0_desc1 -+ * palette: dma0_desc_palette --> dma0_desc0 -+ * --> dma0_desc1 --> dma0_desc_palette --> ... -+ * -+ * SMART LCD TFT panel(dma0_desc_cmd)'s DMA Chan0: -+ * TO LCD Panel: -+ * no palette: dma0_desc_cmd <<==>> dma0_desc0 -+ * palette : dma0_desc_palette --> dma0_desc_cmd -+ * --> dma0_desc0 --> dma0_desc_palette --> ... -+ * TO TV Encoder: -+ * no palette: dma0_desc_cmd --> dma0_desc0 -+ * --> dma0_desc1 --> dma0_desc_cmd --> ... -+ * palette: dma0_desc_palette --> dma0_desc_cmd -+ * --> dma0_desc0 --> dma0_desc1 -+ * --> dma0_desc_palette --> ... -+ * DMA Chan1: -+ * TO LCD Panel: -+ * dma1_desc0 <<==>> dma1_desc0 -+ * TO TV Encoder: -+ * dma1_desc0 <<==>> dma1_desc1 -+ */ -+ -+#if defined(CONFIG_FB_JZ4750_SLCD) -+ /* First CMD descriptors, use only once, cmd_num isn't 0 */ -+ dma0_desc_cmd0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd0->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf); -+ dma0_desc_cmd0->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */ -+ dma0_desc_cmd0->cmd = LCD_CMD_CMD | 3; /* command */ -+ dma0_desc_cmd0->offsize = 0; -+ dma0_desc_cmd0->page_width = 0; -+ dma0_desc_cmd0->cmd_num = 3; -+ -+ /* Dummy Command Descriptor, cmd_num is 0 */ -+ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd->databuf = 0; -+ dma0_desc_cmd->frame_id = (unsigned int)0x0da000cd; /* dma0's cmd0 */ -+ dma0_desc_cmd->cmd = LCD_CMD_CMD | 0; /* dummy command */ -+ dma0_desc_cmd->cmd_num = 0; -+ dma0_desc_cmd->offsize = 0; -+ dma0_desc_cmd->page_width = 0; -+ -+ /* Palette Descriptor */ -+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd0); -+#else -+ /* Palette Descriptor */ -+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+#endif -+ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette); -+ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa; -+ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */ -+ -+ /* DMA0 Descriptor0 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); -+ else{ /* Normal TFT LCD */ -+#if defined(CONFIG_FB_JZ4750_SLCD) -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+#else -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+#endif -+ } -+ -+ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0); -+ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ -+ -+ /* DMA0 Descriptor1 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ -+ -+ -+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */ -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); -+ else -+#if defined(CONFIG_FB_JZ4750_SLCD) /* for smatlcd */ -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+#else -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+#endif -+ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */ -+ } -+ -+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup */ -+ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette); -+ else { -+#if defined(CONFIG_FB_JZ4750_SLCD) /* for smartlcd */ -+ REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd0); //smart lcd -+#else -+ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft -+#endif -+ } -+ -+ /* DMA1 Descriptor0 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ -+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); -+ else /* Normal TFT LCD */ -+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); -+ -+ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1); -+ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */ -+ -+ /* DMA1 Descriptor1 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ -+ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); -+ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */ -+ } -+ -+ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ -+ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); -+ -+#if 0 -+ /* Palette Descriptor */ -+ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) -+// dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); -+ else -+ dma0_desc_palette->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_palette->databuf = (unsigned int)virt_to_phys((void *)lcd_palette); -+ dma0_desc_palette->frame_id = (unsigned int)0xaaaaaaaa; -+ dma0_desc_palette->cmd = LCD_CMD_PAL | pal_size; /* Palette Descriptor */ -+ -+ /* Dummy Command Descriptor, cmd_num is 0 */ -+ dma0_desc_cmd->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd->databuf = (unsigned int)virt_to_phys((void *)lcd_cmdbuf); -+ dma0_desc_cmd->frame_id = (unsigned int)0x0da0cad0; /* dma0's cmd0 */ -+ dma0_desc_cmd->cmd = LCD_CMD_CMD | 3; /* dummy command */ -+ dma0_desc_cmd->offsize = 0; /* dummy command */ -+ dma0_desc_cmd->page_width = 0; /* dummy command */ -+ dma0_desc_cmd->cmd_num = 3; -+ -+//--------------------------------- -+ dma0_desc_cmd1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc_cmd1->databuf = 0; -+ dma0_desc_cmd1->frame_id = (unsigned int)0x0da0cad1; /* dma0's cmd0 */ -+ dma0_desc_cmd1->cmd = LCD_CMD_CMD | 0; /* dummy command */ -+ dma0_desc_cmd1->cmd_num = 0; -+ dma0_desc_cmd1->offsize = 0; /* dummy command */ -+ dma0_desc_cmd1->page_width = 0; /* dummy command */ -+//----------------------------------- -+ /* DMA0 Descriptor0 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc1); -+ else{ /* Normal TFT LCD */ -+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ -+// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); //tft -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); // smart lcd -+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd1); -+// dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+ else -+ dma0_desc0->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ } -+ -+ dma0_desc0->databuf = virt_to_phys((void *)lcd_frame0); -+ dma0_desc0->frame_id = (unsigned int)0x0000da00; /* DMA0'0 */ -+ -+ /* DMA0 Descriptor1 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ -+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_palette); -+ -+ else if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc_cmd); -+ else -+ dma0_desc1->next_desc = (unsigned int)virt_to_phys(dma0_desc0); -+ dma0_desc1->frame_id = (unsigned int)0x0000da01; /* DMA0'1 */ -+ } -+ -+ /* DMA1 Descriptor0 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) /* TVE mode */ -+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc1); -+ else /* Normal TFT LCD */ -+ dma1_desc0->next_desc = (unsigned int)virt_to_phys(dma1_desc0); -+ -+ dma1_desc0->databuf = virt_to_phys((void *)lcd_frame1); -+ dma1_desc0->frame_id = (unsigned int)0x0000da10; /* DMA1'0 */ -+ -+ /* DMA1 Descriptor1 */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* TVE mode */ -+ dma1_desc1->next_desc = (unsigned int)virt_to_phys(dma1_desc0); -+ dma1_desc1->frame_id = (unsigned int)0x0000da11; /* DMA1'1 */ -+ } -+ -+ if (lcd_info->osd.fg0.bpp <= 8) /* load palette only once at setup?? */ -+ REG_LCD_DA0 = virt_to_phys(dma0_desc_palette); -+ else -+// REG_LCD_DA0 = virt_to_phys(dma0_desc_cmd); //smart lcd -+ REG_LCD_DA0 = virt_to_phys(dma0_desc0); //tft -+ REG_LCD_DA1 = virt_to_phys(dma1_desc0); /* set Dma-chan1's Descripter Addrress */ -+ dma_cache_wback_inv((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); -+#endif -+} -+ -+static void jz4750fb_set_panel_mode( struct jz4750lcd_info * lcd_info ) -+{ -+ struct jz4750lcd_panel_t *panel = &lcd_info->panel; -+ -+ /* set bpp */ -+ lcd_info->panel.ctrl &= ~LCD_CTRL_BPP_MASK; -+ if ( lcd_info->osd.fg0.bpp == 1 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_1; -+ else if ( lcd_info->osd.fg0.bpp == 2 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_2; -+ else if ( lcd_info->osd.fg0.bpp == 4 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_4; -+ else if ( lcd_info->osd.fg0.bpp == 8 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_8; -+ else if ( lcd_info->osd.fg0.bpp == 15 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB555; -+ else if ( lcd_info->osd.fg0.bpp == 16 ) -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_16 | LCD_CTRL_RGB565; -+ else if ( lcd_info->osd.fg0.bpp > 16 && lcd_info->osd.fg0.bpp < 32+1 ) { -+ lcd_info->osd.fg0.bpp = 32; -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24; -+ } -+ else { -+ printk("The BPP %d is not supported\n", lcd_info->osd.fg0.bpp); -+ lcd_info->osd.fg0.bpp = 32; -+ lcd_info->panel.ctrl |= LCD_CTRL_BPP_18_24; -+ } -+ -+ lcd_info->panel.cfg |= LCD_CFG_NEWDES; /* use 8words descriptor always */ -+ -+ REG_LCD_CTRL = lcd_info->panel.ctrl; /* LCDC Controll Register */ -+ REG_LCD_CFG = lcd_info->panel.cfg; /* LCDC Configure Register */ -+ REG_SLCD_CFG = lcd_info->panel.slcd_cfg; /* Smart LCD Configure Register */ -+ -+ if ( lcd_info->panel.cfg & LCD_CFG_LCDPIN_SLCD ) /* enable Smart LCD DMA */ -+ REG_SLCD_CTRL = SLCD_CTRL_DMA_EN; -+ -+ switch ( lcd_info->panel.cfg & LCD_CFG_MODE_MASK ) { -+ case LCD_CFG_MODE_GENERIC_TFT: -+ case LCD_CFG_MODE_INTER_CCIR656: -+ case LCD_CFG_MODE_NONINTER_CCIR656: -+ case LCD_CFG_MODE_SLCD: -+ default: /* only support TFT16 TFT32, not support STN and Special TFT by now(10-06-2008)*/ -+ REG_LCD_VAT = (((panel->blw + panel->w + panel->elw + panel->hsw)) << 16) | (panel->vsw + panel->bfw + panel->h + panel->efw); -+ REG_LCD_DAH = ((panel->hsw + panel->blw) << 16) | (panel->hsw + panel->blw + panel->w); -+ REG_LCD_DAV = ((panel->vsw + panel->bfw) << 16) | (panel->vsw + panel->bfw + panel->h); -+ REG_LCD_HSYNC = (0 << 16) | panel->hsw; -+ REG_LCD_VSYNC = (0 << 16) | panel->vsw; -+ break; -+ } -+} -+ -+ -+static void jz4750fb_set_osd_mode( struct jz4750lcd_info * lcd_info ) -+{ -+ dprintk("%s, %d\n", __FILE__, __LINE__ ); -+ lcd_info->osd.osd_ctrl &= ~(LCD_OSDCTRL_OSDBPP_MASK); -+ if ( lcd_info->osd.fg1.bpp == 15 ) -+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB555; -+ else if ( lcd_info->osd.fg1.bpp == 16 ) -+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_15_16|LCD_OSDCTRL_RGB565; -+ else { -+ lcd_info->osd.fg1.bpp = 32; -+ lcd_info->osd.osd_ctrl |= LCD_OSDCTRL_OSDBPP_18_24; -+ } -+ -+ REG_LCD_OSDC = lcd_info->osd.osd_cfg; /* F0, F1, alpha, */ -+ -+ REG_LCD_OSDCTRL = lcd_info->osd.osd_ctrl; /* IPUEN, bpp */ -+ REG_LCD_RGBC = lcd_info->osd.rgb_ctrl; -+ REG_LCD_BGC = lcd_info->osd.bgcolor; -+ REG_LCD_KEY0 = lcd_info->osd.colorkey0; -+ REG_LCD_KEY1 = lcd_info->osd.colorkey1; -+ REG_LCD_ALPHA = lcd_info->osd.alpha; -+ REG_LCD_IPUR = lcd_info->osd.ipu_restart; -+} -+ -+static void jz4750fb_foreground_resize( struct jz4750lcd_info * lcd_info ) -+{ -+ int fg0_line_size, fg0_frm_size, fg1_line_size, fg1_frm_size; -+ /* -+ * NOTE: -+ * Foreground change sequence: -+ * 1. Change Position Registers -> LCD_OSDCTL.Change; -+ * 2. LCD_OSDCTRL.Change -> descripter->Size -+ * Foreground, only one of the following can be change at one time: -+ * 1. F0 size; -+ * 2. F0 position -+ * 3. F1 size -+ * 4. F1 position -+ */ -+ -+ /* -+ * The rules of f0, f1's position: -+ * f0.x + f0.w <= panel.w; -+ * f0.y + f0.h <= panel.h; -+ * -+ * When output is LCD panel, fg.y and fg.h can be odd number or even number. -+ * When output is TVE, as the TVE has odd frame and even frame, -+ * to simplified operation, fg.y and fg.h should be even number always. -+ * -+ */ -+ -+ /* Foreground 0 */ -+ if ( lcd_info->osd.fg0.x >= lcd_info->panel.w ) -+ lcd_info->osd.fg0.x = lcd_info->panel.w - 1; -+ if ( lcd_info->osd.fg0.y >= lcd_info->panel.h ) -+ lcd_info->osd.fg0.y = lcd_info->panel.h - 1; -+ if ( lcd_info->osd.fg0.x + lcd_info->osd.fg0.w > lcd_info->panel.w ) -+ lcd_info->osd.fg0.w = lcd_info->panel.w - lcd_info->osd.fg0.x; -+ if ( lcd_info->osd.fg0.y + lcd_info->osd.fg0.h > lcd_info->panel.h ) -+ lcd_info->osd.fg0.h = lcd_info->panel.h - lcd_info->osd.fg0.y; -+ /* Foreground 1 */ -+ /* Case TVE ??? TVE 720x573 or 720x480*/ -+ if ( lcd_info->osd.fg1.x >= lcd_info->panel.w ) -+ lcd_info->osd.fg1.x = lcd_info->panel.w - 1; -+ if ( lcd_info->osd.fg1.y >= lcd_info->panel.h ) -+ lcd_info->osd.fg1.y = lcd_info->panel.h - 1; -+ if ( lcd_info->osd.fg1.x + lcd_info->osd.fg1.w > lcd_info->panel.w ) -+ lcd_info->osd.fg1.w = lcd_info->panel.w - lcd_info->osd.fg1.x; -+ if ( lcd_info->osd.fg1.y + lcd_info->osd.fg1.h > lcd_info->panel.h ) -+ lcd_info->osd.fg1.h = lcd_info->panel.h - lcd_info->osd.fg1.y; -+ -+// fg0_line_size = lcd_info->osd.fg0.w*((lcd_info->osd.fg0.bpp+7)/8); -+ fg0_line_size = (lcd_info->osd.fg0.w*(lcd_info->osd.fg0.bpp)/8); -+ fg0_line_size = ((fg0_line_size+3)>>2)<<2; /* word aligned */ -+ fg0_frm_size = fg0_line_size * lcd_info->osd.fg0.h; -+ -+ fg1_line_size = lcd_info->osd.fg1.w*((lcd_info->osd.fg1.bpp+7)/8); -+ fg1_line_size = ((fg1_line_size+3)>>2)<<2; /* word aligned */ -+ fg1_frm_size = fg1_line_size * lcd_info->osd.fg1.h; -+ -+ if ( lcd_info->osd.fg_change ) { -+ if ( lcd_info->osd.fg_change & FG0_CHANGE_POSITION ) { /* F1 change position */ -+ REG_LCD_XYP0 = lcd_info->osd.fg0.y << 16 | lcd_info->osd.fg0.x; -+ } -+ if ( lcd_info->osd.fg_change & FG1_CHANGE_POSITION ) { /* F1 change position */ -+ REG_LCD_XYP1 = lcd_info->osd.fg1.y << 16 | lcd_info->osd.fg1.x; -+ } -+ -+ /* set change */ -+ if ( !(lcd_info->osd.osd_ctrl & LCD_OSDCTRL_IPU) && -+ (lcd_info->osd.fg_change != FG_CHANGE_ALL) ) -+ REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES; -+ -+ /* wait change ready??? */ -+// while ( REG_LCD_OSDS & LCD_OSDS_READY ) /* fix in the future, Wolfgang, 06-20-2008 */ -+ print_dbg("wait LCD_OSDS_READY\n"); -+ -+ if ( lcd_info->osd.fg_change & FG0_CHANGE_SIZE ) { /* change FG0 size */ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ -+ dma0_desc0->cmd = dma0_desc1->cmd = (fg0_frm_size/4)/2; -+ dma0_desc0->offsize = dma0_desc1->offsize -+ = fg0_line_size/4; -+ dma0_desc0->page_width = dma0_desc1->page_width -+ = fg0_line_size/4; -+ dma0_desc1->databuf = virt_to_phys((void *)(lcd_frame0 + fg0_line_size)); -+ } -+ else { -+ dma0_desc0->cmd = dma0_desc1->cmd = fg0_frm_size/4; -+ dma0_desc0->offsize = dma0_desc1->offsize =0; -+ dma0_desc0->page_width = dma0_desc1->page_width = 0; -+ } -+ -+ dma0_desc0->desc_size = dma0_desc1->desc_size -+ = lcd_info->osd.fg0.h << 16 | lcd_info->osd.fg0.w; -+ REG_LCD_SIZE0 = (lcd_info->osd.fg0.h<<16)|lcd_info->osd.fg0.w; -+ -+ } -+ -+ if ( lcd_info->osd.fg_change & FG1_CHANGE_SIZE ) { /* change FG1 size*/ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* output to TV */ -+ dma1_desc0->cmd = dma1_desc1->cmd = (fg1_frm_size/4)/2; -+ dma1_desc0->offsize = dma1_desc1->offsize = fg1_line_size/4; -+ dma1_desc0->page_width = dma1_desc1->page_width = fg1_line_size/4; -+ dma1_desc1->databuf = virt_to_phys((void *)(lcd_frame1 + fg1_line_size)); -+ } -+ else { -+ dma1_desc0->cmd = dma1_desc1->cmd = fg1_frm_size/4; -+ dma1_desc0->offsize = dma1_desc1->offsize = 0; -+ dma1_desc0->page_width = dma1_desc1->page_width = 0; -+ } -+ -+ dma1_desc0->desc_size = dma1_desc1->desc_size -+ = lcd_info->osd.fg1.h << 16 | lcd_info->osd.fg1.w; -+ REG_LCD_SIZE1 = lcd_info->osd.fg1.h << 16|lcd_info->osd.fg1.w; -+ } -+ -+ dma_cache_wback((unsigned int)(dma_desc_base), (DMA_DESC_NUM)*sizeof(struct jz4750_lcd_dma_desc)); -+ lcd_info->osd.fg_change = FG_NOCHANGE; /* clear change flag */ -+ } -+} -+ -+static void jz4750fb_change_clock( struct jz4750lcd_info * lcd_info ) -+{ -+#if defined(CONFIG_JZ4750_FUWA) || defined(CONFIG_JZ4750_APUS) /* FPGA test, pixdiv */ -+#if 0 -+ REG_LCD_REV = 0x00000004; -+ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV); -+ printk("Fuwa test, pixclk %d\n", JZ_EXTAL/(((REG_LCD_REV&0xFF)+1)*2)); -+#endif -+ unsigned int val = 0; -+ unsigned int pclk; -+ /* Timing setting */ -+ __cpm_stop_lcd(); -+ -+ val = lcd_info->panel.fclk; /* frame clk */ -+ -+ if ( (lcd_info->panel.cfg & LCD_CFG_MODE_MASK) != LCD_CFG_MODE_SERIAL_TFT) { -+ pclk = val * (lcd_info->panel.w + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */ -+ } -+ else { -+ /* serial mode: Hsync period = 3*Width_Pixel */ -+ pclk = val * (lcd_info->panel.w*3 + lcd_info->panel.hsw + lcd_info->panel.elw + lcd_info->panel.blw) * (lcd_info->panel.h + lcd_info->panel.vsw + lcd_info->panel.efw + lcd_info->panel.bfw); /* Pixclk */ -+ } -+ -+ /********* In TVE mode PCLK = 27MHz ***********/ -+ if ( lcd_info->panel.cfg & LCD_CFG_TVEN ) { /* LCDC output to TVE */ -+ REG_CPM_LPCDR |= CPM_LPCDR_LTCS; -+ val = 11; /* PLLCLK = 324 */ -+ __cpm_set_pixdiv(val); -+ -+ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR); -+ -+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ -+ -+ val =(__cpm_get_pllout()) / val; -+ if ( val > 0x1f ) { -+ printk("lcd clock divide is too large, set it to 0x1f\n"); -+ val = 0x1f; -+ } -+ __cpm_set_ldiv( val ); -+ REG_CPM_LPCDR |= CPM_LPCDR_LTCS; -+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ -+ -+ } -+ else { /* LCDC output to LCD panel */ -+// REG_CPM_LPCDR = 0; -+ val = __cpm_get_pllout2() / pclk; /* pclk */ -+ val--; -+ dprintk("ratio: val = %d\n", val); -+ if ( val > 0x7ff ) { -+ printk("pixel clock divid is too large, set it to 0x7ff\n"); -+ val = 0x7ff; -+ } -+ -+ __cpm_set_pixdiv(val); -+ -+ dprintk("REG_CPM_LPCDR = 0x%08x\n", REG_CPM_LPCDR); -+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ -+ val =__cpm_get_pllout2() / val; -+ if ( val > 0x1f ) { -+ printk("lcd clock divide is too large, set it to 0x1f\n"); -+ val = 0x1f; -+ } -+ __cpm_set_ldiv( val ); -+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ -+ -+ } -+ -+ dprintk("REG_CPM_LPCDR=0x%08x\n", REG_CPM_LPCDR); -+ dprintk("REG_CPM_CPCCR=0x%08x\n", REG_CPM_CPCCR); -+ -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ printk("LCDC: PixClock:%d LcdClock:%d\n", -+ jz_clocks.pixclk, jz_clocks.lcdclk); -+ -+ __cpm_start_lcd(); -+ udelay(1000); -+#else -+ -+#error "Set lcd clock first, Not support your chipset now!!!" -+ /* -+ * set lcd device clock and lcd pixel clock. -+ * what about TVE mode??? -+ * -+ */ -+#endif -+ -+} -+ -+/* -+ * jz4750fb_set_mode(), set osd configure, resize foreground -+ * -+ */ -+static void jz4750fb_set_mode( struct jz4750lcd_info * lcd_info ) -+{ -+ struct lcd_cfb_info *cfb = jz4750fb_info; -+ -+ jz4750fb_set_osd_mode(lcd_info); -+ jz4750fb_foreground_resize(lcd_info); -+ jz4750fb_set_var(&cfb->fb.var, -1, &cfb->fb); -+} -+ -+/* -+ * jz4750fb_deep_set_mode, -+ * -+ */ -+static void jz4750fb_deep_set_mode( struct jz4750lcd_info * lcd_info ) -+{ -+ /* configurate sequence: -+ * 1. disable lcdc. -+ * 2. init frame descriptor. -+ * 3. set panel mode -+ * 4. set osd mode -+ * 5. start lcd clock in CPM -+ * 6. enable lcdc. -+ */ -+ -+ __lcd_clr_ena(); /* Quick Disable */ -+ lcd_info->osd.fg_change = FG_CHANGE_ALL; /* change FG0, FG1 size, postion??? */ -+ jz4750fb_descriptor_init(lcd_info); -+ jz4750fb_set_panel_mode(lcd_info); -+ jz4750fb_set_mode(lcd_info); -+ jz4750fb_change_clock(lcd_info); -+ __lcd_set_ena(); /* enable lcdc */ -+} -+ -+ -+static irqreturn_t jz4750fb_interrupt_handler(int irq, void *dev_id) -+{ -+ unsigned int state; -+ static int irqcnt=0; -+ -+ state = REG_LCD_STATE; -+ dprintk("In the lcd interrupt handler, state=0x%x\n", state); -+ -+ if (state & LCD_STATE_EOF) /* End of frame */ -+ REG_LCD_STATE = state & ~LCD_STATE_EOF; -+ -+ if (state & LCD_STATE_IFU0) { -+ printk("%s, InFiFo0 underrun\n", __FUNCTION__); -+ REG_LCD_STATE = state & ~LCD_STATE_IFU0; -+ } -+ -+ if (state & LCD_STATE_IFU1) { -+ printk("%s, InFiFo1 underrun\n", __FUNCTION__); -+ REG_LCD_STATE = state & ~LCD_STATE_IFU1; -+ } -+ -+ if (state & LCD_STATE_OFU) { /* Out fifo underrun */ -+ REG_LCD_STATE = state & ~LCD_STATE_OFU; -+ if ( irqcnt++ > 100 ) { -+ __lcd_disable_ofu_intr(); -+ printk("disable Out FiFo underrun irq.\n"); -+ } -+ printk("%s, Out FiFo underrun.\n", __FUNCTION__); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+#ifdef CONFIG_PM -+ -+/* -+ * Suspend the LCDC. -+ */ -+static int jzfb_suspend(void) -+{ -+ __lcd_clr_ena(); /* Quick Disable */ -+ __lcd_display_off(); -+ __cpm_stop_lcd(); -+ -+ return 0; -+} -+ -+/* -+ * Resume the LCDC. -+ */ -+static int jzfb_resume(void) -+{ -+ __cpm_start_lcd(); -+ __gpio_set_pin(GPIO_DISP_OFF_N); -+ __lcd_special_on(); -+ __lcd_set_ena(); -+ mdelay(200); -+ __lcd_set_backlight_level(80); -+ -+ return 0; -+} -+ -+/* -+ * Power management hook. Note that we won't be called from IRQ context, -+ * unlike the blank functions above, so we may sleep. -+ */ -+static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct lcd_cfb_info *cfb = pm_dev->data; -+ -+ if (!cfb) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jzfb_suspend(); -+ break; -+ -+ case PM_RESUME: -+ ret = jzfb_resume(); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#else -+#define jzfb_suspend NULL -+#define jzfb_resume NULL -+#endif /* CONFIG_PM */ -+ -+/* The following routine is only for test */ -+ -+#ifdef DEBUG -+static void test_gpio(int gpio_num, int delay) { -+ __gpio_as_output(gpio_num); -+ while(1) { -+ __gpio_set_pin(gpio_num); -+ udelay(delay); -+ __gpio_clear_pin(gpio_num); -+ udelay(delay); -+ } -+} -+static void display_v_color_bar(int w, int h, int bpp) { -+ int i, j, wpl, data = 0; -+ int *ptr; -+ ptr = (int *)lcd_frame0; -+// ptr = (int *)lcd_frame1; -+ wpl = w*bpp/32; -+ if (!(bpp > 8)) -+ switch(bpp){ -+ case 1: -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ *ptr++ = 0x00ff00ff; -+ } -+ break; -+ case 2: -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ data = (i%4)*0x55555555; -+ *ptr++ = data; -+ } -+ break; -+ case 4: -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ data = (i%16)*0x11111111; -+ *ptr++ = data; -+ } -+ break; -+ case 8: -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i+=2) { -+ data = (i%(256))*0x01010101; -+ *ptr++ = data; -+ *ptr++ = data; -+ } -+ break; -+ } -+ else { -+ switch(bpp) { -+ case 16: -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ if((i/4)%8==0) -+ *ptr++ = 0xffffffff; -+ else if ((i/4)%8==1) -+ *ptr++ = 0xf800f800; -+ else if ((i/4)%8==2) -+ *ptr++ = 0xffe0ffe0; -+ else if ((i/4)%8==3) -+ *ptr++ = 0x07e007e0; -+ else if ((i/4)%8==4) -+ *ptr++ = 0x07ff07ff; -+ else if ((i/4)%8==5) -+ *ptr++ = 0x001f001f; -+ else if ((i/4)%8==6) -+ *ptr++ = 0xf81ff81f; -+ else if ((i/4)%8==7) -+ *ptr++ = 0x00000000; -+ } -+ break; -+ case 18: -+ case 24: -+ case 32: -+ default: -+#if 1 -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ if((i/8)%8==7) -+ *ptr++ = 0xffffff; -+ else if ((i/8)%8==1) -+ *ptr++ = 0xff0000; -+ else if ((i/8)%8==2) -+ *ptr++ = 0xffff00; -+ else if ((i/8)%8==3) -+ *ptr++ = 0x00ff00; -+ else if ((i/8)%8==4) -+ *ptr++ = 0x00ffff; -+ else if ((i/8)%8==5) -+ *ptr++ = 0x0000ff; -+ else if ((i/8)%8==6) -+ *ptr++ = 0xff00ff; -+ else if ((i/8)%8==0) -+ *ptr++ = 0x000000; -+ } -+#else -+ for (j = 0;j < h; j++) -+ for (i = 0;i < wpl; i++) { -+ if((i/8)%8==7) -+ *ptr++ = 0x00ff0000; -+ else if ((i/8)%8==1) -+ *ptr++ = 0xffff0000; -+ else if ((i/8)%8==2) -+ *ptr++ = 0x20ff0000; -+ else if ((i/8)%8==3) -+ *ptr++ = 0x40ff0000; -+ else if ((i/8)%8==4) -+ *ptr++ = 0x60ff0000; -+ else if ((i/8)%8==5) -+ *ptr++ = 0x80ff0000; -+ else if ((i/8)%8==6) -+ *ptr++ = 0xa0ff0000; -+ else if ((i/8)%8==0) -+ *ptr++ = 0xc0ff0000; -+ } -+#endif -+ break; -+ } -+ } -+} -+static void display_h_color_bar(int w, int h, int bpp) { -+ int i, data = 0; -+ int *ptr; -+ int wpl; //word_per_line -+ ptr = (int *)lcd_frame0; -+// ptr = (int *)lcd_frame1; -+ wpl = w*bpp/32; -+ if (!(bpp > 8)) -+ for (i = 0;i < wpl*h;i++) { -+ switch(bpp){ -+ case 1: -+ if(i%(wpl*8)==0) -+ data = ((i/(wpl*8))%2)*0xffffffff; -+ *ptr++ = data; -+ break; -+ case 2: -+ if(i%(wpl*8)==0) -+ data = ((i/(wpl*8))%4)*0x55555555; -+ *ptr++ = data; -+ break; -+ case 4: -+ if(i%(wpl*8)==0) -+ data = ((i/(wpl*8))%16)*0x11111111; -+ *ptr++ = data; -+ break; -+ case 8: -+ if(i%(wpl*8)==0) -+ data = ((i/(wpl*8))%256)*0x01010101; -+ *ptr++ = data; -+ break; -+ } -+ } -+ else { -+ -+ switch(bpp) { -+ case 15: -+ case 16: -+ for (i = 0;i < wpl*h;i++) { -+ if (((i/(wpl*8)) % 8) == 0) -+ *ptr++ = 0xffffffff; -+ else if (((i/(wpl*8)) % 8) == 1) -+ *ptr++ = 0xf800f800; -+ else if (((i/(wpl*8)) % 8) == 2) -+ *ptr++ = 0xffe0ffe0; -+ else if (((i/(wpl*8)) % 8) == 3) -+ *ptr++ = 0x07e007e0; -+ else if (((i/(wpl*8)) % 8) == 4) -+ *ptr++ = 0x07ff07ff; -+ else if (((i/(wpl*8)) % 8) == 5) -+ *ptr++ = 0x001f001f; -+ else if (((i/(wpl*8)) % 8) == 6) -+ *ptr++ = 0xf81ff81f; -+ else if (((i/(wpl*8)) % 8) == 7) -+ *ptr++ = 0x00000000; -+ } -+ break; -+ case 18: -+ case 24: -+ case 32: -+ default: -+ for (i = 0;i < wpl*h;i++) { -+ if (((i/(wpl*8)) % 8) == 7) -+ *ptr++ = 0xffffff; -+ else if (((i/(wpl*8)) % 8) == 2) -+ *ptr++ = 0xff0000; -+ else if (((i/(wpl*8)) % 8) == 4) -+ *ptr++ = 0xffff00; -+ else if (((i/(wpl*8)) % 8) == 6) -+ *ptr++ = 0x00ff00; -+ else if (((i/(wpl*8)) % 8) == 1) -+ *ptr++ = 0x00ffff; -+ else if (((i/(wpl*8)) % 8) == 3) -+ *ptr++ = 0x0000ff; -+ else if (((i/(wpl*8)) % 8) == 5) -+ *ptr++ = 0x000000; -+ else if (((i/(wpl*8)) % 8) == 0) -+ *ptr++ = 0xff00ff; -+ } -+ break; -+ } -+ -+ } -+ -+} -+#endif -+ -+static int __init jz4750fb_init(void) -+{ -+ struct lcd_cfb_info *cfb; -+ int err = 0; -+ -+ /* gpio init __gpio_as_lcd */ -+ if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_16BIT) -+ __gpio_as_lcd_16bit(); -+ else if (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_TFT_24BIT) -+ __gpio_as_lcd_24bit(); -+ else -+ __gpio_as_lcd_18bit(); -+ /* In special mode, we only need init special pin, -+ * as general lcd pin has init in uboot */ -+#if defined(CONFIG_SOC_JZ4750) -+ switch (jz4750_lcd_info->panel.cfg & LCD_CFG_MODE_MASK) { -+ case LCD_CFG_MODE_SPECIAL_TFT_1: -+ case LCD_CFG_MODE_SPECIAL_TFT_2: -+ case LCD_CFG_MODE_SPECIAL_TFT_3: -+ __gpio_as_lcd_special(); -+ break; -+ default: -+ ; -+ } -+#endif -+ if ( jz4750_lcd_info->osd.fg0.bpp > 16 && -+ jz4750_lcd_info->osd.fg0.bpp < 32 ) { -+ jz4750_lcd_info->osd.fg0.bpp = 32; -+ } -+ -+ switch ( jz4750_lcd_info->osd.fg1.bpp ) { -+ case 15: -+ case 16: -+ break; -+ case 17 ... 32: -+ jz4750_lcd_info->osd.fg1.bpp = 32; -+ break; -+ default: -+ printk("jz4750fb fg1 not support bpp(%d), force to 32bpp\n", -+ jz4750_lcd_info->osd.fg1.bpp); -+ jz4750_lcd_info->osd.fg1.bpp = 32; -+ } -+ __lcd_clr_dis(); -+ __lcd_clr_ena(); -+ -+ /* Configure SLCD module for setting smart lcd control registers */ -+#if defined(CONFIG_FB_JZ4750_SLCD) -+ __lcd_as_smart_lcd(); -+ __slcd_disable_dma(); -+ __init_slcd_bus(); /* Note: modify this depend on you lcd */ -+ -+#endif -+ /* init clk */ -+ jz4750fb_change_clock(jz4750_lcd_info); -+ __lcd_display_pin_init(); -+ __lcd_slcd_special_on(); -+ -+ cfb = jz4750fb_alloc_fb_info(); -+ if (!cfb) -+ goto failed; -+ -+ err = jz4750fb_map_smem(cfb); -+ if (err) -+ goto failed; -+ -+ jz4750fb_deep_set_mode( jz4750_lcd_info ); -+ -+ err = register_framebuffer(&cfb->fb); -+ if (err < 0) { -+ dprintk("jzfb_init(): register framebuffer err.\n"); -+ goto failed; -+ } -+ printk("fb%d: %s frame buffer device, using %dK of video memory\n", -+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); -+ -+ if (request_irq(IRQ_LCD, jz4750fb_interrupt_handler, IRQF_DISABLED, -+ "lcd", 0)) { -+ err = -EBUSY; -+ goto failed; -+ } -+ -+#ifdef CONFIG_PM -+ /* -+ * Note that the console registers this as well, but we want to -+ * power down the display prior to sleeping. -+ */ -+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback); -+ if (cfb->pm) -+ cfb->pm->data = cfb; -+#endif -+ -+ __lcd_set_ena(); /* enalbe LCD Controller */ -+ __lcd_display_on(); -+ -+#ifdef DEBUG -+ display_h_color_bar(jz4750_lcd_info->osd.fg0.w, jz4750_lcd_info->osd.fg0.h, jz4750_lcd_info->osd.fg0.bpp); -+#endif -+ print_lcdc_registers(); -+ return 0; -+ -+failed: -+ print_dbg(); -+ jz4750fb_unmap_smem(cfb); -+ jz4750fb_free_fb_info(cfb); -+ -+ return err; -+} -+ -+#if 0 -+static int jzfb_remove(struct device *dev) -+{ -+ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); -+ jzfb_unmap_smem(cfb); -+ jzfb_free_fb_info(cfb); -+ return 0; -+} -+#endif -+ -+#if 0 -+static struct device_driver jzfb_driver = { -+ .name = "jz-lcd", -+ .bus = &platform_bus_type, -+ .probe = jzfb_probe, -+ .remove = jzfb_remove, -+ .suspend = jzfb_suspend, -+ .resume = jzfb_resume, -+}; -+#endif -+ -+static void __exit jz4750fb_cleanup(void) -+{ -+ //driver_unregister(&jzfb_driver); -+ //jzfb_remove(); -+} -+ -+module_init(jz4750fb_init); -+module_exit(jz4750fb_cleanup); -diff -urN linux-2.6.24.7.old/drivers/video/jz4750_lcd.h linux-2.6.24.7/drivers/video/jz4750_lcd.h ---- linux-2.6.24.7.old/drivers/video/jz4750_lcd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4750_lcd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,756 @@ -+/* -+ * linux/drivers/video/jz4750_lcd.h -- Ingenic Jz4750 On-Chip LCD frame buffer device -+ * -+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. -+ * -+ * 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 __JZ4750_LCD_H__ -+#define __JZ4750_LCD_H__ -+ -+//#include -+ -+ -+#define NR_PALETTE 256 -+#define PALETTE_SIZE (NR_PALETTE*2) -+ -+/* use new descriptor(8 words) */ -+struct jz4750_lcd_dma_desc { -+ unsigned int next_desc; /* LCDDAx */ -+ unsigned int databuf; /* LCDSAx */ -+ unsigned int frame_id; /* LCDFIDx */ -+ unsigned int cmd; /* LCDCMDx */ -+ unsigned int offsize; /* Stride Offsize(in word) */ -+ unsigned int page_width; /* Stride Pagewidth(in word) */ -+ unsigned int cmd_num; /* Command Number(for SLCD) */ -+ unsigned int desc_size; /* Foreground Size */ -+}; -+ -+struct jz4750lcd_panel_t { -+ unsigned int cfg; /* panel mode and pin usage etc. */ -+ unsigned int slcd_cfg; /* Smart lcd configurations */ -+ unsigned int ctrl; /* lcd controll register */ -+ unsigned int w; /* Panel Width(in pixel) */ -+ unsigned int h; /* Panel Height(in line) */ -+ unsigned int fclk; /* frame clk */ -+ unsigned int hsw; /* hsync width, in pclk */ -+ unsigned int vsw; /* vsync width, in line count */ -+ unsigned int elw; /* end of line, in pclk */ -+ unsigned int blw; /* begin of line, in pclk */ -+ unsigned int efw; /* end of frame, in line count */ -+ unsigned int bfw; /* begin of frame, in line count */ -+}; -+ -+ -+struct jz4750lcd_fg_t { -+ int bpp; /* foreground bpp */ -+ int x; /* foreground start position x */ -+ int y; /* foreground start position y */ -+ int w; /* foreground width */ -+ int h; /* foreground height */ -+}; -+ -+struct jz4750lcd_osd_t { -+ unsigned int osd_cfg; /* OSDEN, ALHPAEN, F0EN, F1EN, etc */ -+ unsigned int osd_ctrl; /* IPUEN, OSDBPP, etc */ -+ unsigned int rgb_ctrl; /* RGB Dummy, RGB sequence, RGB to YUV */ -+ unsigned int bgcolor; /* background color(RGB888) */ -+ unsigned int colorkey0; /* foreground0's Colorkey enable, Colorkey value */ -+ unsigned int colorkey1; /* foreground1's Colorkey enable, Colorkey value */ -+ unsigned int alpha; /* ALPHAEN, alpha value */ -+ unsigned int ipu_restart; /* IPU Restart enable, ipu restart interval time */ -+ -+#define FG_NOCHANGE 0x0000 -+#define FG0_CHANGE_SIZE 0x0001 -+#define FG0_CHANGE_POSITION 0x0002 -+#define FG1_CHANGE_SIZE 0x0010 -+#define FG1_CHANGE_POSITION 0x0020 -+#define FG_CHANGE_ALL ( FG0_CHANGE_SIZE | FG0_CHANGE_POSITION | \ -+ FG1_CHANGE_SIZE | FG1_CHANGE_POSITION ) -+ int fg_change; -+ struct jz4750lcd_fg_t fg0; /* foreground 0 */ -+ struct jz4750lcd_fg_t fg1; /* foreground 1 */ -+}; -+ -+struct jz4750lcd_info { -+ struct jz4750lcd_panel_t panel; -+ struct jz4750lcd_osd_t osd; -+}; -+ -+ -+/* Jz LCDFB supported I/O controls. */ -+#define FBIOSETBACKLIGHT 0x4688 /* set back light level */ -+#define FBIODISPON 0x4689 /* display on */ -+#define FBIODISPOFF 0x468a /* display off */ -+#define FBIORESET 0x468b /* lcd reset */ -+#define FBIOPRINT_REG 0x468c /* print lcd registers(debug) */ -+#define FBIOROTATE 0x46a0 /* rotated fb */ -+#define FBIOGETBUFADDRS 0x46a1 /* get buffers addresses */ -+#define FBIO_GET_MODE 0x46a2 /* get lcd info */ -+#define FBIO_SET_MODE 0x46a3 /* set osd mode */ -+#define FBIO_DEEP_SET_MODE 0x46a4 /* set panel and osd mode */ -+#define FBIO_MODE_SWITCH 0x46a5 /* switch mode between LCD and TVE */ -+#define FBIO_GET_TVE_MODE 0x46a6 /* get tve info */ -+#define FBIO_SET_TVE_MODE 0x46a7 /* set tve mode */ -+ -+/* -+ * LCD panel specific definition -+ */ -+/* AUO */ -+#if defined(CONFIG_JZ4750_LCD_AUO_A043FL01V2) -+#if defined(CONFIG_JZ4750_APUS) /* board pavo */ -+ #define SPEN (32*3+29) /*LCD_CS*/ -+ #define SPCK (32*3+26) /*LCD_SCL*/ -+ #define SPDA (32*3+27) /*LCD_SDA*/ -+ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/ -+#elif defined(CONFIG_JZ4750_FUWA) /* board pavo */ -+ #define SPEN (32*3+29) /*LCD_CS*/ -+ #define SPCK (32*3+26) /*LCD_SCL*/ -+ #define SPDA (32*3+27) /*LCD_SDA*/ -+ #define LCD_RET (32*5+2) /*LCD_DISP_N use for lcd reset*/ -+#else -+#error "driver/video/Jzlcd.h, please define SPI pins on your board." -+#endif -+ -+#define __spi_write_reg(reg, val) \ -+ do { \ -+ unsigned char no; \ -+ unsigned short value; \ -+ unsigned char a=0; \ -+ unsigned char b=0; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ a=reg; \ -+ b=val; \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(50); \ -+ value=((a<<8)|(b&0xFF)); \ -+ for(no=0;no<16;no++) \ -+ { \ -+ if((value&0x8000)==0x8000){ \ -+ __gpio_set_pin(SPDA);} \ -+ else{ \ -+ __gpio_clear_pin(SPDA); } \ -+ udelay(50); \ -+ __gpio_set_pin(SPCK); \ -+ value=(value<<1); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPCK); \ -+ } \ -+ __gpio_set_pin(SPEN); \ -+ udelay(400); \ -+ } while (0) -+#define __spi_read_reg(reg,val) \ -+ do{ \ -+ unsigned char no; \ -+ unsigned short value; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ value = ((reg << 0) | (1 << 7)); \ -+ val = 0; \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(50); \ -+ for (no = 0; no < 16; no++ ) { \ -+ udelay(50); \ -+ if(no < 8) \ -+ { \ -+ if (value & 0x80) /* send data */ \ -+ __gpio_set_pin(SPDA); \ -+ else \ -+ __gpio_clear_pin(SPDA); \ -+ udelay(50); \ -+ __gpio_set_pin(SPCK); \ -+ value = (value << 1); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPCK); \ -+ if(no == 7) \ -+ __gpio_as_input(SPDA); \ -+ } \ -+ else \ -+ { \ -+ udelay(100); \ -+ __gpio_set_pin(SPCK); \ -+ udelay(50); \ -+ val = (val << 1); \ -+ val |= __gpio_get_pin(SPDA); \ -+ __gpio_clear_pin(SPCK); \ -+ } \ -+ } \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ udelay(400); \ -+ } while(0) -+ -+#define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ __gpio_as_output(LCD_RET); \ -+ udelay(50); \ -+ __gpio_clear_pin(LCD_RET); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RET); \ -+ } while (0) -+#define __lcd_special_on() \ -+ do { \ -+ udelay(50); \ -+ __gpio_clear_pin(LCD_RET); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RET); \ -+} while (0) -+ -+ #define __lcd_special_off() \ -+ do { \ -+ __gpio_clear_pin(LCD_RET); \ -+ } while (0) -+ -+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ -+ -+/* TRULY_TFTG320240DTSW */ -+#if defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_16BIT) || defined(CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW_18BIT) -+ -+#if defined(CONFIG_JZ4750_FUWA) -+#define LCD_RESET_PIN (32*3+25)// LCD_REV, GPD25 -+#else -+#error "Define LCD_RESET_PIN on your board" -+#endif -+ -+#define __lcd_special_on() \ -+do { \ -+ __gpio_as_output(32*3+30);\ -+ __gpio_clear_pin(32*3+30);\ -+ __gpio_as_output(LCD_RESET_PIN); \ -+ __gpio_set_pin(LCD_RESET_PIN); \ -+ udelay(100); \ -+ __gpio_clear_pin(LCD_RESET_PIN); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RESET_PIN); \ -+} while (0) -+ -+#endif /* CONFIG_JZ4750_LCD_TRULY_TFTG320240DTSW */ -+ -+// Wolfgang 2008.02.23 -+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA) || defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY) -+ -+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA) -+#define PANEL_MODE 0x02 /* RGB Delta */ -+#elif defined(CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DUMMY) -+#define PANEL_MODE 0x00 /* RGB Dummy */ -+#endif -+ -+#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */ -+ #define SPEN (32*3+16) //LCD_D16 - GPD16 -+ #define SPCK (32*3+17) //LCD_D17 - GPD17 -+ #define SPDA (32*3+21) //LCD_DE - GPD21 -+ #define LCD_RET (32*3+25) //LCD_REV - GPD25 //use for lcd reset -+#else -+#error "please define SPI pins on your board." -+#endif -+ -+ #define __spi_write_reg1(reg, val) \ -+ do { \ -+ unsigned char no;\ -+ unsigned short value;\ -+ unsigned char a=0;\ -+ unsigned char b=0;\ -+ a=reg;\ -+ b=val;\ -+ __gpio_set_pin(SPEN);\ -+ udelay(100);\ -+ __gpio_clear_pin(SPCK);\ -+ __gpio_clear_pin(SPDA);\ -+ __gpio_clear_pin(SPEN);\ -+ udelay(25);\ -+ value=((a<<8)|(b&0xFF));\ -+ for(no=0;no<16;no++)\ -+ {\ -+ __gpio_clear_pin(SPCK);\ -+ if((value&0x8000)==0x8000)\ -+ __gpio_set_pin(SPDA);\ -+ else\ -+ __gpio_clear_pin(SPDA);\ -+ udelay(25);\ -+ __gpio_set_pin(SPCK);\ -+ value=(value<<1); \ -+ udelay(25);\ -+ }\ -+ __gpio_clear_pin(SPCK);\ -+ __gpio_set_pin(SPEN);\ -+ udelay(100);\ -+ } while (0) -+ -+ #define __spi_write_reg(reg, val) \ -+ do {\ -+ __spi_write_reg1((reg<<2), val); \ -+ udelay(100); \ -+ }while(0) -+ -+ #define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */\ -+ __gpio_as_output(SPCK); /* use SPCK */\ -+ __gpio_as_output(SPDA); /* use SPDA */\ -+ __gpio_as_output(SPDA); /* use reset */\ -+ __gpio_as_output(LCD_RET); /* use reset */\ -+ __gpio_set_pin(LCD_RET);\ -+ mdelay(15);\ -+ __gpio_clear_pin(LCD_RET);\ -+ mdelay(15);\ -+ __gpio_set_pin(LCD_RET);\ -+ } while (0) -+ -+ #define __lcd_special_on() \ -+ do { \ -+ mdelay(10); \ -+ __spi_write_reg(0x00, 0x10); \ -+ __spi_write_reg(0x01, 0xB1); \ -+ __spi_write_reg(0x00, 0x10); \ -+ __spi_write_reg(0x01, 0xB1); \ -+ __spi_write_reg(0x02, PANEL_MODE); /* RGBD MODE */ \ -+ __spi_write_reg(0x03, 0x01); /* Noninterlace*/ \ -+ mdelay(10); \ -+ } while (0) -+ -+ #define __lcd_special_off() \ -+ do { \ -+ } while (0) -+ -+#endif /* CONFIG_JZ4750_LCD_TOPPOLY_TD025THEA7_RGB_DELTA */ -+ -+ -+#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) || defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) -+ -+#if defined(CONFIG_JZ4750_LCD_FOXCONN_PT035TN01) /* board FUWA */ -+#define MODE 0xcd /* 24bit parellel RGB */ -+#endif -+#if defined(CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL) -+#define MODE 0xc9 /* 8bit serial RGB */ -+#endif -+ -+#if defined(CONFIG_JZ4750_FUWA) /* board FuWa */ -+#if 0 -+ #define SPEN (32*5+7) //LCD_SPL GPF7 -+ #define SPCK (32*5+6) //LCD_CLS GPF6 -+ #define SPDA (32*5+5) //LCD_PS GPF5 -+ #define LCD_RET (32*5+4) //LCD_REV GPF4 //use for lcd reset -+#endif -+ #define SPEN (32*3+29) /*LCD_CS*/ -+ #define SPCK (32*3+26) /*LCD_SCL*/ -+ #define SPDA (32*3+27) /*LCD_SDA*/ -+ #define LCD_RET (32*4+25) /*LCD_DISP_N use for lcd reset*/ -+#else -+#error "driver/video/Jzlcd.h, please define SPI pins on your board." -+#endif -+ -+ #define __spi_write_reg1(reg, val) \ -+ do { \ -+ unsigned char no;\ -+ unsigned short value;\ -+ unsigned char a=0;\ -+ unsigned char b=0;\ -+ a=reg;\ -+ b=val;\ -+ __gpio_set_pin(SPEN);\ -+ __gpio_set_pin(SPCK);\ -+ __gpio_clear_pin(SPDA);\ -+ __gpio_clear_pin(SPEN);\ -+ udelay(25);\ -+ value=((a<<8)|(b&0xFF));\ -+ for(no=0;no<16;no++)\ -+ {\ -+ __gpio_clear_pin(SPCK);\ -+ if((value&0x8000)==0x8000)\ -+ __gpio_set_pin(SPDA);\ -+ else\ -+ __gpio_clear_pin(SPDA);\ -+ udelay(25);\ -+ __gpio_set_pin(SPCK);\ -+ value=(value<<1); \ -+ udelay(25);\ -+ }\ -+ __gpio_set_pin(SPEN);\ -+ udelay(100);\ -+ } while (0) -+ -+ #define __spi_write_reg(reg, val) \ -+ do {\ -+ __spi_write_reg1((reg<<2|2), val); \ -+ udelay(100); \ -+ }while(0) -+ -+ #define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */\ -+ __gpio_as_output(SPCK); /* use SPCK */\ -+ __gpio_as_output(SPDA); /* use SPDA */\ -+ __gpio_as_output(LCD_RET);\ -+ udelay(50);\ -+ __gpio_clear_pin(LCD_RET);\ -+ mdelay(150);\ -+ __gpio_set_pin(LCD_RET);\ -+ } while (0) -+ -+ #define __lcd_special_on() \ -+ do { \ -+ udelay(50);\ -+ __gpio_clear_pin(LCD_RET);\ -+ mdelay(150);\ -+ __gpio_set_pin(LCD_RET);\ -+ mdelay(10);\ -+ __spi_write_reg(0x00, 0x03); \ -+ __spi_write_reg(0x01, 0x40); \ -+ __spi_write_reg(0x02, 0x11); \ -+ __spi_write_reg(0x03, MODE); /* mode */ \ -+ __spi_write_reg(0x04, 0x32); \ -+ __spi_write_reg(0x05, 0x0e); \ -+ __spi_write_reg(0x07, 0x03); \ -+ __spi_write_reg(0x08, 0x08); \ -+ __spi_write_reg(0x09, 0x32); \ -+ __spi_write_reg(0x0A, 0x88); \ -+ __spi_write_reg(0x0B, 0xc6); \ -+ __spi_write_reg(0x0C, 0x20); \ -+ __spi_write_reg(0x0D, 0x20); \ -+ } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ -+/* __spi_write_reg(0x02, 0x03); \ -+ __spi_write_reg(0x06, 0x40); \ -+ __spi_write_reg(0x0a, 0x11); \ -+ __spi_write_reg(0x0e, 0xcd); \ -+ __spi_write_reg(0x12, 0x32); \ -+ __spi_write_reg(0x16, 0x0e); \ -+ __spi_write_reg(0x1e, 0x03); \ -+ __spi_write_reg(0x22, 0x08); \ -+ __spi_write_reg(0x26, 0x40); \ -+ __spi_write_reg(0x2a, 0x88); \ -+ __spi_write_reg(0x2e, 0x88); \ -+ __spi_write_reg(0x32, 0x20); \ -+ __spi_write_reg(0x36, 0x20); \ -+*/ -+// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ -+ #define __lcd_special_off() \ -+ do { \ -+ __spi_write_reg(0x00, 0x03); \ -+ } while (0) -+ -+#endif /* CONFIG_JZ4750_LCD_FOXCONN_PT035TN01 or CONFIG_JZ4750_LCD_INNOLUX_PT035TN01_SERIAL */ -+ -+#if defined(CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W) -+static inline void CmdWrite(unsigned int cmd) -+{ -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ -+ udelay(30); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; -+} -+ -+static inline void DataWrite(unsigned int data) -+{ -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); /* wait slcd ready */ -+// udelay(30); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; -+} -+ -+ -+static inline void delay(long delay_time) -+{ -+ long cnt; -+ -+// delay_time *= (384/8); -+ delay_time *= (43/8); -+ -+ for (cnt=0;cnt SETP 3 -+ CmdWrite(0x0000); -+ CmdWrite(0x01A0); -+ CmdWrite(0x3B01); -+ -+ CmdWrite(0x2809); -+ delay(1000); -+ CmdWrite(0x1900); -+ delay(1000); -+ CmdWrite(0x2110); -+ delay(1000); -+ CmdWrite(0x1805); -+ delay(1000); -+ CmdWrite(0x1E01); -+ delay(1000); -+ CmdWrite(0x1847); -+ delay(1000); -+ CmdWrite(0x1867); -+ delay(1000); -+ CmdWrite(0x18F7); -+ delay(1000); -+ CmdWrite(0x2100); -+ delay(1000); -+ CmdWrite(0x2809); -+ delay(1000); -+ CmdWrite(0x1A05); -+ delay(1000); -+ CmdWrite(0x19E8); -+ delay(1000); -+ CmdWrite(0x1F64); -+ delay(1000); -+ CmdWrite(0x2045); -+ delay(1000); -+ CmdWrite(0x1E81); -+ delay(1000); -+ CmdWrite(0x1B09); -+ delay(1000); -+ CmdWrite(0x0020); -+ delay(1000); -+ CmdWrite(0x0120); -+ delay(1000); -+ -+ CmdWrite(0x3B01); -+ delay(1000); -+ -+ /* Set Window(239,319), Set Cursor(239,319) */ -+ CmdWrite(0x0510); -+ CmdWrite(0x01C0); -+ CmdWrite(0x4500); -+ CmdWrite(0x46EF); -+ CmdWrite(0x4800); -+ CmdWrite(0x4700); -+ CmdWrite(0x4A3F); -+ CmdWrite(0x4901); -+ CmdWrite(0x42EF); -+ CmdWrite(0x443F); -+ CmdWrite(0x4301); -+ -+} -+ -+#if defined(CONFIG_JZ4750_FUWA) -+//#define PIN_CS_N (32*2+xx) /* a low voltage */ -+#define PIN_RD_N (32*3+21) /* LCD_DE: GP D21, a high voltage */ -+#define PIN_RESET_N (32*3+25) /* LCD_REV GP D25 */ -+#else -+#error "Define special lcd pins for your platform." -+#endif -+ -+#define __lcd_slcd_pin_init() \ -+ do { \ -+ __gpio_as_output(PIN_RD_N); /* RD#: LCD_REV */ \ -+ __gpio_as_output(PIN_RESET_N); /* RESET#: LCD_SPL */ \ -+ __gpio_set_pin(PIN_RD_N); /*set read signal high */ \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+ __gpio_clear_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ /* Configure SLCD module */ \ -+ REG_LCD_CTRL &= ~(LCD_CTRL_ENA|LCD_CTRL_DIS); /* disable lcdc */ \ -+ REG_LCD_CFG = LCD_CFG_LCDPIN_SLCD | 0x0D; /* LCM */ \ -+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; /* disable slcd dma */ \ -+ REG_SLCD_CFG = SLCD_CFG_DWIDTH_16BIT | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING | SLCD_CFG_TYPE_PARALLEL; \ -+ REG_LCD_REV = 0x04; /* lcd clock??? */ \ -+ printk("Fuwa test, pixclk divide REG_LCD_REV=0x%08x\n", REG_LCD_REV); \ -+}while (0) -+ -+#define __lcd_slcd_special_on() \ -+ do { \ -+ __lcd_slcd_pin_init(); \ -+ SlcdInit(); \ -+ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \ -+ } while (0) -+ -+#endif /* #if CONFIG_JZ4750_LCD_TRULY_TFT_GG1P0319LTSW_W */ -+ -+#ifndef __lcd_special_pin_init -+#define __lcd_special_pin_init() -+#endif -+#ifndef __lcd_special_on -+#define __lcd_special_on() -+#endif -+#ifndef __lcd_special_off -+#define __lcd_special_off() -+#endif -+ -+ -+/* -+ * Platform specific definition -+ */ -+#if defined(CONFIG_SOC_JZ4750) -+ -+#if defined(CONFIG_JZ4750_APUS) /* board apus */ -+#define __lcd_display_pin_init() \ -+do { \ -+ __gpio_as_output(GPIO_LCD_VCC_EN_N); \ -+ __lcd_special_pin_init(); \ -+} while (0) -+#define __lcd_display_on() \ -+do { \ -+ __gpio_clear_pin(GPIO_LCD_VCC_EN_N); \ -+ __lcd_special_on(); \ -+ __lcd_set_backlight_level(80); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_close_backlight(); \ -+ __lcd_special_off(); \ -+} while (0) -+ -+#else /* other boards */ -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __lcd_special_pin_init(); \ -+} while (0) -+#define __lcd_display_on() \ -+do { \ -+ __lcd_special_on(); \ -+ __lcd_set_backlight_level(80); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_close_backlight(); \ -+ __lcd_special_off(); \ -+} while (0) -+#endif /* APUS */ -+#endif /* CONFIG_SOC_JZ4750 */ -+ -+ -+/***************************************************************************** -+ * LCD display pin dummy macros -+ *****************************************************************************/ -+ -+#ifndef __lcd_display_pin_init -+#define __lcd_display_pin_init() -+#endif -+#ifndef __lcd_slcd_special_on -+#define __lcd_slcd_special_on() -+#endif -+#ifndef __lcd_display_on -+#define __lcd_display_on() -+#endif -+#ifndef __lcd_display_off -+#define __lcd_display_off() -+#endif -+#ifndef __lcd_set_backlight_level -+#define __lcd_set_backlight_level(n) -+#endif -+ -+#endif /* __JZ4750_LCD_H__ */ -diff -urN linux-2.6.24.7.old/drivers/video/jz4750_tve.c linux-2.6.24.7/drivers/video/jz4750_tve.c ---- linux-2.6.24.7.old/drivers/video/jz4750_tve.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4750_tve.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,104 @@ -+ -+/* -+ * linux/drivers/video/jz4750_tve.c -- Ingenic Jz4750 TVE Controller operation -+ * interface. -+ * Copyright (C) 2005-2008, Ingenic Semiconductor Inc. -+ * Author: Wolfgang Wang, -+ * -+ * 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. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+ -+#include -+#include "jz4750_tve.h" -+ -+struct jz4750tve_info jz4750_tve_info_PAL = { -+ .ctrl = (4 << TVE_CTRL_YCDLY_BIT) | TVE_CTRL_SYNCT | TVE_CTRL_PAL | TVE_CTRL_SWRST, /* PAL, SVIDEO */ -+ .frcfg = (23 << TVE_FRCFG_L1ST_BIT) | (625 << TVE_FRCFG_NLINE_BIT), -+ .slcfg1 = (800<ctrl = (jz4750_tve_info->ctrl | TVE_CTRL_DAPD) & ( ~( TVE_CTRL_DAPD1 | TVE_CTRL_DAPD2)); -+ jz4750_tve_info->ctrl &= ~TVE_CTRL_SWRST; -+ REG_TVE_CTRL = jz4750_tve_info->ctrl; -+} -+ -+/* turn off TVE, turn off DACn... */ -+void jz4750tve_disable_tve(void) -+{ -+ jz4750_tve_info->ctrl &= ~TVE_CTRL_DAPD;/* DACn disabled??? */ -+ jz4750_tve_info->ctrl |= TVE_CTRL_SWRST;/* DACn disabled??? */ -+ REG_TVE_CTRL = jz4750_tve_info->ctrl; -+} -+ -+void jz4750tve_set_tve_mode( struct jz4750tve_info *tve ) -+{ -+ REG_TVE_CTRL = tve->ctrl; -+ REG_TVE_FRCFG = tve->frcfg; -+ REG_TVE_SLCFG1 = tve->slcfg1; -+ REG_TVE_SLCFG2 = tve->slcfg2; -+ REG_TVE_SLCFG3 = tve->slcfg3; -+ REG_TVE_LTCFG1 = tve->ltcfg1; -+ REG_TVE_LTCFG2 = tve->ltcfg2; -+ REG_TVE_CFREQ = tve->cfreq; -+ REG_TVE_CPHASE = tve->cphase; -+ REG_TVE_CBCRCFG = tve->cbcrcfg; -+ REG_TVE_WSSCR = tve->wsscr; -+ REG_TVE_WSSCFG1 = tve->wsscfg1; -+ REG_TVE_WSSCFG2 = tve->wsscfg2; -+ REG_TVE_WSSCFG3 = tve->wsscfg3; -+} -+ -+void jz4750tve_init( int tve_mode ) -+{ -+ switch ( tve_mode ) { -+ case PANEL_MODE_TVE_PAL: -+ jz4750_tve_info = &jz4750_tve_info_PAL; -+ break; -+ case PANEL_MODE_TVE_NTSC: -+ jz4750_tve_info = &jz4750_tve_info_NTSC; -+ break; -+ } -+ -+ jz4750tve_set_tve_mode( jz4750_tve_info ); -+// jz4750tve_enable_tve(); -+} -diff -urN linux-2.6.24.7.old/drivers/video/jz4750_tve.h linux-2.6.24.7/drivers/video/jz4750_tve.h ---- linux-2.6.24.7.old/drivers/video/jz4750_tve.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz4750_tve.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,45 @@ -+#ifndef __JZ4750_TVE_H__ -+#define __JZ4750_TVE_H__ -+ -+ -+#define PANEL_MODE_LCD_PANEL 0 -+#define PANEL_MODE_TVE_PAL 1 -+#define PANEL_MODE_TVE_NTSC 2 -+ -+/* TV parameter */ -+#define TVE_WIDTH_PAL 720 -+#define TVE_HEIGHT_PAL 573 -+#define TVE_FREQ_PAL 50 -+#define TVE_WIDTH_NTSC 720 -+#define TVE_HEIGHT_NTSC 482 -+#define TVE_FREQ_NTSC 60 -+ -+ -+/* Structure for TVE */ -+struct jz4750tve_info { -+ unsigned int ctrl; -+ unsigned int frcfg; -+ unsigned int slcfg1; -+ unsigned int slcfg2; -+ unsigned int slcfg3; -+ unsigned int ltcfg1; -+ unsigned int ltcfg2; -+ unsigned int cfreq; -+ unsigned int cphase; -+ unsigned int cbcrcfg; -+ unsigned int wsscr; -+ unsigned int wsscfg1; -+ unsigned int wsscfg2; -+ unsigned int wsscfg3; -+}; -+ -+extern struct jz4750tve_info *jz4750_tve_info; -+ -+extern void jz4750tve_enable_tve(void); -+extern void jz4750tve_disable_tve(void); -+ -+extern void jz4750tve_set_tve_mode( struct jz4750tve_info *tve ); -+extern void jz4750tve_init( int tve_mode ); -+ -+ -+#endif /* __JZ4750_TVE_H__ */ -diff -urN linux-2.6.24.7.old/drivers/video/jz_kgm_spfd5420a.h linux-2.6.24.7/drivers/video/jz_kgm_spfd5420a.h ---- linux-2.6.24.7.old/drivers/video/jz_kgm_spfd5420a.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz_kgm_spfd5420a.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,382 @@ -+/* Set registers of smart lcd acording to the following routines -+ * Note: BUS width and CMD width and register value width -+ * This example: BUS is 8, 9, 16 or 18-bit; CMD and DATA is 16-bit -+ * Configure SLCD module to initialize smart lcd registers -+ -+ switch (bus) { -+ case 8: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_8bit(); -+ break; -+ case 9: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_8_x2 -+ | SLCD_CFG_CWIDTH_8BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_9bit(); -+ break; -+ case 16: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_16 -+ | SLCD_CFG_CWIDTH_16BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_16bit(); -+ break; -+ case 18: -+ REG_SLCD_CFG = SLCD_CFG_BURST_8_WORD | SLCD_CFG_DWIDTH_18 -+ | SLCD_CFG_CWIDTH_18BIT | SLCD_CFG_CS_ACTIVE_LOW -+ | SLCD_CFG_RS_CMD_LOW | SLCD_CFG_CLK_ACTIVE_FALLING -+ | SLCD_CFG_TYPE_PARALLEL; -+ __gpio_as_slcd_18bit(); -+ break; -+ } -+ -+ static void Mcupanel_RegSet(unsigned int cmd, unsigned int data) -+ { -+ switch (bus) { -+ case 8: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); -+ break; -+ case 9: -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ data = ((data << 6) & 0xfc0000) | ((data << 4) & 0xfc00) | ((data << 2) & 0xfc); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; -+ break; -+ case 16: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | (data&0xffff); -+ break; -+ case 18: -+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); -+ break; -+ default: -+ printk("Don't support %d bit Bus\n", jzfb.bus ); -+ break; -+ } -+ } -+ -+ static void Mcupanel_Command(unsigned int cmd) { -+ switch (bus) { -+ case 8: -+ case 9: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) >> 8); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff) >> 0); -+ break; -+ case 16: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | (cmd&0xffff); -+ break; -+ case 18: -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); -+ break; -+ default: -+ printk("Don't support %d bit Bus\n", jzfb.bus ); -+ break; -+ } -+ } -+ -+ *Display---------------------------------------- -+ Note: BUS and BPP, send data to gram data register to display -+ BUS: 8, 9, 16 or 18-bit; BPP: 8, 16, 18-bit -+ switch (bus) { -+ case 8: -+ switch (bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15: -+ case 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 9: -+ switch (bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15 ... 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x2; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_9_x2; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 16: -+ switch (bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15 ... 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x3; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ case 18: -+ switch (bpp) { -+ case 8: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_8_x1; -+ break; -+ case 15: -+ case 16: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_16; -+ break; -+ case 17 ... 32: -+ REG_SLCD_CFG &= ~SLCD_CFG_DWIDTH_MASK; -+ REG_SLCD_CFG |= SLCD_CFG_DWIDTH_18; -+ break; -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ break; -+ } -+ break; -+ default: -+ printk("Error: The BUS %d is not supported\n", jzfb.bus); -+ break; -+ } -+ dprintk("SLCD_CFG=0x%x\n", REG_SLCD_CFG); -+} -+ ************************************************************************************************/ -+ -+#ifndef __JZ_KGM_SPF5420A_H__ -+#define __JZ_KGM_SPF5420A_H__ -+ -+#include -+ -+#if defined(CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A) -+#define WR_GRAM_CMD 0x0202 -+ -+#if defined(CONFIG_JZ4750_FUWA) -+#define PIN_CS_N (32*3+24) // Chip select //GPD24; -+#define PIN_RESET_N (32*5+6) /* LCD_REV GPF6 */ -+#else -+#error "Define special lcd pins for your platform." -+#endif -+ -+/* Sent a command with data (18-bit bus, 16-bit index, 16-bit register value) */ -+static void Mcupanel_RegSet(unsigned int cmd, unsigned int data) -+{ -+ cmd = ((cmd & 0xff) << 1) | ((cmd & 0xff00) << 2); -+ data = ((data & 0xff) << 1) | ((data & 0xff00) << 2); -+ data = ((data<<6)&0xfc0000)|((data<<4)&0xfc00) | ((data<<2)&0xfc); -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | cmd; -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_DATA | data; -+} -+ -+/* Sent a command without data (18-bit bus, 16-bit index) */ -+static void Mcupanel_Command(unsigned int cmd) { -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); -+ REG_SLCD_DATA = SLCD_DATA_RS_COMMAND | ((cmd&0xff00) << 2) | ((cmd&0xff) << 1); -+} -+ -+/* Set the start address of screen, for example (0, 0) */ -+void Mcupanel_SetAddr(u32 x, u32 y) //u32 -+{ -+ Mcupanel_RegSet(0x200,x) ; -+ udelay(1); -+ Mcupanel_RegSet(0x201,y) ; -+ udelay(1); -+ Mcupanel_Command(0x202); -+ -+} -+ -+#undef __lcd_special_pin_init -+#define __lcd_special_pin_init() \ -+do { \ -+ __gpio_as_output(PIN_CS_N); \ -+ __gpio_as_output(PIN_RESET_N); \ -+ __gpio_clear_pin(PIN_CS_N); /* Clear CS */ \ -+ mdelay(100); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_clear_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+} while(0) -+ -+ -+#define GAMMA() \ -+do { \ -+ Mcupanel_RegSet(0x0300,0x0101); \ -+ Mcupanel_RegSet(0x0301,0x0b27); \ -+ Mcupanel_RegSet(0x0302,0x132a); \ -+ Mcupanel_RegSet(0x0303,0x2a13); \ -+ Mcupanel_RegSet(0x0304,0x270b); \ -+ Mcupanel_RegSet(0x0305,0x0101); \ -+ Mcupanel_RegSet(0x0306,0x1205); \ -+ Mcupanel_RegSet(0x0307,0x0512); \ -+ Mcupanel_RegSet(0x0308,0x0005); \ -+ Mcupanel_RegSet(0x0309,0x0003); \ -+ Mcupanel_RegSet(0x030a,0x0f04); \ -+ Mcupanel_RegSet(0x030b,0x0f00); \ -+ Mcupanel_RegSet(0x030c,0x000f); \ -+ Mcupanel_RegSet(0x030d,0x040f); \ -+ Mcupanel_RegSet(0x030e,0x0300); \ -+ Mcupanel_RegSet(0x030f,0x0500); \ -+ /*** secorrect gamma2 ***/ \ -+ Mcupanel_RegSet(0x0400,0x3500); \ -+ Mcupanel_RegSet(0x0401,0x0001); \ -+ Mcupanel_RegSet(0x0404,0x0000); \ -+ Mcupanel_RegSet(0x0500,0x0000); \ -+ Mcupanel_RegSet(0x0501,0x0000); \ -+ Mcupanel_RegSet(0x0502,0x0000); \ -+ Mcupanel_RegSet(0x0503,0x0000); \ -+ Mcupanel_RegSet(0x0504,0x0000); \ -+ Mcupanel_RegSet(0x0505,0x0000); \ -+ Mcupanel_RegSet(0x0600,0x0000); \ -+ Mcupanel_RegSet(0x0606,0x0000); \ -+ Mcupanel_RegSet(0x06f0,0x0000); \ -+ Mcupanel_RegSet(0x07f0,0x5420); \ -+ Mcupanel_RegSet(0x07f3,0x288a); \ -+ Mcupanel_RegSet(0x07f4,0x0022); \ -+ Mcupanel_RegSet(0x07f5,0x0001); \ -+ Mcupanel_RegSet(0x07f0,0x0000); \ -+} while(0) -+ -+#define SlcdInit() \ -+do { \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_clear_pin(PIN_RESET_N); \ -+ mdelay(10); \ -+ __gpio_set_pin(PIN_RESET_N); \ -+ mdelay(100); \ -+ Mcupanel_RegSet(0x0600, 0x0001); /*soft reset*/ \ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0600, 0x0000); /*soft reset*/ \ -+ mdelay(10); \ -+ Mcupanel_RegSet(0x0606,0x0000); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0007,0x0001); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0110,0x0001); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0100,0x17b0); \ -+ Mcupanel_RegSet(0x0101,0x0147); \ -+ Mcupanel_RegSet(0x0102,0x019d); \ -+ Mcupanel_RegSet(0x0103,0x8600); \ -+ Mcupanel_RegSet(0x0281,0x0010); \ -+ udelay(10); \ -+ Mcupanel_RegSet(0x0102,0x01bd); \ -+ udelay(10); \ -+ /************initial************/\ -+ Mcupanel_RegSet(0x0000,0x0000); \ -+ Mcupanel_RegSet(0x0001,0x0000); \ -+ Mcupanel_RegSet(0x0002,0x0400); \ -+ Mcupanel_RegSet(0x0003,0x12b8); /*up:0x1288 down:0x12B8 left:0x1290 right:0x12A0*/ \ -+ Mcupanel_RegSet(0x0006,0x0000); \ -+ Mcupanel_RegSet(0x0008,0x0503); \ -+ Mcupanel_RegSet(0x0009,0x0001); \ -+ Mcupanel_RegSet(0x000b,0x0010); \ -+ Mcupanel_RegSet(0x000c,0x0000); \ -+ Mcupanel_RegSet(0x000f,0x0000); \ -+ Mcupanel_RegSet(0x0007,0x0001); \ -+ Mcupanel_RegSet(0x0010,0x0010); \ -+ Mcupanel_RegSet(0x0011,0x0202); \ -+ Mcupanel_RegSet(0x0012,0x0300); \ -+ Mcupanel_RegSet(0x0020,0x021e); \ -+ Mcupanel_RegSet(0x0021,0x0202); \ -+ Mcupanel_RegSet(0x0022,0x0100); \ -+ Mcupanel_RegSet(0x0090,0x0000); \ -+ Mcupanel_RegSet(0x0092,0x0000); \ -+ Mcupanel_RegSet(0x0100,0x16b0); \ -+ Mcupanel_RegSet(0x0101,0x0147); \ -+ Mcupanel_RegSet(0x0102,0x01bd); \ -+ Mcupanel_RegSet(0x0103,0x2c00); \ -+ Mcupanel_RegSet(0x0107,0x0000); \ -+ Mcupanel_RegSet(0x0110,0x0001); \ -+ Mcupanel_RegSet(0x0210,0x0000); \ -+ Mcupanel_RegSet(0x0211,0x00ef); \ -+ Mcupanel_RegSet(0x0212,0x0000); \ -+ Mcupanel_RegSet(0x0213,0x018f); \ -+ Mcupanel_RegSet(0x0280,0x0000); \ -+ Mcupanel_RegSet(0x0281,0x0001); \ -+ Mcupanel_RegSet(0x0282,0x0000); \ -+ GAMMA(); \ -+ Mcupanel_RegSet(0x0007,0x0173); \ -+ Mcupanel_Command(0x0202); /*Write Data to GRAM */ \ -+ udelay(10);\ -+ Mcupanel_SetAddr(0,0);\ -+ udelay(100);\ -+} while(0) -+ -+/*---- LCD Initial ----*/ -+#undef __lcd_slcd_pin_init -+#define __lcd_slcd_pin_init() \ -+ do { \ -+ __lcd_special_pin_init(); \ -+}while (0) -+ -+#undef __lcd_slcd_special_on -+#define __lcd_slcd_special_on() \ -+ do { \ -+ __lcd_slcd_pin_init(); \ -+ SlcdInit(); \ -+ REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN; /* slcdc dma enable */ \ -+ } while (0) -+ -+#define __init_slcd_bus()\ -+do{\ -+ __slcd_set_data_18bit();\ -+ __slcd_set_cmd_18bit();\ -+ __slcd_set_cs_low();\ -+ __slcd_set_rs_low();\ -+ __slcd_set_clk_falling();\ -+ __slcd_set_parallel_type();\ -+}while(0) -+#endif /* #if CONFIG_JZ4750_SLCD_KGM701A3_TFT_SPFD5420A */ -+ -+#endif /* __JZ_KGM_SPF5420A_H__ */ -diff -urN linux-2.6.24.7.old/drivers/video/jz_toppoly_td043mgeb1.h linux-2.6.24.7/drivers/video/jz_toppoly_td043mgeb1.h ---- linux-2.6.24.7.old/drivers/video/jz_toppoly_td043mgeb1.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jz_toppoly_td043mgeb1.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,264 @@ -+ -+#ifndef __JZ_KGM_TOPPOLY_TD043MGEB1_H__ -+#define __JZ_KGM_TOPPOLY_TD043MGEB1_H__ -+ -+#include -+ -+#if defined(CONFIG_JZ4750_LCD_TOPPOLY_TD043MGEB1) -+#if defined(CONFIG_JZ4750_APUS) /* board FuWa */ -+ #define SPEN (32*3+29) /*LCD_CS*/ -+ #define SPCK (32*3+26) /*LCD_SCL*/ -+ #define SPDA (32*3+27) /*LCD_SDA*/ -+ #define LCD_RET (32*4+23) /*LCD_DISP_N use for lcd reset*/ -+ #define LCD_STBY (32*4+25) /*LCD_STBY, use for lcd standby*/ -+#else -+#error "driver/video/Jzlcd.h, please define SPI pins on your board." -+#endif -+ -+#define __spi_write_reg(reg, val) \ -+ do { \ -+ unsigned char no; \ -+ unsigned short value; \ -+ unsigned char a=0; \ -+ unsigned char b=0; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ a=reg; \ -+ b=val; \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(500); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(500); \ -+ value=((a<<8)|(b&0xFF)); \ -+ for(no=0;no<16;no++) \ -+ { \ -+ if((value&0x8000)==0x8000){ \ -+ __gpio_set_pin(SPDA);} \ -+ else{ \ -+ __gpio_clear_pin(SPDA); } \ -+ udelay(500); \ -+ __gpio_set_pin(SPCK); \ -+ value=(value<<1); \ -+ udelay(500); \ -+ __gpio_clear_pin(SPCK); \ -+ } \ -+ __gpio_set_pin(SPEN); \ -+ udelay(4000); \ -+ } while (0) -+#define __spi_read_reg(reg,val) \ -+ do{ \ -+ unsigned char no; \ -+ unsigned short value; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ value = ((reg << 0) | (1 << 7)); \ -+ val = 0; \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(50); \ -+ for (no = 0; no < 16; no++ ) { \ -+ udelay(50); \ -+ if(no < 8) \ -+ { \ -+ if (value & 0x80) /* send data */ \ -+ __gpio_set_pin(SPDA); \ -+ else \ -+ __gpio_clear_pin(SPDA); \ -+ udelay(50); \ -+ __gpio_set_pin(SPCK); \ -+ value = (value << 1); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPCK); \ -+ if(no == 7) \ -+ __gpio_as_input(SPDA); \ -+ } \ -+ else \ -+ { \ -+ udelay(100); \ -+ __gpio_set_pin(SPCK); \ -+ udelay(50); \ -+ val = (val << 1); \ -+ val |= __gpio_get_pin(SPDA); \ -+ __gpio_clear_pin(SPCK); \ -+ } \ -+ } \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ udelay(400); \ -+ } while(0) -+ -+#define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ __gpio_as_output(LCD_STBY); \ -+ __gpio_as_output(LCD_RET); \ -+ udelay(500); \ -+ __gpio_clear_pin(LCD_RET); \ -+ udelay(1000); \ -+ __gpio_set_pin(LCD_RET); \ -+ udelay(1000); \ -+ __gpio_set_pin(LCD_STBY); \ -+ udelay(1000); \ -+ } while (0) -+#define __lcd_special_on() \ -+ do { \ -+} while (0) -+ -+ #define __lcd_special_off() \ -+ do { \ -+ __gpio_clear_pin(LCD_RET); \ -+ } while (0) -+ -+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ -+ -+#endif /* __JZ_KGM_TOPPOLY_TD043MGEB1_H__ */ -+/* 2.2 -+ __spi_write_reg(0x02, 0x07 ); \ -+ __spi_write_reg(0x03, 0x5f); \ -+ __spi_write_reg(0x04, 0x17); \ -+ __spi_write_reg(0x05, 0x20); \ -+ __spi_write_reg(0x06, 0x08); \ -+ __spi_write_reg(0x07, 0x26); \ -+ __spi_write_reg(0x08, 0x13); \ -+ __spi_write_reg(0x09, 0x33); \ -+ __spi_write_reg(0x0a, 0x20); \ -+ __spi_write_reg(0x0b, 0x20); \ -+ __spi_write_reg(0x0c, 0x20); \ -+ __spi_write_reg(0x0d, 0x20); \ -+ __spi_write_reg(0x0e, 0x10); \ -+ __spi_write_reg(0x0f, 0x10); \ -+ __spi_write_reg(0x10, 0x10); \ -+ __spi_write_reg(0x11, 0x15); \ -+ __spi_write_reg(0x12, 0xaa); \ -+ __spi_write_reg(0x13, 0xff); \ -+ __spi_write_reg(0x14, 0x86); \ -+ __spi_write_reg(0x15, 0x8e); \ -+ __spi_write_reg(0x16, 0xd6); \ -+ __spi_write_reg(0x17, 0xfe); \ -+ __spi_write_reg(0x18, 0x28); \ -+ __spi_write_reg(0x19, 0x52); \ -+ __spi_write_reg(0x1a, 0x7c); \ -+ __spi_write_reg(0x1b, 0xe9); \ -+ __spi_write_reg(0x1c, 0x42); \ -+ __spi_write_reg(0x1d, 0x88); \ -+ __spi_write_reg(0x1e, 0xb8); \ -+ __spi_write_reg(0x1f, 0xff); \ -+ __spi_write_reg(0x20, 0xf0); \ -+ __spi_write_reg(0x21, 0xf0); \ -+ __spi_write_reg(0x22, 0x07); \ -+*/ -+/* 3.1 -+ __spi_write_reg(0x02, 0x07); \ -+ __spi_write_reg(0x03, 0x5f); \ -+ __spi_write_reg(0x04, 0x17); \ -+ __spi_write_reg(0x05, 0x20); \ -+ __spi_write_reg(0x06, 0x08); \ -+ __spi_write_reg(0x07, 0x20); \ -+ __spi_write_reg(0x08, 0x20); \ -+ __spi_write_reg(0x09, 0x20); \ -+ __spi_write_reg(0x0a, 0x20); \ -+ __spi_write_reg(0x0b, 0x20); \ -+ __spi_write_reg(0x0c, 0x20); \ -+ __spi_write_reg(0x0d, 0x22); \ -+ __spi_write_reg(0x0e, 0x10); \ -+ __spi_write_reg(0x0f, 0x10); \ -+ __spi_write_reg(0x10, 0x10); \ -+ __spi_write_reg(0x11, 0x15); \ -+ __spi_write_reg(0x12, 0x6a); \ -+ __spi_write_reg(0x13, 0xff); \ -+ __spi_write_reg(0x14, 0x86); \ -+ __spi_write_reg(0x15, 0x7c); \ -+ __spi_write_reg(0x16, 0xc2); \ -+ __spi_write_reg(0x17, 0xd1); \ -+ __spi_write_reg(0x18, 0xf5); \ -+ __spi_write_reg(0x19, 0x25); \ -+ __spi_write_reg(0x1a, 0x4a); \ -+ __spi_write_reg(0x1b, 0xbf); \ -+ __spi_write_reg(0x1c, 0x15); \ -+ __spi_write_reg(0x1d, 0x6a); \ -+ __spi_write_reg(0x1e, 0xa4); \ -+ __spi_write_reg(0x1f, 0xff); \ -+ __spi_write_reg(0x20, 0xf0); \ -+ __spi_write_reg(0x21, 0xf0); \ -+ __spi_write_reg(0x22, 0x08); \ -+ */ -+ /* 2.5 -+ __spi_write_reg(0x02, 0x07); \ -+ __spi_write_reg(0x03, 0x5f); \ -+ __spi_write_reg(0x04, 0x17); \ -+ __spi_write_reg(0x05, 0x20); \ -+ __spi_write_reg(0x06, 0x08); \ -+ __spi_write_reg(0x07, 0x20); \ -+ __spi_write_reg(0x08, 0x20); \ -+ __spi_write_reg(0x09, 0x20); \ -+ __spi_write_reg(0x0a, 0x20); \ -+ __spi_write_reg(0x0b, 0x20); \ -+ __spi_write_reg(0x0c, 0x20); \ -+ __spi_write_reg(0x0d, 0x22); \ -+ __spi_write_reg(0x0e, 0x10); \ -+ __spi_write_reg(0x0f, 0x10); \ -+ __spi_write_reg(0x10, 0x10); \ -+ __spi_write_reg(0x11, 0x15); \ -+ __spi_write_reg(0x12, 0xaa); \ -+ __spi_write_reg(0x13, 0xff); \ -+ __spi_write_reg(0x14, 0x86); \ -+ __spi_write_reg(0x15, 0x89); \ -+ __spi_write_reg(0x16, 0xc6); \ -+ __spi_write_reg(0x17, 0xea); \ -+ __spi_write_reg(0x18, 0x0c); \ -+ __spi_write_reg(0x19, 0x33); \ -+ __spi_write_reg(0x1a, 0x5e); \ -+ __spi_write_reg(0x1b, 0xd0); \ -+ __spi_write_reg(0x1c, 0x33); \ -+ __spi_write_reg(0x1d, 0x7e); \ -+ __spi_write_reg(0x1e, 0xb3); \ -+ __spi_write_reg(0x1f, 0xff); \ -+ __spi_write_reg(0x20, 0xf0); \ -+ __spi_write_reg(0x21, 0xf0); \ -+ __spi_write_reg(0x22, 0x08); \ -+*/ -+/* -+ __spi_write_reg(0x02, 0x07); \ -+ __spi_write_reg(0x03, 0x5f); \ -+ __spi_write_reg(0x04, 0x17); \ -+ __spi_write_reg(0x05, 0x20); \ -+ __spi_write_reg(0x06, 0x08); \ -+ __spi_write_reg(0x07, 0x20); \ -+ __spi_write_reg(0x08, 0x20); \ -+ __spi_write_reg(0x09, 0x20); \ -+ __spi_write_reg(0x0a, 0x20); \ -+ __spi_write_reg(0x0b, 0x20); \ -+ __spi_write_reg(0x0c, 0x20); \ -+ __spi_write_reg(0x0d, 0x22); \ -+ __spi_write_reg(0x0e, 0x10); \ -+ __spi_write_reg(0x0f, 0x10); \ -+ __spi_write_reg(0x10, 0x10); \ -+ __spi_write_reg(0x11, 0x15); \ -+ __spi_write_reg(0x12, 0xaa); \ -+ __spi_write_reg(0x13, 0xff); \ -+ __spi_write_reg(0x14, 0x86); \ -+ __spi_write_reg(0x15, 0x84); \ -+ __spi_write_reg(0x16, 0xc3); \ -+ __spi_write_reg(0x17, 0xd8); \ -+ __spi_write_reg(0x18, 0x01); \ -+ __spi_write_reg(0x19, 0x28); \ -+ __spi_write_reg(0x1a, 0x53); \ -+ __spi_write_reg(0x1b, 0xc5); \ -+ __spi_write_reg(0x1c, 0x26); \ -+ __spi_write_reg(0x1d, 0x74); \ -+ __spi_write_reg(0x1e, 0xae); \ -+ __spi_write_reg(0x1f, 0xff); \ -+ __spi_write_reg(0x20, 0xf0); \ -+ __spi_write_reg(0x21, 0xf0); \ -+ __spi_write_reg(0x22, 0x08); \ -+ */ -diff -urN linux-2.6.24.7.old/drivers/video/jzlcd.c linux-2.6.24.7/drivers/video/jzlcd.c ---- linux-2.6.24.7.old/drivers/video/jzlcd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jzlcd.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1571 @@ -+/* -+ * linux/drivers/video/jzlcd.c -- Ingenic On-Chip LCD frame buffer device -+ * -+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "console/fbcon.h" -+ -+#include "jzlcd.h" -+ -+#undef DEBUG -+//#define DEBUG -+#ifdef DEBUG -+#define dprintk(x...) printk(x) -+#else -+#define dprintk(x...) -+#endif -+ -+#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg) -+#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg) -+#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg) -+#ifdef DEBUG -+#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg) -+#else -+#define print_dbg(f, arg...) do {} while (0) -+#endif -+ -+struct lcd_cfb_info { -+ struct fb_info fb; -+ struct display_switch *dispsw; -+ signed int currcon; -+ int func_use_count; -+ -+ struct { -+ u16 red, green, blue; -+ } palette[NR_PALETTE]; -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ struct task_struct *rotate_daemon_thread; -+#endif -+}; -+ -+static struct lcd_cfb_info *jzlcd_info; -+ -+struct jzfb_info { -+ unsigned int cfg; /* panel mode and pin usage etc. */ -+ unsigned int w; -+ unsigned int h; -+ unsigned int bpp; /* bit per pixel */ -+ unsigned int fclk; /* frame clk */ -+ unsigned int hsw; /* hsync width, in pclk */ -+ unsigned int vsw; /* vsync width, in line count */ -+ unsigned int elw; /* end of line, in pclk */ -+ unsigned int blw; /* begin of line, in pclk */ -+ unsigned int efw; /* end of frame, in line count */ -+ unsigned int bfw; /* begin of frame, in line count */ -+}; -+ -+static struct jzfb_info jzfb = { -+#if defined(CONFIG_JZLCD_SHARP_LQ035Q7) -+ MODE_TFT_SHARP | PCLK_N | VSYNC_N, -+ 240, 320, 16, 60, 1, 2, 1, 2, 0, 6 -+#endif -+#if defined(CONFIG_JZLCD_SAMSUNG_LTS350Q1) -+ MODE_TFT_SAMSUNG | PCLK_N, -+ 240, 320, 16, 60, 1, 2, (254-240), 0, 7, 0 -+#endif -+#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N, -+ 320, 240, 16, 70, 19, 4, 20, 14, 18, 6 -+#endif -+#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF01) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N, -+ 480, 272, 16, 60, 41, 10, 2, 2, 2, 2 -+#endif -+ -+#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF02) -+ /* MODE_TFT_18BIT: JZ4740@ version */ -+ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N, -+ 480, 272, 32, 60, 41, 10, 2, 2, 2, 2 -+#endif -+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N, -+ 320, 240, 16, 85, 30, 3, 38, 20, 11, 8 -+#endif -+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL) -+ MODE_8BIT_SERIAL_TFT | HSYNC_N | VSYNC_N | PCLK_N, -+ /* serial mode 280 lines, parallel mode 240 lines */ -+ 320, 280, 32, 60, (30*3), 3, (20*3), (38*3), 46, 23 -+#endif -+#if defined(CONFIG_JZLCD_AUO_A030FL01_V1) -+ MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N, -+ 480, 272, 32, 60, 39, 10, 8, 4, 4, 2 -+#endif -+#if defined(CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N | DE_N, -+ 320, 240, 16, 60, 3, 3, 3, 3, 3, 85 /* 320x240 */ -+#endif -+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && defined(CONFIG_JZ4740_PAVO) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | MODE_TFT_18BIT | PCLK_N, -+// 320, 240, 18, 110, 1, 1, 10, 50, 10, 13 -+ 320, 240, 18, 80, 1, 1, 10, 50, 10, 13 -+#endif -+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && !(defined(CONFIG_JZ4740_PAVO)) -+ MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N, -+ 320, 240, 16, 110, 1, 1, 10, 50, 10, 13 -+#endif -+#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL) -+ MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N, -+ 320, 240, 32, 60, 1, 1, 10, 50, 10, 13 -+#endif -+#if defined(CONFIG_JZLCD_HYNIX_HT10X21) -+ MODE_TFT_GEN | PCLK_N, -+ 1024, 768, 16, 45, 1, 1, 75, 0, 3, 0 -+#endif -+#if defined(CONFIG_JZLCD_TOSHIBA_LTM084P363) -+ MODE_TFT_GEN | PCLK_N, -+ 800, 600, 16, 50, 1, 2, 199, 0, 2, 0 -+#endif -+#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42) -+ MODE_TFT_SHARP | PCLK_N, -+ 800, 600, 16, 40, 1, 1, 255, 0, 34, 0 -+#endif -+#if defined(CONFIG_JZLCD_CSTN_800x600) -+ MODE_STN_COLOR_DUAL | STN_DAT_PIN8, -+ 800, 600, 16, 30, 8, 1, 0, 0, 0, 0 -+#endif -+#if defined(CONFIG_JZLCD_CSTN_320x240) -+ MODE_STN_COLOR_SINGLE | STN_DAT_PIN8, -+ 320, 240, 16, 120, 8, 1, 8, 0, 0, 0 -+#endif -+#if defined(CONFIG_JZLCD_MSTN_640x480) -+ MODE_STN_MONO_DUAL | STN_DAT_PIN4, -+ 640, 480, 8, 110, 4, 1, 4, 0, 0, 0 -+#endif -+#if defined(CONFIG_JZLCD_MSTN_320x240) -+ MODE_STN_MONO_SINGLE | STN_DAT_PIN4, -+ 320, 240, 8, 110, 4, 1, 4, 0, 0, 0 -+#endif -+#if defined(CONFIG_JZLCD_MSTN_480x320) -+ MODE_STN_MONO_SINGLE | STN_DAT_PIN8 -+#if defined(CONFIG_JZLCD_MSTN_INVERSE) -+ | DATA_INVERSE -+#endif -+ , 480, 320, 8, 65, 8, 1, 8, 0, 0, 0 -+#endif -+ -+#if defined(CONFIG_JZLCD_MSTN_240x128) -+ MODE_STN_MONO_SINGLE | STN_DAT_PIN1 -+#if defined(CONFIG_JZLCD_MSTN_INVERSE) -+ | DATA_INVERSE -+#endif -+ , 240, 128, 8, 100, 1, 1, 1, 0, 0, 0 -+#endif -+}; -+ -+static struct lcd_desc *lcd_desc_base; -+static struct lcd_desc *lcd_palette_desc; -+static struct lcd_desc *lcd_frame_desc0; -+static struct lcd_desc *lcd_frame_desc1; -+ -+static unsigned char *lcd_palette; -+static unsigned char *lcd_frame[CONFIG_JZLCD_FRAMEBUFFER_MAX]; -+struct jz_lcd_buffer_addrs_t jz_lcd_buffer_addrs; -+//extern struct display fb_display[MAX_NR_CONSOLES]; -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+static unsigned char *lcd_frame_user_fb; -+/* default rotate angle */ -+static volatile int rotate_angle = CONFIG_JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE; -+#endif -+ -+#ifdef DEBUG -+static void print_regs(void) /* debug */ -+{ -+ printk("REG_LCD_CFG:\t0x%8.8x\n", REG_LCD_CFG); -+ printk("REG_LCD_VSYNC:\t0x%8.8x\n", REG_LCD_VSYNC); -+ printk("REG_LCD_HSYNC:\t0x%8.8x\n", REG_LCD_HSYNC); -+ printk("REG_LCD_VAT:\t0x%8.8x\n", REG_LCD_VAT); -+ printk("REG_LCD_DAH:\t0x%8.8x\n", REG_LCD_DAH); -+ printk("REG_LCD_DAV:\t0x%8.8x\n", REG_LCD_DAV); -+ printk("REG_LCD_PS:\t0x%8.8x\n", REG_LCD_PS); -+ printk("REG_LCD_CLS:\t0x%8.8x\n", REG_LCD_CLS); -+ printk("REG_LCD_SPL:\t0x%8.8x\n", REG_LCD_SPL); -+ printk("REG_LCD_REV:\t0x%8.8x\n", REG_LCD_REV); -+ printk("REG_LCD_CTRL:\t0x%8.8x\n", REG_LCD_CTRL); -+ printk("REG_LCD_STATE:\t0x%8.8x\n", REG_LCD_STATE); -+ printk("REG_LCD_IID:\t0x%8.8x\n", REG_LCD_IID); -+ printk("REG_LCD_DA0:\t0x%8.8x\n", REG_LCD_DA0); -+ printk("REG_LCD_SA0:\t0x%8.8x\n", REG_LCD_SA0); -+ printk("REG_LCD_FID0:\t0x%8.8x\n", REG_LCD_FID0); -+ printk("REG_LCD_CMD0:\t0x%8.8x\n", REG_LCD_CMD0); -+ -+ printk("==================================\n"); -+ printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff); -+ printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff); -+ printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff); -+ printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff); -+ printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff); -+ printk("==================================\n"); -+ -+} -+#else -+#define print_regs() -+#endif -+ -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+static int jzfb_rotate_daemon_thread(void *info) -+{ -+ int i,j; -+ struct fb_info *fb = &jzlcd_info->fb; -+ -+ while (!kthread_should_stop()) { -+#if (CONFIG_JZLCD_FRAMEBUFFER_BPP == 8) -+ unsigned char *plcd_frame = (unsigned char *)lcd_frame[0]; -+ unsigned char *pfb = (unsigned char *) (fb->screen_base); -+#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 16) -+ unsigned short *plcd_frame = (unsigned short *)lcd_frame[0]; -+ unsigned short *pfb = (unsigned short *) (fb->screen_base); -+#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 32) -+ unsigned int *plcd_frame = (unsigned int *)lcd_frame[0]; -+ unsigned int *pfb = (unsigned int *) (fb->screen_base); -+#else -+#error "ERROR, rotate not support this bpp." -+#endif -+ switch ( rotate_angle ) { -+ case FB_ROTATE_UR: -+ printk("%s, Warning, this shouldn't reache\n", __FUNCTION__); -+ ssleep(1); -+ break; -+ case FB_ROTATE_UD: /* cost about 30ms, can be accelrated by dma in the future */ -+ plcd_frame += jzfb.w*jzfb.h -1; -+ for (i=0;ivar.height+1; i++) { -+ for (j=1; j < fb->var.width+1; j++) -+ plcd_frame[j*fb->var.height-i] = *pfb++; -+ } -+ msleep(100); /* sleep 100ms */ -+ break; -+ case FB_ROTATE_CCW: /* cost about 80ms */ -+ for (i=0;ivar.height;i++) { -+ for ( j=fb->var.width-1;j>=0;j--) -+ plcd_frame[j*fb->var.height+i] = *pfb++; -+ } -+ msleep(100); /* sleep 100ms */ -+ break; -+ default: /* FB_ROTATE_UR */ -+ dprintk("Unknown rotate(%d) type\n", rotate_angle); -+ ssleep(1); -+ } -+ -+ dma_cache_wback_inv((unsigned int)(lcd_frame_user_fb), fb->fix.smem_len); -+ } -+ return 0; -+} -+/* -+ * rotate param angle: -+ * 0: FB_ROTATE_UR, 0'C -+ * 1: FB_ROTATE_CW, 90'C -+ * 2: FB_ROTATE_UD, 180'C -+ * 3: FB_ROTATE_CCW, 270'C -+ */ -+static int jzfb_rotate_change( int angle ) -+{ -+ struct fb_info *fb = &jzlcd_info->fb; -+ -+ /* clear frame buffer */ -+ memset((void*)lcd_frame_user_fb, 0x00, fb->fix.smem_len); -+ switch ( angle ) { -+ case FB_ROTATE_UR: -+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w; -+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h; -+ /* change lcd controller's data buffer to lcd_frame_user_fb*/ -+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame_user_fb); -+ if ( rotate_angle != FB_ROTATE_UR ) -+ kthread_stop(jzlcd_info->rotate_daemon_thread); -+ rotate_angle = angle; -+ break; -+ case FB_ROTATE_UD: -+ case FB_ROTATE_CW: -+ case FB_ROTATE_CCW: -+ if ( angle == FB_ROTATE_UD ) { -+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.w; -+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.h; -+ } -+ else { /* CW, CCW */ -+ fb->var.width = fb->var.xres = fb->var.xres_virtual = jzfb.h; -+ fb->var.height = fb->var.yres = fb->var.yres_virtual = jzfb.w; -+ } -+ /* change lcd controller's data buffer to lcd_frame[0]*/ -+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]); -+ if ( rotate_angle == FB_ROTATE_UR || \ -+ jzlcd_info->rotate_daemon_thread == NULL) -+ jzlcd_info->rotate_daemon_thread = kthread_run( jzfb_rotate_daemon_thread, jzlcd_info, "%s", "jzlcd-rotate-daemon"); /* start rotate daemon */ -+ rotate_angle = angle; -+ break; -+ default: -+ printk("Invalid angle(%d)\n", (unsigned int)angle); -+ } -+ fb->fix.line_length = fb->var.xres * CONFIG_JZLCD_FRAMEBUFFER_BPP/8; -+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc)); -+ return 0; -+} -+ -+void jzfb_fb_rotate(struct fb_info *fbi, int angle) -+{ -+ jzfb_rotate_change( angle/90 ); -+} -+#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ -+ -+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) -+{ -+ chan &= 0xffff; -+ chan >>= 16 - bf->length; -+ return chan << bf->offset; -+} -+ -+static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, -+ u_int transp, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned short *ptr, ctmp; -+ -+// print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp); -+ if (regno >= NR_PALETTE) -+ return 1; -+ -+ cfb->palette[regno].red = red ; -+ cfb->palette[regno].green = green; -+ cfb->palette[regno].blue = blue; -+ if (cfb->fb.var.bits_per_pixel <= 16) { -+ red >>= 8; -+ green >>= 8; -+ blue >>= 8; -+ -+ red &= 0xff; -+ green &= 0xff; -+ blue &= 0xff; -+ } -+ switch (cfb->fb.var.bits_per_pixel) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) { -+ ctmp = (77L * red + 150L * green + 29L * blue) >> 8; -+ ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) | -+ (ctmp >> 3); -+ } else { -+ /* RGB 565 */ -+ if (((red >> 3) == 0) && ((red >> 2) != 0)) -+ red = 1 << 3; -+ if (((blue >> 3) == 0) && ((blue >> 2) != 0)) -+ blue = 1 << 3; -+ ctmp = ((red >> 3) << 11) -+ | ((green >> 2) << 5) | (blue >> 3); -+ } -+ -+ ptr = (unsigned short *)lcd_palette; -+ ptr = (unsigned short *)(((u32)ptr)|0xa0000000); -+ ptr[regno] = ctmp; -+ -+ break; -+ -+ case 15: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 10) | -+ ((green >> 3) << 5) | -+ (blue >> 3); -+ break; -+ case 16: -+ if (regno < 16) { -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ ((red >> 3) << 11) | -+ ((green >> 2) << 5) | -+ (blue >> 3); -+ } -+ break; -+ case 18: -+ case 24: -+ case 32: -+ if (regno < 16) -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = -+ (red << 16) | -+ (green << 8) | -+ (blue << 0); -+ -+/* if (regno < 16) { -+ unsigned val; -+ val = chan_to_field(red, &cfb->fb.var.red); -+ val |= chan_to_field(green, &cfb->fb.var.green); -+ val |= chan_to_field(blue, &cfb->fb.var.blue); -+ ((u32 *)cfb->fb.pseudo_palette)[regno] = val; -+ } -+*/ -+ -+ break; -+ } -+ return 0; -+} -+ -+ -+static int jzfb_ioctl (struct fb_info *fb, unsigned int cmd, unsigned long arg ) -+{ -+ int ret = 0; -+ void __user *argp = (void __user *)arg; -+ -+ switch (cmd) { -+ case FBIOSETBACKLIGHT: -+ __lcd_set_backlight_level(arg); /* We support 8 levels here. */ -+ break; -+ case FBIODISPON: -+ __lcd_display_on(); -+ break; -+ case FBIODISPOFF: -+ __lcd_display_off(); -+ break; -+ case FBIOPRINT_REGS: -+ print_regs(); -+ break; -+ case FBIOGETBUFADDRS: -+ if ( copy_to_user(argp, &jz_lcd_buffer_addrs, -+ sizeof(struct jz_lcd_buffer_addrs_t)) ) -+ return -EFAULT; -+ break; -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ case FBIOROTATE: -+ ret = jzfb_rotate_change(arg); -+ break; -+#endif /* defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ -+ default: -+ printk("Warn: Command(%x) not support\n", cmd); -+ ret = -1; -+ break; -+ } -+ return ret; -+ -+} -+ -+/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */ -+static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ unsigned long start; -+ unsigned long off; -+ u32 len; -+ -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ //fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); -+ -+ /* frame buffer memory */ -+ start = cfb->fb.fix.smem_start; -+ len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len); -+ start &= PAGE_MASK; -+ -+ if ((vma->vm_end - vma->vm_start + off) > len) -+ return -EINVAL; -+ off += start; -+ -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ vma->vm_flags |= VM_IO; -+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Uncacheable */ -+ -+#if 1 -+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; -+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; /* Uncacheable */ -+// pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; /* Write-Through */ -+#endif -+ -+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot)) { -+ return -EAGAIN; -+ } -+ return 0; -+} -+ -+/* checks var and eventually tweaks it to something supported, -+ * DO NOT MODIFY PAR */ -+static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ print_dbg("jzfb_check_var"); -+ return 0; -+} -+ -+ -+/* -+ * set the video mode according to info->var -+ */ -+static int jzfb_set_par(struct fb_info *info) -+{ -+ print_dbg("jzfb_set_par"); -+ return 0; -+} -+ -+ -+/* -+ * (Un)Blank the display. -+ * Fix me: should we use VESA value? -+ */ -+static int jzfb_blank(int blank_mode, struct fb_info *info) -+{ -+ -+ dprintk("fb_blank %d %p", blank_mode, info); -+ -+ switch (blank_mode) { -+ -+ case FB_BLANK_UNBLANK: -+ //case FB_BLANK_NORMAL: -+ /* Turn on panel */ -+ __lcd_set_ena(); -+ __lcd_display_on(); -+ break; -+ -+ case FB_BLANK_NORMAL: -+ case FB_BLANK_VSYNC_SUSPEND: -+ case FB_BLANK_HSYNC_SUSPEND: -+ case FB_BLANK_POWERDOWN: -+#if 0 -+ /* Turn off panel */ -+ __lcd_set_dis(); -+ __lcd_display_off(); -+#endif -+ break; -+ default: -+ break; -+ -+ } -+ return 0; -+} -+ -+/* -+ * pan display -+ */ -+static int jzfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ int dy; -+ -+ if (!var || !cfb) { -+ return -EINVAL; -+ } -+ -+ if (var->xoffset - cfb->fb.var.xoffset) { -+ /* No support for X panning for now! */ -+ return -EINVAL; -+ } -+ -+ dy = var->yoffset - cfb->fb.var.yoffset; -+ print_dbg("var.yoffset: %d", dy); -+ if (dy) { -+ -+ print_dbg("Panning screen of %d lines", dy); -+ -+ lcd_frame_desc0->databuf += (cfb->fb.fix.line_length * dy); -+ /* TODO: Wait for current frame to finished */ -+ } -+ -+ return 0; -+} -+ -+ -+/* use default function cfb_fillrect, cfb_copyarea, cfb_imageblit */ -+static struct fb_ops jzfb_ops = { -+ .owner = THIS_MODULE, -+ .fb_setcolreg = jzfb_setcolreg, -+ .fb_check_var = jzfb_check_var, -+ .fb_set_par = jzfb_set_par, -+ .fb_blank = jzfb_blank, -+ .fb_pan_display = jzfb_pan_display, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, -+ .fb_mmap = jzfb_mmap, -+ .fb_ioctl = jzfb_ioctl, -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ .fb_rotate = jzfb_fb_rotate, -+#endif -+}; -+ -+static int jzfb_set_var(struct fb_var_screeninfo *var, int con, -+ struct fb_info *info) -+{ -+ struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info; -+ int chgvar = 0; -+ -+ var->height = jzfb.h ; -+ var->width = jzfb.w ; -+ var->bits_per_pixel = jzfb.bpp; -+ -+ var->vmode = FB_VMODE_NONINTERLACED; -+ var->activate = cfb->fb.var.activate; -+ var->xres = var->width; -+ var->yres = var->height; -+ var->xres_virtual = var->width; -+ var->yres_virtual = var->height; -+ var->xoffset = 0; -+ var->yoffset = 0; -+ var->pixclock = 0; -+ var->left_margin = 0; -+ var->right_margin = 0; -+ var->upper_margin = 0; -+ var->lower_margin = 0; -+ var->hsync_len = 0; -+ var->vsync_len = 0; -+ var->sync = 0; -+ var->activate &= ~FB_ACTIVATE_TEST; -+ -+ /* -+ * CONUPDATE and SMOOTH_XPAN are equal. However, -+ * SMOOTH_XPAN is only used internally by fbcon. -+ */ -+ if (var->vmode & FB_VMODE_CONUPDATE) { -+ var->vmode |= FB_VMODE_YWRAP; -+ var->xoffset = cfb->fb.var.xoffset; -+ var->yoffset = cfb->fb.var.yoffset; -+ } -+ -+ if (var->activate & FB_ACTIVATE_TEST) -+ return 0; -+ -+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) -+ return -EINVAL; -+ -+ if (cfb->fb.var.xres != var->xres) -+ chgvar = 1; -+ if (cfb->fb.var.yres != var->yres) -+ chgvar = 1; -+ if (cfb->fb.var.xres_virtual != var->xres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.yres_virtual != var->yres_virtual) -+ chgvar = 1; -+ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) -+ chgvar = 1; -+ -+ var->red.msb_right = 0; -+ var->green.msb_right = 0; -+ var->blue.msb_right = 0; -+ -+ switch(var->bits_per_pixel){ -+ case 1: /* Mono */ -+ cfb->fb.fix.visual = FB_VISUAL_MONO01; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 2: /* Mono */ -+ var->red.offset = 0; -+ var->red.length = 2; -+ var->green.offset = 0; -+ var->green.length = 2; -+ var->blue.offset = 0; -+ var->blue.length = 2; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = (var->xres * var->bits_per_pixel) / 8; -+ break; -+ case 4: /* PSEUDOCOLOUR*/ -+ var->red.offset = 0; -+ var->red.length = 4; -+ var->green.offset = 0; -+ var->green.length = 4; -+ var->blue.offset = 0; -+ var->blue.length = 4; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres / 2; -+ break; -+ case 8: /* PSEUDOCOLOUR, 256 */ -+ var->red.offset = 0; -+ var->red.length = 8; -+ var->green.offset = 0; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; -+ cfb->fb.fix.line_length = var->xres ; -+ break; -+ case 15: /* DIRECTCOLOUR, 32k */ -+ var->bits_per_pixel = 15; -+ var->red.offset = 10; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 5; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 16: /* DIRECTCOLOUR, 64k */ -+ var->bits_per_pixel = 16; -+ var->red.offset = 11; -+ var->red.length = 5; -+ var->green.offset = 5; -+ var->green.length = 6; -+ var->blue.offset = 0; -+ var->blue.length = 5; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 2; -+ break; -+ case 18: -+ case 24: -+ case 32: -+ /* DIRECTCOLOUR, 16M */ -+ var->bits_per_pixel = 32; -+ -+ var->red.offset = 16; -+ var->red.length = 8; -+ var->green.offset = 8; -+ var->green.length = 8; -+ var->blue.offset = 0; -+ var->blue.length = 8; -+ var->transp.offset = 24; -+ var->transp.length = 8; -+ -+ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; -+ cfb->fb.fix.line_length = var->xres_virtual * 4; -+ break; -+ -+ default: /* in theory this should never happen */ -+ printk(KERN_WARNING "%s: don't support for %dbpp\n", -+ cfb->fb.fix.id, var->bits_per_pixel); -+ break; -+ } -+ -+ cfb->fb.var = *var; -+ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; -+ -+ /* -+ * Update the old var. The fbcon drivers still use this. -+ * Once they are using cfb->fb.var, this can be dropped. -+ * --rmk -+ */ -+ //display->var = cfb->fb.var; -+ /* -+ * If we are setting all the virtual consoles, also set the -+ * defaults used to create new consoles. -+ */ -+ fb_set_cmap(&cfb->fb.cmap, &cfb->fb); -+ dprintk("jzfb_set_var: after fb_set_cmap...\n"); -+ -+ return 0; -+} -+ -+static struct lcd_cfb_info * jzfb_alloc_fb_info(void) -+{ -+ struct lcd_cfb_info *cfb; -+ -+ cfb = kmalloc(sizeof(struct lcd_cfb_info) + sizeof(u32) * 16, GFP_KERNEL); -+ -+ if (!cfb) -+ return NULL; -+ -+ jzlcd_info = cfb; -+ -+ memset(cfb, 0, sizeof(struct lcd_cfb_info) ); -+ -+ cfb->currcon = -1; -+ -+ -+ strcpy(cfb->fb.fix.id, "jz-lcd"); -+ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; -+ cfb->fb.fix.type_aux = 0; -+ cfb->fb.fix.xpanstep = 1; -+ cfb->fb.fix.ypanstep = 1; -+ cfb->fb.fix.ywrapstep = 0; -+ cfb->fb.fix.accel = FB_ACCEL_NONE; -+ -+ cfb->fb.var.nonstd = 0; -+ cfb->fb.var.activate = FB_ACTIVATE_NOW; -+ cfb->fb.var.height = -1; -+ cfb->fb.var.width = -1; -+ cfb->fb.var.accel_flags = FB_ACCELF_TEXT; -+ -+ cfb->fb.fbops = &jzfb_ops; -+ cfb->fb.flags = FBINFO_FLAG_DEFAULT; -+ -+ cfb->fb.pseudo_palette = (void *)(cfb + 1); -+ -+ switch (jzfb.bpp) { -+ case 1: -+ fb_alloc_cmap(&cfb->fb.cmap, 4, 0); -+ break; -+ case 2: -+ fb_alloc_cmap(&cfb->fb.cmap, 8, 0); -+ break; -+ case 4: -+ fb_alloc_cmap(&cfb->fb.cmap, 32, 0); -+ break; -+ case 8: -+ -+ default: -+ fb_alloc_cmap(&cfb->fb.cmap, 256, 0); -+ break; -+ } -+ dprintk("fb_alloc_cmap,fb.cmap.len:%d....\n", cfb->fb.cmap.len); -+ -+ return cfb; -+} -+ -+/* -+ * Map screen memory -+ */ -+static int jzfb_map_smem(struct lcd_cfb_info *cfb) -+{ -+ struct page * map = NULL; -+ unsigned char *tmp; -+ unsigned int page_shift, needroom, t; -+#if defined(CONFIG_SOC_JZ4740) -+ if (jzfb.bpp == 18 || jzfb.bpp == 24) -+ t = 32; -+ else -+ t = jzfb.bpp; -+#else -+ if (jzfb.bpp == 15) -+ t = 16; -+ else -+ t = jzfb.bpp; -+#endif -+ -+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ -+ /* lcd_palette room total 4KB: -+ * 0 -- 512: lcd palette -+ * 1024 -- [1024+16*3]: lcd descripters -+ * [1024+16*3] -- 4096: reserved -+ */ -+ lcd_palette = (unsigned char *)__get_free_pages(GFP_KERNEL, 0); -+ if ((!lcd_palette)) -+ return -ENOMEM; -+ -+ memset((void *)lcd_palette, 0, PAGE_SIZE); -+ map = virt_to_page(lcd_palette); -+ set_bit(PG_reserved, &map->flags); -+ lcd_desc_base = (struct lcd_desc *)(lcd_palette + 1024); -+ -+ jz_lcd_buffer_addrs.fb_num = CONFIG_JZLCD_FRAMEBUFFER_MAX; -+ printk("jzlcd use %d framebuffer:\n", CONFIG_JZLCD_FRAMEBUFFER_MAX); -+ /* alloc frame buffer space */ -+ for ( t = 0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { -+ lcd_frame[t] = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ if ((!lcd_frame[t])) { -+ printk("no mem for fb[%d]\n", t); -+ return -ENOMEM; -+ } -+// memset((void *)lcd_frame[t], 0, PAGE_SIZE << page_shift); -+ for (tmp=(unsigned char *)lcd_frame[t]; -+ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ set_bit(PG_reserved, &map->flags); -+ } -+ jz_lcd_buffer_addrs.fb_phys_addr[t] = virt_to_phys((void *)lcd_frame[t]); -+ printk("jzlcd fb[%d] phys addr =0x%08x\n", -+ t, jz_lcd_buffer_addrs.fb_phys_addr[t]); -+ } -+#if !defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame[0]); -+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); -+ cfb->fb.screen_base = -+ (unsigned char *)(((unsigned int)lcd_frame[0] & 0x1fffffff) | 0xa0000000); -+#else /* Framebuffer rotate */ -+ lcd_frame_user_fb = (unsigned char *)__get_free_pages(GFP_KERNEL, page_shift); -+ if ((!lcd_frame_user_fb)) { -+ printk("no mem for fb[%d]\n", t); -+ return -ENOMEM; -+ } -+ memset((void *)lcd_frame_user_fb, 0, PAGE_SIZE << page_shift); -+ for (tmp=(unsigned char *)lcd_frame_user_fb; -+ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ set_bit(PG_reserved, &map->flags); -+ } -+ -+ printk("Rotate userfb phys addr =0x%08x\n", -+ (unsigned int)virt_to_phys((void *)lcd_frame_user_fb)); -+ cfb->fb.fix.smem_start = virt_to_phys((void *)lcd_frame_user_fb); -+ cfb->fb.fix.smem_len = (PAGE_SIZE << page_shift); -+ cfb->fb.screen_base = (unsigned char *)(((unsigned int)lcd_frame_user_fb & 0x1fffffff) | 0xa0000000); -+ -+#endif /* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */ -+ if (!cfb->fb.screen_base) { -+ printk("%s: unable to map screen memory\n", cfb->fb.fix.id); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void jzfb_free_fb_info(struct lcd_cfb_info *cfb) -+{ -+ if (cfb) { -+ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); -+ kfree(cfb); -+ } -+} -+ -+static void jzfb_unmap_smem(struct lcd_cfb_info *cfb) -+{ -+ struct page * map = NULL; -+ unsigned char *tmp; -+ unsigned int page_shift, needroom, t; -+#if defined(CONFIG_SOC_JZ4740) -+ if (jzfb.bpp == 18 || jzfb.bpp == 24) -+ t = 32; -+ else -+ t = jzfb.bpp; -+#else -+ if (jzfb.bpp == 15) -+ t = 16; -+ else -+ t = jzfb.bpp; -+#endif -+ needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h; -+ for (page_shift = 0; page_shift < 12; page_shift++) -+ if ((PAGE_SIZE << page_shift) >= needroom) -+ break; -+ -+ if (cfb && cfb->fb.screen_base) { -+ iounmap(cfb->fb.screen_base); -+ cfb->fb.screen_base = NULL; -+ release_mem_region(cfb->fb.fix.smem_start, -+ cfb->fb.fix.smem_len); -+ } -+ -+ if (lcd_palette) { -+ map = virt_to_page(lcd_palette); -+ clear_bit(PG_reserved, &map->flags); -+ free_pages((int)lcd_palette, 0); -+ } -+ -+ for ( t=0; t < CONFIG_JZLCD_FRAMEBUFFER_MAX; t++ ) { -+ if (lcd_frame[t]) { -+ for (tmp=(unsigned char *)lcd_frame[t]; -+ tmp < lcd_frame[t] + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ clear_bit(PG_reserved, &map->flags); -+ } -+ free_pages((int)lcd_frame[t], page_shift); -+ } -+ } -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ if (lcd_frame_user_fb) { -+ for (tmp=(unsigned char *)lcd_frame_user_fb; -+ tmp < lcd_frame_user_fb + (PAGE_SIZE << page_shift); -+ tmp += PAGE_SIZE) { -+ map = virt_to_page(tmp); -+ clear_bit(PG_reserved, &map->flags); -+ } -+ free_pages((int)lcd_frame_user_fb, page_shift); -+ } -+ -+#endif -+} -+ -+static void lcd_descriptor_init(void) -+{ -+ int i; -+ unsigned int pal_size; -+ unsigned int frm_size, ln_size; -+ unsigned char dual_panel = 0; -+ -+ i = jzfb.bpp; -+#if defined(CONFIG_SOC_JZ4740) -+ if (i == 18 || i == 24) -+ i = 32; -+#else -+ if (i == 15) -+ i = 16; -+#endif -+ frm_size = (jzfb.w*jzfb.h*i)>>3; -+ ln_size = (jzfb.w*i)>>3; -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) { -+ dual_panel = 1; -+ frm_size >>= 1; -+ } -+ -+ frm_size = frm_size / 4; -+ ln_size = ln_size / 4; -+ -+ switch (jzfb.bpp) { -+ case 1: -+ pal_size = 4; -+ break; -+ case 2: -+ pal_size = 8; -+ break; -+ case 4: -+ pal_size = 32; -+ break; -+ case 8: -+ default: -+ pal_size = 512; -+ } -+ -+ pal_size /= 4; -+ -+ lcd_frame_desc0 = lcd_desc_base + 0; -+ lcd_frame_desc1 = lcd_desc_base + 1; -+ lcd_palette_desc = lcd_desc_base + 2; -+ -+ jz_lcd_buffer_addrs.lcd_desc_phys_addr = (unsigned int)virt_to_phys(lcd_frame_desc0); -+ -+ /* Palette Descriptor */ -+ lcd_palette_desc->next_desc = (int)virt_to_phys(lcd_frame_desc0); -+ lcd_palette_desc->databuf = (int)virt_to_phys((void *)lcd_palette); -+ lcd_palette_desc->frame_id = (unsigned int)0xdeadbeaf; -+ lcd_palette_desc->cmd = pal_size|LCD_CMD_PAL; /* Palette Descriptor */ -+ -+ /* Frame Descriptor 0 */ -+ if (jzfb.bpp <= 8) -+ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_palette_desc); -+ else -+ lcd_frame_desc0->next_desc = (int)virt_to_phys(lcd_frame_desc0); -+ lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]); -+ lcd_frame_desc0->frame_id = (unsigned int)0xbeafbeaf; -+ lcd_frame_desc0->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; -+ dma_cache_wback_inv((unsigned int)(lcd_palette_desc),0x10); -+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc0),0x10); -+ -+ if (!(dual_panel)) -+ return; -+ -+ /* Frame Descriptor 1 */ -+ lcd_frame_desc1->next_desc = (int)virt_to_phys(lcd_frame_desc1); -+ lcd_frame_desc1->databuf = virt_to_phys((void *)(lcd_frame[0] + frm_size * 4)); -+ lcd_frame_desc1->frame_id = (unsigned int)0xdeaddead; -+ lcd_frame_desc1->cmd = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size; -+ dma_cache_wback_inv((unsigned int)(lcd_frame_desc1),0x10); -+} -+ -+static int lcd_hw_init(void) -+{ -+ unsigned int val = 0; -+ unsigned int pclk; -+ unsigned int stnH; -+ int ret = 0; -+ -+ /* Setting Control register */ -+ switch (jzfb.bpp) { -+ case 1: -+ val |= LCD_CTRL_BPP_1; -+ break; -+ case 2: -+ val |= LCD_CTRL_BPP_2; -+ break; -+ case 4: -+ val |= LCD_CTRL_BPP_4; -+ break; -+ case 8: -+ val |= LCD_CTRL_BPP_8; -+ break; -+ case 15: -+ val |= LCD_CTRL_RGB555; -+ case 16: -+ val |= LCD_CTRL_BPP_16; -+ break; -+#if defined(CONFIG_SOC_JZ4740) -+ case 17 ... 32: -+ val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */ -+ break; -+#endif -+ default: -+ printk("The BPP %d is not supported\n", jzfb.bpp); -+ val |= LCD_CTRL_BPP_16; -+ break; -+ } -+ -+ switch (jzfb.cfg & MODE_MASK) { -+ case MODE_STN_MONO_DUAL: -+ case MODE_STN_COLOR_DUAL: -+ case MODE_STN_MONO_SINGLE: -+ case MODE_STN_COLOR_SINGLE: -+ switch (jzfb.bpp) { -+ case 1: -+ case 2: -+ val |= LCD_CTRL_FRC_2; -+ break; -+ case 4: -+ val |= LCD_CTRL_FRC_4; -+ break; -+ case 8: -+ default: -+ val |= LCD_CTRL_FRC_16; -+ break; -+ } -+ break; -+ } -+ -+ val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */ -+ -+ switch (jzfb.cfg & MODE_MASK) { -+ case MODE_STN_MONO_DUAL: -+ case MODE_STN_COLOR_DUAL: -+ case MODE_STN_MONO_SINGLE: -+ case MODE_STN_COLOR_SINGLE: -+ switch (jzfb.cfg & STN_DAT_PINMASK) { -+#define align2(n) (n)=((((n)+1)>>1)<<1) -+#define align4(n) (n)=((((n)+3)>>2)<<2) -+#define align8(n) (n)=((((n)+7)>>3)<<3) -+ case STN_DAT_PIN1: -+ /* Do not adjust the hori-param value. */ -+ break; -+ case STN_DAT_PIN2: -+ align2(jzfb.hsw); -+ align2(jzfb.elw); -+ align2(jzfb.blw); -+ break; -+ case STN_DAT_PIN4: -+ align4(jzfb.hsw); -+ align4(jzfb.elw); -+ align4(jzfb.blw); -+ break; -+ case STN_DAT_PIN8: -+ align8(jzfb.hsw); -+ align8(jzfb.elw); -+ align8(jzfb.blw); -+ break; -+ } -+ break; -+ } -+ -+ val |= 1 << 26; /* Output FIFO underrun protection */ -+ REG_LCD_CTRL = val; -+ -+ switch (jzfb.cfg & MODE_MASK) { -+ case MODE_STN_MONO_DUAL: -+ case MODE_STN_COLOR_DUAL: -+ case MODE_STN_MONO_SINGLE: -+ case MODE_STN_COLOR_SINGLE: -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) -+ stnH = jzfb.h >> 1; -+ else -+ stnH = jzfb.h; -+ -+ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw; -+ REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw); -+ -+ /* Screen setting */ -+ REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw); -+ REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w); -+ REG_LCD_DAV = (0 << 16) | (stnH); -+ -+ /* AC BIAs signal */ -+ REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw); -+ -+ break; -+ -+ case MODE_TFT_GEN: -+ case MODE_TFT_SHARP: -+ case MODE_TFT_CASIO: -+ case MODE_TFT_SAMSUNG: -+ case MODE_8BIT_SERIAL_TFT: -+ case MODE_TFT_18BIT: -+ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw; -+#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42) -+ REG_LCD_DAV = (0 << 16) | ( jzfb.h ); -+#else -+ REG_LCD_DAV = ((jzfb.vsw + jzfb.bfw) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h); -+#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ -+ REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw); -+ REG_LCD_HSYNC = (0 << 16) | jzfb.hsw; -+ REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w); -+ break; -+ } -+ -+ switch (jzfb.cfg & MODE_MASK) { -+ case MODE_TFT_SAMSUNG: -+ { -+ unsigned int total, tp_s, tp_e, ckv_s, ckv_e; -+ unsigned int rev_s, rev_e, inv_s, inv_e; -+ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw; -+ tp_s = jzfb.blw + jzfb.w + 1; -+ tp_e = tp_s + 1; -+ ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); -+ ckv_e = tp_s + total; -+ rev_s = tp_s - 11; /* -11.5 clk */ -+ rev_e = rev_s + total; -+ inv_s = tp_s; -+ inv_e = inv_s + total; -+ REG_LCD_CLS = (tp_s << 16) | tp_e; -+ REG_LCD_PS = (ckv_s << 16) | ckv_e; -+ REG_LCD_SPL = (rev_s << 16) | rev_e; -+ REG_LCD_REV = (inv_s << 16) | inv_e; -+ jzfb.cfg |= STFT_REVHI | STFT_SPLHI; -+ break; -+ } -+ case MODE_TFT_SHARP: -+ { -+ unsigned int total, cls_s, cls_e, ps_s, ps_e; -+ unsigned int spl_s, spl_e, rev_s, rev_e; -+ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw; -+#if !defined(CONFIG_JZLCD_INNOLUX_AT080TN42) -+ spl_s = 1; -+ spl_e = spl_s + 1; -+ cls_s = 0; -+ cls_e = total - 60; /* > 4us (pclk = 80ns) */ -+ ps_s = cls_s; -+ ps_e = cls_e; -+ rev_s = total - 40; /* > 3us (pclk = 80ns) */ -+ rev_e = rev_s + total; -+ jzfb.cfg |= STFT_PSHI; -+#else /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ -+ spl_s = total - 5; /* LD */ -+ spl_e = total - 3; -+ cls_s = 32; /* CKV */ -+ cls_e = 145; -+ ps_s = 0; /* OEV */ -+ ps_e = 45; -+ rev_s = 0; /* POL */ -+ rev_e = 0; -+#endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/ -+ REG_LCD_SPL = (spl_s << 16) | spl_e; -+ REG_LCD_CLS = (cls_s << 16) | cls_e; -+ REG_LCD_PS = (ps_s << 16) | ps_e; -+ REG_LCD_REV = (rev_s << 16) | rev_e; -+ break; -+ } -+ case MODE_TFT_CASIO: -+ break; -+ } -+ -+ /* Configure the LCD panel */ -+ REG_LCD_CFG = jzfb.cfg; -+ -+ /* Timing setting */ -+ __cpm_stop_lcd(); -+ -+ val = jzfb.fclk; /* frame clk */ -+ -+ if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) { -+ pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) * -+ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ -+ } -+ else { -+ /* serial mode: Hsync period = 3*Width_Pixel */ -+ pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) * -+ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */ -+ } -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL)) -+ pclk = (pclk * 3); -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) -+ pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4); -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) -+ pclk >>= 1; -+#if defined(CONFIG_SOC_JZ4730) -+ val = __cpm_get_pllout() / pclk; -+ REG_CPM_CFCR2 = val - 1; -+ val = __cpm_get_pllout() / (pclk * 4); -+ val = __cpm_divisor_encode(val); -+ __cpm_set_lcdclk_div(val); -+ REG_CPM_CFCR |= CPM_CFCR_UPE; -+#elif defined(CONFIG_SOC_JZ4740) -+ val = ( __cpm_get_pllout2()) / pclk; -+ val--; -+ if ( val > 0x3ff ) { -+ printk("pixel clock divid is too large, set it to 0x3ff\n"); -+ val = 0x3ff; -+ } -+ __cpm_set_pixdiv(val); -+ -+ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */ -+ val =__cpm_get_pllout() / val; -+ if ( val > 0x1f ) { -+ printk("lcd clock divide is too large, set it to 0x1f\n"); -+ val = 0x1f; -+ } -+ __cpm_set_ldiv( val ); -+ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */ -+ -+#else -+ printk("drivers/video/Jzlcd.c, CONFIG_MIPS, please set chip type.\n"); -+#endif /*#ifdef CONFIG_MIPS_JZ4730 */ -+ -+ jz_clocks.pixclk = __cpm_get_pixclk(); -+ jz_clocks.lcdclk = __cpm_get_lcdclk(); -+ printk("LCDC: PixClock:%d LcdClock:%d\n", -+ jz_clocks.pixclk, jz_clocks.lcdclk); -+ -+ __cpm_start_lcd(); -+ udelay(1000); -+ return ret; -+} -+ -+static irqreturn_t lcd_interrupt_handler(int irq, void *dev_id) -+{ -+ unsigned int state; -+ -+ state = REG_LCD_STATE; -+ -+ if (state & LCD_STATE_EOF) /* End of frame */ -+ REG_LCD_STATE = state & ~LCD_STATE_EOF; -+ -+ if (state & LCD_STATE_IFU0) { -+ dprintk("InFiFo0 underrun\n"); -+ REG_LCD_STATE = state & ~LCD_STATE_IFU0; -+ } -+ -+ if (state & LCD_STATE_OFU) { /* Out fifo underrun */ -+ REG_LCD_STATE = state & ~LCD_STATE_OFU; -+ dprintk("Out FiFo underrun.\n"); -+ } -+ return IRQ_HANDLED; -+} -+ -+#ifdef CONFIG_PM -+ -+/* -+ * Suspend the LCDC. -+ */ -+static int jzfb_suspend(void) -+{ -+ __lcd_clr_ena(); /* Quick Disable */ -+ __lcd_display_off(); -+ __cpm_stop_lcd(); -+ -+ return 0; -+} -+ -+/* -+ * Resume the LCDC. -+ */ -+#ifdef CONFIG_SOC_JZ4730 -+static int jzfb_resume(void) -+{ -+ __cpm_start_lcd(); -+ -+ __lcd_display_pin_init(); -+ -+ __lcd_display_on(); -+ -+ lcd_hw_init(); -+ -+ if (jzfb.bpp <= 8) -+ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); -+ else -+ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) -+ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); -+ -+ __lcd_set_ena(); -+ return 0; -+} -+ -+#else -+/* -+ * Resume the LCDC. -+ */ -+static int jzfb_resume(void) -+{ -+ __cpm_start_lcd(); -+ __gpio_set_pin(GPIO_DISP_OFF_N); -+ __lcd_special_on(); -+ __lcd_set_ena(); -+ mdelay(200); -+ __lcd_set_backlight_level(80); -+ -+ return 0; -+} -+#endif /* CONFIG_MIPS_JZ4730 */ -+ -+/* -+ * Power management hook. Note that we won't be called from IRQ context, -+ * unlike the blank functions above, so we may sleep. -+ */ -+static int jzlcd_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct lcd_cfb_info *cfb = pm_dev->data; -+ -+ if (!cfb) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jzfb_suspend(); -+ break; -+ -+ case PM_RESUME: -+ ret = jzfb_resume(); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#else -+#define jzfb_suspend NULL -+#define jzfb_resume NULL -+#endif /* CONFIG_PM */ -+ -+static int __init jzfb_init(void) -+{ -+ struct lcd_cfb_info *cfb; -+ int err = 0; -+ -+ /* In special mode, we only need init special pin, -+ * as general lcd pin has init in uboot */ -+#if defined(CONFIG_SOC_JZ4740) || defined(CONFIG_SOC_JZ4750) -+ switch (jzfb.cfg & MODE_MASK) { -+ case LCD_CFG_MODE_SPECIAL_TFT_1: -+ case LCD_CFG_MODE_SPECIAL_TFT_2: -+ case LCD_CFG_MODE_SPECIAL_TFT_3: -+ __gpio_as_lcd_special(); -+ break; -+ default: -+ ; -+ } -+#endif -+ __lcd_display_pin_init(); -+ -+ cfb = jzfb_alloc_fb_info(); -+ if (!cfb) -+ goto failed; -+ -+ err = jzfb_map_smem(cfb); -+ if (err) -+ goto failed; -+ -+ jzfb_set_var(&cfb->fb.var, -1, &cfb->fb); -+ -+ lcd_descriptor_init(); -+ -+ err = lcd_hw_init(); -+ if (err) -+ goto failed; -+ -+ if (jzfb.bpp <= 8) -+ REG_LCD_DA0 = virt_to_phys(lcd_palette_desc); -+ else -+ REG_LCD_DA0 = virt_to_phys(lcd_frame_desc0); -+ -+ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) || -+ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) -+ REG_LCD_DA1 = virt_to_phys(lcd_frame_desc1); -+ -+ __lcd_set_ena(); -+ -+ if (request_irq(IRQ_LCD, lcd_interrupt_handler, IRQF_DISABLED, -+ "lcd", 0)) { -+ err = -EBUSY; -+ goto failed; -+ } -+ -+ __lcd_enable_ofu_intr(); /* enable OutFifo underrun */ -+// __lcd_enable_ifu0_intr(); /* needn't enable InFifo underrun */ -+ -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ jzfb_rotate_change(rotate_angle); -+ /* sleep n??? */ -+#endif -+ err = register_framebuffer(&cfb->fb); -+ if (err < 0) { -+ dprintk("jzfb_init(): register framebuffer err.\n"); -+ goto failed; -+ } -+ -+ printk("fb%d: %s frame buffer device, using %dK of video memory\n", -+ cfb->fb.node, cfb->fb.fix.id, cfb->fb.fix.smem_len>>10); -+ -+#ifdef CONFIG_PM -+ /* -+ * Note that the console registers this as well, but we want to -+ * power down the display prior to sleeping. -+ */ -+ cfb->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, jzlcd_pm_callback); -+ if (cfb->pm) -+ cfb->pm->data = cfb; -+#endif -+ -+ __lcd_display_on(); -+ -+ return 0; -+ -+failed: -+ jzfb_unmap_smem(cfb); -+ jzfb_free_fb_info(cfb); -+ -+ return err; -+} -+ -+#if 0 -+static int jzfb_remove(struct device *dev) -+{ -+ struct lcd_cfb_info *cfb = dev_get_drvdata(dev); -+ jzfb_unmap_smem(cfb); -+ jzfb_free_fb_info(cfb); -+ return 0; -+} -+#endif -+ -+#if 0 -+static struct device_driver jzfb_driver = { -+ .name = "jz-lcd", -+ .bus = &platform_bus_type, -+ .probe = jzfb_probe, -+ .remove = jzfb_remove, -+ .suspend = jzfb_suspend, -+ .resume = jzfb_resume, -+}; -+#endif -+ -+static void __exit jzfb_cleanup(void) -+{ -+#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) -+ kthread_stop(jzlcd_info->rotate_daemon_thread); -+#endif -+// driver_unregister(&jzfb_driver); -+// jzfb_remove(); -+} -+ -+module_init(jzfb_init); -+module_exit(jzfb_cleanup); -+ -+MODULE_DESCRIPTION("JzSOC LCD Controller driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/drivers/video/jzlcd.h linux-2.6.24.7/drivers/video/jzlcd.h ---- linux-2.6.24.7.old/drivers/video/jzlcd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/video/jzlcd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,791 @@ -+/* -+ * linux/drivers/video/jzlcd.h -- Ingenic On-Chip LCD frame buffer device -+ * -+ * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. -+ * -+ * 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 __JZLCD_H__ -+#define __JZLCD_H__ -+ -+#include -+ -+#define NR_PALETTE 256 -+ -+struct lcd_desc{ -+ unsigned int next_desc; /* LCDDAx */ -+ unsigned int databuf; /* LCDSAx */ -+ unsigned int frame_id; /* LCDFIDx */ -+ unsigned int cmd; /* LCDCMDx */ -+}; -+ -+#define MODE_MASK 0x0f -+#define MODE_TFT_GEN 0x00 -+#define MODE_TFT_SHARP 0x01 -+#define MODE_TFT_CASIO 0x02 -+#define MODE_TFT_SAMSUNG 0x03 -+#define MODE_CCIR656_NONINT 0x04 -+#define MODE_CCIR656_INT 0x05 -+#define MODE_STN_COLOR_SINGLE 0x08 -+#define MODE_STN_MONO_SINGLE 0x09 -+#define MODE_STN_COLOR_DUAL 0x0a -+#define MODE_STN_MONO_DUAL 0x0b -+#define MODE_8BIT_SERIAL_TFT 0x0c -+ -+#define MODE_TFT_18BIT (1<<7) -+ -+#define STN_DAT_PIN1 (0x00 << 4) -+#define STN_DAT_PIN2 (0x01 << 4) -+#define STN_DAT_PIN4 (0x02 << 4) -+#define STN_DAT_PIN8 (0x03 << 4) -+#define STN_DAT_PINMASK STN_DAT_PIN8 -+ -+#define STFT_PSHI (1 << 15) -+#define STFT_CLSHI (1 << 14) -+#define STFT_SPLHI (1 << 13) -+#define STFT_REVHI (1 << 12) -+ -+#define SYNC_MASTER (0 << 16) -+#define SYNC_SLAVE (1 << 16) -+ -+#define DE_P (0 << 9) -+#define DE_N (1 << 9) -+ -+#define PCLK_P (0 << 10) -+#define PCLK_N (1 << 10) -+ -+#define HSYNC_P (0 << 11) -+#define HSYNC_N (1 << 11) -+ -+#define VSYNC_P (0 << 8) -+#define VSYNC_N (1 << 8) -+ -+#define DATA_NORMAL (0 << 17) -+#define DATA_INVERSE (1 << 17) -+ -+ -+/* Jz LCDFB supported I/O controls. */ -+#define FBIOSETBACKLIGHT 0x4688 -+#define FBIODISPON 0x4689 -+#define FBIODISPOFF 0x468a -+#define FBIORESET 0x468b -+#define FBIOPRINT_REGS 0x468c -+#define FBIOGETBUFADDRS 0x468d -+#define FBIOROTATE 0x46a0 /* rotated fb */ -+ -+struct jz_lcd_buffer_addrs_t { -+ int fb_num; -+ unsigned int lcd_desc_phys_addr; -+ unsigned int fb_phys_addr[CONFIG_JZLCD_FRAMEBUFFER_MAX]; -+}; -+ -+ -+/* -+ * LCD panel specific definition -+ */ -+#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW) -+ -+#if defined(CONFIG_JZ4730_PMP) -+#define LCD_RESET_PIN 63 -+#endif -+ -+#define __lcd_special_on() \ -+do { \ -+ __gpio_set_pin(LCD_RESET_PIN); \ -+ __gpio_as_output(LCD_RESET_PIN); \ -+ __gpio_clear_pin(LCD_RESET_PIN); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RESET_PIN); \ -+} while (0) -+ -+#endif /* CONFIG_JZLCD_TRULY_TFTG320240DTSW */ -+ -+#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04) -+ -+#if defined(CONFIG_JZ4730_FPRINT) -+#define PortSDI 60 -+#define PortSCL 61 -+#define PortCS 62 -+#define PortRST 63 -+#define PortSht 64 -+#endif -+ -+#if defined(CONFIG_JZ4730_GPS) -+#define PortSDI 74 -+#define PortSCL 72 -+#define PortCS 73 -+#define PortRST 60 -+#define PortSht 59 -+#endif -+ -+#ifndef PortSDI -+#define PortSDI 0 -+#endif -+#ifndef PortSCL -+#define PortSCL 0 -+#endif -+#ifndef PortCS -+#define PortCS 0 -+#endif -+#ifndef PortRST -+#define PortRST 0 -+#endif -+#ifndef PortSht -+#define PortSht 0 -+#endif -+ -+#define __lcd_special_pin_init() \ -+do { \ -+ __gpio_as_output(PortSDI); /* SDI */\ -+ __gpio_as_output(PortSCL); /* SCL */ \ -+ __gpio_as_output(PortCS); /* CS */ \ -+ __gpio_as_output(PortRST); /* Reset */ \ -+ __gpio_as_output(PortSht); /* Shut Down # */ \ -+ __gpio_set_pin(PortCS); \ -+ __gpio_set_pin(PortSCL); \ -+ __gpio_set_pin(PortSDI); \ -+} while (0) -+ -+#define __spi_out(val) \ -+do { \ -+ int __i__; \ -+ unsigned int _t_ = (val); \ -+ __gpio_clear_pin(PortCS); \ -+ udelay(25); \ -+ for (__i__ = 0; __i__ < 24; __i__++ ) { \ -+ __gpio_clear_pin(PortSCL); \ -+ if (_t_ & 0x800000) \ -+ __gpio_set_pin(PortSDI); \ -+ else \ -+ __gpio_clear_pin(PortSDI); \ -+ _t_ <<= 1; \ -+ udelay(25); \ -+ __gpio_set_pin(PortSCL); \ -+ udelay(25); \ -+ } \ -+ __gpio_set_pin(PortCS); \ -+ udelay(25); \ -+ __gpio_set_pin(PortSDI); \ -+ udelay(25); \ -+ __gpio_set_pin(PortSCL); \ -+} while (0) -+ -+#define __spi_id_op_data(rs, rw, val) \ -+ __spi_out((0x1d<<18)|((rs)<<17)|((rw)<<16)|(val)) -+ -+#define __spi_write_reg(reg, val) \ -+do { \ -+ __spi_id_op_data(0, 0, (reg)); \ -+ __spi_id_op_data(1, 0, (val)); \ -+} while (0) -+ -+#define __lcd_special_on() \ -+do { \ -+ __gpio_set_pin(PortSht); \ -+ __gpio_clear_pin(PortRST); \ -+ mdelay(10); \ -+ __gpio_set_pin(PortRST); \ -+ mdelay(1); \ -+ __spi_write_reg(0x09, 0); \ -+ mdelay(10); \ -+ __spi_write_reg(0x09, 0x4000); \ -+ __spi_write_reg(0x0a, 0x2000); \ -+ mdelay(40); \ -+ __spi_write_reg(0x09, 0x4055); \ -+ mdelay(50); \ -+ __spi_write_reg(0x01, 0x409d); \ -+ __spi_write_reg(0x02, 0x0204); \ -+ __spi_write_reg(0x03, 0x0100); \ -+ __spi_write_reg(0x04, 0x3000); \ -+ __spi_write_reg(0x05, 0x4003); \ -+ __spi_write_reg(0x06, 0x000a); \ -+ __spi_write_reg(0x07, 0x0021); \ -+ __spi_write_reg(0x08, 0x0c00); \ -+ __spi_write_reg(0x10, 0x0103); \ -+ __spi_write_reg(0x11, 0x0301); \ -+ __spi_write_reg(0x12, 0x1f0f); \ -+ __spi_write_reg(0x13, 0x1f0f); \ -+ __spi_write_reg(0x14, 0x0707); \ -+ __spi_write_reg(0x15, 0x0307); \ -+ __spi_write_reg(0x16, 0x0707); \ -+ __spi_write_reg(0x17, 0x0000); \ -+ __spi_write_reg(0x18, 0x0004); \ -+ __spi_write_reg(0x19, 0x0000); \ -+ mdelay(60); \ -+ __spi_write_reg(0x09, 0x4a55); \ -+ __spi_write_reg(0x05, 0x5003); \ -+} while (0) -+ -+#define __lcd_special_off() \ -+do { \ -+ __spi_write_reg(0x09, 0x4055); \ -+ __spi_write_reg(0x05, 0x4003); \ -+ __spi_write_reg(0x0a, 0x0000); \ -+ mdelay(10); \ -+ __spi_write_reg(0x09, 0x4000); \ -+ __gpio_clear_pin(PortSht); \ -+} while (0) -+ -+#endif /* CONFIG_JZLCD_SAMSUNG_LTV350QVF04 */ -+ -+#if defined(CONFIG_JZLCD_AUO_A030FL01_V1) -+#if defined(CONFIG_JZ4740_PAVO) /* board pavo */ -+ #define SPEN (32*1+18) /*LCD_CS*/ -+ #define SPCK (32*1+17) /*LCD_SCL*/ -+ #define SPDA (32*2+12) /*LCD_SDA*/ -+ #define LCD_RET (32*2+23) /*use for lcd reset*/ -+#elif defined(CONFIG_JZ4740_LYRA) /* board lyra */ -+ #define SPEN (32*3+19) //LCD_CS -+ #define SPCK (32*3+18) //LCD_SCL -+ #define SPDA (32*3+20) //LCD_SDA -+ #define LCD_RET (32*3+31) //use for lcd reset -+#else -+#error "driver/video/Jzlcd.h, please define SPI pins on your board." -+#endif -+ -+#define __spi_write_reg(reg, val) \ -+ do { \ -+ unsigned char no; \ -+ unsigned short value; \ -+ unsigned char a=0; \ -+ unsigned char b=0; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ a=reg; \ -+ b=val; \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(50); \ -+ value=((a<<8)|(b&0xFF)); \ -+ for(no=0;no<16;no++) \ -+ { \ -+ if((value&0x8000)==0x8000){ \ -+ __gpio_set_pin(SPDA);} \ -+ else{ \ -+ __gpio_clear_pin(SPDA); } \ -+ udelay(400); \ -+ __gpio_set_pin(SPCK); \ -+ value=(value<<1); \ -+ udelay(50); \ -+ __gpio_clear_pin(SPCK); \ -+ } \ -+ __gpio_set_pin(SPEN); \ -+ udelay(400); \ -+ } while (0) -+#define __spi_read_reg(reg,val) \ -+ do{ \ -+ unsigned char no; \ -+ unsigned short value; \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ value = ((reg << 0) | (1 << 7)); \ -+ val = 0; \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ __gpio_set_pin(SPCK); \ -+ udelay(1); \ -+ __gpio_clear_pin(SPDA); \ -+ __gpio_clear_pin(SPEN); \ -+ udelay(1); \ -+ for (no = 0; no < 16; no++ ) { \ -+ __gpio_clear_pin(SPCK); \ -+ udelay(1); \ -+ if(no < 8) \ -+ { \ -+ if (value & 0x80) /* send data */ \ -+ __gpio_set_pin(SPDA); \ -+ else \ -+ __gpio_clear_pin(SPDA); \ -+ value = (value << 1); \ -+ udelay(1); \ -+ __gpio_set_pin(SPCK); \ -+ udelay(1); \ -+ } \ -+ else \ -+ { \ -+ __gpio_as_input(SPDA); \ -+ udelay(1); \ -+ __gpio_set_pin(SPCK); \ -+ udelay(1); \ -+ val = (val << 1); \ -+ val |= __gpio_get_pin(SPDA); \ -+ udelay(1); \ -+ } \ -+ udelay(400); \ -+ } \ -+ __gpio_as_output(SPDA); \ -+ __gpio_set_pin(SPEN); \ -+ udelay(400); \ -+ } while(0) -+ -+#define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */ \ -+ __gpio_as_output(SPCK); /* use SPCK */ \ -+ __gpio_as_output(SPDA); /* use SPDA */ \ -+ __gpio_as_output(LCD_RET); \ -+ udelay(50); \ -+ __gpio_clear_pin(LCD_RET); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RET); \ -+ } while (0) -+#define __lcd_special_on() \ -+ do { \ -+ udelay(50); \ -+ __gpio_clear_pin(LCD_RET); \ -+ udelay(100); \ -+ __gpio_set_pin(LCD_RET); \ -+ __spi_write_reg(0x0D, 0x44); \ -+ __spi_write_reg(0x0D, 0x4D); \ -+ __spi_write_reg(0x0B, 0x06); \ -+ __spi_write_reg(0x40, 0xC0); \ -+ __spi_write_reg(0x42, 0x43); \ -+ __spi_write_reg(0x44, 0x28); \ -+ __spi_write_reg(0x0D, 0x4F); \ -+} while (0) -+ -+ #define __lcd_special_off() \ -+ do { \ -+ __spi_write_reg(0x04, 0x4C); \ -+ } while (0) -+ -+#endif /* CONFIG_JZLCD_AUO_A030FL01_V1 */ -+ -+//#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) -+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) || defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL) -+ -+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) /* board pmp */ -+#define MODE 0xcd /* 24bit parellel RGB */ -+#endif -+#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL) -+#define MODE 0xc9 /* 8bit serial RGB */ -+#endif -+ -+#if defined(CONFIG_JZ4730_PMP) -+ #define SPEN 60 //LCD_SPL -+ #define SPCK 61 //LCD_CLS -+ #define SPDA 62 //LCD_PS -+ #define LCD_RET 63 //LCD_REV //use for lcd reset -+#elif defined(CONFIG_JZ4740_LEO) /* board leo */ -+ #define SPEN (32*1+18) //LCD_SPL -+ #define SPCK (32*1+17) //LCD_CLS -+ #define SPDA (32*2+22) //LCD_PS -+ #define LCD_RET (32*2+23) //LCD_REV //use for lcd reset -+#elif defined(CONFIG_JZ4740_PAVO) /* board pavo */ -+ #define SPEN (32*1+18) //LCD_SPL -+ #define SPCK (32*1+17) //LCD_CLS -+ #define SPDA (32*2+12) //LCD_D12 -+ #define LCD_RET (32*2+23) //LCD_REV, GPC23 -+#if 0 /*old driver*/ -+ #define SPEN (32*1+18) //LCD_SPL -+ #define SPCK (32*1+17) //LCD_CLS -+ #define SPDA (32*2+12) //LCD_D12 -+ #define LCD_RET (32*3+27) //PWM4 //use for lcd reset -+#endif -+#else -+#error "driver/video/Jzlcd.h, please define SPI pins on your board." -+#endif -+ -+ #define __spi_write_reg1(reg, val) \ -+ do { \ -+ unsigned char no;\ -+ unsigned short value;\ -+ unsigned char a=0;\ -+ unsigned char b=0;\ -+ a=reg;\ -+ b=val;\ -+ __gpio_set_pin(SPEN);\ -+ __gpio_set_pin(SPCK);\ -+ __gpio_clear_pin(SPDA);\ -+ __gpio_clear_pin(SPEN);\ -+ udelay(25);\ -+ value=((a<<8)|(b&0xFF));\ -+ for(no=0;no<16;no++)\ -+ {\ -+ __gpio_clear_pin(SPCK);\ -+ if((value&0x8000)==0x8000)\ -+ __gpio_set_pin(SPDA);\ -+ else\ -+ __gpio_clear_pin(SPDA);\ -+ udelay(25);\ -+ __gpio_set_pin(SPCK);\ -+ value=(value<<1); \ -+ udelay(25);\ -+ }\ -+ __gpio_set_pin(SPEN);\ -+ udelay(100);\ -+ } while (0) -+ -+ #define __spi_write_reg(reg, val) \ -+ do {\ -+ __spi_write_reg1((reg<<2|2), val); \ -+ udelay(100); \ -+ }while(0) -+ -+ #define __lcd_special_pin_init() \ -+ do { \ -+ __gpio_as_output(SPEN); /* use SPDA */\ -+ __gpio_as_output(SPCK); /* use SPCK */\ -+ __gpio_as_output(SPDA); /* use SPDA */\ -+ __gpio_as_output(LCD_RET);\ -+ udelay(50);\ -+ __gpio_clear_pin(LCD_RET);\ -+ mdelay(150);\ -+ __gpio_set_pin(LCD_RET);\ -+ } while (0) -+ -+ #define __lcd_special_on() \ -+ do { \ -+ udelay(50);\ -+ __gpio_clear_pin(LCD_RET);\ -+ mdelay(150);\ -+ __gpio_set_pin(LCD_RET);\ -+ mdelay(10);\ -+ __spi_write_reg(0x00, 0x03); \ -+ __spi_write_reg(0x01, 0x40); \ -+ __spi_write_reg(0x02, 0x11); \ -+ __spi_write_reg(0x03, MODE); /* mode */ \ -+ __spi_write_reg(0x04, 0x32); \ -+ __spi_write_reg(0x05, 0x0e); \ -+ __spi_write_reg(0x07, 0x03); \ -+ __spi_write_reg(0x08, 0x08); \ -+ __spi_write_reg(0x09, 0x32); \ -+ __spi_write_reg(0x0A, 0x88); \ -+ __spi_write_reg(0x0B, 0xc6); \ -+ __spi_write_reg(0x0C, 0x20); \ -+ __spi_write_reg(0x0D, 0x20); \ -+ } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ -+/* __spi_write_reg(0x02, 0x03); \ -+ __spi_write_reg(0x06, 0x40); \ -+ __spi_write_reg(0x0a, 0x11); \ -+ __spi_write_reg(0x0e, 0xcd); \ -+ __spi_write_reg(0x12, 0x32); \ -+ __spi_write_reg(0x16, 0x0e); \ -+ __spi_write_reg(0x1e, 0x03); \ -+ __spi_write_reg(0x22, 0x08); \ -+ __spi_write_reg(0x26, 0x40); \ -+ __spi_write_reg(0x2a, 0x88); \ -+ __spi_write_reg(0x2e, 0x88); \ -+ __spi_write_reg(0x32, 0x20); \ -+ __spi_write_reg(0x36, 0x20); \ -+*/ -+// } while (0) //reg 0x0a is control the display direction:DB0->horizontal level DB1->vertical level -+ -+ #define __lcd_special_off() \ -+ do { \ -+ __spi_write_reg(0x00, 0x03); \ -+ } while (0) -+ -+#endif /* CONFIG_JZLCD_FOXCONN_PT035TN01 or CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL */ -+ -+ -+#ifndef __lcd_special_pin_init -+#define __lcd_special_pin_init() -+#endif -+#ifndef __lcd_special_on -+#define __lcd_special_on() -+#endif -+#ifndef __lcd_special_off -+#define __lcd_special_off() -+#endif -+ -+ -+/* -+ * Platform specific definition -+ */ -+ -+#if defined(CONFIG_JZ4730_GPS) -+ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ ; \ -+} while (0) -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __lcd_special_pin_init(); \ -+ __gpio_as_output(94); /* PWM0 pin */ \ -+ __gpio_as_output(95); /* PWM1 pin */ \ -+} while (0) -+ -+#define __lcd_display_on() \ -+do { \ -+ __lcd_special_on(); \ -+ __gpio_set_pin(94); /* PWM0 pin */ \ -+ __gpio_set_pin(95); /* PWM1 pin */ \ -+ __lcd_set_backlight_level(8); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_special_off(); \ -+} while (0) -+ -+#endif /* CONFIG_JZ4730_GPS */ -+ -+#if defined(CONFIG_JZ4730_FPRINT) -+ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ REG_PWM_DUT(0) = n; \ -+ REG_PWM_PER(0) = 7; \ -+ REG_PWM_CTR(0) = 0x81; \ -+} while (0) -+ -+#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __lcd_special_pin_init();\ -+ __gpio_as_pwm();\ -+ __lcd_set_backlight_level(8);\ -+} while (0) -+ -+#define __lcd_display_on() \ -+do { \ -+ __lcd_set_backlight_level(8); \ -+ __lcd_special_on();\ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_set_backlight_level(0); \ -+ __lcd_special_off();\ -+} while (0) -+ -+#else -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __gpio_as_output(GPIO_DISP_OFF_N); \ -+ __gpio_as_pwm(); \ -+ __lcd_set_backlight_level(8); \ -+} while (0) -+ -+#define __lcd_display_on() \ -+do { \ -+ __lcd_set_backlight_level(8); \ -+ __gpio_set_pin(GPIO_DISP_OFF_N); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_set_backlight_level(0); \ -+ __gpio_clear_pin(GPIO_DISP_OFF_N); \ -+} while (0) -+#endif -+ -+#endif /* CONFIG_JZ4730_FPRINT */ -+ -+#if defined(CONFIG_JZ4730_LIBRA) -+ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+} while (0) -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __lcd_special_pin_init(); \ -+ __gpio_clear_pin(100); \ -+ __gpio_as_output(100); \ -+ __gpio_as_output(94); \ -+ __gpio_as_output(95); \ -+ __lcd_set_backlight_level(8); \ -+} while (0) -+ -+#define __lcd_display_on() \ -+do { \ -+ __lcd_special_on(); \ -+ __gpio_set_pin(100); \ -+ __gpio_set_pin(94); \ -+ __gpio_set_pin(95); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_special_off(); \ -+ __gpio_clear_pin(100); \ -+ __gpio_clear_pin(94); \ -+ __gpio_clear_pin(95); \ -+} while (0) -+ -+#endif /* CONFIG_JZ4730_LIBRA */ -+ -+#if defined(CONFIG_JZ4730_PMP) -+ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ REG_PWM_DUT(0) = n; \ -+ REG_PWM_PER(0) = 7; \ -+ REG_PWM_CTR(0) = 0x81; \ -+} while (0) -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __gpio_as_output(GPIO_DISP_OFF_N); \ -+ __gpio_as_pwm(); \ -+ __lcd_set_backlight_level(10); \ -+ __lcd_special_pin_init(); \ -+} while (0) -+ -+#define __lcd_display_on() \ -+do { \ -+ __lcd_special_on(); \ -+ __lcd_set_backlight_level(8); \ -+ __gpio_set_pin(GPIO_DISP_OFF_N); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_special_off(); \ -+ __lcd_set_backlight_level(0); \ -+ __gpio_clear_pin(GPIO_DISP_OFF_N); \ -+} while (0) -+ -+#endif /* CONFIG_JZ4730_PMP */ -+ -+/*#if defined(CONFIG_JZ4740_LEO) || defined(CONFIG_JZ4740_PAVO)*/ -+#if defined(CONFIG_SOC_JZ4740) -+#if defined(CONFIG_JZ4740_PAVO) || defined(CONFIG_JZ4740_LYRA) -+#define GPIO_PWM 123 /* GP_D27 */ -+#define PWM_CHN 4 /* pwm channel */ -+#define PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+#define __lcd_set_backlight_level(n)\ -+do { \ -+__gpio_as_output(32*3+27); \ -+__gpio_set_pin(32*3+27); \ -+} while (0) -+ -+#define __lcd_close_backlight() \ -+do { \ -+__gpio_as_output(GPIO_PWM); \ -+__gpio_clear_pin(GPIO_PWM); \ -+} while (0) -+ -+#elif defined(CONFIG_JZ4720_VIRGO) -+#define GPIO_PWM 119 /* GP_D23 */ -+#define PWM_CHN 0 /* pwm channel */ -+#define PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+/*#define __lcd_set_backlight_level(n) \ -+do { \ -+ __gpio_as_pwm(0); \ -+ __tcu_disable_pwm_output(PWM_CHN); \ -+ __tcu_stop_counter(PWM_CHN); \ -+ __tcu_init_pwm_output_high(PWM_CHN); \ -+ __tcu_set_pwm_output_shutdown_abrupt(PWM_CHN); \ -+ __tcu_select_clk_div1(PWM_CHN); \ -+ __tcu_mask_full_match_irq(PWM_CHN); \ -+ __tcu_mask_half_match_irq(PWM_CHN); \ -+ __tcu_set_count(PWM_CHN,0); \ -+ __tcu_set_full_data(PWM_CHN,__cpm_get_extalclk()/1000); \ -+ __tcu_set_half_data(PWM_CHN,__cpm_get_extalclk()/1000*n/100); \ -+ __tcu_enable_pwm_output(PWM_CHN); \ -+ __tcu_select_extalclk(PWM_CHN); \ -+ __tcu_start_counter(PWM_CHN); \ -+} while (0) -+*/ -+ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ __gpio_as_output(GPIO_PWM); \ -+ __gpio_set_pin(GPIO_PWM); \ -+} while (0) -+ -+#define __lcd_close_backlight() \ -+do { \ -+__gpio_as_output(GPIO_PWM); \ -+__gpio_clear_pin(GPIO_PWM); \ -+} while (0) -+ -+#else -+#define __lcd_set_backlight_level(n) -+#define __lcd_close_backlight() -+ -+#endif /* #if defined(CONFIG_MIPS_JZ4740_PAVO) */ -+ -+#define __lcd_display_pin_init() \ -+do { \ -+ __gpio_as_output(GPIO_DISP_OFF_N); \ -+ __cpm_start_tcu(); \ -+ __lcd_special_pin_init(); \ -+} while (0) -+/* __lcd_set_backlight_level(100); \*/ -+#define __lcd_display_on() \ -+do { \ -+ __gpio_set_pin(GPIO_DISP_OFF_N); \ -+ __lcd_special_on(); \ -+ __lcd_set_backlight_level(80); \ -+} while (0) -+ -+#define __lcd_display_off() \ -+do { \ -+ __lcd_special_off(); \ -+ __lcd_close_backlight(); \ -+ __gpio_clear_pin(GPIO_DISP_OFF_N); \ -+} while (0) -+ -+#endif /* CONFIG_MIPS_JZ4740_LEO */ -+ -+#if defined(CONFIG_JZLCD_MSTN_240x128) -+ -+#if 0 /* The final version does not use software emulation of VCOM. */ -+ -+#define GPIO_VSYNC 59 -+#define GPIO_VCOM 90 -+ -+#define REG_VCOM REG_GPIO_GPDR((GPIO_VCOM>>5)) -+#define VCOM_BIT (1 << (GPIO_VCOM & 0x1f)) -+static unsigned int vcom_static; -+static void vsync_irq(int irq, void *dev_id, struct pt_regs *reg) -+{ -+ vcom_static = REG_VCOM; -+ vcom_static ^= VCOM_BIT; -+ REG_VCOM = vcom_static; -+} -+ -+#define __lcd_display_pin_init() \ -+ __gpio_as_irq_rise_edge(GPIO_VSYNC); \ -+ __gpio_as_output(GPIO_VCOM); \ -+ { \ -+ static int inited = 0; \ -+ if (!inited) { \ -+ inited = 1; \ -+ if (request_irq(IRQ_GPIO_0 + GPIO_VSYNC, vsync_irq, SA_INTERRUPT, \ -+ "vsync", 0)) { \ -+ err = -EBUSY; \ -+ goto failed; \ -+ }}} -+ -+#endif -+ -+/* We uses AC BIAs pin to generate VCOM signal, so above code should be removed. -+ */ -+#endif -+/***************************************************************************** -+ * LCD display pin dummy macros -+ *****************************************************************************/ -+#ifndef __lcd_display_pin_init -+#define __lcd_display_pin_init() -+#endif -+#ifndef __lcd_display_on -+#define __lcd_display_on() -+#endif -+#ifndef __lcd_display_off -+#define __lcd_display_off() -+#endif -+#ifndef __lcd_set_backlight_level -+#define __lcd_set_backlight_level(n) -+#endif -+ -+#endif /* __JZLCD_H__ */ -diff -urN linux-2.6.24.7.old/drivers/watchdog/Kconfig linux-2.6.24.7/drivers/watchdog/Kconfig ---- linux-2.6.24.7.old/drivers/watchdog/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/watchdog/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -45,6 +45,15 @@ - - # Architecture Independent - -+config JZ_WDT -+ bool 'JzSoC On-Chip watchdog' -+ help -+ Watchdog timer embedded into JZSOC chips. This will reboot your -+ system when the timeout is reached. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called jz_wdt. -+ - config SOFT_WATCHDOG - tristate "Software watchdog" - help -diff -urN linux-2.6.24.7.old/drivers/watchdog/Makefile linux-2.6.24.7/drivers/watchdog/Makefile ---- linux-2.6.24.7.old/drivers/watchdog/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/drivers/watchdog/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -10,6 +10,9 @@ - # that also fails then you can fall back to the software watchdog - # to give you some cover. - -+# JZ-watchdog timer -+obj-$(CONFIG_JZ_WDT) += jz_wdt.o -+ - # ISA-based Watchdog Cards - obj-$(CONFIG_PCWATCHDOG) += pcwd.o - obj-$(CONFIG_MIXCOMWD) += mixcomwd.o -diff -urN linux-2.6.24.7.old/drivers/watchdog/jz_wdt.c linux-2.6.24.7/drivers/watchdog/jz_wdt.c ---- linux-2.6.24.7.old/drivers/watchdog/jz_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/drivers/watchdog/jz_wdt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,203 @@ -+/* -+ * linux/drivers/char/jz_wdt.c -+ * -+ * Watchdog driver for the Ingenic JzSOC -+ * -+ * Author: Wei Jianli -+ * -+ * 2005 (c) Ingenic Semiconductor. This file is licensed under the -+ * terms of the GNU General Public License version 2. This program is -+ * licensed "as is" without any warranty of any kind, whether express -+ * or implied. -+ */ -+ -+#include -+//#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ -+ -+static unsigned int timer_margin = TIMER_MARGIN; /* in seconds */ -+static unsigned int timer_rate; -+static unsigned int pre_margin; -+static unsigned long jz_wdt_users = 0; -+ -+#ifdef MODULE -+MODULE_PARM(timer_margin, "i"); -+#endif -+ -+static void -+jz_wdt_ping(void) -+{ -+ printk("jz_wdt_ping\n"); -+ /* reload counter with (new) margin */ -+#ifdef CONFIG_SOC_JZ4730 -+ pre_margin = 0xffffffff - timer_rate * timer_margin; -+ __wdt_set_count(pre_margin); -+#endif -+#ifdef CONFIG_SOC_JZ4740 -+ pre_margin = timer_rate * timer_margin; -+ __wdt_set_count(0); -+ __wdt_set_data(pre_margin); -+#endif -+} -+ -+/* -+ * Allow only one person to hold it open -+ */ -+ -+static int -+jz_wdt_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(1, &jz_wdt_users)) -+ return -EBUSY; -+ -+ printk("jz_wdt_open\n"); -+#ifdef CONFIG_SOC_JZ4730 -+ if (REG_CPM_OCR & CPM_OCR_EXT_RTC_CLK) -+ timer_rate = 32768; -+ else -+ timer_rate = JZ_EXTAL/128; -+#endif -+ -+#ifdef CONFIG_SOC_JZ4740 -+ /* Initialize the wdt clocks */ -+ __wdt_select_rtcclk(); -+ __wdt_select_clk_div1024(); -+ __tcu_start_wdt_clock(); -+ timer_rate = 32; /* 32768 / 1024 */ -+#endif -+ -+ jz_wdt_ping(); -+ __wdt_start(); -+ -+ return 0; -+} -+ -+static int -+jz_wdt_release(struct inode *inode, struct file *file) -+{ -+ /* -+ * Shut off the timer. -+ * Lock it in if it's a module and we defined ...NOWAYOUT -+ */ -+ jz_wdt_ping(); -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ /* SW can't stop wdt once it was started */ -+#endif -+ jz_wdt_users = 0; -+ return 0; -+} -+ -+static ssize_t -+jz_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos) -+{ -+ /* Can't seek (pwrite) on this device */ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ -+ printk("jz_wdt_write\n"); -+ -+ /* Refresh counter */ -+ if (len) { -+ jz_wdt_ping(); -+ return 1; -+ } -+ return 0; -+} -+ -+static int -+jz_wdt_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int new_margin; -+ static struct watchdog_info ident = { -+ .identity = "JzSOC Watchdog", -+ .options = WDIOF_SETTIMEOUT, -+ .firmware_version = 0, -+ }; -+ -+ switch (cmd) { -+ default: -+ return -ENOIOCTLCMD; -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *) arg, &ident, -+ sizeof (ident)); -+ case WDIOC_GETSTATUS: -+ return put_user(0, (int *) arg); -+ case WDIOC_GETBOOTSTATUS: -+#ifdef CONFIG_SOC_JZ4730 -+ return put_user(REG_CPM_RSTR, (int *) arg); -+#endif -+#ifdef CONFIG_SOC_JZ4740 -+ return put_user(REG_RTC_HWRSR, (int *) arg); -+#endif -+ case WDIOC_KEEPALIVE: -+ jz_wdt_ping(); -+ return 0; -+ case WDIOC_SETTIMEOUT: -+ if (get_user(new_margin, (int *) arg)) -+ return -EFAULT; -+ if (new_margin < 1) -+ return -EINVAL; -+ timer_margin = new_margin; -+ jz_wdt_ping(); -+ /* Fall */ -+ case WDIOC_GETTIMEOUT: -+ return put_user(timer_margin, (int *) arg); -+ } -+} -+ -+static struct file_operations jz_wdt_fops = { -+ .owner = THIS_MODULE, -+ .write = jz_wdt_write, -+ .ioctl = jz_wdt_ioctl, -+ .open = jz_wdt_open, -+ .release = jz_wdt_release, -+}; -+ -+static struct miscdevice jz_wdt_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "jz_wdt", -+ .fops = &jz_wdt_fops -+}; -+ -+static int __init -+jz_wdt_init(void) -+{ -+ int ret; -+ -+ ret = misc_register(&jz_wdt_miscdev); -+ -+ if (ret) -+ return ret; -+ -+ printk("JzSOC Watchdog Timer: timer margin %d sec\n", timer_margin); -+ -+ return 0; -+} -+ -+static void __exit -+jz_wdt_exit(void) -+{ -+ misc_deregister(&jz_wdt_miscdev); -+} -+ -+module_init(jz_wdt_init); -+module_exit(jz_wdt_exit); -+ -+MODULE_AUTHOR("Wei Jianli"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/fs/Kconfig linux-2.6.24.7/fs/Kconfig ---- linux-2.6.24.7.old/fs/Kconfig 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/fs/Kconfig 2009-04-12 18:27:23.000000000 +0200 -@@ -1389,6 +1389,9 @@ - - endchoice - -+# UBIFS File system configuration -+source "fs/ubifs/Kconfig" -+ - config CRAMFS - tristate "Compressed ROM file system support (cramfs)" - depends on BLOCK -diff -urN linux-2.6.24.7.old/fs/Kconfig.orig linux-2.6.24.7/fs/Kconfig.orig ---- linux-2.6.24.7.old/fs/Kconfig.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/Kconfig.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,2202 @@ -+# -+# File system configuration -+# -+ -+menu "File systems" -+ -+if BLOCK -+ -+config EXT2_FS -+ tristate "Second extended fs support" -+ help -+ Ext2 is a standard Linux file system for hard disks. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called ext2. -+ -+ If unsure, say Y. -+ -+config EXT2_FS_XATTR -+ bool "Ext2 extended attributes" -+ depends on EXT2_FS -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). -+ -+ If unsure, say N. -+ -+config EXT2_FS_POSIX_ACL -+ bool "Ext2 POSIX Access Control Lists" -+ depends on EXT2_FS_XATTR -+ select FS_POSIX_ACL -+ help -+ Posix Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the Posix ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config EXT2_FS_SECURITY -+ bool "Ext2 Security Labels" -+ depends on EXT2_FS_XATTR -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the ext2 filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config EXT2_FS_XIP -+ bool "Ext2 execute in place support" -+ depends on EXT2_FS && MMU -+ help -+ Execute in place can be used on memory-backed block devices. If you -+ enable this option, you can select to mount block devices which are -+ capable of this feature without using the page cache. -+ -+ If you do not use a block device that is capable of using this, -+ or if unsure, say N. -+ -+config FS_XIP -+# execute in place -+ bool -+ depends on EXT2_FS_XIP -+ default y -+ -+config EXT3_FS -+ tristate "Ext3 journalling file system support" -+ select JBD -+ help -+ This is the journalling version of the Second extended file system -+ (often called ext3), the de facto standard Linux file system -+ (method to organize files on a storage device) for hard disks. -+ -+ The journalling code included in this driver means you do not have -+ to run e2fsck (file system checker) on your file systems after a -+ crash. The journal keeps track of any changes that were being made -+ at the time the system crashed, and can ensure that your file system -+ is consistent without the need for a lengthy check. -+ -+ Other than adding the journal to the file system, the on-disk format -+ of ext3 is identical to ext2. It is possible to freely switch -+ between using the ext3 driver and the ext2 driver, as long as the -+ file system has been cleanly unmounted, or e2fsck is run on the file -+ system. -+ -+ To add a journal on an existing ext2 file system or change the -+ behavior of ext3 file systems, you can use the tune2fs utility ("man -+ tune2fs"). To modify attributes of files and directories on ext3 -+ file systems, use chattr ("man chattr"). You need to be using -+ e2fsprogs version 1.20 or later in order to create ext3 journals -+ (available at ). -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called ext3. -+ -+config EXT3_FS_XATTR -+ bool "Ext3 extended attributes" -+ depends on EXT3_FS -+ default y -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). -+ -+ If unsure, say N. -+ -+ You need this for POSIX ACL support on ext3. -+ -+config EXT3_FS_POSIX_ACL -+ bool "Ext3 POSIX Access Control Lists" -+ depends on EXT3_FS_XATTR -+ select FS_POSIX_ACL -+ help -+ Posix Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the Posix ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config EXT3_FS_SECURITY -+ bool "Ext3 Security Labels" -+ depends on EXT3_FS_XATTR -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the ext3 filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config EXT4DEV_FS -+ tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)" -+ depends on EXPERIMENTAL -+ select JBD2 -+ select CRC16 -+ help -+ Ext4dev is a predecessor filesystem of the next generation -+ extended fs ext4, based on ext3 filesystem code. It will be -+ renamed ext4 fs later, once ext4dev is mature and stabilized. -+ -+ Unlike the change from ext2 filesystem to ext3 filesystem, -+ the on-disk format of ext4dev is not the same as ext3 any more: -+ it is based on extent maps and it supports 48-bit physical block -+ numbers. These combined on-disk format changes will allow -+ ext4dev/ext4 to handle more than 16 TB filesystem volumes -- -+ a hard limit that ext3 cannot overcome without changing the -+ on-disk format. -+ -+ Other than extent maps and 48-bit block numbers, ext4dev also is -+ likely to have other new features such as persistent preallocation, -+ high resolution time stamps, and larger file support etc. These -+ features will be added to ext4dev gradually. -+ -+ To compile this file system support as a module, choose M here. The -+ module will be called ext4dev. -+ -+ If unsure, say N. -+ -+config EXT4DEV_FS_XATTR -+ bool "Ext4dev extended attributes" -+ depends on EXT4DEV_FS -+ default y -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). -+ -+ If unsure, say N. -+ -+ You need this for POSIX ACL support on ext4dev/ext4. -+ -+config EXT4DEV_FS_POSIX_ACL -+ bool "Ext4dev POSIX Access Control Lists" -+ depends on EXT4DEV_FS_XATTR -+ select FS_POSIX_ACL -+ help -+ POSIX Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the POSIX ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config EXT4DEV_FS_SECURITY -+ bool "Ext4dev Security Labels" -+ depends on EXT4DEV_FS_XATTR -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the ext4dev/ext4 filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config JBD -+ tristate -+ help -+ This is a generic journalling layer for block devices. It is -+ currently used by the ext3 and OCFS2 file systems, but it could -+ also be used to add journal support to other file systems or block -+ devices such as RAID or LVM. -+ -+ If you are using the ext3 or OCFS2 file systems, you need to -+ say Y here. If you are not using ext3 OCFS2 then you will probably -+ want to say N. -+ -+ To compile this device as a module, choose M here: the module will be -+ called jbd. If you are compiling ext3 or OCFS2 into the kernel, -+ you cannot compile this code as a module. -+ -+config JBD_DEBUG -+ bool "JBD (ext3) debugging support" -+ depends on JBD && DEBUG_FS -+ help -+ If you are using the ext3 journaled file system (or potentially any -+ other file system/device using JBD), this option allows you to -+ enable debugging output while the system is running, in order to -+ help track down any problems you are having. By default the -+ debugging output will be turned off. -+ -+ If you select Y here, then you will be able to turn on debugging -+ with "echo N > /sys/kernel/debug/jbd/jbd-debug", where N is a -+ number between 1 and 5, the higher the number, the more debugging -+ output is generated. To turn debugging off again, do -+ "echo 0 > /sys/kernel/debug/jbd/jbd-debug". -+ -+config JBD2 -+ tristate -+ help -+ This is a generic journaling layer for block devices that support -+ both 32-bit and 64-bit block numbers. It is currently used by -+ the ext4dev/ext4 filesystem, but it could also be used to add -+ journal support to other file systems or block devices such -+ as RAID or LVM. -+ -+ If you are using ext4dev/ext4, you need to say Y here. If you are not -+ using ext4dev/ext4 then you will probably want to say N. -+ -+ To compile this device as a module, choose M here. The module will be -+ called jbd2. If you are compiling ext4dev/ext4 into the kernel, -+ you cannot compile this code as a module. -+ -+config JBD2_DEBUG -+ bool "JBD2 (ext4dev/ext4) debugging support" -+ depends on JBD2 && DEBUG_FS -+ help -+ If you are using the ext4dev/ext4 journaled file system (or -+ potentially any other filesystem/device using JBD2), this option -+ allows you to enable debugging output while the system is running, -+ in order to help track down any problems you are having. -+ By default, the debugging output will be turned off. -+ -+ If you select Y here, then you will be able to turn on debugging -+ with "echo N > /sys/kernel/debug/jbd2/jbd2-debug", where N is a -+ number between 1 and 5. The higher the number, the more debugging -+ output is generated. To turn debugging off again, do -+ "echo 0 > /sys/kernel/debug/jbd2/jbd2-debug". -+ -+config FS_MBCACHE -+# Meta block cache for Extended Attributes (ext2/ext3/ext4) -+ tristate -+ depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR -+ default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y -+ default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m -+ -+config REISERFS_FS -+ tristate "Reiserfs support" -+ help -+ Stores not just filenames but the files themselves in a balanced -+ tree. Uses journalling. -+ -+ Balanced trees are more efficient than traditional file system -+ architectural foundations. -+ -+ In general, ReiserFS is as fast as ext2, but is very efficient with -+ large directories and small files. Additional patches are needed -+ for NFS and quotas, please see for links. -+ -+ It is more easily extended to have features currently found in -+ database and keyword search systems than block allocation based file -+ systems are. The next version will be so extended, and will support -+ plugins consistent with our motto ``It takes more than a license to -+ make source code open.'' -+ -+ Read to learn more about reiserfs. -+ -+ Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com. -+ -+ If you like it, you can pay us to add new features to it that you -+ need, buy a support contract, or pay us to port it to another OS. -+ -+config REISERFS_CHECK -+ bool "Enable reiserfs debug mode" -+ depends on REISERFS_FS -+ help -+ If you set this to Y, then ReiserFS will perform every check it can -+ possibly imagine of its internal consistency throughout its -+ operation. It will also go substantially slower. More than once we -+ have forgotten that this was on, and then gone despondent over the -+ latest benchmarks.:-) Use of this option allows our team to go all -+ out in checking for consistency when debugging without fear of its -+ effect on end users. If you are on the verge of sending in a bug -+ report, say Y and you might get a useful error message. Almost -+ everyone should say N. -+ -+config REISERFS_PROC_INFO -+ bool "Stats in /proc/fs/reiserfs" -+ depends on REISERFS_FS && PROC_FS -+ help -+ Create under /proc/fs/reiserfs a hierarchy of files, displaying -+ various ReiserFS statistics and internal data at the expense of -+ making your kernel or module slightly larger (+8 KB). This also -+ increases the amount of kernel memory required for each mount. -+ Almost everyone but ReiserFS developers and people fine-tuning -+ reiserfs or tracing problems should say N. -+ -+config REISERFS_FS_XATTR -+ bool "ReiserFS extended attributes" -+ depends on REISERFS_FS -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). -+ -+ If unsure, say N. -+ -+config REISERFS_FS_POSIX_ACL -+ bool "ReiserFS POSIX Access Control Lists" -+ depends on REISERFS_FS_XATTR -+ select FS_POSIX_ACL -+ help -+ Posix Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the Posix ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config REISERFS_FS_SECURITY -+ bool "ReiserFS Security Labels" -+ depends on REISERFS_FS_XATTR -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the ReiserFS filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config JFS_FS -+ tristate "JFS filesystem support" -+ select NLS -+ help -+ This is a port of IBM's Journaled Filesystem . More information is -+ available in the file . -+ -+ If you do not intend to use the JFS filesystem, say N. -+ -+config JFS_POSIX_ACL -+ bool "JFS POSIX Access Control Lists" -+ depends on JFS_FS -+ select FS_POSIX_ACL -+ help -+ Posix Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the Posix ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config JFS_SECURITY -+ bool "JFS Security Labels" -+ depends on JFS_FS -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the jfs filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config JFS_DEBUG -+ bool "JFS debugging" -+ depends on JFS_FS -+ help -+ If you are experiencing any problems with the JFS filesystem, say -+ Y here. This will result in additional debugging messages to be -+ written to the system log. Under normal circumstances, this -+ results in very little overhead. -+ -+config JFS_STATISTICS -+ bool "JFS statistics" -+ depends on JFS_FS -+ help -+ Enabling this option will cause statistics from the JFS file system -+ to be made available to the user in the /proc/fs/jfs/ directory. -+ -+config FS_POSIX_ACL -+# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs) -+# -+# NOTE: you can implement Posix ACLs without these helpers (XFS does). -+# Never use this symbol for ifdefs. -+# -+ bool -+ default n -+ -+source "fs/xfs/Kconfig" -+source "fs/gfs2/Kconfig" -+source "fs/yaffs2/Kconfig" -+ -+config OCFS2_FS -+ tristate "OCFS2 file system support" -+ depends on NET && SYSFS -+ select CONFIGFS_FS -+ select JBD -+ select CRC32 -+ help -+ OCFS2 is a general purpose extent based shared disk cluster file -+ system with many similarities to ext3. It supports 64 bit inode -+ numbers, and has automatically extending metadata groups which may -+ also make it attractive for non-clustered use. -+ -+ You'll want to install the ocfs2-tools package in order to at least -+ get "mount.ocfs2". -+ -+ Project web page: http://oss.oracle.com/projects/ocfs2 -+ Tools web page: http://oss.oracle.com/projects/ocfs2-tools -+ OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/ -+ -+ Note: Features which OCFS2 does not support yet: -+ - extended attributes -+ - quotas -+ - cluster aware flock -+ - Directory change notification (F_NOTIFY) -+ - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease) -+ - POSIX ACLs -+ - readpages / writepages (not user visible) -+ -+config OCFS2_DEBUG_MASKLOG -+ bool "OCFS2 logging support" -+ depends on OCFS2_FS -+ default y -+ help -+ The ocfs2 filesystem has an extensive logging system. The system -+ allows selection of events to log via files in /sys/o2cb/logmask/. -+ This option will enlarge your kernel, but it allows debugging of -+ ocfs2 filesystem issues. -+ -+config OCFS2_DEBUG_FS -+ bool "OCFS2 expensive checks" -+ depends on OCFS2_FS -+ default n -+ help -+ This option will enable expensive consistency checks. Enable -+ this option for debugging only as it is likely to decrease -+ performance of the filesystem. -+ -+config MINI_FO -+ tristate "Mini fanout overlay filesystem" -+ -+config MINIX_FS -+ tristate "Minix fs support" -+ help -+ Minix is a simple operating system used in many classes about OS's. -+ The minix file system (method to organize files on a hard disk -+ partition or a floppy disk) was the original file system for Linux, -+ but has been superseded by the second extended file system ext2fs. -+ You don't want to use the minix file system on your hard disk -+ because of certain built-in restrictions, but it is sometimes found -+ on older Linux floppy disks. This option will enlarge your kernel -+ by about 28 KB. If unsure, say N. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called minix. Note that the file system of your root -+ partition (the one containing the directory /) cannot be compiled as -+ a module. -+ -+config ROMFS_FS -+ tristate "ROM file system support" -+ ---help--- -+ This is a very small read-only file system mainly intended for -+ initial ram disks of installation disks, but it could be used for -+ other read-only media as well. Read -+ for details. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called romfs. Note that the file system of your -+ root partition (the one containing the directory /) cannot be a -+ module. -+ -+ If you don't know whether you need it, then you don't need it: -+ answer N. -+ -+endif -+ -+config INOTIFY -+ bool "Inotify file change notification support" -+ default y -+ ---help--- -+ Say Y here to enable inotify support. Inotify is a file change -+ notification system and a replacement for dnotify. Inotify fixes -+ numerous shortcomings in dnotify and introduces several new features -+ including multiple file events, one-shot support, and unmount -+ notification. -+ -+ For more information, see -+ -+ If unsure, say Y. -+ -+config INOTIFY_USER -+ bool "Inotify support for userspace" -+ depends on INOTIFY -+ default y -+ ---help--- -+ Say Y here to enable inotify support for userspace, including the -+ associated system calls. Inotify allows monitoring of both files and -+ directories via a single open fd. Events are read from the file -+ descriptor, which is also select()- and poll()-able. -+ -+ For more information, see -+ -+ If unsure, say Y. -+ -+config QUOTA -+ bool "Quota support" -+ help -+ If you say Y here, you will be able to set per user limits for disk -+ usage (also called disk quotas). Currently, it works for the -+ ext2, ext3, and reiserfs file system. ext3 also supports journalled -+ quotas for which you don't need to run quotacheck(8) after an unclean -+ shutdown. -+ For further details, read the Quota mini-HOWTO, available from -+ , or the documentation provided -+ with the quota tools. Probably the quota support is only useful for -+ multi user systems. If unsure, say N. -+ -+config QUOTA_NETLINK_INTERFACE -+ bool "Report quota messages through netlink interface" -+ depends on QUOTA && NET -+ help -+ If you say Y here, quota warnings (about exceeding softlimit, reaching -+ hardlimit, etc.) will be reported through netlink interface. If unsure, -+ say Y. -+ -+config PRINT_QUOTA_WARNING -+ bool "Print quota warnings to console (OBSOLETE)" -+ depends on QUOTA -+ default y -+ help -+ If you say Y here, quota warnings (about exceeding softlimit, reaching -+ hardlimit, etc.) will be printed to the process' controlling terminal. -+ Note that this behavior is currently deprecated and may go away in -+ future. Please use notification via netlink socket instead. -+ -+config QFMT_V1 -+ tristate "Old quota format support" -+ depends on QUOTA -+ help -+ This quota format was (is) used by kernels earlier than 2.4.22. If -+ you have quota working and you don't want to convert to new quota -+ format say Y here. -+ -+config QFMT_V2 -+ tristate "Quota format v2 support" -+ depends on QUOTA -+ help -+ This quota format allows using quotas with 32-bit UIDs/GIDs. If you -+ need this functionality say Y here. -+ -+config QUOTACTL -+ bool -+ depends on XFS_QUOTA || QUOTA -+ default y -+ -+config DNOTIFY -+ bool "Dnotify support" -+ default y -+ help -+ Dnotify is a directory-based per-fd file change notification system -+ that uses signals to communicate events to user-space. There exist -+ superior alternatives, but some applications may still rely on -+ dnotify. -+ -+ If unsure, say Y. -+ -+config AUTOFS_FS -+ tristate "Kernel automounter support" -+ help -+ The automounter is a tool to automatically mount remote file systems -+ on demand. This implementation is partially kernel-based to reduce -+ overhead in the already-mounted case; this is unlike the BSD -+ automounter (amd), which is a pure user space daemon. -+ -+ To use the automounter you need the user-space tools from the autofs -+ package; you can find the location in . -+ You also want to answer Y to "NFS file system support", below. -+ -+ If you want to use the newer version of the automounter with more -+ features, say N here and say Y to "Kernel automounter v4 support", -+ below. -+ -+ To compile this support as a module, choose M here: the module will be -+ called autofs. -+ -+ If you are not a part of a fairly large, distributed network, you -+ probably do not need an automounter, and can say N here. -+ -+config AUTOFS4_FS -+ tristate "Kernel automounter version 4 support (also supports v3)" -+ help -+ The automounter is a tool to automatically mount remote file systems -+ on demand. This implementation is partially kernel-based to reduce -+ overhead in the already-mounted case; this is unlike the BSD -+ automounter (amd), which is a pure user space daemon. -+ -+ To use the automounter you need the user-space tools from -+ ; you also -+ want to answer Y to "NFS file system support", below. -+ -+ To compile this support as a module, choose M here: the module will be -+ called autofs4. You will need to add "alias autofs autofs4" to your -+ modules configuration file. -+ -+ If you are not a part of a fairly large, distributed network or -+ don't have a laptop which needs to dynamically reconfigure to the -+ local network, you probably do not need an automounter, and can say -+ N here. -+ -+config FUSE_FS -+ tristate "Filesystem in Userspace support" -+ help -+ With FUSE it is possible to implement a fully functional filesystem -+ in a userspace program. -+ -+ There's also companion library: libfuse. This library along with -+ utilities is available from the FUSE homepage: -+ -+ -+ See for more information. -+ See for needed library/utility version. -+ -+ If you want to develop a userspace FS, or if you want to use -+ a filesystem based on FUSE, answer Y or M. -+ -+config GENERIC_ACL -+ bool -+ select FS_POSIX_ACL -+ -+if BLOCK -+menu "CD-ROM/DVD Filesystems" -+ -+config ISO9660_FS -+ tristate "ISO 9660 CDROM file system support" -+ help -+ This is the standard file system used on CD-ROMs. It was previously -+ known as "High Sierra File System" and is called "hsfs" on other -+ Unix systems. The so-called Rock-Ridge extensions which allow for -+ long Unix filenames and symbolic links are also supported by this -+ driver. If you have a CD-ROM drive and want to do more with it than -+ just listen to audio CDs and watch its LEDs, say Y (and read -+ and the CD-ROM-HOWTO, -+ available from ), thereby -+ enlarging your kernel by about 27 KB; otherwise say N. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called isofs. -+ -+config JOLIET -+ bool "Microsoft Joliet CDROM extensions" -+ depends on ISO9660_FS -+ select NLS -+ help -+ Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system -+ which allows for long filenames in unicode format (unicode is the -+ new 16 bit character code, successor to ASCII, which encodes the -+ characters of almost all languages of the world; see -+ for more information). Say Y here if you -+ want to be able to read Joliet CD-ROMs under Linux. -+ -+config ZISOFS -+ bool "Transparent decompression extension" -+ depends on ISO9660_FS -+ select ZLIB_INFLATE -+ help -+ This is a Linux-specific extension to RockRidge which lets you store -+ data in compressed form on a CD-ROM and have it transparently -+ decompressed when the CD-ROM is accessed. See -+ for the tools -+ necessary to create such a filesystem. Say Y here if you want to be -+ able to read such compressed CD-ROMs. -+ -+config UDF_FS -+ tristate "UDF file system support" -+ help -+ This is the new file system used on some CD-ROMs and DVDs. Say Y if -+ you intend to mount DVD discs or CDRW's written in packet mode, or -+ if written to by other UDF utilities, such as DirectCD. -+ Please read . -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called udf. -+ -+ If unsure, say N. -+ -+config UDF_NLS -+ bool -+ default y -+ depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y) -+ -+endmenu -+endif -+ -+if BLOCK -+menu "DOS/FAT/NT Filesystems" -+ -+config FAT_FS -+ tristate -+ select NLS -+ help -+ If you want to use one of the FAT-based file systems (the MS-DOS and -+ VFAT (Windows 95) file systems), then you must say Y or M here -+ to include FAT support. You will then be able to mount partitions or -+ diskettes with FAT-based file systems and transparently access the -+ files on them, i.e. MSDOS files will look and behave just like all -+ other Unix files. -+ -+ This FAT support is not a file system in itself, it only provides -+ the foundation for the other file systems. You will have to say Y or -+ M to at least one of "MSDOS fs support" or "VFAT fs support" in -+ order to make use of it. -+ -+ Another way to read and write MSDOS floppies and hard drive -+ partitions from within Linux (but not transparently) is with the -+ mtools ("man mtools") program suite. You don't need to say Y here in -+ order to do that. -+ -+ If you need to move large files on floppies between a DOS and a -+ Linux box, say Y here, mount the floppy under Linux with an MSDOS -+ file system and use GNU tar's M option. GNU tar is a program -+ available for Unix and DOS ("man tar" or "info tar"). -+ -+ The FAT support will enlarge your kernel by about 37 KB. If unsure, -+ say Y. -+ -+ To compile this as a module, choose M here: the module will be called -+ fat. Note that if you compile the FAT support as a module, you -+ cannot compile any of the FAT-based file systems into the kernel -+ -- they will have to be modules as well. -+ -+config MSDOS_FS -+ tristate "MSDOS fs support" -+ select FAT_FS -+ help -+ This allows you to mount MSDOS partitions of your hard drive (unless -+ they are compressed; to access compressed MSDOS partitions under -+ Linux, you can either use the DOS emulator DOSEMU, described in the -+ DOSEMU-HOWTO, available from -+ , or try dmsdosfs in -+ . If you -+ intend to use dosemu with a non-compressed MSDOS partition, say Y -+ here) and MSDOS floppies. This means that file access becomes -+ transparent, i.e. the MSDOS files look and behave just like all -+ other Unix files. -+ -+ If you have Windows 95 or Windows NT installed on your MSDOS -+ partitions, you should use the VFAT file system (say Y to "VFAT fs -+ support" below), or you will not be able to see the long filenames -+ generated by Windows 95 / Windows NT. -+ -+ This option will enlarge your kernel by about 7 KB. If unsure, -+ answer Y. This will only work if you said Y to "DOS FAT fs support" -+ as well. To compile this as a module, choose M here: the module will -+ be called msdos. -+ -+config VFAT_FS -+ tristate "VFAT (Windows-95) fs support" -+ select FAT_FS -+ help -+ This option provides support for normal Windows file systems with -+ long filenames. That includes non-compressed FAT-based file systems -+ used by Windows 95, Windows 98, Windows NT 4.0, and the Unix -+ programs from the mtools package. -+ -+ The VFAT support enlarges your kernel by about 10 KB and it only -+ works if you said Y to the "DOS FAT fs support" above. Please read -+ the file for details. If -+ unsure, say Y. -+ -+ To compile this as a module, choose M here: the module will be called -+ vfat. -+ -+config FAT_DEFAULT_CODEPAGE -+ int "Default codepage for FAT" -+ depends on MSDOS_FS || VFAT_FS -+ default 437 -+ help -+ This option should be set to the codepage of your FAT filesystems. -+ It can be overridden with the "codepage" mount option. -+ See for more information. -+ -+config FAT_DEFAULT_IOCHARSET -+ string "Default iocharset for FAT" -+ depends on VFAT_FS -+ default "iso8859-1" -+ help -+ Set this to the default input/output character set you'd -+ like FAT to use. It should probably match the character set -+ that most of your FAT filesystems use, and can be overridden -+ with the "iocharset" mount option for FAT filesystems. -+ Note that "utf8" is not recommended for FAT filesystems. -+ If unsure, you shouldn't set "utf8" here. -+ See for more information. -+ -+config NTFS_FS -+ tristate "NTFS file system support" -+ select NLS -+ help -+ NTFS is the file system of Microsoft Windows NT, 2000, XP and 2003. -+ -+ Saying Y or M here enables read support. There is partial, but -+ safe, write support available. For write support you must also -+ say Y to "NTFS write support" below. -+ -+ There are also a number of user-space tools available, called -+ ntfsprogs. These include ntfsundelete and ntfsresize, that work -+ without NTFS support enabled in the kernel. -+ -+ This is a rewrite from scratch of Linux NTFS support and replaced -+ the old NTFS code starting with Linux 2.5.11. A backport to -+ the Linux 2.4 kernel series is separately available as a patch -+ from the project web site. -+ -+ For more information see -+ and . -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called ntfs. -+ -+ If you are not using Windows NT, 2000, XP or 2003 in addition to -+ Linux on your computer it is safe to say N. -+ -+config NTFS_DEBUG -+ bool "NTFS debugging support" -+ depends on NTFS_FS -+ help -+ If you are experiencing any problems with the NTFS file system, say -+ Y here. This will result in additional consistency checks to be -+ performed by the driver as well as additional debugging messages to -+ be written to the system log. Note that debugging messages are -+ disabled by default. To enable them, supply the option debug_msgs=1 -+ at the kernel command line when booting the kernel or as an option -+ to insmod when loading the ntfs module. Once the driver is active, -+ you can enable debugging messages by doing (as root): -+ echo 1 > /proc/sys/fs/ntfs-debug -+ Replacing the "1" with "0" would disable debug messages. -+ -+ If you leave debugging messages disabled, this results in little -+ overhead, but enabling debug messages results in very significant -+ slowdown of the system. -+ -+ When reporting bugs, please try to have available a full dump of -+ debugging messages while the misbehaviour was occurring. -+ -+config NTFS_RW -+ bool "NTFS write support" -+ depends on NTFS_FS -+ help -+ This enables the partial, but safe, write support in the NTFS driver. -+ -+ The only supported operation is overwriting existing files, without -+ changing the file length. No file or directory creation, deletion or -+ renaming is possible. Note only non-resident files can be written to -+ so you may find that some very small files (<500 bytes or so) cannot -+ be written to. -+ -+ While we cannot guarantee that it will not damage any data, we have -+ so far not received a single report where the driver would have -+ damaged someones data so we assume it is perfectly safe to use. -+ -+ Note: While write support is safe in this version (a rewrite from -+ scratch of the NTFS support), it should be noted that the old NTFS -+ write support, included in Linux 2.5.10 and before (since 1997), -+ is not safe. -+ -+ This is currently useful with TopologiLinux. TopologiLinux is run -+ on top of any DOS/Microsoft Windows system without partitioning your -+ hard disk. Unlike other Linux distributions TopologiLinux does not -+ need its own partition. For more information see -+ -+ -+ It is perfectly safe to say N here. -+ -+endmenu -+endif -+ -+menu "Pseudo filesystems" -+ -+config PROC_FS -+ bool "/proc file system support" if EMBEDDED -+ default y -+ help -+ This is a virtual file system providing information about the status -+ of the system. "Virtual" means that it doesn't take up any space on -+ your hard disk: the files are created on the fly by the kernel when -+ you try to access them. Also, you cannot read the files with older -+ version of the program less: you need to use more or cat. -+ -+ It's totally cool; for example, "cat /proc/interrupts" gives -+ information about what the different IRQs are used for at the moment -+ (there is a small number of Interrupt ReQuest lines in your computer -+ that are used by the attached devices to gain the CPU's attention -- -+ often a source of trouble if two devices are mistakenly configured -+ to use the same IRQ). The program procinfo to display some -+ information about your system gathered from the /proc file system. -+ -+ Before you can use the /proc file system, it has to be mounted, -+ meaning it has to be given a location in the directory hierarchy. -+ That location should be /proc. A command such as "mount -t proc proc -+ /proc" or the equivalent line in /etc/fstab does the job. -+ -+ The /proc file system is explained in the file -+ and on the proc(5) manpage -+ ("man 5 proc"). -+ -+ This option will enlarge your kernel by about 67 KB. Several -+ programs depend on this, so everyone should say Y here. -+ -+config PROC_KCORE -+ bool "/proc/kcore support" if !ARM -+ depends on PROC_FS && MMU -+ -+config PROC_VMCORE -+ bool "/proc/vmcore support (EXPERIMENTAL)" -+ depends on PROC_FS && EXPERIMENTAL && CRASH_DUMP -+ default y -+ help -+ Exports the dump image of crashed kernel in ELF format. -+ -+config PROC_SYSCTL -+ bool "Sysctl support (/proc/sys)" if EMBEDDED -+ depends on PROC_FS -+ select SYSCTL -+ default y -+ ---help--- -+ The sysctl interface provides a means of dynamically changing -+ certain kernel parameters and variables on the fly without requiring -+ a recompile of the kernel or reboot of the system. The primary -+ interface is through /proc/sys. If you say Y here a tree of -+ modifiable sysctl entries will be generated beneath the -+ /proc/sys directory. They are explained in the files -+ in . Note that enabling this -+ option will enlarge the kernel by at least 8 KB. -+ -+ As it is generally a good thing, you should say Y here unless -+ building a kernel for install/rescue disks or your system is very -+ limited in memory. -+ -+config SYSFS -+ bool "sysfs file system support" if EMBEDDED -+ default y -+ help -+ The sysfs filesystem is a virtual filesystem that the kernel uses to -+ export internal kernel objects, their attributes, and their -+ relationships to one another. -+ -+ Users can use sysfs to ascertain useful information about the running -+ kernel, such as the devices the kernel has discovered on each bus and -+ which driver each is bound to. sysfs can also be used to tune devices -+ and other kernel subsystems. -+ -+ Some system agents rely on the information in sysfs to operate. -+ /sbin/hotplug uses device and object attributes in sysfs to assist in -+ delegating policy decisions, like persistently naming devices. -+ -+ sysfs is currently used by the block subsystem to mount the root -+ partition. If sysfs is disabled you must specify the boot device on -+ the kernel boot command line via its major and minor numbers. For -+ example, "root=03:01" for /dev/hda1. -+ -+ Designers of embedded systems may wish to say N here to conserve space. -+ -+config TMPFS -+ bool "Virtual memory file system support (former shm fs)" -+ help -+ Tmpfs is a file system which keeps all files in virtual memory. -+ -+ Everything in tmpfs is temporary in the sense that no files will be -+ created on your hard drive. The files live in memory and swap -+ space. If you unmount a tmpfs instance, everything stored therein is -+ lost. -+ -+ See for details. -+ -+config TMPFS_POSIX_ACL -+ bool "Tmpfs POSIX Access Control Lists" -+ depends on TMPFS -+ select GENERIC_ACL -+ help -+ POSIX Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the POSIX ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N. -+ -+config HUGETLBFS -+ bool "HugeTLB file system support" -+ depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || BROKEN -+ help -+ hugetlbfs is a filesystem backing for HugeTLB pages, based on -+ ramfs. For architectures that support it, say Y here and read -+ for details. -+ -+ If unsure, say N. -+ -+config HUGETLB_PAGE -+ def_bool HUGETLBFS -+ -+config CONFIGFS_FS -+ tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)" -+ depends on SYSFS && EXPERIMENTAL -+ help -+ configfs is a ram-based filesystem that provides the converse -+ of sysfs's functionality. Where sysfs is a filesystem-based -+ view of kernel objects, configfs is a filesystem-based manager -+ of kernel objects, or config_items. -+ -+ Both sysfs and configfs can and should exist together on the -+ same system. One is not a replacement for the other. -+ -+endmenu -+ -+menu "Miscellaneous filesystems" -+ -+config ADFS_FS -+ tristate "ADFS file system support (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ help -+ The Acorn Disc Filing System is the standard file system of the -+ RiscOS operating system which runs on Acorn's ARM-based Risc PC -+ systems and the Acorn Archimedes range of machines. If you say Y -+ here, Linux will be able to read from ADFS partitions on hard drives -+ and from ADFS-formatted floppy discs. If you also want to be able to -+ write to those devices, say Y to "ADFS write support" below. -+ -+ The ADFS partition should be the first partition (i.e., -+ /dev/[hs]d?1) on each of your drives. Please read the file -+ for further details. -+ -+ To compile this code as a module, choose M here: the module will be -+ called adfs. -+ -+ If unsure, say N. -+ -+config ADFS_FS_RW -+ bool "ADFS write support (DANGEROUS)" -+ depends on ADFS_FS -+ help -+ If you say Y here, you will be able to write to ADFS partitions on -+ hard drives and ADFS-formatted floppy disks. This is experimental -+ codes, so if you're unsure, say N. -+ -+config AFFS_FS -+ tristate "Amiga FFS file system support (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ help -+ The Fast File System (FFS) is the common file system used on hard -+ disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y -+ if you want to be able to read and write files from and to an Amiga -+ FFS partition on your hard drive. Amiga floppies however cannot be -+ read with this driver due to an incompatibility of the floppy -+ controller used in an Amiga and the standard floppy controller in -+ PCs and workstations. Read -+ and . -+ -+ With this driver you can also mount disk files used by Bernd -+ Schmidt's Un*X Amiga Emulator -+ (). -+ If you want to do this, you will also need to say Y or M to "Loop -+ device support", above. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called affs. If unsure, say N. -+ -+config ECRYPT_FS -+ tristate "eCrypt filesystem layer support (EXPERIMENTAL)" -+ depends on EXPERIMENTAL && KEYS && CRYPTO && NET -+ help -+ Encrypted filesystem that operates on the VFS layer. See -+ to learn more about -+ eCryptfs. Userspace components are required and can be -+ obtained from . -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called ecryptfs. -+ -+config HFS_FS -+ tristate "Apple Macintosh file system support (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ select NLS -+ help -+ If you say Y here, you will be able to mount Macintosh-formatted -+ floppy disks and hard drive partitions with full read-write access. -+ Please read to learn about -+ the available mount options. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called hfs. -+ -+config HFSPLUS_FS -+ tristate "Apple Extended HFS file system support" -+ depends on BLOCK -+ select NLS -+ select NLS_UTF8 -+ help -+ If you say Y here, you will be able to mount extended format -+ Macintosh-formatted hard drive partitions with full read-write access. -+ -+ This file system is often called HFS+ and was introduced with -+ MacOS 8. It includes all Mac specific filesystem data such as -+ data forks and creator codes, but it also has several UNIX -+ style features such as file ownership and permissions. -+ -+config BEFS_FS -+ tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ select NLS -+ help -+ The BeOS File System (BeFS) is the native file system of Be, Inc's -+ BeOS. Notable features include support for arbitrary attributes -+ on files and directories, and database-like indices on selected -+ attributes. (Also note that this driver doesn't make those features -+ available at this time). It is a 64 bit filesystem, so it supports -+ extremely large volumes and files. -+ -+ If you use this filesystem, you should also say Y to at least one -+ of the NLS (native language support) options below. -+ -+ If you don't know what this is about, say N. -+ -+ To compile this as a module, choose M here: the module will be -+ called befs. -+ -+config BEFS_DEBUG -+ bool "Debug BeFS" -+ depends on BEFS_FS -+ help -+ If you say Y here, you can use the 'debug' mount option to enable -+ debugging output from the driver. -+ -+config BFS_FS -+ tristate "BFS file system support (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ help -+ Boot File System (BFS) is a file system used under SCO UnixWare to -+ allow the bootloader access to the kernel image and other important -+ files during the boot process. It is usually mounted under /stand -+ and corresponds to the slice marked as "STAND" in the UnixWare -+ partition. You should say Y if you want to read or write the files -+ on your /stand slice from within Linux. You then also need to say Y -+ to "UnixWare slices support", below. More information about the BFS -+ file system is contained in the file -+ . -+ -+ If you don't know what this is about, say N. -+ -+ To compile this as a module, choose M here: the module will be called -+ bfs. Note that the file system of your root partition (the one -+ containing the directory /) cannot be compiled as a module. -+ -+ -+ -+config EFS_FS -+ tristate "EFS file system support (read only) (EXPERIMENTAL)" -+ depends on BLOCK && EXPERIMENTAL -+ help -+ EFS is an older file system used for non-ISO9660 CD-ROMs and hard -+ disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer -+ uses the XFS file system for hard disk partitions however). -+ -+ This implementation only offers read-only access. If you don't know -+ what all this is about, it's safe to say N. For more information -+ about EFS see its home page at . -+ -+ To compile the EFS file system support as a module, choose M here: the -+ module will be called efs. -+ -+config JFFS2_FS -+ tristate "Journalling Flash File System v2 (JFFS2) support" -+ select CRC32 -+ depends on MTD -+ help -+ JFFS2 is the second generation of the Journalling Flash File System -+ for use on diskless embedded devices. It provides improved wear -+ levelling, compression and support for hard links. You cannot use -+ this on normal block devices, only on 'MTD' devices. -+ -+ Further information on the design and implementation of JFFS2 is -+ available at . -+ -+config JFFS2_FS_DEBUG -+ int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" -+ depends on JFFS2_FS -+ default "0" -+ help -+ This controls the amount of debugging messages produced by the JFFS2 -+ code. Set it to zero for use in production systems. For evaluation, -+ testing and debugging, it's advisable to set it to one. This will -+ enable a few assertions and will print debugging messages at the -+ KERN_DEBUG loglevel, where they won't normally be visible. Level 2 -+ is unlikely to be useful - it enables extra debugging in certain -+ areas which at one point needed debugging, but when the bugs were -+ located and fixed, the detailed messages were relegated to level 2. -+ -+ If reporting bugs, please try to have available a full dump of the -+ messages at debug level 1 while the misbehaviour was occurring. -+ -+config JFFS2_FS_WRITEBUFFER -+ bool "JFFS2 write-buffering support" -+ depends on JFFS2_FS -+ default y -+ help -+ This enables the write-buffering support in JFFS2. -+ -+ This functionality is required to support JFFS2 on the following -+ types of flash devices: -+ - NAND flash -+ - NOR flash with transparent ECC -+ - DataFlash -+ -+config JFFS2_FS_WBUF_VERIFY -+ bool "Verify JFFS2 write-buffer reads" -+ depends on JFFS2_FS_WRITEBUFFER -+ default n -+ help -+ This causes JFFS2 to read back every page written through the -+ write-buffer, and check for errors. -+ -+config JFFS2_SUMMARY -+ bool "JFFS2 summary support (EXPERIMENTAL)" -+ depends on JFFS2_FS && EXPERIMENTAL -+ default n -+ help -+ This feature makes it possible to use summary information -+ for faster filesystem mount. -+ -+ The summary information can be inserted into a filesystem image -+ by the utility 'sumtool'. -+ -+ If unsure, say 'N'. -+ -+config JFFS2_FS_XATTR -+ bool "JFFS2 XATTR support (EXPERIMENTAL)" -+ depends on JFFS2_FS && EXPERIMENTAL -+ default n -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). -+ -+ If unsure, say N. -+ -+config JFFS2_FS_POSIX_ACL -+ bool "JFFS2 POSIX Access Control Lists" -+ depends on JFFS2_FS_XATTR -+ default y -+ select FS_POSIX_ACL -+ help -+ Posix Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ To learn more about Access Control Lists, visit the Posix ACLs for -+ Linux website . -+ -+ If you don't know what Access Control Lists are, say N -+ -+config JFFS2_FS_SECURITY -+ bool "JFFS2 Security Labels" -+ depends on JFFS2_FS_XATTR -+ default y -+ help -+ Security labels support alternative access control models -+ implemented by security modules like SELinux. This option -+ enables an extended attribute handler for file security -+ labels in the jffs2 filesystem. -+ -+ If you are not using a security module that requires using -+ extended attributes for file security labels, say N. -+ -+config JFFS2_COMPRESSION_OPTIONS -+ bool "Advanced compression options for JFFS2" -+ depends on JFFS2_FS -+ default n -+ help -+ Enabling this option allows you to explicitly choose which -+ compression modules, if any, are enabled in JFFS2. Removing -+ compressors can mean you cannot read existing file systems, -+ and enabling experimental compressors can mean that you -+ write a file system which cannot be read by a standard kernel. -+ -+ If unsure, you should _definitely_ say 'N'. -+ -+config JFFS2_ZLIB -+ bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS -+ select ZLIB_INFLATE -+ select ZLIB_DEFLATE -+ depends on JFFS2_FS -+ default y -+ help -+ Zlib is designed to be a free, general-purpose, legally unencumbered, -+ lossless data-compression library for use on virtually any computer -+ hardware and operating system. See for -+ further information. -+ -+ Say 'Y' if unsure. -+ -+config JFFS2_LZO -+ bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS -+ select LZO_COMPRESS -+ select LZO_DECOMPRESS -+ depends on JFFS2_FS -+ default n -+ help -+ minilzo-based compression. Generally works better than Zlib. -+ -+ This feature was added in July, 2007. Say 'N' if you need -+ compatibility with older bootloaders or kernels. -+ -+config JFFS2_RTIME -+ bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS -+ depends on JFFS2_FS -+ default y -+ help -+ Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. -+ -+config JFFS2_RUBIN -+ bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS -+ depends on JFFS2_FS -+ default n -+ help -+ RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. -+ -+choice -+ prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS -+ default JFFS2_CMODE_PRIORITY -+ depends on JFFS2_FS -+ help -+ You can set here the default compression mode of JFFS2 from -+ the available compression modes. Don't touch if unsure. -+ -+config JFFS2_CMODE_NONE -+ bool "no compression" -+ help -+ Uses no compression. -+ -+config JFFS2_CMODE_PRIORITY -+ bool "priority" -+ help -+ Tries the compressors in a predefined order and chooses the first -+ successful one. -+ -+config JFFS2_CMODE_SIZE -+ bool "size (EXPERIMENTAL)" -+ help -+ Tries all compressors and chooses the one which has the smallest -+ result. -+ -+config JFFS2_CMODE_FAVOURLZO -+ bool "Favour LZO" -+ help -+ Tries all compressors and chooses the one which has the smallest -+ result but gives some preference to LZO (which has faster -+ decompression) at the expense of size. -+ -+endchoice -+ -+config CRAMFS -+ tristate "Compressed ROM file system support (cramfs)" -+ depends on BLOCK -+ select ZLIB_INFLATE -+ help -+ Saying Y here includes support for CramFs (Compressed ROM File -+ System). CramFs is designed to be a simple, small, and compressed -+ file system for ROM based embedded systems. CramFs is read-only, -+ limited to 256MB file systems (with 16MB files), and doesn't support -+ 16/32 bits uid/gid, hard links and timestamps. -+ -+ See and -+ for further information. -+ -+ To compile this as a module, choose M here: the module will be called -+ cramfs. Note that the root file system (the one containing the -+ directory /) cannot be compiled as a module. -+ -+ If unsure, say N. -+ -+config SQUASHFS -+ tristate "SquashFS 3.0 - Squashed file system support" -+ select ZLIB_INFLATE -+ help -+ Saying Y here includes support for SquashFS 3.0 (a Compressed Read-Only File -+ System). Squashfs is a highly compressed read-only filesystem for Linux. -+ It uses zlib compression to compress both files, inodes and directories. -+ Inodes in the system are very small and all blocks are packed to minimise -+ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K. -+ SquashFS 3.0 supports 64 bit filesystems and files (larger than 4GB), full -+ uid/gid information, hard links and timestamps. -+ -+ Squashfs is intended for general read-only filesystem use, for archival -+ use (i.e. in cases where a .tar.gz file may be used), and in embedded -+ systems where low overhead is needed. Further information and filesystem tools -+ are available from http://squashfs.sourceforge.net. -+ -+ If you want to compile this as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want), -+ say M here and read . The module -+ will be called squashfs. Note that the root file system (the one -+ containing the directory /) cannot be compiled as a module. -+ -+ If unsure, say N. -+ -+config SQUASHFS_EMBEDDED -+ -+ bool "Additional options for memory-constrained systems" -+ depends on SQUASHFS -+ default n -+ help -+ Saying Y here allows you to specify cache sizes and how Squashfs -+ allocates memory. This is only intended for memory constrained -+ systems. -+ -+ If unsure, say N. -+ -+config SQUASHFS_FRAGMENT_CACHE_SIZE -+ int "Number of fragments cached" if SQUASHFS_EMBEDDED -+ depends on SQUASHFS -+ default "3" -+ help -+ By default SquashFS caches the last 3 fragments read from -+ the filesystem. Increasing this amount may mean SquashFS -+ has to re-read fragments less often from disk, at the expense -+ of extra system memory. Decreasing this amount will mean -+ SquashFS uses less memory at the expense of extra reads from disk. -+ -+ Note there must be at least one cached fragment. Anything -+ much more than three will probably not make much difference. -+ -+config SQUASHFS_VMALLOC -+ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED -+ depends on SQUASHFS -+ default n -+ help -+ By default SquashFS uses kmalloc to obtain fragment cache memory. -+ Kmalloc memory is the standard kernel allocator, but it can fail -+ on memory constrained systems. Because of the way Vmalloc works, -+ Vmalloc can succeed when kmalloc fails. Specifying this option -+ will make SquashFS always use Vmalloc to allocate the -+ fragment cache memory. -+ -+ If unsure, say N. -+ -+config VXFS_FS -+ tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" -+ depends on BLOCK -+ help -+ FreeVxFS is a file system driver that support the VERITAS VxFS(TM) -+ file system format. VERITAS VxFS(TM) is the standard file system -+ of SCO UnixWare (and possibly others) and optionally available -+ for Sunsoft Solaris, HP-UX and many other operating systems. -+ Currently only readonly access is supported. -+ -+ NOTE: the file system type as used by mount(1), mount(2) and -+ fstab(5) is 'vxfs' as it describes the file system format, not -+ the actual driver. -+ -+ To compile this as a module, choose M here: the module will be -+ called freevxfs. If unsure, say N. -+ -+ -+config HPFS_FS -+ tristate "OS/2 HPFS file system support" -+ depends on BLOCK -+ help -+ OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS -+ is the file system used for organizing files on OS/2 hard disk -+ partitions. Say Y if you want to be able to read files from and -+ write files to an OS/2 HPFS partition on your hard drive. OS/2 -+ floppies however are in regular MSDOS format, so you don't need this -+ option in order to be able to read them. Read -+ . -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called hpfs. If unsure, say N. -+ -+ -+ -+config QNX4FS_FS -+ tristate "QNX4 file system support (read only)" -+ depends on BLOCK -+ help -+ This is the file system used by the real-time operating systems -+ QNX 4 and QNX 6 (the latter is also called QNX RTP). -+ Further information is available at . -+ Say Y if you intend to mount QNX hard disks or floppies. -+ Unless you say Y to "QNX4FS read-write support" below, you will -+ only be able to read these file systems. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called qnx4. -+ -+ If you don't know whether you need it, then you don't need it: -+ answer N. -+ -+config QNX4FS_RW -+ bool "QNX4FS write support (DANGEROUS)" -+ depends on QNX4FS_FS && EXPERIMENTAL && BROKEN -+ help -+ Say Y if you want to test write support for QNX4 file systems. -+ -+ It's currently broken, so for now: -+ answer N. -+ -+ -+ -+config SYSV_FS -+ tristate "System V/Xenix/V7/Coherent file system support" -+ depends on BLOCK -+ help -+ SCO, Xenix and Coherent are commercial Unix systems for Intel -+ machines, and Version 7 was used on the DEC PDP-11. Saying Y -+ here would allow you to read from their floppies and hard disk -+ partitions. -+ -+ If you have floppies or hard disk partitions like that, it is likely -+ that they contain binaries from those other Unix systems; in order -+ to run these binaries, you will want to install linux-abi which is -+ a set of kernel modules that lets you run SCO, Xenix, Wyse, -+ UnixWare, Dell Unix and System V programs under Linux. It is -+ available via FTP (user: ftp) from -+ ). -+ NOTE: that will work only for binaries from Intel-based systems; -+ PDP ones will have to wait until somebody ports Linux to -11 ;-) -+ -+ If you only intend to mount files from some other Unix over the -+ network using NFS, you don't need the System V file system support -+ (but you need NFS file system support obviously). -+ -+ Note that this option is generally not needed for floppies, since a -+ good portable way to transport files and directories between unixes -+ (and even other operating systems) is given by the tar program ("man -+ tar" or preferably "info tar"). Note also that this option has -+ nothing whatsoever to do with the option "System V IPC". Read about -+ the System V file system in -+ . -+ Saying Y here will enlarge your kernel by about 27 KB. -+ -+ To compile this as a module, choose M here: the module will be called -+ sysv. -+ -+ If you haven't heard about all of this before, it's safe to say N. -+ -+ -+ -+config UFS_FS -+ tristate "UFS file system support (read only)" -+ depends on BLOCK -+ help -+ BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, -+ OpenBSD and NeXTstep) use a file system called UFS. Some System V -+ Unixes can create and mount hard disk partitions and diskettes using -+ this file system as well. Saying Y here will allow you to read from -+ these partitions; if you also want to write to them, say Y to the -+ experimental "UFS file system write support", below. Please read the -+ file for more information. -+ -+ The recently released UFS2 variant (used in FreeBSD 5.x) is -+ READ-ONLY supported. -+ -+ If you only intend to mount files from some other Unix over the -+ network using NFS, you don't need the UFS file system support (but -+ you need NFS file system support obviously). -+ -+ Note that this option is generally not needed for floppies, since a -+ good portable way to transport files and directories between unixes -+ (and even other operating systems) is given by the tar program ("man -+ tar" or preferably "info tar"). -+ -+ When accessing NeXTstep files, you may need to convert them from the -+ NeXT character set to the Latin1 character set; use the program -+ recode ("info recode") for this purpose. -+ -+ To compile the UFS file system support as a module, choose M here: the -+ module will be called ufs. -+ -+ If you haven't heard about all of this before, it's safe to say N. -+ -+config UFS_FS_WRITE -+ bool "UFS file system write support (DANGEROUS)" -+ depends on UFS_FS && EXPERIMENTAL -+ help -+ Say Y here if you want to try writing to UFS partitions. This is -+ experimental, so you should back up your UFS partitions beforehand. -+ -+config UFS_DEBUG -+ bool "UFS debugging" -+ depends on UFS_FS -+ help -+ If you are experiencing any problems with the UFS filesystem, say -+ Y here. This will result in _many_ additional debugging messages to be -+ written to the system log. -+ -+endmenu -+ -+menuconfig NETWORK_FILESYSTEMS -+ bool "Network File Systems" -+ default y -+ depends on NET -+ ---help--- -+ Say Y here to get to see options for network filesystems and -+ filesystem-related networking code, such as NFS daemon and -+ RPCSEC security modules. -+ This option alone does not add any kernel code. -+ -+ If you say N, all options in this submenu will be skipped and -+ disabled; if unsure, say Y here. -+ -+if NETWORK_FILESYSTEMS -+ -+config NFS_FS -+ tristate "NFS file system support" -+ depends on INET -+ select LOCKD -+ select SUNRPC -+ select NFS_ACL_SUPPORT if NFS_V3_ACL -+ help -+ If you are connected to some other (usually local) Unix computer -+ (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing -+ on that computer (the NFS server) using the Network File Sharing -+ protocol, say Y. "Mounting files" means that the client can access -+ the files with usual UNIX commands as if they were sitting on the -+ client's hard disk. For this to work, the server must run the -+ programs nfsd and mountd (but does not need to have NFS file system -+ support enabled in its kernel). NFS is explained in the Network -+ Administrator's Guide, available from -+ , on its man page: "man -+ nfs", and in the NFS-HOWTO. -+ -+ A superior but less widely used alternative to NFS is provided by -+ the Coda file system; see "Coda file system support" below. -+ -+ If you say Y here, you should have said Y to TCP/IP networking also. -+ This option would enlarge your kernel by about 27 KB. -+ -+ To compile this file system support as a module, choose M here: the -+ module will be called nfs. -+ -+ If you are configuring a diskless machine which will mount its root -+ file system over NFS at boot time, say Y here and to "Kernel -+ level IP autoconfiguration" above and to "Root file system on NFS" -+ below. You cannot compile this driver as a module in this case. -+ There are two packages designed for booting diskless machines over -+ the net: netboot, available from -+ , and Etherboot, -+ available from . -+ -+ If you don't know what all this is about, say N. -+ -+config NFS_V3 -+ bool "Provide NFSv3 client support" -+ depends on NFS_FS -+ help -+ Say Y here if you want your NFS client to be able to speak version -+ 3 of the NFS protocol. -+ -+ If unsure, say Y. -+ -+config NFS_V3_ACL -+ bool "Provide client support for the NFSv3 ACL protocol extension" -+ depends on NFS_V3 -+ help -+ Implement the NFSv3 ACL protocol extension for manipulating POSIX -+ Access Control Lists. The server should also be compiled with -+ the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option. -+ -+ If unsure, say N. -+ -+config NFS_V4 -+ bool "Provide NFSv4 client support (EXPERIMENTAL)" -+ depends on NFS_FS && EXPERIMENTAL -+ select RPCSEC_GSS_KRB5 -+ help -+ Say Y here if you want your NFS client to be able to speak the newer -+ version 4 of the NFS protocol. -+ -+ Note: Requires auxiliary userspace daemons which may be found on -+ http://www.citi.umich.edu/projects/nfsv4/ -+ -+ If unsure, say N. -+ -+config NFS_DIRECTIO -+ bool "Allow direct I/O on NFS files" -+ depends on NFS_FS -+ help -+ This option enables applications to perform uncached I/O on files -+ in NFS file systems using the O_DIRECT open() flag. When O_DIRECT -+ is set for a file, its data is not cached in the system's page -+ cache. Data is moved to and from user-level application buffers -+ directly. Unlike local disk-based file systems, NFS O_DIRECT has -+ no alignment restrictions. -+ -+ Unless your program is designed to use O_DIRECT properly, you are -+ much better off allowing the NFS client to manage data caching for -+ you. Misusing O_DIRECT can cause poor server performance or network -+ storms. This kernel build option defaults OFF to avoid exposing -+ system administrators unwittingly to a potentially hazardous -+ feature. -+ -+ For more details on NFS O_DIRECT, see fs/nfs/direct.c. -+ -+ If unsure, say N. This reduces the size of the NFS client, and -+ causes open() to return EINVAL if a file residing in NFS is -+ opened with the O_DIRECT flag. -+ -+config NFSD -+ tristate "NFS server support" -+ depends on INET -+ select LOCKD -+ select SUNRPC -+ select EXPORTFS -+ select NFSD_V2_ACL if NFSD_V3_ACL -+ select NFS_ACL_SUPPORT if NFSD_V2_ACL -+ select NFSD_TCP if NFSD_V4 -+ select CRYPTO_MD5 if NFSD_V4 -+ select CRYPTO if NFSD_V4 -+ select FS_POSIX_ACL if NFSD_V4 -+ help -+ If you want your Linux box to act as an NFS *server*, so that other -+ computers on your local network which support NFS can access certain -+ directories on your box transparently, you have two options: you can -+ use the self-contained user space program nfsd, in which case you -+ should say N here, or you can say Y and use the kernel based NFS -+ server. The advantage of the kernel based solution is that it is -+ faster. -+ -+ In either case, you will need support software; the respective -+ locations are given in the file in the -+ NFS section. -+ -+ If you say Y here, you will get support for version 2 of the NFS -+ protocol (NFSv2). If you also want NFSv3, say Y to the next question -+ as well. -+ -+ Please read the NFS-HOWTO, available from -+ . -+ -+ To compile the NFS server support as a module, choose M here: the -+ module will be called nfsd. If unsure, say N. -+ -+config NFSD_V2_ACL -+ bool -+ depends on NFSD -+ -+config NFSD_V3 -+ bool "Provide NFSv3 server support" -+ depends on NFSD -+ help -+ If you would like to include the NFSv3 server as well as the NFSv2 -+ server, say Y here. If unsure, say Y. -+ -+config NFSD_V3_ACL -+ bool "Provide server support for the NFSv3 ACL protocol extension" -+ depends on NFSD_V3 -+ help -+ Implement the NFSv3 ACL protocol extension for manipulating POSIX -+ Access Control Lists on exported file systems. NFS clients should -+ be compiled with the NFSv3 ACL protocol extension; see the -+ CONFIG_NFS_V3_ACL option. If unsure, say N. -+ -+config NFSD_V4 -+ bool "Provide NFSv4 server support (EXPERIMENTAL)" -+ depends on NFSD && NFSD_V3 && EXPERIMENTAL -+ select RPCSEC_GSS_KRB5 -+ help -+ If you would like to include the NFSv4 server as well as the NFSv2 -+ and NFSv3 servers, say Y here. This feature is experimental, and -+ should only be used if you are interested in helping to test NFSv4. -+ If unsure, say N. -+ -+config NFSD_TCP -+ bool "Provide NFS server over TCP support" -+ depends on NFSD -+ default y -+ help -+ If you want your NFS server to support TCP connections, say Y here. -+ TCP connections usually perform better than the default UDP when -+ the network is lossy or congested. If unsure, say Y. -+ -+config ROOT_NFS -+ bool "Root file system on NFS" -+ depends on NFS_FS=y && IP_PNP -+ help -+ If you want your Linux box to mount its whole root file system (the -+ one containing the directory /) from some other computer over the -+ net via NFS (presumably because your box doesn't have a hard disk), -+ say Y. Read for details. It is -+ likely that in this case, you also want to say Y to "Kernel level IP -+ autoconfiguration" so that your box can discover its network address -+ at boot time. -+ -+ Most people say N here. -+ -+config LOCKD -+ tristate -+ -+config LOCKD_V4 -+ bool -+ depends on NFSD_V3 || NFS_V3 -+ default y -+ -+config EXPORTFS -+ tristate -+ -+config NFS_ACL_SUPPORT -+ tristate -+ select FS_POSIX_ACL -+ -+config NFS_COMMON -+ bool -+ depends on NFSD || NFS_FS -+ default y -+ -+config SUNRPC -+ tristate -+ -+config SUNRPC_GSS -+ tristate -+ -+config SUNRPC_XPRT_RDMA -+ tristate "RDMA transport for sunrpc (EXPERIMENTAL)" -+ depends on SUNRPC && INFINIBAND && EXPERIMENTAL -+ default m -+ help -+ Adds a client RPC transport for supporting kernel NFS over RDMA -+ mounts, including Infiniband and iWARP. Experimental. -+ -+config SUNRPC_BIND34 -+ bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" -+ depends on SUNRPC && EXPERIMENTAL -+ help -+ Provides kernel support for querying rpcbind servers via versions 3 -+ and 4 of the rpcbind protocol. The kernel automatically falls back -+ to version 2 if a remote rpcbind service does not support versions -+ 3 or 4. -+ -+ If unsure, say N to get traditional behavior (version 2 rpcbind -+ requests only). -+ -+config RPCSEC_GSS_KRB5 -+ tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" -+ depends on SUNRPC && EXPERIMENTAL -+ select SUNRPC_GSS -+ select CRYPTO -+ select CRYPTO_MD5 -+ select CRYPTO_DES -+ select CRYPTO_CBC -+ help -+ Provides for secure RPC calls by means of a gss-api -+ mechanism based on Kerberos V5. This is required for -+ NFSv4. -+ -+ Note: Requires an auxiliary userspace daemon which may be found on -+ http://www.citi.umich.edu/projects/nfsv4/ -+ -+ If unsure, say N. -+ -+config RPCSEC_GSS_SPKM3 -+ tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)" -+ depends on SUNRPC && EXPERIMENTAL -+ select SUNRPC_GSS -+ select CRYPTO -+ select CRYPTO_MD5 -+ select CRYPTO_DES -+ select CRYPTO_CAST5 -+ select CRYPTO_CBC -+ help -+ Provides for secure RPC calls by means of a gss-api -+ mechanism based on the SPKM3 public-key mechanism. -+ -+ Note: Requires an auxiliary userspace daemon which may be found on -+ http://www.citi.umich.edu/projects/nfsv4/ -+ -+ If unsure, say N. -+ -+config SMB_FS -+ tristate "SMB file system support (to mount Windows shares etc.)" -+ depends on INET -+ select NLS -+ help -+ SMB (Server Message Block) is the protocol Windows for Workgroups -+ (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share -+ files and printers over local networks. Saying Y here allows you to -+ mount their file systems (often called "shares" in this context) and -+ access them just like any other Unix directory. Currently, this -+ works only if the Windows machines use TCP/IP as the underlying -+ transport protocol, and not NetBEUI. For details, read -+ and the SMB-HOWTO, -+ available from . -+ -+ Note: if you just want your box to act as an SMB *server* and make -+ files and printing services available to Windows clients (which need -+ to have a TCP/IP stack), you don't need to say Y here; you can use -+ the program SAMBA (available from ) -+ for that. -+ -+ General information about how to connect Linux, Windows machines and -+ Macs is on the WWW at . -+ -+ To compile the SMB support as a module, choose M here: the module will -+ be called smbfs. Most people say N, however. -+ -+config SMB_NLS_DEFAULT -+ bool "Use a default NLS" -+ depends on SMB_FS -+ help -+ Enabling this will make smbfs use nls translations by default. You -+ need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls -+ settings and you need to give the default nls for the SMB server as -+ CONFIG_SMB_NLS_REMOTE. -+ -+ The nls settings can be changed at mount time, if your smbmount -+ supports that, using the codepage and iocharset parameters. -+ -+ smbmount from samba 2.2.0 or later supports this. -+ -+config SMB_NLS_REMOTE -+ string "Default Remote NLS Option" -+ depends on SMB_NLS_DEFAULT -+ default "cp437" -+ help -+ This setting allows you to specify a default value for which -+ codepage the server uses. If this field is left blank no -+ translations will be done by default. The local codepage/charset -+ default to CONFIG_NLS_DEFAULT. -+ -+ The nls settings can be changed at mount time, if your smbmount -+ supports that, using the codepage and iocharset parameters. -+ -+ smbmount from samba 2.2.0 or later supports this. -+ -+config CIFS -+ tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)" -+ depends on INET -+ select NLS -+ help -+ This is the client VFS module for the Common Internet File System -+ (CIFS) protocol which is the successor to the Server Message Block -+ (SMB) protocol, the native file sharing mechanism for most early -+ PC operating systems. The CIFS protocol is fully supported by -+ file servers such as Windows 2000 (including Windows 2003, NT 4 -+ and Windows XP) as well by Samba (which provides excellent CIFS -+ server support for Linux and many other operating systems). Limited -+ support for OS/2 and Windows ME and similar servers is provided as well. -+ -+ The intent of the cifs module is to provide an advanced -+ network file system client for mounting to CIFS compliant servers, -+ including support for dfs (hierarchical name space), secure per-user -+ session establishment, safe distributed caching (oplock), optional -+ packet signing, Unicode and other internationalization improvements. -+ If you need to mount to Samba or Windows from this machine, say Y. -+ -+config CIFS_STATS -+ bool "CIFS statistics" -+ depends on CIFS -+ help -+ Enabling this option will cause statistics for each server share -+ mounted by the cifs client to be displayed in /proc/fs/cifs/Stats -+ -+config CIFS_STATS2 -+ bool "Extended statistics" -+ depends on CIFS_STATS -+ help -+ Enabling this option will allow more detailed statistics on SMB -+ request timing to be displayed in /proc/fs/cifs/DebugData and also -+ allow optional logging of slow responses to dmesg (depending on the -+ value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details). -+ These additional statistics may have a minor effect on performance -+ and memory utilization. -+ -+ Unless you are a developer or are doing network performance analysis -+ or tuning, say N. -+ -+config CIFS_WEAK_PW_HASH -+ bool "Support legacy servers which use weaker LANMAN security" -+ depends on CIFS -+ help -+ Modern CIFS servers including Samba and most Windows versions -+ (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) -+ security mechanisms. These hash the password more securely -+ than the mechanisms used in the older LANMAN version of the -+ SMB protocol needed to establish sessions with old SMB servers. -+ -+ Enabling this option allows the cifs module to mount to older -+ LANMAN based servers such as OS/2 and Windows 95, but such -+ mounts may be less secure than mounts using NTLM or more recent -+ security mechanisms if you are on a public network. Unless you -+ have a need to access old SMB servers (and are on a private -+ network) you probably want to say N. Even if this support -+ is enabled in the kernel build, they will not be used -+ automatically. At runtime LANMAN mounts are disabled but -+ can be set to required (or optional) either in -+ /proc/fs/cifs (see fs/cifs/README for more detail) or via an -+ option on the mount command. This support is disabled by -+ default in order to reduce the possibility of a downgrade -+ attack. -+ -+ If unsure, say N. -+ -+config CIFS_XATTR -+ bool "CIFS extended attributes" -+ depends on CIFS -+ help -+ Extended attributes are name:value pairs associated with inodes by -+ the kernel or by users (see the attr(5) manual page, or visit -+ for details). CIFS maps the name of -+ extended attributes beginning with the user namespace prefix -+ to SMB/CIFS EAs. EAs are stored on Windows servers without the -+ user namespace prefix, but their names are seen by Linux cifs clients -+ prefaced by the user namespace prefix. The system namespace -+ (used by some filesystems to store ACLs) is not supported at -+ this time. -+ -+ If unsure, say N. -+ -+config CIFS_POSIX -+ bool "CIFS POSIX Extensions" -+ depends on CIFS_XATTR -+ help -+ Enabling this option will cause the cifs client to attempt to -+ negotiate a newer dialect with servers, such as Samba 3.0.5 -+ or later, that optionally can handle more POSIX like (rather -+ than Windows like) file behavior. It also enables -+ support for POSIX ACLs (getfacl and setfacl) to servers -+ (such as Samba 3.10 and later) which can negotiate -+ CIFS POSIX ACL support. If unsure, say N. -+ -+config CIFS_DEBUG2 -+ bool "Enable additional CIFS debugging routines" -+ depends on CIFS -+ help -+ Enabling this option adds a few more debugging routines -+ to the cifs code which slightly increases the size of -+ the cifs module and can cause additional logging of debug -+ messages in some error paths, slowing performance. This -+ option can be turned off unless you are debugging -+ cifs problems. If unsure, say N. -+ -+config CIFS_EXPERIMENTAL -+ bool "CIFS Experimental Features (EXPERIMENTAL)" -+ depends on CIFS && EXPERIMENTAL -+ help -+ Enables cifs features under testing. These features are -+ experimental and currently include DFS support and directory -+ change notification ie fcntl(F_DNOTIFY), as well as the upcall -+ mechanism which will be used for Kerberos session negotiation -+ and uid remapping. Some of these features also may depend on -+ setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental -+ (which is disabled by default). See the file fs/cifs/README -+ for more details. If unsure, say N. -+ -+config CIFS_UPCALL -+ bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" -+ depends on CIFS_EXPERIMENTAL -+ depends on KEYS -+ help -+ Enables an upcall mechanism for CIFS which will be used to contact -+ userspace helper utilities to provide SPNEGO packaged Kerberos -+ tickets which are needed to mount to certain secure servers -+ (for which more secure Kerberos authentication is required). If -+ unsure, say N. -+ -+config NCP_FS -+ tristate "NCP file system support (to mount NetWare volumes)" -+ depends on IPX!=n || INET -+ help -+ NCP (NetWare Core Protocol) is a protocol that runs over IPX and is -+ used by Novell NetWare clients to talk to file servers. It is to -+ IPX what NFS is to TCP/IP, if that helps. Saying Y here allows you -+ to mount NetWare file server volumes and to access them just like -+ any other Unix directory. For details, please read the file -+ in the kernel source and -+ the IPX-HOWTO from . -+ -+ You do not have to say Y here if you want your Linux box to act as a -+ file *server* for Novell NetWare clients. -+ -+ General information about how to connect Linux, Windows machines and -+ Macs is on the WWW at . -+ -+ To compile this as a module, choose M here: the module will be called -+ ncpfs. Say N unless you are connected to a Novell network. -+ -+source "fs/ncpfs/Kconfig" -+ -+config CODA_FS -+ tristate "Coda file system support (advanced network fs)" -+ depends on INET -+ help -+ Coda is an advanced network file system, similar to NFS in that it -+ enables you to mount file systems of a remote server and access them -+ with regular Unix commands as if they were sitting on your hard -+ disk. Coda has several advantages over NFS: support for -+ disconnected operation (e.g. for laptops), read/write server -+ replication, security model for authentication and encryption, -+ persistent client caches and write back caching. -+ -+ If you say Y here, your Linux box will be able to act as a Coda -+ *client*. You will need user level code as well, both for the -+ client and server. Servers are currently user level, i.e. they need -+ no kernel support. Please read -+ and check out the Coda -+ home page . -+ -+ To compile the coda client support as a module, choose M here: the -+ module will be called coda. -+ -+config CODA_FS_OLD_API -+ bool "Use 96-bit Coda file identifiers" -+ depends on CODA_FS -+ help -+ A new kernel-userspace API had to be introduced for Coda v6.0 -+ to support larger 128-bit file identifiers as needed by the -+ new realms implementation. -+ -+ However this new API is not backward compatible with older -+ clients. If you really need to run the old Coda userspace -+ cache manager then say Y. -+ -+ For most cases you probably want to say N. -+ -+config AFS_FS -+ tristate "Andrew File System support (AFS) (EXPERIMENTAL)" -+ depends on INET && EXPERIMENTAL -+ select AF_RXRPC -+ help -+ If you say Y here, you will get an experimental Andrew File System -+ driver. It currently only supports unsecured read-only AFS access. -+ -+ See for more information. -+ -+ If unsure, say N. -+ -+config AFS_DEBUG -+ bool "AFS dynamic debugging" -+ depends on AFS_FS -+ help -+ Say Y here to make runtime controllable debugging messages appear. -+ -+ See for more information. -+ -+ If unsure, say N. -+ -+config 9P_FS -+ tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)" -+ depends on INET && NET_9P && EXPERIMENTAL -+ help -+ If you say Y here, you will get experimental support for -+ Plan 9 resource sharing via the 9P2000 protocol. -+ -+ See for more information. -+ -+ If unsure, say N. -+ -+endif # NETWORK_FILESYSTEMS -+ -+if BLOCK -+menu "Partition Types" -+ -+source "fs/partitions/Kconfig" -+ -+endmenu -+endif -+ -+source "fs/nls/Kconfig" -+source "fs/dlm/Kconfig" -+ -+endmenu -+ -diff -urN linux-2.6.24.7.old/fs/fs-writeback.c linux-2.6.24.7/fs/fs-writeback.c ---- linux-2.6.24.7.old/fs/fs-writeback.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/fs/fs-writeback.c 2009-04-12 18:13:57.000000000 +0200 -@@ -386,8 +386,6 @@ - * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so - * that it can be located for waiting on in __writeback_single_inode(). - * -- * Called under inode_lock. -- * - * If `bdi' is non-zero then we're being asked to writeback a specific queue. - * This function assumes that the blockdev superblock's inodes are backed by - * a variety of queues, so all inodes are searched. For other superblocks, -@@ -403,11 +401,12 @@ - * on the writer throttling path, and we get decent balancing between many - * throttled threads: we don't want them all piling up on inode_sync_wait. - */ --static void --sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) -+void generic_sync_sb_inodes(struct super_block *sb, -+ struct writeback_control *wbc) - { - const unsigned long start = jiffies; /* livelock avoidance */ - -+ spin_lock(&inode_lock); - if (!wbc->for_kupdate || list_empty(&sb->s_io)) - queue_io(sb, wbc->older_than_this); - -@@ -482,8 +481,16 @@ - if (wbc->nr_to_write <= 0) - break; - } -+ spin_unlock(&inode_lock); - return; /* Leave any unwritten inodes on s_io */ - } -+EXPORT_SYMBOL_GPL(generic_sync_sb_inodes); -+ -+static void sync_sb_inodes(struct super_block *sb, -+ struct writeback_control *wbc) -+{ -+ generic_sync_sb_inodes(sb, wbc); -+} - - /* - * Start writeback of dirty pagecache data against all unlocked inodes. -@@ -524,11 +531,8 @@ - * be unmounted by the time it is released. - */ - if (down_read_trylock(&sb->s_umount)) { -- if (sb->s_root) { -- spin_lock(&inode_lock); -+ if (sb->s_root) - sync_sb_inodes(sb, wbc); -- spin_unlock(&inode_lock); -- } - up_read(&sb->s_umount); - } - spin_lock(&sb_lock); -@@ -566,9 +570,7 @@ - (inodes_stat.nr_inodes - inodes_stat.nr_unused) + - nr_dirty + nr_unstable; - wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ -- spin_lock(&inode_lock); - sync_sb_inodes(sb, &wbc); -- spin_unlock(&inode_lock); - } - - /* -diff -urN linux-2.6.24.7.old/fs/ubifs/Kconfig linux-2.6.24.7/fs/ubifs/Kconfig ---- linux-2.6.24.7.old/fs/ubifs/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,71 @@ -+config UBIFS_FS -+ tristate "UBIFS file system support" -+ select CRC16 -+ select CRC32 -+ depends on MTD_UBI -+ help -+ UBIFS is a file system for flash devices which works on top of UBI. -+ -+config UBIFS_FS_XATTR -+ bool "Extended attributes support" -+ depends on UBIFS_FS -+ help -+ This option enables support of extended attributes. -+ -+config UBIFS_FS_ADVANCED_COMPR -+ bool "Advanced compression options" -+ depends on UBIFS_FS -+ help -+ This option allows to explicitly choose which compressions, if any, -+ are enabled in UBIFS. Removing compressors means inbility to read -+ existing file systems. -+ -+ If unsure, say 'N'. -+ -+config UBIFS_FS_LZO -+ bool "LZO compression support" if UBIFS_FS_ADVANCED_COMPR -+ select CRYPTO -+ select CRYPTO_LZO -+ depends on UBIFS_FS -+ default y -+ help -+ LZO compressor is generally faster then zlib but compresses worse. -+ Say 'Y' if unsure. -+ -+config UBIFS_FS_ZLIB -+ bool "ZLIB compression support" if UBIFS_FS_ADVANCED_COMPR -+ select CRYPTO -+ select CRYPTO_DEFLATE -+ depends on UBIFS_FS -+ default y -+ help -+ Zlib copresses better then LZO but it is slower. Say 'Y' if unsure. -+ -+# Debugging-related stuff -+config UBIFS_FS_DEBUG -+ bool "Enable debugging" -+ depends on UBIFS_FS -+ select DEBUG_FS -+ select KALLSYMS_ALL -+ help -+ This option enables UBIFS debugging. -+ -+config UBIFS_FS_DEBUG_MSG_LVL -+ int "Default message level (0 = no extra messages, 3 = lots)" -+ depends on UBIFS_FS_DEBUG -+ default "0" -+ help -+ This controls the amount of debugging messages produced by UBIFS. -+ If reporting bugs, please try to have available a full dump of the -+ messages at level 1 while the misbehaviour was occurring. Level 2 -+ may become necessary if level 1 messages were not enough to find the -+ bug. Generally Level 3 should be avoided. -+ -+config UBIFS_FS_DEBUG_CHKS -+ bool "Enable extra checks" -+ depends on UBIFS_FS_DEBUG -+ help -+ If extra checks are enabled UBIFS will check the consistency of its -+ internal data structures during operation. However, UBIFS performance -+ is dramatically slower when this option is selected especially if the -+ file system is large. -diff -urN linux-2.6.24.7.old/fs/ubifs/Kconfig.debug linux-2.6.24.7/fs/ubifs/Kconfig.debug ---- linux-2.6.24.7.old/fs/ubifs/Kconfig.debug 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/Kconfig.debug 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,173 @@ -+# UBIFS debugging configuration options, part of fs/ubifs/Kconfig -+ -+config UBIFS_FS_DEBUG -+ bool "Enable debugging" -+ default n -+ depends on UBIFS_FS -+ select DEBUG_FS -+ select KALLSYMS_ALL -+ help -+ This option enables UBIFS debugging. -+ -+menu "Debugging messages" -+ depends on UBIFS_FS_DEBUG -+ -+config UBIFS_FS_DEBUG_MSG_GEN -+ bool "General messages" -+ default n -+ help -+ This option enables general debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_JRN -+ bool "Journal messages" -+ default n -+ help -+ This option enables detailed journal debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_CMT -+ bool "Commit messages" -+ default n -+ help -+ This option enables detailed journal commit debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_BUDG -+ bool "Budgeting messages" -+ default n -+ help -+ This option enables detailed budgeting debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_LOG -+ bool "Log messages" -+ default n -+ help -+ This option enables detailed journal log debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_TNC -+ bool "Tree Node Cache (TNC) messages" -+ default n -+ help -+ This option enables detailed TNC debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_LP -+ bool "LEB properties (lprops) messages" -+ default n -+ help -+ This option enables detailed lprops debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_FIND -+ bool "LEB search messages" -+ default n -+ help -+ This option enables detailed LEB search debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_MNT -+ bool "Mount messages" -+ default n -+ help -+ This option enables detailed mount debugging messages, including -+ recovery messages. -+ -+config UBIFS_FS_DEBUG_MSG_IO -+ bool "Input/output messages" -+ default n -+ help -+ This option enables detailed I/O debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_GC -+ bool "Garbage collection messages" -+ default n -+ help -+ This option enables detailed garbage collection debugging messages. -+ -+config UBIFS_FS_DEBUG_MSG_SCAN -+ bool "Scan messages" -+ default n -+ help -+ This option enables detailed scan debugging messages. -+ -+endmenu -+ -+menu "Extra self-checks" -+ depends on UBIFS_FS_DEBUG -+ -+config UBIFS_FS_DEBUG_CHK_MEMPRESS -+ bool "Create memory pressure" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option causes kernel memory pressure in order to make TNC shrinker -+ run. -+ -+config UBIFS_FS_DEBUG_CHK_LPROPS -+ bool "Check LEB properties (lprops)" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables a function which runs during journal commit and -+ checks that the dirty and free space is correct for every LEB. Note, -+ this option makes UBIFS scan whole media before each commit which is -+ very slow. -+ -+config UBIFS_FS_DEBUG_CHK_TNC -+ bool "Check Tree Node Cache (TNC)" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables a function which runs after every -+ TNC insert / delete and checks that the TNC nodes are correct. -+ -+config UBIFS_FS_DEBUG_CHK_ORPH -+ bool "Check orphan area" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables a function which runs during journal commit and -+ checks that the orphan area is correct. -+ -+config UBIFS_FS_DEBUG_CHK_IDX_SZ -+ bool "Check indexing tree size" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables checking of the znode size accounting variables. -+ -+config UBIFS_FS_DEBUG_CHK_OLD_IDX -+ bool "Check old indexing tree" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables checking of the old indexing tree which must be -+ intact to allow recovery in the event of an unclean unmount. -+ -+config UBIFS_FS_DEBUG_CHK_OTHER -+ bool "Other checks" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option enables different checks which are light-weight and do not -+ affect file-system performance too much. -+ -+endmenu -+ -+config UBIFS_FS_DEBUG_FORCE_IN_THE_GAPS -+ bool "Force in-the-gaps commit method" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option makes UBIFS use the in-the-gap commit method much more -+ often than it is normally used (normally it is used only as fall-back -+ method when there is no space to do the "normal" commit method). It -+ is useful to run tests with this option enabled from time to time -+ because it may reveal UBIFS bugs which would otherwise be really -+ difficult to hit. -+ -+config UBIFS_FS_DEBUG_TEST_RCVRY -+ bool "Simulate random device removal (recovery testing)" -+ default n -+ depends on UBIFS_FS_DEBUG -+ help -+ This option provides the ability to test recovery from unclean -+ unmounts. It causes UBIFS to simulate device removal. At a some -+ random point UBIFS will switch to "failure mode" after which all I/O -+ operations will fail. UBIFS can then be unmounted and mounted again -+ at which point "failure mode" is switched off and recovery ensues. -diff -urN linux-2.6.24.7.old/fs/ubifs/Makefile linux-2.6.24.7/fs/ubifs/Makefile ---- linux-2.6.24.7.old/fs/ubifs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,9 @@ -+obj-$(CONFIG_UBIFS_FS) += ubifs.o -+ -+ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o -+ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o -+ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o -+ubifs-y += recovery.o ioctl.o compat.o lpt_commit.o tnc_misc.o -+ -+ubifs-$(CONFIG_UBIFS_FS_DEBUG) += debug.o -+ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o -diff -urN linux-2.6.24.7.old/fs/ubifs/budget.c linux-2.6.24.7/fs/ubifs/budget.c ---- linux-2.6.24.7.old/fs/ubifs/budget.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/budget.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,871 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements the budgeting unit which is responsible for UBIFS space -+ * management. -+ * -+ * Factors such as compression, wasted space at the ends of LEBs, space in other -+ * journal heads, the effect of updates on the index, and so on, make it -+ * impossible to accurately predict the amount of space needed. Consequently -+ * approximations are used. -+ */ -+ -+#include "ubifs.h" -+#include -+#include -+ -+/* -+ * When pessimistic budget calculations say that there is no enough space, -+ * UBIFS starts writing back dirty inodes and pages, doing garbage collection, -+ * or committing. The below constants define maximum number of times UBIFS -+ * repeats the operations. -+ */ -+#define MAX_SHRINK_RETRIES 8 -+#define MAX_GC_RETRIES 4 -+#define MAX_CMT_RETRIES 2 -+#define MAX_NOSPC_RETRIES 1 -+ -+/* -+ * The below constant defines amount of dirty pages which should be written -+ * back at when trying to shrink the liability. -+ */ -+#define NR_TO_WRITE 16 -+ -+/** -+ * struct retries_info - information about re-tries while making free space. -+ * @prev_liability: previous liability -+ * @shrink_cnt: how many times the liability was shrinked -+ * @shrink_retries: count of liability shrink re-tries (increased when -+ * liability does not shrink) -+ * @try_gc: GC should be tried first -+ * @gc_retries: how many times GC was run -+ * @cmt_retries: how many times commit has been done -+ * @nospc_retries: how many times GC returned %-ENOSPC -+ * -+ * Since we consider budgeting to be the fast-path, and this structure has to -+ * be allocated on stack and zeroed out, we make it smaller using bit-fields. -+ */ -+struct retries_info { -+ long long prev_liability; -+ unsigned int shrink_cnt; -+ unsigned int shrink_retries:5; -+ unsigned int try_gc:1; -+ unsigned int gc_retries:4; -+ unsigned int cmt_retries:3; -+ unsigned int nospc_retries:1; -+}; -+ -+/* TODO: remove compatibility stuff as late as possible */ -+#ifndef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+/** -+ * shrink_liability - write-back some dirty pages/inodes. -+ * @c: UBIFS file-system description object -+ * @nr_to_write: how many dirty pages to write-back -+ * -+ * This function shrinks UBIFS liability by means of writing back some amount -+ * of dirty inodes and their pages. Returns the amount of pages which were -+ * written back. The returned value does not include dirty inodes which were -+ * synchronized. -+ * -+ * Note, this function synchronizes even VFS inodes which are locked -+ * (@i_mutex) by the caller of the budgeting function, because write-back does -+ * not touch @i_mutex. -+ */ -+static int shrink_liability(struct ubifs_info *c, int nr_to_write) -+{ -+ struct writeback_control wbc = { -+ .sync_mode = WB_SYNC_NONE, -+ .range_end = LLONG_MAX, -+ .nr_to_write = nr_to_write, -+ }; -+ -+ generic_sync_sb_inodes(c->vfs_sb, &wbc); -+ dbg_budg("%ld pages were written back", nr_to_write - wbc.nr_to_write); -+ return nr_to_write - wbc.nr_to_write; -+} -+ -+ -+/** -+ * run_gc - run garbage collector. -+ * @c: UBIFS file-system description object -+ * -+ * This function runs garbage collector to make some more free space. Returns -+ * zero if a free LEB has been produced, %-EAGAIN if commit is required, and a -+ * negative error code in case of failure. -+ */ -+static int run_gc(struct ubifs_info *c) -+{ -+ int err, lnum; -+ -+ /* Make some free space by garbage-collecting dirty space */ -+ down_read(&c->commit_sem); -+ lnum = ubifs_garbage_collect(c, 1); -+ up_read(&c->commit_sem); -+ if (lnum < 0) -+ return lnum; -+ -+ /* GC freed one LEB, return it to lprops */ -+ dbg_budg("GC freed LEB %d", lnum); -+ err = ubifs_return_leb(c, lnum); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/** -+ * make_free_space - make more free space on the file-system. -+ * @c: UBIFS file-system description object -+ * @ri: information about previous invocations of this function -+ * -+ * This function is called when an operation cannot be budgeted because there -+ * is supposedly no free space. But in most cases there is some free space: -+ * o budgeting is pessimistic, so it always budgets more then it is actually -+ * needed, so shrinking the liability is one way to make free space - the -+ * cached data will take less space then it was budgeted for; -+ * o GC may turn some dark space into free space (budgeting treats dark space -+ * as not available); -+ * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs. -+ * -+ * So this function tries to do the above. Returns %-EAGAIN if some free space -+ * was presumably made and the caller has to re-try budgeting the operation. -+ * Returns %-ENOSPC if it couldn't do more free space, and other negative error -+ * codes on failures. -+ */ -+static int make_free_space(struct ubifs_info *c, struct retries_info *ri) -+{ -+ int err; -+ -+ /* -+ * If we have some dirty pages and inodes (liability), try to write -+ * them back unless this was tried too many times without effect -+ * already. -+ */ -+ if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) { -+ long long liability; -+ -+ spin_lock(&c->space_lock); -+ liability = c->budg_idx_growth + c->budg_data_growth + -+ c->budg_dd_growth; -+ spin_unlock(&c->space_lock); -+ -+ if (ri->prev_liability >= liability) { -+ /* Liability does not shrink, next time try GC then */ -+ ri->shrink_retries += 1; -+ if (ri->gc_retries < MAX_GC_RETRIES) -+ ri->try_gc = 1; -+ dbg_budg("liability did not shrink: retries %d of %d", -+ ri->shrink_retries, MAX_SHRINK_RETRIES); -+ } -+ -+ dbg_budg("force write-back (count %d)", ri->shrink_cnt); -+ shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt); -+ -+ ri->prev_liability = liability; -+ ri->shrink_cnt += 1; -+ return -EAGAIN; -+ } -+ -+ /* -+ * Try to run garbage collector unless it was already tried too many -+ * times. -+ */ -+ if (ri->gc_retries < MAX_GC_RETRIES) { -+ ri->gc_retries += 1; -+ dbg_budg("run GC, retries %d of %d", -+ ri->gc_retries, MAX_GC_RETRIES); -+ -+ ri->try_gc = 0; -+ err = run_gc(c); -+ if (!err) -+ return -EAGAIN; -+ -+ if (err == -EAGAIN) { -+ dbg_budg("GC asked to commit"); -+ err = ubifs_run_commit(c); -+ if (err) -+ return err; -+ return -EAGAIN; -+ } -+ -+ if (err != -ENOSPC) -+ return err; -+ -+ /* -+ * GC could not make any progress. If this is the first time, -+ * then it makes sense to try to commit, because it might make -+ * some dirty space. -+ */ -+ dbg_budg("GC returned -ENOSPC, retries %d", -+ ri->nospc_retries); -+ if (ri->nospc_retries >= MAX_NOSPC_RETRIES) -+ return err; -+ ri->nospc_retries += 1; -+ } -+ -+ /* Neither GC nor write-back helped, try to commit */ -+ if (ri->cmt_retries < MAX_CMT_RETRIES) { -+ ri->cmt_retries += 1; -+ dbg_budg("run commit, retries %d of %d", -+ ri->cmt_retries, MAX_CMT_RETRIES); -+ err = ubifs_run_commit(c); -+ if (err) -+ return err; -+ return -EAGAIN; -+ } -+ -+ return -ENOSPC; -+} -+#endif /* UBIFS_COMPAT_USE_OLD_PREPARE_WRITE */ -+ -+/** -+ * ubifs_calc_min_idx_lebs - calculate amount of eraseblocks for the index. -+ * @c: UBIFS file-system description object -+ * -+ * This function calculates and returns the number of eraseblocks which should -+ * be kept for index usage. -+ */ -+int ubifs_calc_min_idx_lebs(struct ubifs_info *c) -+{ -+ int ret; -+ uint64_t idx_size; -+ -+ idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx; -+ -+ /* And make sure we have twice the index size of space reserved */ -+ idx_size <<= 1; -+ -+ /* -+ * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' -+ * pair, nor similarly the two variables for the new index size, so we -+ * have to do this costly 64-bit division on fast-path. -+ */ -+ if (do_div(idx_size, c->leb_size - c->max_idx_node_sz)) -+ ret = idx_size + 1; -+ else -+ ret = idx_size; -+ /* -+ * The index head is not available for the in-the-gaps method, so add an -+ * extra LEB to compensate. -+ */ -+ ret += 1; -+ /* -+ * At present the index needs at least 2 LEBs: one for the index head -+ * and one for in-the-gaps method (which currently does not cater for -+ * the index head and so excludes it from consideration). -+ */ -+ if (ret < 2) -+ ret = 2; -+ return ret; -+} -+ -+/** -+ * ubifs_calc_available - calculate available FS space. -+ * @c: UBIFS file-system description object -+ * -+ * This function calculates and returns amount of FS space available for use. -+ */ -+long long ubifs_calc_available(const struct ubifs_info *c) -+{ -+ long long available, subtract_lebs; -+ -+ /* -+ * Force the amount available to the total size reported if the used -+ * space is zero. -+ */ -+ if (c->lst.total_used <= UBIFS_INO_NODE_SZ && -+ c->budg_data_growth + c->budg_dd_growth == 0) { -+ /* Do the same calculation as for c->block_cnt */ -+ available = c->main_lebs - 2; -+ available *= c->leb_size - c->dark_wm; -+ return available; -+ } -+ -+ available = c->main_bytes - c->lst.total_used; -+ -+ /* -+ * Now 'available' contains theoretically available flash space -+ * assuming there is no index, so we have to subtract the space which -+ * is reserved for the index. -+ */ -+ subtract_lebs = c->min_idx_lebs; -+ -+ /* Take into account that GC reserves one LEB for its own needs */ -+ subtract_lebs += 1; -+ -+ /* -+ * The GC journal head LEB is not really accessible. And since -+ * different write types go to different heads, we may count only on -+ * one head's space. -+ */ -+ subtract_lebs += c->jhead_cnt - 1; -+ -+ /* We also reserve one LEB for deletions, which bypass budgeting */ -+ subtract_lebs += 1; -+ -+ available -= subtract_lebs * c->leb_size; -+ -+ /* Subtract the dead space which is not available for use */ -+ available -= c->lst.total_dead; -+ -+ /* -+ * Subtract dark space, which might or might not be usable - it depends -+ * on the data which we have on the media and which will be written. If -+ * this is a lot of uncompressed or not-compressible data, the dark -+ * space cannot be used. -+ */ -+ available -= c->lst.total_dark; -+ -+ /* -+ * However, there is more dark space. The index may be bigger than -+ * min_idx_lebs. Those extra LEBs are assumed to be available, but -+ * their dark space is not included in total_dark, so it is subtracted -+ * here. -+ */ -+ if (c->lst.idx_lebs > c->min_idx_lebs) { -+ subtract_lebs = c->lst.idx_lebs - c->min_idx_lebs; -+ available -= subtract_lebs * c->dark_wm; -+ } -+ -+ return available; -+} -+ -+/** -+ * rp_can_write - check whether the user is allowed to write. -+ * @c: UBIFS file-system description object -+ * @avail: available space on FS -+ * -+ * UBIFS has so-called "reserved pool" which is flash space reserved -+ * for the superuser and for uses whose UID/GID is recorded in UBIFS superblock. -+ * This function checks whether current user is allowed to write -+ * to the file-system - it returns %1 if there is plenty of space or the user -+ * is eligible to use the reserved pool and %0 otherwise. -+ */ -+static int rp_can_write(struct ubifs_info *c, long long avail) -+{ -+ if (avail > c->rp_size || current->fsuid == c->rp_uid || -+ capable(CAP_SYS_RESOURCE) || -+ (c->rp_gid != 0 && in_group_p(c->rp_gid))) -+ return 1; -+ -+ return 0; -+} -+ -+/** -+ * do_budget_space - reserve flash space for index and data growth. -+ * @c: UBIFS file-system description object -+ * -+ * This function makes sure UBIFS has enough free eraseblocks for index growth -+ * and data. -+ * -+ * When budgeting index space, UBIFS reserves twice as more LEBs as the index -+ * would take if it was consolidated and written to the flash. This guarantees -+ * that the "in-the-gaps" commit method always succeeds and UBIFS will always -+ * be able to commit dirty index. So this function basically adds amount of -+ * budgeted index space to the size of the current index, multiplies this by 2, -+ * and makes sure this does not exceed the amount of free eraseblocks. -+ * -+ * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables: -+ * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might -+ * be large, because UBIFS does not do any index consolidation as long as -+ * there is free space. IOW, the index may take a lot of LEBs, but the LEBs -+ * will contain a lot of dirt. -+ * o @c->min_idx_lebs is the the index presumably takes. IOW, the index may be -+ * consolidated to take up to @c->min_idx_lebs LEBs. -+ * -+ * This function returns zero in case of success, and %-ENOSPC in case of -+ * failure. -+ */ -+static int do_budget_space(struct ubifs_info *c) -+{ -+ long long outstanding, available; -+ int lebs, rsvd_idx_lebs, min_idx_lebs; -+ -+ /* First budget index space */ -+ min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ -+ /* Now 'min_idx_lebs' contains number of LEBs to reserve */ -+ if (min_idx_lebs > c->lst.idx_lebs) -+ rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; -+ else -+ rsvd_idx_lebs = 0; -+ -+ /* -+ * The number of LEBs that are available to be used by the index is: -+ * -+ * @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt - -+ * @c->lst.taken_empty_lebs -+ * -+ * @empty_lebs are available because they are empty. @freeable_cnt are -+ * available because they contain only free and dirty space and the -+ * index allocation always occurs after wbufs are synch'ed. -+ * @idx_gc_cnt are available because they are index LEBs that have been -+ * garbage collected (including trivial GC) and are awaiting the commit -+ * before they can be unmapped - note that the in-the-gaps method will -+ * grab these if it needs them. @taken_empty_lebs are empty_lebs that -+ * have already been allocated for some purpose (also includes those -+ * LEBs on the @idx_gc list). -+ * -+ * Note, @taken_empty_lebs may temporarily be higher by one because of -+ * the way we serialize LEB allocations and budgeting. See a comment in -+ * 'ubifs_find_free_space()'. -+ */ -+ lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - -+ c->lst.taken_empty_lebs; -+ if (unlikely(rsvd_idx_lebs > lebs)) { -+ dbg_budg("out of indexing space: min_idx_lebs %d (old %d), " -+ "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs, -+ rsvd_idx_lebs); -+ return -ENOSPC; -+ } -+ -+ available = ubifs_calc_available(c); -+ outstanding = c->budg_data_growth + c->budg_dd_growth; -+ -+ if (unlikely(available < outstanding)) { -+ dbg_budg("out of data space: available %lld, outstanding %lld", -+ available, outstanding); -+ return -ENOSPC; -+ } -+ -+ if (!rp_can_write(c, available - outstanding)) -+ return -ENOSPC; -+ -+ c->min_idx_lebs = min_idx_lebs; -+ return 0; -+} -+ -+/** -+ * calc_idx_growth - calculate approximate index growth from budgeting request. -+ * @c: UBIFS file-system description object -+ * @req: budgeting request -+ * -+ * For now we assume each new node adds one znode. But this is rather poor -+ * approximation, though. -+ */ -+static int calc_idx_growth(const struct ubifs_info *c, -+ const struct ubifs_budget_req *req) -+{ -+ int znodes; -+ -+ znodes = req->new_ino + (req->new_page << UBIFS_BLOCKS_PER_PAGE_SHIFT) + -+ req->new_dent; -+ return znodes * c->max_idx_node_sz; -+} -+ -+/** -+ * calc_data_growth - calculate approximate amount of new data from budgeting -+ * request. -+ * @c: UBIFS file-system description object -+ * @req: budgeting request -+ */ -+static int calc_data_growth(const struct ubifs_info *c, -+ const struct ubifs_budget_req *req) -+{ -+ int data_growth; -+ -+ data_growth = req->new_ino ? c->inode_budget : 0; -+ if (req->new_page) -+ data_growth += c->page_budget; -+ if (req->new_dent) -+ data_growth += c->dent_budget; -+ data_growth += req->new_ino_d; -+ -+ return data_growth; -+} -+ -+/** -+ * calc_dd_growth - calculate approximate amount of data which makes other data -+ * dirty from budgeting request. -+ * @c: UBIFS file-system description object -+ * @req: budgeting request -+ */ -+static int calc_dd_growth(const struct ubifs_info *c, -+ const struct ubifs_budget_req *req) -+{ -+ int dd_growth; -+ -+ dd_growth = req->dirtied_page ? c->page_budget : 0; -+ -+ if (req->dirtied_ino) -+ dd_growth += c->inode_budget << (req->dirtied_ino - 1); -+ if (req->mod_dent) -+ dd_growth += c->dent_budget; -+ dd_growth += req->dirtied_ino_d; -+ -+ return dd_growth; -+} -+ -+/** -+ * ubifs_budget_space - ensure there is enough space to complete an operation. -+ * @c: UBIFS file-system description object -+ * @req: budget request -+ * -+ * This function allocates budget for an operation. It uses pessimistic -+ * approximation of how much flash space the operation needs. The goal of this -+ * function is to make sure UBIFS always has flash space to flush all dirty -+ * pages, dirty inodes, and dirty znodes (liability). This function may force -+ * commit, garbage-collection or write-back. Returns zero in case of success, -+ * %-ENOSPC if there is no free space and other negative error codes in case of -+ * failures. -+ */ -+int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) -+{ -+ int uninitialized_var(cmt_retries), uninitialized_var(wb_retries); -+ int err, idx_growth, data_growth, dd_growth; -+ struct retries_info ri; -+ -+ data_growth = calc_data_growth(c, req); -+ dd_growth = calc_dd_growth(c, req); -+ if (!data_growth && !dd_growth) -+ return 0; -+ idx_growth = calc_idx_growth(c, req); -+ memset(&ri, 0, sizeof(struct retries_info)); -+ -+again: -+ spin_lock(&c->space_lock); -+ ubifs_assert(c->budg_idx_growth >= 0); -+ ubifs_assert(c->budg_data_growth >= 0); -+ ubifs_assert(c->budg_dd_growth >= 0); -+ -+ c->budg_idx_growth += idx_growth; -+ c->budg_data_growth += data_growth; -+ c->budg_dd_growth += dd_growth; -+ -+ err = do_budget_space(c); -+ if (unlikely(err)) { -+ /* Restore the old values */ -+ c->budg_idx_growth -= idx_growth; -+ c->budg_data_growth -= data_growth; -+ c->budg_dd_growth -= dd_growth; -+ spin_unlock(&c->space_lock); -+ -+ goto make_space; -+ } -+ -+ req->idx_growth = idx_growth; -+ req->data_growth = data_growth; -+ req->dd_growth = dd_growth; -+ spin_unlock(&c->space_lock); -+ -+ return 0; -+ -+make_space: -+/* TODO: remove compatibility stuff as late as possible */ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+ err = ubifs_make_free_space(c, &ri, req->locked_pg); -+#else -+ err = make_free_space(c, &ri); -+#endif -+ -+ if (err == -EAGAIN) { -+ dbg_budg("try again"); -+ cond_resched(); -+ goto again; -+ } else if (err == -ENOSPC) -+ dbg_budg("FS is full, -ENOSPC"); -+ else -+ ubifs_err("cannot budget space, error %d", err); -+ -+ return err; -+} -+ -+/** -+ * ubifs_release_budget - release budgeted free space. -+ * @c: UBIFS file-system description object -+ * @req: budget request -+ * -+ * This function releases the space budgeted by 'ubifs_budget_space()'. Note, -+ * since the index changes (which were budgeted for in @req->idx_growth) will -+ * only be written to the media on commit, this function moves the index budget -+ * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be -+ * zeroed by the commit operation. -+ */ -+void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) -+{ -+ if (!req->data_growth && !req->dd_growth) -+ return; -+ -+ if (req->idx_growth == -1) -+ req->idx_growth = calc_idx_growth(c, req); -+ -+ spin_lock(&c->space_lock); -+ c->budg_idx_growth -= req->idx_growth; -+ c->budg_uncommitted_idx += req->idx_growth; -+ c->budg_data_growth -= req->data_growth; -+ c->budg_dd_growth -= req->dd_growth; -+ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ -+ ubifs_assert(c->budg_idx_growth >= 0); -+ ubifs_assert(c->budg_data_growth >= 0); -+ ubifs_assert(c->min_idx_lebs < c->main_lebs); -+ spin_unlock(&c->space_lock); -+} -+ -+/** -+ * ubifs_convert_page_budget - convert budget of a new page. -+ * @c: UBIFS file-system description object -+ * -+ * This function converts budget which was allocated for a new page of data to -+ * the budget of changing an existing page of data. The latter is not larger -+ * then the former, so this function only does simple re-calculation and does -+ * not involve any write-back. -+ */ -+void ubifs_convert_page_budget(struct ubifs_info *c) -+{ -+ spin_lock(&c->space_lock); -+ /* Release the index growth reservation */ -+ c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT; -+ /* Release the data growth reservation */ -+ c->budg_data_growth -= c->page_budget; -+ /* Increase the dirty data growth reservation instead */ -+ c->budg_dd_growth += c->page_budget; -+ /* And re-calculate the indexing space reservation */ -+ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ spin_unlock(&c->space_lock); -+} -+ -+/** -+ * ubifs_budget_inode_op - budget an operation on inode. -+ * @c: UBIFS file-system description object -+ * @inode: VFS inode which will be made dirty by the operation -+ * @req: budget request of the operation -+ * -+ * This function is called to get budget for an operation which changes an -+ * inode. The inode may be in dirty or clean state. The former means there is -+ * no need to allocate the budget as it has already been allocated before. The -+ * latter means that the inode change budget has to be allocated. -+ * -+ * The caller has to pass the inode which is going to be changed. This function -+ * acquires budget the for as described in @req plus the budget for changing -+ * the inode dirty, if needed. Returns zero in case of success, %-ENOSPC if -+ * there is no more flash space, and other negative error codes in case of -+ * failure. -+ * -+ * Note, upon exit, this function leaves the inode locked, and the -+ * 'ubifs_release_ino_dirty()' or 'ubifs_release_ino_clean()' function has to -+ * be called to unlock it. -+ */ -+int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req) -+{ -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ int err, old = req->dirtied_ino; -+ -+ ubifs_assert(req->dirtied_ino <= 3); -+ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 3); -+ -+again: -+ /* -+ * If the inode is clean, it will be dirtied by this operation and we -+ * have to budget for this. -+ */ -+ req->dirtied_ino += !ui->dirty; -+ if (req->dirtied_ino > old) -+ req->dirtied_ino_d += ui->data_len; -+ -+ /* -+ * Note, if the budget request does not actually request anything -+ * (i.e., @req contains only zeroes), 'ubifs_budget_space()' will -+ * return almost straight away. -+ */ -+ err = ubifs_budget_space(c, req); -+ if (unlikely(err)) -+ return err; -+ -+ mutex_lock(&ui->budg_mutex); -+ -+ if (req->dirtied_ino != old + !ui->dirty) { -+ /* The inode has probably been written back meanwhile */ -+ ubifs_release_budget(c, req); -+ mutex_unlock(&ui->budg_mutex); -+ req->dirtied_ino = old; -+ req->dirtied_ino_d -= ui->data_len; -+ goto again; -+ } -+ -+ UBIFS_DBG(ui->budgeted = 1); -+ return 0; -+} -+ -+/** -+ * ubifs_release_ino_dirty - release budget of a "dirtying" operation. -+ * @c: UBIFS file-system description object -+ * @inode: VFS inode the operation worked on -+ * @req: budget to release -+ * -+ * This function has to be called at the end of VFS operations which acquired -+ * budget via 'ubifs_budget_inode_op()'. It assumes that the inode has been -+ * marked as dirty and will be synchronized later by write-back, so it does not -+ * release the budget of the inode. -+ * -+ * Note, this function also avoids releasing page budgets which are released -+ * separately. -+ */ -+void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req) -+{ -+ ubifs_assert(req->dirtied_ino <= 4); -+ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); -+ ubifs_assert(req->idx_growth >= 0); -+ ubifs_assert(req->data_growth >= 0); -+ ubifs_assert(req->dd_growth >= 0); -+ -+ if (req->dirtied_ino) { -+ req->dd_growth -= c->inode_budget; -+ req->dd_growth -= req->dirtied_ino_d; -+ } -+ -+ if (req->dirtied_page) { -+ req->dd_growth -= c->page_budget; -+ ubifs_assert(req->new_page == 0); -+ } else if (req->new_page) { -+ req->idx_growth -= -+ c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT; -+ req->data_growth -= c->page_budget; -+ ubifs_assert(req->dirtied_page == 0); -+ } -+ -+ ubifs_assert(req->dd_growth >= 0); -+ ubifs_release_budget(c, req); -+ mutex_unlock(&ubifs_inode(inode)->budg_mutex); -+} -+ -+/** -+ * ubifs_cancel_ino_op - cancel budget of an operation on inode. -+ * @c: UBIFS file-system description object -+ * @inode: VFS inode the operation worked on -+ * @req: budget to release -+ * -+ * This function has to be called if the operation failed and whole budget has -+ * to be released, including the budget for inode which would had been -+ * dirtied. It is important not to mark the inode dirty before calling this -+ * function. -+ */ -+void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req) -+{ -+ ubifs_assert(req->dirtied_ino <= 4); -+ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); -+ ubifs_assert(req->idx_growth >= 0); -+ ubifs_assert(req->data_growth >= 0); -+ ubifs_assert(req->dd_growth >= 0); -+ -+ ubifs_release_budget(c, req); -+ mutex_unlock(&ubifs_inode(inode)->budg_mutex); -+} -+ -+/** -+ * ubifs_release_ino_clean - release budget of a "cleaning" operation. -+ * @c: UBIFS file-system description object -+ * @inode: VFS inode the operation worked on -+ * @req: budget to release -+ * -+ * This function has to be called at the end of VFS operations which acquired -+ * budget via 'ubifs_budget_inode_op()'. It assumed the operation synchronized -+ * the inode, so it marks the inode clean, unlocks it and releases whole budget. -+ * -+ * Note, this function also avoids releasing page budgets which are released -+ * separately. -+ */ -+void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req) -+{ -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ ubifs_assert(req->dirtied_ino <= 4); -+ ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); -+ ubifs_assert(req->idx_growth >= 0); -+ ubifs_assert(req->data_growth >= 0); -+ ubifs_assert(req->dd_growth >= 0); -+ ubifs_assert(!req->dirtied_page); -+ ubifs_assert(!req->new_page); -+ UBIFS_DBG(ui->budgeted = 0); -+ -+ ubifs_release_budget(c, req); -+ if (ui->dirty) { -+ ui->dirty = 0; -+ /* -+ * Note, VFS still treats the inode as dirty and -+ * 'ubifs_write_inode()' will be called, but it'll do nothing -+ * because @ui->dirty is %0. -+ */ -+ atomic_long_dec(&c->dirty_ino_cnt); -+ } -+ mutex_unlock(&ubifs_inode(inode)->budg_mutex); -+} -+ -+/** -+ * ubifs_release_new_page_budget - release budget of a new page. -+ * @c: UBIFS file-system description object -+ * -+ * This is a helper function which releases budget corresponding to the budget -+ * of one new page of data. -+ */ -+void ubifs_release_new_page_budget(struct ubifs_info *c) -+{ -+ struct ubifs_budget_req req = { .new_page = 1, -+ .idx_growth = -1, -+ .data_growth = c->page_budget }; -+ -+ ubifs_release_budget(c, &req); -+} -+ -+/** -+ * ubifs_budg_get_free_space - return amount of free space. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns amount of free space on the file-system. -+ */ -+long long ubifs_budg_get_free_space(struct ubifs_info *c) -+{ -+ int min_idx_lebs, rsvd_idx_lebs; -+ long long available, outstanding, free; -+ -+ /* Do exactly the same calculations as in 'do_budget_space()' */ -+ spin_lock(&c->space_lock); -+ min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ -+ if (min_idx_lebs > c->lst.idx_lebs) -+ rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; -+ else -+ rsvd_idx_lebs = 0; -+ -+ if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -+ - c->lst.taken_empty_lebs) { -+ spin_unlock(&c->space_lock); -+ return 0; -+ } -+ -+ c->min_idx_lebs = min_idx_lebs; -+ available = ubifs_calc_available(c); -+ outstanding = c->budg_data_growth + c->budg_dd_growth; -+ spin_unlock(&c->space_lock); -+ -+ if (available > outstanding) -+ free = ubifs_reported_space(c, available - outstanding); -+ else -+ free = 0; -+ -+ return free; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/build.c linux-2.6.24.7/fs/ubifs/build.c ---- linux-2.6.24.7.old/fs/ubifs/build.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/build.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1423 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS initialization, mount and un-mount. Some -+ * initialization stuff which is rather large and complex is placed at -+ * corresponding subsystems, but most of it is here. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubifs.h" -+ -+/* Slab cache for UBIFS inodes */ -+struct kmem_cache *ubifs_inode_slab; -+ -+/* TODO: remove compatibility stuff as late as possible */ -+#ifndef UBIFS_COMPAT_NO_SHRINKER -+/* UBIFS TNC shrinker description */ -+static struct shrinker ubifs_shrinker_info = { -+ .shrink = ubifs_shrinker, -+ .seeks = DEFAULT_SEEKS, -+}; -+#endif -+ -+/** -+ * init_constants_early - initialize UBIFS constants. -+ * @c: UBIFS file-system description object -+ * -+ * This function initialize UBIFS constants which do not need the superblock to -+ * be read. It also checks that the UBI volume satisfies basic UBIFS -+ * requirements. Returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int init_constants_early(struct ubifs_info *c) -+{ -+ if (c->vi.corrupted) { -+ ubifs_warn("UBI volume is corrupted - read-only mode"); -+ c->ro_media = 1; -+ } -+ -+ if (c->di.ro_mode) { -+ ubifs_msg("read-only UBI device"); -+ c->ro_media = 1; -+ } -+ -+ if (c->vi.vol_type == UBI_STATIC_VOLUME) { -+ ubifs_msg("static UBI volume - read-only mode"); -+ c->ro_media = 1; -+ } -+ -+ c->leb_cnt = c->vi.size; -+ c->leb_size = c->vi.usable_leb_size; -+ c->half_leb_size = c->leb_size / 2; -+ c->min_io_size = c->di.min_io_size; -+ c->min_io_shift = fls(c->min_io_size) - 1; -+ -+ if (c->leb_size < UBIFS_MIN_LEB_SZ) { -+ ubifs_err("too small LEBs (%d bytes), min. is %d bytes", -+ c->leb_size, UBIFS_MIN_LEB_SZ); -+ return -EINVAL; -+ } -+ -+ if (c->leb_cnt < UBIFS_MIN_LEB_CNT) { -+ ubifs_err("too few LEBs (%d), min. is %d", -+ c->leb_cnt, UBIFS_MIN_LEB_CNT); -+ return -EINVAL; -+ } -+ -+ if (!is_power_of_2(c->min_io_size)) { -+ ubifs_err("bad min. I/O size %d", c->min_io_size); -+ return -EINVAL; -+ } -+ -+ /* -+ * UBIFS aligns all node to 8-byte boundary, so to make function in -+ * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is -+ * less than 8. -+ */ -+ if (c->min_io_size < 8) { -+ c->min_io_size = 8; -+ c->min_io_shift = 3; -+ } -+ -+ c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); -+ c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size); -+ -+ /* -+ * Initialize node length ranges which are mostly needed for node -+ * length validation. -+ */ -+ c->ranges[UBIFS_PAD_NODE].len = UBIFS_PAD_NODE_SZ; -+ c->ranges[UBIFS_SB_NODE].len = UBIFS_SB_NODE_SZ; -+ c->ranges[UBIFS_MST_NODE].len = UBIFS_MST_NODE_SZ; -+ c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; -+ c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; -+ c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; -+ -+ c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; -+ c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; -+ c->ranges[UBIFS_ORPH_NODE].min_len = -+ UBIFS_ORPH_NODE_SZ + sizeof(__le64); -+ c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size; -+ c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ; -+ c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ; -+ c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ; -+ c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ; -+ c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ; -+ c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ; -+ /* -+ * Minimum indexing node size is amended later when superblock is -+ * read and the key length is known. -+ */ -+ c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ; -+ /* -+ * Maximum indexing node size is amended later when superblock is -+ * read and the fanout is known. -+ */ -+ c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX; -+ -+ /* -+ * Initialize dead and dark LEB space watermarks. -+ * -+ * Dead space is the space which cannot be used. Its watermark is -+ * equivalent to min. I/O unit or minimum node size if it is greater -+ * then min. I/O unit. -+ * -+ * Dark space is the space which might be used, or might not, depending -+ * on which node should be written to the LEB. Its watermark is -+ * equivalent to maximum UBIFS node size. -+ */ -+ c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); -+ c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); -+ -+ return 0; -+} -+ -+/** -+ * bud_wbuf_callback - bud LEB write-buffer synchronization call-back. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB the write-buffer was synchronized to -+ * @free: how many free bytes left in this LEB -+ * @pad: how many bytes were padded -+ * -+ * This is a callback function which is called by the I/O unit when the -+ * write-buffer is synchronized. We need this to correctly maintain space -+ * accounting in bud logical eraseblocks. This function returns zero in case of -+ * success and a negative error code in case of failure. -+ * -+ * This function actually belongs to the journal, but we keep it here because -+ * we want to keep it static. -+ */ -+static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad) -+{ -+ return ubifs_update_one_lp(c, lnum, free, pad, 0, 0); -+} -+ -+/* -+ * init_constants_late - initialize UBIFS constants. -+ * @c: UBIFS file-system description object -+ * -+ * This is a helper function which initializes various UBIFS constants after -+ * the superblock has been read. It also checks various UBIFS parameters and -+ * makes sure they are all right. Returns zero in case of success and a -+ * negative error code in case of failure. -+ */ -+static int init_constants_late(struct ubifs_info *c) -+{ -+ int tmp, err; -+ uint64_t tmp64; -+ -+ c->main_bytes = c->main_lebs * c->leb_size; -+ -+ c->max_znode_sz = sizeof(struct ubifs_znode) + -+ c->fanout * sizeof(struct ubifs_zbranch); -+ -+ tmp = ubifs_idx_node_sz(c, 1); -+ c->ranges[UBIFS_IDX_NODE].min_len = tmp; -+ c->min_idx_node_sz = ALIGN(tmp, 8); -+ -+ tmp = ubifs_idx_node_sz(c, c->fanout); -+ c->ranges[UBIFS_IDX_NODE].max_len = tmp; -+ c->max_idx_node_sz = ALIGN(tmp, 8); -+ -+ /* Make sure LEB size is large enough to fit full commit */ -+ tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt; -+ tmp = ALIGN(tmp, c->min_io_size); -+ if (tmp > c->leb_size) { -+ dbg_err("too small LEB size %d, at least %d needed", -+ c->leb_size, tmp); -+ return -EINVAL; -+ } -+ -+ /* -+ * Make sure that the log is large enough to fit reference nodes for -+ * all buds plus one reserved LEB. -+ */ -+ tmp64 = c->max_bud_bytes; -+ tmp = do_div(tmp64, c->leb_size); -+ c->max_bud_cnt = tmp64 + !!tmp; -+ tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1); -+ tmp /= c->leb_size; -+ tmp += 1; -+ if (c->log_lebs < tmp) { -+ dbg_err("too small log %d LEBs, required min. %d LEBs", -+ c->log_lebs, tmp); -+ return -EINVAL; -+ } -+ -+ /* -+ * When budgeting we assume worst-case scenarios when the pages are not -+ * be compressed and direntries are of the maximum size. -+ * -+ * Note, data, which may be stored in inodes is budgeted separately, so -+ * it is not included into 'c->inode_budget'. -+ * -+ * c->page_budget is PAGE_CACHE_SIZE + UBIFS_CH_SZ * blocks_per_page -+ */ -+ c->page_budget = PAGE_CACHE_SIZE + UBIFS_CH_SZ; -+ c->inode_budget = UBIFS_INO_NODE_SZ; -+ c->dent_budget = UBIFS_MAX_DENT_NODE_SZ; -+ -+ /* -+ * When the amount of flash space used by buds becomes -+ * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit. -+ * The writers are unblocked when the commit is finished. To avoid -+ * writers to be blocked UBIFS initiates background commit in advance, -+ * when number of bud bytes becomes above the limit defined below. -+ */ -+ c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4; -+ -+ /* -+ * Ensure minimum journal size. All the bytes in the journal heads are -+ * considered to be used, when calculating the current journal usage. -+ * Consequently, if the journal is too small, UBIFS will treat it as -+ * always full. -+ */ -+ tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1; -+ if (c->bg_bud_bytes < tmp64) -+ c->bg_bud_bytes = tmp64; -+ if (c->max_bud_bytes < tmp64 + c->leb_size) -+ c->max_bud_bytes = tmp64 + c->leb_size; -+ -+ err = ubifs_calc_lpt_geom(c); -+ if (err) -+ return err; -+ -+ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ -+ /* -+ * Calculate total amount of FS blocks. This number is not used -+ * internally because it does not make much sense for UBIFS, but it is -+ * necessary to report something for the 'statfs()' call. -+ * -+ * Subtract the LEB reserved for GC and the LEB which is reserved for -+ * deletions. -+ * -+ * Review 'ubifs_calc_available()' if changing this calculation. -+ */ -+ tmp64 = c->main_lebs - 2; -+ tmp64 *= c->leb_size - c->dark_wm; -+ tmp64 = ubifs_reported_space(c, tmp64); -+ c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; -+ -+ return 0; -+} -+ -+/** -+ * care_about_gc_lnum - take care about reserved GC LEB. -+ * @c: UBIFS file-system description object -+ * -+ * This function ensures that the LEB reserved for garbage collection is -+ * unmapped and is marked as "taken" in lprops. We also have to set free space -+ * to LEB size and dirty space to zero, because lprops may contain out-of-date -+ * information if the file-system was un-mounted before it has been committed. -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int care_about_gc_lnum(struct ubifs_info *c) -+{ -+ int err; -+ -+ if (c->gc_lnum == -1) { -+ ubifs_err("no LEB for GC"); -+ return -EINVAL; -+ } -+ -+ err = ubifs_leb_unmap(c, c->gc_lnum); -+ if (err) -+ return err; -+ -+ /* And we have to tell lprops that this LEB is taken */ -+ err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0, -+ LPROPS_TAKEN, 0, 0); -+ return err; -+} -+ -+/** -+ * alloc_wbufs - allocate write-buffers. -+ * @c: UBIFS file-system description object -+ * -+ * This helper function allocates and initializes UBIFS write-buffers. Returns -+ * zero in case of success and %-ENOMEM in case of failure. -+ */ -+static int alloc_wbufs(struct ubifs_info *c) -+{ -+ int i, err; -+ -+ c->jheads = kzalloc(c->jhead_cnt * sizeof(struct ubifs_jhead), -+ GFP_KERNEL); -+ if (!c->jheads) -+ return -ENOMEM; -+ -+ /* Initialize journal heads */ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ INIT_LIST_HEAD(&c->jheads[i].buds_list); -+ err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); -+ if (err) -+ return err; -+ -+ c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; -+ c->jheads[i].wbuf.jhead = i; -+ } -+ -+ c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM; -+ /* -+ * Garbage Collector head likely contains long-term data and -+ * does not need to be synchronized by timer. -+ */ -+ c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; -+ c->jheads[GCHD].wbuf.timeout = 0; -+ -+ sprintf(c->bgt_name, "%s%d_%d", SYNCER_BG_NAME, -+ c->vi.ubi_num, c->vi.vol_id); -+ -+ return 0; -+} -+ -+/** -+ * free_wbufs - free write-buffers. -+ * @c: UBIFS file-system description object -+ */ -+static void free_wbufs(struct ubifs_info *c) -+{ -+ int i; -+ -+ if (c->jheads) { -+ for (i = 0; i < c->jhead_cnt; i++) { -+ kfree(c->jheads[i].wbuf.buf); -+ kfree(c->jheads[i].wbuf.inodes); -+ } -+ kfree(c->jheads); -+ c->jheads = NULL; -+ } -+} -+ -+/** -+ * free_orphans - free orphans. -+ * @c: UBIFS file-system description object -+ */ -+static void free_orphans(struct ubifs_info *c) -+{ -+ struct ubifs_orphan *orph; -+ -+ while (c->orph_dnext) { -+ orph = c->orph_dnext; -+ c->orph_dnext = orph->dnext; -+ list_del(&orph->list); -+ kfree(orph); -+ } -+ -+ while (!list_empty(&c->orph_list)) { -+ orph = list_entry(c->orph_list.next, struct ubifs_orphan, list); -+ list_del(&orph->list); -+ kfree(orph); -+ dbg_err("orphan list not empty at unmount"); -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->orph_buf); -+#else -+ vfree(c->orph_buf); -+#endif -+ c->orph_buf = NULL; -+} -+ -+/** -+ * free_buds - free per-bud objects. -+ * @c: UBIFS file-system description object -+ */ -+static void free_buds(struct ubifs_info *c) -+{ -+ struct rb_node *this = c->buds.rb_node; -+ struct ubifs_bud *bud; -+ -+ while (this) { -+ if (this->rb_left) -+ this = this->rb_left; -+ else if (this->rb_right) -+ this = this->rb_right; -+ else { -+ bud = rb_entry(this, struct ubifs_bud, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &bud->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(bud); -+ } -+ } -+} -+ -+/** -+ * check_volume_empty - check if the UBI volume is empty. -+ * @c: UBIFS file-system description object -+ * -+ * This function checks if the UBIFS volume is empty by looking if its LEBs are -+ * mapped or not. The result of checking is stored in the @c->empty variable. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int check_volume_empty(struct ubifs_info *c) -+{ -+ int lnum, err; -+ -+ c->empty = 1; -+ for (lnum = 0; lnum < c->leb_cnt; lnum++) { -+ err = ubi_is_mapped(c->ubi, lnum); -+ if (unlikely(err < 0)) -+ return err; -+ if (err == 1) { -+ c->empty = 0; -+ break; -+ } -+ -+ cond_resched(); -+ } -+ -+ return 0; -+} -+ -+/** -+ * mount_ubifs - mount UBIFS file-system. -+ * @c: UBIFS file-system description object -+ * -+ * This function mounts UBIFS file system. Returns zero in case of success and -+ * a negative error code in case of failure. -+ * -+ * Note, the function does not de-allocate resources it it fails half way -+ * through, and the caller has to do this instead. -+ */ -+static int mount_ubifs(struct ubifs_info *c) -+{ -+ struct super_block *sb = c->vfs_sb; -+ int err, mounted_read_only = (sb->s_flags & MS_RDONLY); -+ unsigned long long x; -+ size_t sz; -+ -+ err = init_constants_early(c); -+ if (err) -+ return err; -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->dbg_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->dbg_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->dbg_buf) -+ return -ENOMEM; -+#endif -+ -+ err = check_volume_empty(c); -+ if (err) -+ return err; -+ -+ if (c->empty && (mounted_read_only || c->ro_media)) { -+ /* -+ * This UBI volume is empty, and read-only, or the file system -+ * is mounted read-only - we cannot format it. -+ */ -+ ubifs_err("can't format empty UBI volume: read-only %s", -+ c->ro_media ? "UBI volume" : "mount"); -+ return -EROFS; -+ } -+ -+ if (c->ro_media && !mounted_read_only) { -+ ubifs_err("cannot mount read-write - read-only media"); -+ return -EROFS; -+ } -+ -+ /* -+ * The requirement for the buffer is that it should fit indexing B-tree -+ * height amount of integers. We assume the height if the TNC tree will -+ * never exceed 64. -+ */ -+ c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL); -+ if (!c->bottom_up_buf) -+ return -ENOMEM; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->sbuf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->sbuf = vmalloc(c->leb_size); -+#endif -+ if (!c->sbuf) -+ return -ENOMEM; -+ -+ if (!mounted_read_only) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ileb_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->ileb_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->ileb_buf) -+ return -ENOMEM; -+ } -+ -+ err = ubifs_read_superblock(c); -+ if (err) -+ return err; -+ -+ /* -+ * Make sure the compressor which is set as the default on in the -+ * superblock was actually compiled in. -+ */ -+ if (!ubifs_compr_present(c->default_compr)) { -+ ubifs_warn("'%s' compressor is set by superblock, but not " -+ "compiled in", ubifs_compr_name(c->default_compr)); -+ c->default_compr = UBIFS_COMPR_NONE; -+ } -+ -+ dbg_failure_mode_registration(c); -+ -+ err = init_constants_late(c); -+ if (err) -+ return err; -+ -+ sz = ALIGN(c->max_idx_node_sz, c->min_io_size); -+ sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size); -+ c->cbuf = kmalloc(sz, GFP_NOFS); -+ if (!c->cbuf) -+ return -ENOMEM; -+ -+ if (!mounted_read_only) { -+ err = alloc_wbufs(c); -+ if (err) -+ return err; -+ -+ /* Create background thread */ -+ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); -+ if (!c->bgt) -+ c->bgt = ERR_PTR(-EINVAL); -+ if (IS_ERR(c->bgt)) { -+ err = PTR_ERR(c->bgt); -+ c->bgt = NULL; -+ ubifs_err("cannot spawn \"%s\", error %d", -+ c->bgt_name, err); -+ return err; -+ } -+ } -+ -+ err = ubifs_read_master(c); -+ if (err) -+ return err; -+ -+ if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) { -+ ubifs_msg("recovery needed"); -+ c->need_recovery = 1; -+ if (!mounted_read_only) { -+ err = ubifs_recover_inl_heads(c, c->sbuf); -+ if (err) -+ return err; -+ } -+ } else if (!mounted_read_only) { -+ /* -+ * Set the "dirty" flag so that if we reboot uncleanly we -+ * will notice this immediately on the next mount. -+ */ -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ err = ubifs_write_master(c); -+ if (err) -+ return err; -+ } -+ -+ err = ubifs_lpt_init(c, 1, !mounted_read_only); -+ if (err) -+ return err; -+ -+ err = dbg_check_idx_size(c, c->old_idx_sz); -+ if (err) -+ return err; -+ -+ err = ubifs_replay_journal(c); -+ if (err) -+ return err; -+ -+ if (!mounted_read_only) { -+ int lnum; -+ -+ if (c->need_recovery) -+ err = ubifs_recover_gc_lnum(c); -+ else -+ err = care_about_gc_lnum(c); -+ if (err) -+ return err; -+ err = ubifs_mount_orphans(c, c->need_recovery); -+ if (err) -+ return err; -+ -+ /* Check for enough log space */ -+ lnum = c->lhead_lnum + 1; -+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) -+ lnum = UBIFS_LOG_LNUM; -+ if (lnum == c->ltail_lnum) { -+ err = ubifs_consolidate_log(c); -+ if (err) -+ return err; -+ } -+ -+ /* Check for enough free space */ -+ if (ubifs_calc_available(c) <= 0) { -+ ubifs_err("insufficient available space"); -+ return -EINVAL; -+ } -+ -+ err = dbg_check_lprops(c); -+ if (err) -+ return err; -+ } -+ -+ if (c->need_recovery) { -+ err = ubifs_recover_size(c); -+ if (err) -+ return err; -+ } -+ -+ spin_lock(&ubifs_infos_lock); -+ list_add_tail(&c->infos_list, &ubifs_infos); -+ spin_unlock(&ubifs_infos_lock); -+ -+ if (c->need_recovery) { -+ if (mounted_read_only) -+ ubifs_msg("recovery deferred"); -+ else { -+ c->need_recovery = 0; -+ ubifs_msg("recovery completed"); -+ } -+ } -+ -+ ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num, -+ c->vi.vol_id); -+ if (mounted_read_only) -+ ubifs_msg("mounted read-only"); -+ ubifs_msg("minimal I/O unit size: %d bytes", c->min_io_size); -+ ubifs_msg("logical eraseblock size: %d bytes (%d KiB)", -+ c->leb_size, c->leb_size / 1024); -+ x = (unsigned long long)c->main_lebs * c->leb_size; -+ ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, " -+ "%d LEBs)", x, x >> 10, x >> 20, c->main_lebs); -+ x = (unsigned long long)c->log_lebs * c->leb_size + c->max_bud_bytes; -+ ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, " -+ "%d LEBs)", x, x >> 10, x >> 20, -+ c->log_lebs + c->max_bud_cnt); -+ ubifs_msg("data journal heads: %d", -+ c->jhead_cnt - NONDATA_JHEADS_CNT); -+ ubifs_msg("default compressor: %s", -+ ubifs_compr_name(c->default_compr)); -+ -+ dbg_msg("compiled on: " __DATE__ " at " __TIME__); -+ dbg_msg("fast unmount: %d", c->fast_unmount); -+ dbg_msg("big_lpt %d", c->big_lpt); -+ dbg_msg("log LEBs: %d (%d - %d)", -+ c->log_lebs, UBIFS_LOG_LNUM, c->log_last); -+ dbg_msg("LPT area LEBs: %d (%d - %d)", -+ c->lpt_lebs, c->lpt_first, c->lpt_last); -+ dbg_msg("orphan area LEBs: %d (%d - %d)", -+ c->orph_lebs, c->orph_first, c->orph_last); -+ dbg_msg("main area LEBs: %d (%d - %d)", -+ c->main_lebs, c->main_first, c->leb_cnt - 1); -+ dbg_msg("index LEBs: %d", c->lst.idx_lebs); -+ dbg_msg("total index bytes: %lld (%lld KiB, %lld MiB)", -+ c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20); -+ dbg_msg("key hash type: %d", c->key_hash_type); -+ dbg_msg("tree fanout: %d", c->fanout); -+ dbg_msg("reserved GC LEB: %d", c->gc_lnum); -+ dbg_msg("first main LEB: %d", c->main_first); -+ dbg_msg("dead watermark: %d", c->dead_wm); -+ dbg_msg("dark watermark: %d", c->dark_wm); -+ x = c->main_lebs * c->dark_wm; -+ dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)", -+ x, x >> 10, x >> 20); -+ dbg_msg("maximum bud bytes: %lld (%lld KiB, %lld MiB)", -+ c->max_bud_bytes, c->max_bud_bytes >> 10, -+ c->max_bud_bytes >> 20); -+ dbg_msg("BG commit bud bytes: %lld (%lld KiB, %lld MiB)", -+ c->bg_bud_bytes, c->bg_bud_bytes >> 10, -+ c->bg_bud_bytes >> 20); -+ dbg_msg("current bud bytes %lld (%lld KiB, %lld MiB)", -+ c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20); -+ dbg_msg("max. seq. number: %llu", c->max_sqnum); -+ dbg_msg("commit number: %llu", c->cmt_no); -+ -+ return 0; -+} -+ -+/** -+ * ubifs_umount - un-mount UBIFS file-system. -+ * @c: UBIFS file-system description object -+ * -+ * Note, this function is called to free allocated resourced when un-mounting, -+ * as well as free resources when an error occurred while we were half way -+ * through mounting (error path cleanup function). So it has to make sure the -+ * resource was actually allocated before freeing it. -+ */ -+void ubifs_umount(struct ubifs_info *c) -+{ -+ dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, -+ c->vi.vol_id); -+ -+ ubifs_destroy_size_tree(c); -+ -+ if (c->bgt) -+ kthread_stop(c->bgt); -+ -+ free_buds(c); -+ ubifs_destroy_idx_gc(c); -+ ubifs_tnc_close(c); -+ -+ free_wbufs(c); -+ free_orphans(c); -+ ubifs_lpt_free(c, 0); -+ -+ while (!list_empty(&c->unclean_leb_list)) { -+ struct ubifs_unclean_leb *ucleb; -+ -+ ucleb = list_entry(c->unclean_leb_list.next, -+ struct ubifs_unclean_leb, list); -+ list_del(&ucleb->list); -+ kfree(ucleb); -+ } -+ -+ while (!list_empty(&c->old_buds)) { -+ struct ubifs_bud *bud; -+ -+ bud = list_entry(c->old_buds.next, struct ubifs_bud, list); -+ list_del(&bud->list); -+ kfree(bud); -+ } -+ -+ kfree(c->rcvrd_mst_node); -+ kfree(c->mst_node); -+ kfree(c->bottom_up_buf); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->sbuf); -+ UBIFS_DBG(kfree(c->dbg_buf)); -+ kfree(c->ileb_buf); -+#else -+ vfree(c->sbuf); -+ UBIFS_DBG(vfree(c->dbg_buf)); -+ vfree(c->ileb_buf); -+#endif -+ dbg_failure_mode_deregistration(c); -+} -+ -+/** -+ * ubifs_remount_rw - re-mount in read-write mode. -+ * @c: UBIFS file-system description object -+ * -+ * UBIFS avoids allocating many unnecessary resources when mounted in read-only -+ * mode. This function allocates the needed resources and re-mounts UBIFS in -+ * read-write mode. -+ */ -+int ubifs_remount_rw(struct ubifs_info *c) -+{ -+ int err, lnum; -+ -+ if (c->ro_media) -+ return -EINVAL; -+ -+ mutex_lock(&c->umount_mutex); -+ c->remounting_rw = 1; -+ -+ /* Check for enough free space */ -+ if (ubifs_calc_available(c) <= 0) { -+ ubifs_err("insufficient available space"); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (c->old_leb_cnt != c->leb_cnt) { -+ struct ubifs_sb_node *sup; -+ -+ sup = ubifs_read_sb_node(c); -+ if (IS_ERR(sup)) { -+ err = PTR_ERR(sup); -+ goto out; -+ } -+ sup->leb_cnt = cpu_to_le32(c->leb_cnt); -+ err = ubifs_write_sb_node(c, sup); -+ if (err) -+ goto out; -+ } -+ -+ if (c->need_recovery) { -+ ubifs_msg("completing deferred recovery"); -+ err = ubifs_write_rcvrd_mst_node(c); -+ if (err) -+ goto out; -+ err = ubifs_recover_size(c); -+ if (err) -+ goto out; -+ err = ubifs_clean_lebs(c, c->sbuf); -+ if (err) -+ goto out; -+ err = ubifs_recover_inl_heads(c, c->sbuf); -+ if (err) -+ goto out; -+ } -+ -+ if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) { -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ err = ubifs_write_master(c); -+ if (err) -+ goto out; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ileb_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->ileb_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->ileb_buf) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ err = ubifs_lpt_init(c, 0, 1); -+ if (err) -+ goto out; -+ -+ err = alloc_wbufs(c); -+ if (err) -+ goto out; -+ -+ ubifs_create_buds_lists(c); -+ -+ /* Create background thread */ -+ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); -+ if (!c->bgt) -+ c->bgt = ERR_PTR(-EINVAL); -+ if (IS_ERR(c->bgt)) { -+ err = PTR_ERR(c->bgt); -+ c->bgt = NULL; -+ ubifs_err("cannot spawn \"%s\", error %d", -+ c->bgt_name, err); -+ return err; -+ } -+ -+ if (c->need_recovery) -+ err = ubifs_recover_gc_lnum(c); -+ else -+ err = care_about_gc_lnum(c); -+ if (err) -+ goto out; -+ -+ err = ubifs_mount_orphans(c, c->need_recovery); -+ if (err) -+ goto out; -+ /* Check for enough log space */ -+ lnum = c->lhead_lnum + 1; -+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) -+ lnum = UBIFS_LOG_LNUM; -+ if (lnum == c->ltail_lnum) { -+ err = ubifs_consolidate_log(c); -+ if (err) -+ goto out; -+ } -+ -+ if (c->need_recovery) { -+ c->need_recovery = 0; -+ ubifs_msg("deferred recovery completed"); -+ } -+ -+ dbg_gen("re-mounted read-write"); -+ c->vfs_sb->s_flags &= ~MS_RDONLY; -+ c->remounting_rw = 0; -+ mutex_unlock(&c->umount_mutex); -+ return 0; -+ -+out: -+ free_orphans(c); -+ if (c->bgt) { -+ kthread_stop(c->bgt); -+ c->bgt = NULL; -+ } -+ free_wbufs(c); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ileb_buf); -+#else -+ vfree(c->ileb_buf); -+#endif -+ c->ileb_buf = NULL; -+ ubifs_lpt_free(c, 1); -+ c->remounting_rw = 0; -+ mutex_unlock(&c->umount_mutex); -+ return err; -+} -+ -+/** -+ * commit_on_unmount - commit the journal when un-mounting. -+ * @c: UBIFS file-system description object -+ * -+ * This function is called during un-mounting and it commits the journal unless -+ * the "fast unmount" mode is enabled. It also avoids committing the journal if -+ * it contains too few data. -+ * -+ * Sometimes recovery requires the journal to be committed at least once, and -+ * this function takes care about this. -+ */ -+static void commit_on_unmount(struct ubifs_info *c) -+{ -+ if (!c->fast_unmount) { -+ long long bud_bytes; -+ -+ spin_lock(&c->buds_lock); -+ bud_bytes = c->bud_bytes; -+ spin_unlock(&c->buds_lock); -+ if (bud_bytes > c->leb_size) -+ ubifs_run_commit(c); -+ } -+ -+ if (c->recovery_needs_commit) -+ ubifs_recovery_commit(c); -+} -+ -+/** -+ * ubifs_remount_ro - re-mount in read-only mode. -+ * @c: UBIFS file-system description object -+ * -+ * We rely on VFS to have stopped writing. Possibly the background thread could -+ * be running a commit, however kthread_stop will wait in that case. -+ */ -+void ubifs_remount_ro(struct ubifs_info *c) -+{ -+ int i, err; -+ -+ ubifs_assert(!c->need_recovery); -+ -+ commit_on_unmount(c); -+ -+ mutex_lock(&c->umount_mutex); -+ if (c->bgt) { -+ kthread_stop(c->bgt); -+ c->bgt = NULL; -+ } -+ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ del_timer_sync(&c->jheads[i].wbuf.timer); -+ } -+ -+ if (!c->ro_media) { -+ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); -+ err = ubifs_write_master(c); -+ if (err) -+ ubifs_ro_mode(c, err); -+ } -+ -+ ubifs_destroy_idx_gc(c); -+ free_wbufs(c); -+ free_orphans(c); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ileb_buf); -+#else -+ vfree(c->ileb_buf); -+#endif -+ c->ileb_buf = NULL; -+ ubifs_lpt_free(c, 1); -+ mutex_unlock(&c->umount_mutex); -+} -+ -+/** -+ * open_ubi - parse UBI device name string and open the UBI device. -+ * @c: UBIFS file-system description object -+ * @name: UBI volume name -+ * @mode: UBI volume open mode -+ * -+ * There are several ways to specify UBI volumes when mounting UBIFS: -+ * o ubiX_Y - UBI device number X, volume Y; -+ * o ubiY - UBI device number 0, volume Y; -+ * o ubiX:NAME - mount UBI device X, volume with name NAME; -+ * o ubi:NAME - mount UBI device 0, volume with name NAME. -+ * -+ * Alternative '!' separator may be used instead of ':' (because some shells -+ * like busybox may interpret ':' as an NFS host name separator). This function -+ * returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int open_ubi(struct ubifs_info *c, const char *name, int mode) -+{ -+ int dev, vol; -+ char *endptr; -+ -+ if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') -+ return -EINVAL; -+ -+ if ((name[3] == ':' || name[3] == '!') && name[4] != '\0') { -+ /* ubi:NAME method */ -+ c->ubi = ubi_open_volume_nm(0, name + 4, mode); -+ if (IS_ERR(c->ubi)) -+ return PTR_ERR(c->ubi); -+ } else if (isdigit(name[3])) { -+ dev = simple_strtoul(name + 3, &endptr, 0); -+ if (*endptr == '\0') { -+ /* ubiY method */ -+ c->ubi = ubi_open_volume(0, dev, mode); -+ if (IS_ERR(c->ubi)) -+ return PTR_ERR(c->ubi); -+ } else if (*endptr == '_' && isdigit(endptr[1])) { -+ /* ubiX_Y method */ -+ vol = simple_strtoul(endptr + 1, &endptr, 0); -+ if (*endptr != '\0') -+ return -EINVAL; -+ c->ubi = ubi_open_volume(dev, vol, mode); -+ if (IS_ERR(c->ubi)) -+ return PTR_ERR(c->ubi); -+ } else if ((*endptr == ':' || *endptr == '!') && -+ endptr[1] != '\0') { -+ /* ubiX:NAME method */ -+ c->ubi = ubi_open_volume_nm(dev, ++endptr, mode); -+ if (IS_ERR(c->ubi)) -+ return PTR_ERR(c->ubi); -+ } -+ } -+ -+ if (!c->ubi) -+ return -EINVAL; -+ -+ ubi_get_volume_info(c->ubi, &c->vi); -+ ubi_get_device_info(c->vi.ubi_num, &c->di); -+ return 0; -+} -+ -+static int sb_test(struct super_block *sb, void *data) -+{ -+ dev_t *dev = data; -+ -+ return sb->s_dev == *dev; -+} -+ -+static int sb_set(struct super_block *sb, void *data) -+{ -+ return 0; -+} -+ -+/* -+ * UBIFS mount options. -+ * -+ * Opt_fast_unmount: do not run a journal commit before un-mounting -+ * Opt_norm_unmount: run a journal commit before un-mounting -+ * Opt_err: just end of array marker -+ */ -+enum { -+ Opt_fast_unmount, -+ Opt_norm_unmount, -+ Opt_err, -+}; -+ -+static match_table_t tokens = { -+ {Opt_fast_unmount, "fast_unmount"}, -+ {Opt_norm_unmount, "norm_unmount"}, -+ {Opt_err, NULL}, -+}; -+ -+/** -+ * ubifs_parse_options - parse mount parameters. -+ * @c: UBIFS file-system description object -+ * @options: parameters to parse -+ * @is_remount: non-zero if this is FS re-mount -+ * -+ * This function parses UBIFS mount options and returns zero in case success -+ * and a negative error code in case of failure. -+ */ -+int ubifs_parse_options(struct ubifs_info *c, char *options, int is_remount) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ if (!options) -+ return 0; -+ -+ while ((p = strsep(&options, ",")) != NULL) { -+ int token; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, tokens, args); -+ switch (token) { -+ case Opt_fast_unmount: -+ c->mount_opts.unmount_mode = 2; -+ c->fast_unmount = 1; -+ break; -+ case Opt_norm_unmount: -+ c->mount_opts.unmount_mode = 1; -+ c->fast_unmount = 0; -+ break; -+ default: -+ ubifs_err("unrecognized mount option \"%s\" " -+ "or missing value", p); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int ubifs_get_sb(struct file_system_type *fs_type, int flags, -+ const char *name, void *data, struct vfsmount *mnt) -+{ -+ int err; -+ struct super_block *sb; -+ struct ubifs_info *c; -+ struct inode *root; -+ -+ dbg_gen("name %s, flags %#x", name, flags); -+ -+ c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); -+ if (!c) -+ return -ENOMEM; -+ -+ spin_lock_init(&c->cnt_lock); -+ spin_lock_init(&c->cs_lock); -+ spin_lock_init(&c->buds_lock); -+ spin_lock_init(&c->space_lock); -+ spin_lock_init(&c->orphan_lock); -+ init_rwsem(&c->commit_sem); -+ mutex_init(&c->lp_mutex); -+ mutex_init(&c->tnc_mutex); -+ mutex_init(&c->log_mutex); -+ mutex_init(&c->mst_mutex); -+ mutex_init(&c->umount_mutex); -+ init_waitqueue_head(&c->cmt_wq); -+ c->buds = RB_ROOT; -+ c->old_idx = RB_ROOT; -+ c->size_tree = RB_ROOT; -+ c->orph_tree = RB_ROOT; -+ INIT_LIST_HEAD(&c->infos_list); -+ INIT_LIST_HEAD(&c->idx_gc); -+ INIT_LIST_HEAD(&c->replay_list); -+ INIT_LIST_HEAD(&c->replay_buds); -+ INIT_LIST_HEAD(&c->uncat_list); -+ INIT_LIST_HEAD(&c->empty_list); -+ INIT_LIST_HEAD(&c->freeable_list); -+ INIT_LIST_HEAD(&c->frdi_idx_list); -+ INIT_LIST_HEAD(&c->unclean_leb_list); -+ INIT_LIST_HEAD(&c->old_buds); -+ INIT_LIST_HEAD(&c->orph_list); -+ INIT_LIST_HEAD(&c->orph_new); -+ -+ c->highest_inum = UBIFS_FIRST_INO; -+ get_random_bytes(&c->vfs_gen, sizeof(int)); -+ c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; -+ -+ err = ubifs_parse_options(c, data, 0); -+ if (err) -+ goto out_free; -+ -+ /* -+ * Get UBI device number and volume ID. Mount it read-only so far -+ * because this might be a new mount point, and UBI allows only one -+ * read-write user at a time. -+ */ -+ err = open_ubi(c, name, UBI_READONLY); -+ if (err) { -+ ubifs_err("cannot open \"%s\", error %d", name, err); -+ goto out_free; -+ } -+ -+ dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); -+ -+ sb = sget(fs_type, &sb_test, &sb_set, &c->vi.cdev); -+ if (IS_ERR(sb)) { -+ err = PTR_ERR(sb); -+ goto out_close; -+ } -+ -+ if (sb->s_root) { -+ /* A new mount point for already mounted UBIFS */ -+ dbg_gen("this ubi volume is already mounted"); -+ err = simple_set_mnt(mnt, sb); -+ goto out_close; -+ } -+ -+ /* Re-open the UBI device in read-write mode */ -+ ubi_close_volume(c->ubi); -+ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); -+ if (IS_ERR(c->ubi)) { -+ err = PTR_ERR(c->ubi); -+ goto out_free; -+ } -+ -+ c->vfs_sb = sb; -+ sb->s_fs_info = c; -+ sb->s_magic = UBIFS_SUPER_MAGIC; -+ sb->s_blocksize = UBIFS_BLOCK_SIZE; -+ sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; -+ sb->s_dev = c->vi.cdev; -+ sb->s_maxbytes = c->max_inode_sz = -+ min_t(uint64_t, MAX_LFS_FILESIZE, UBIFS_MAX_INODE_SZ); -+ sb->s_op = &ubifs_super_operations; -+ sb->s_flags = flags; -+ -+ mutex_lock(&c->umount_mutex); -+ err = mount_ubifs(c); -+ if (err) { -+ ubifs_assert(err < 0); -+ goto out_umount; -+ } -+ -+ /* Read the root inode */ -+ root = ubifs_iget(sb, UBIFS_ROOT_INO); -+ if (IS_ERR(root)) { -+ err = PTR_ERR(root); -+ goto out_umount; -+ } -+ -+ sb->s_root = d_alloc_root(root); -+ if (!sb->s_root) -+ goto out_iput; -+ -+ mutex_unlock(&c->umount_mutex); -+ -+ /* We do not support atime */ -+ sb->s_flags |= MS_ACTIVE | MS_NOATIME; -+ return simple_set_mnt(mnt, sb); -+ -+out_iput: -+ iput(root); -+out_umount: -+ spin_lock(&ubifs_infos_lock); -+ if (c->infos_list.next) -+ list_del(&c->infos_list); -+ spin_unlock(&ubifs_infos_lock); -+ ubifs_umount(c); -+ mutex_unlock(&c->umount_mutex); -+ up_write(&sb->s_umount); -+ sb->s_root = NULL; -+ deactivate_super(sb); -+out_close: -+ ubi_close_volume(c->ubi); -+out_free: -+ kfree(c); -+ return err; -+} -+ -+static void ubifs_kill_sb(struct super_block *sb) -+{ -+ struct ubifs_info *c = sb->s_fs_info; -+ -+ if (sb->s_root != NULL && !(sb->s_flags & MS_RDONLY)) -+ commit_on_unmount(c); -+ /* The un-mount routine is actually done in put_super() */ -+ generic_shutdown_super(sb); -+} -+ -+static struct file_system_type ubifs_fs_type = { -+ .name = "ubifs", -+ .owner = THIS_MODULE, -+ .get_sb = ubifs_get_sb, -+ .kill_sb = ubifs_kill_sb -+}; -+ -+/* -+ * Inode slab cache constructor. -+ * -+ * TODO: remove backward compatibility as late as possible -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -+static void inode_slab_ctor(void *obj, struct kmem_cache *cachep, -+ unsigned long flags) -+#else -+static void inode_slab_ctor(struct kmem_cache *cachep, void *obj) -+#endif -+{ -+ struct ubifs_inode *inode = obj; -+ inode_init_once(&inode->vfs_inode); -+} -+ -+static int __init ubifs_init(void) -+{ -+ int err; -+ -+ BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24); -+ -+ /* Make sure node sizes are 8-byte aligned */ -+ BUILD_BUG_ON(UBIFS_CH_SZ & 7); -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_CS_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7); -+ -+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_NODE_SZ & 7); -+ BUILD_BUG_ON(MIN_WRITE_SZ & 7); -+ -+ /* Check min. node size */ -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ); -+ -+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ -+ /* We do not support multiple pages per block ATM */ -+ BUILD_BUG_ON(UBIFS_BLOCK_SIZE != PAGE_CACHE_SIZE); -+ -+ /* Defined node sizes */ -+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ != 4096); -+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512); -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160); -+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64); -+ -+ err = bdi_init(&ubifs_backing_dev_info); -+ if (err) -+ return err; -+ -+ err = register_filesystem(&ubifs_fs_type); -+ if (err) { -+ ubifs_err("cannot register file system, error %d", err); -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab", -+ sizeof(struct ubifs_inode), 0, -+ SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT, -+ &inode_slab_ctor UBIFSCOMPATNULL); -+ if (!ubifs_inode_slab) -+ goto out_reg; -+ -+ register_shrinker(&ubifs_shrinker_info); -+ dbg_mempressure_init(); -+ -+ err = ubifs_compressors_init(); -+ if (err) -+ goto out_compr; -+ -+ return 0; -+ -+out_compr: -+ dbg_mempressure_exit(); -+ unregister_shrinker(&ubifs_shrinker_info); -+ kmem_cache_destroy(ubifs_inode_slab); -+out_reg: -+ unregister_filesystem(&ubifs_fs_type); -+out: -+ bdi_destroy(&ubifs_backing_dev_info); -+ return err; -+} -+/* late_initcall to let compressors initialize first */ -+late_initcall(ubifs_init); -+ -+static void __exit ubifs_exit(void) -+{ -+ ubifs_assert(list_empty(&ubifs_infos)); -+ ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); -+ -+ ubifs_compressors_exit(); -+ dbg_mempressure_exit(); -+ unregister_shrinker(&ubifs_shrinker_info); -+ kmem_cache_destroy(ubifs_inode_slab); -+ unregister_filesystem(&ubifs_fs_type); -+ bdi_destroy(&ubifs_backing_dev_info); -+ dbg_leak_report(); -+} -+module_exit(ubifs_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(__stringify(UBIFS_VERSION)); -+MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); -+MODULE_DESCRIPTION("UBIFS - UBI File System"); -diff -urN linux-2.6.24.7.old/fs/ubifs/commit.c linux-2.6.24.7/fs/ubifs/commit.c ---- linux-2.6.24.7.old/fs/ubifs/commit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/commit.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,718 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements functions that manage the running of the commit process. -+ * Each affected module has its own functions to accomplish their part in the -+ * commit and those functions are called here. -+ * -+ * The commit is the process whereby all updates to the index and LEB properties -+ * are written out together and the journal becomes empty. This keeps the -+ * file system consistent - at all times the state can be recreated by reading -+ * the index and LEB properties and then replaying the journal. -+ * -+ * The commit is split into two parts named "commit start" and "commit end". -+ * During commit start, the commit process has exclusive access to the journal -+ * by holding the commit semaphore down for writing. As few I/O operations as -+ * possible are performed during commit start, instead the nodes that are to be -+ * written are merely identified. During commit end, the commit semaphore is no -+ * longer held and the journal is again in operation, allowing users to continue -+ * to use the file system while the bulk of the commit I/O is performed. The -+ * purpose of this two-step approach is to prevent the commit from causing any -+ * latency blips. Note that in any case, the commit does not prevent lookups -+ * (as permitted by the TNC mutex), or access to VFS data structures e.g. page -+ * cache. -+ */ -+ -+#include -+#include -+#include "ubifs.h" -+ -+/** -+ * do_commit - commit the journal. -+ * @c: UBIFS file-system description object -+ * -+ * This function implements UBIFS commit. It has to be called with commit lock -+ * locked. Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int do_commit(struct ubifs_info *c) -+{ -+ int err, new_ltail_lnum, old_ltail_lnum, i; -+ struct ubifs_zbranch zroot; -+ struct ubifs_lp_stats lst; -+ -+ dbg_cmt("start"); -+ if (c->ro_media) { -+ err = -EROFS; -+ goto out_up; -+ } -+ -+ c->recovery_needs_commit = 0; -+ -+ /* Sync all write buffers (necessary for recovery) */ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ if (err) -+ goto out_up; -+ } -+ -+ err = ubifs_gc_start_commit(c); -+ if (err) -+ goto out_up; -+ err = dbg_check_lprops(c); -+ if (err) -+ goto out_up; -+ err = ubifs_log_start_commit(c, &new_ltail_lnum); -+ if (err) -+ goto out_up; -+ err = ubifs_tnc_start_commit(c, &zroot); -+ if (err) -+ goto out_up; -+ err = ubifs_lpt_start_commit(c); -+ if (err) -+ goto out_up; -+ err = ubifs_orphan_start_commit(c); -+ if (err) -+ goto out_up; -+ -+ ubifs_get_lp_stats(c, &lst); -+ -+ up_write(&c->commit_sem); -+ -+ err = ubifs_tnc_end_commit(c); -+ if (err) -+ goto out; -+ err = ubifs_lpt_end_commit(c); -+ if (err) -+ goto out; -+ err = ubifs_orphan_end_commit(c); -+ if (err) -+ goto out; -+ old_ltail_lnum = c->ltail_lnum; -+ err = ubifs_log_end_commit(c, new_ltail_lnum); -+ if (err) -+ goto out; -+ err = dbg_check_old_index(c, &zroot); -+ if (err) -+ goto out; -+ -+ mutex_lock(&c->mst_mutex); -+ c->mst_node->cmt_no = cpu_to_le64(++c->cmt_no); -+ c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); -+ c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); -+ c->mst_node->root_offs = cpu_to_le32(zroot.offs); -+ c->mst_node->root_len = cpu_to_le32(zroot.len); -+ c->mst_node->ihead_lnum = cpu_to_le32(c->ihead_lnum); -+ c->mst_node->ihead_offs = cpu_to_le32(c->ihead_offs); -+ c->mst_node->index_size = cpu_to_le64(c->old_idx_sz); -+ c->mst_node->lpt_lnum = cpu_to_le32(c->lpt_lnum); -+ c->mst_node->lpt_offs = cpu_to_le32(c->lpt_offs); -+ c->mst_node->nhead_lnum = cpu_to_le32(c->nhead_lnum); -+ c->mst_node->nhead_offs = cpu_to_le32(c->nhead_offs); -+ c->mst_node->ltab_lnum = cpu_to_le32(c->ltab_lnum); -+ c->mst_node->ltab_offs = cpu_to_le32(c->ltab_offs); -+ c->mst_node->lsave_lnum = cpu_to_le32(c->lsave_lnum); -+ c->mst_node->lsave_offs = cpu_to_le32(c->lsave_offs); -+ c->mst_node->lscan_lnum = cpu_to_le32(c->lscan_lnum); -+ c->mst_node->empty_lebs = cpu_to_le32(lst.empty_lebs); -+ c->mst_node->idx_lebs = cpu_to_le32(lst.idx_lebs); -+ c->mst_node->total_free = cpu_to_le64(lst.total_free); -+ c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty); -+ c->mst_node->total_used = cpu_to_le64(lst.total_used); -+ c->mst_node->total_dead = cpu_to_le64(lst.total_dead); -+ c->mst_node->total_dark = cpu_to_le64(lst.total_dark); -+ if (c->no_orphs) -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ else -+ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ err = ubifs_write_master(c); -+ mutex_unlock(&c->mst_mutex); -+ if (err) -+ goto out; -+ -+ err = ubifs_log_post_commit(c, old_ltail_lnum); -+ if (err) -+ goto out; -+ err = ubifs_gc_end_commit(c); -+ if (err) -+ goto out; -+ err = ubifs_lpt_post_commit(c); -+ if (err) -+ goto out; -+ -+ spin_lock(&c->cs_lock); -+ c->cmt_state = COMMIT_RESTING; -+ wake_up(&c->cmt_wq); -+ dbg_cmt("commit end"); -+ spin_unlock(&c->cs_lock); -+ -+ return 0; -+ -+out_up: -+ up_write(&c->commit_sem); -+out: -+ ubifs_err("commit failed, error %d", err); -+ spin_lock(&c->cs_lock); -+ c->cmt_state = COMMIT_BROKEN; -+ wake_up(&c->cmt_wq); -+ spin_unlock(&c->cs_lock); -+ ubifs_ro_mode(c, err); -+ return err; -+} -+ -+/** -+ * run_bg_commit - run background commit if it is needed. -+ * @c: UBIFS file-system description object -+ * -+ * This function runs background commit if it is needed. Returns zero in case -+ * of success and a negative error code in case of failure. -+ */ -+static int run_bg_commit(struct ubifs_info *c) -+{ -+ spin_lock(&c->cs_lock); -+ /* -+ * Run background commit only if background commit was requested or if -+ * commit is required. -+ */ -+ if (c->cmt_state != COMMIT_BACKGROUND && -+ c->cmt_state != COMMIT_REQUIRED) -+ goto out; -+ spin_unlock(&c->cs_lock); -+ -+ down_write(&c->commit_sem); -+ spin_lock(&c->cs_lock); -+ if (c->cmt_state == COMMIT_REQUIRED) -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ else if (c->cmt_state == COMMIT_BACKGROUND) -+ c->cmt_state = COMMIT_RUNNING_BACKGROUND; -+ else -+ goto out_cmt_unlock; -+ spin_unlock(&c->cs_lock); -+ -+ return do_commit(c); -+ -+out_cmt_unlock: -+ up_write(&c->commit_sem); -+out: -+ spin_unlock(&c->cs_lock); -+ return 0; -+} -+ -+/** -+ * ubifs_bg_thread - UBIFS background thread function. -+ * @info: points to the file-system description object -+ * -+ * This function implements various file-system background activities: -+ * o when a write-buffer timer expires it synchronizes the appropriate -+ * write-buffer; -+ * o when the journal is about to be full, it starts in-advance commit. -+ * -+ * Note, other stuff like background garbage collection may be added here in -+ * future. -+ */ -+int ubifs_bg_thread(void *info) -+{ -+ int err; -+ struct ubifs_info *c = info; -+ -+ ubifs_msg("background thread \"%s\" started, PID %d", -+ c->bgt_name, current->pid); -+ set_freezable(); -+ -+ while (1) { -+ if (kthread_should_stop()) -+ break; -+ -+ if (try_to_freeze()) -+ continue; -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ /* Check if there is something to do */ -+ if (!c->need_bgt) { -+ /* -+ * Nothing prevents us from going sleep now and -+ * be never woken up and block the task which -+ * could wait in 'kthread_stop()' forever. -+ */ -+ if (kthread_should_stop()) -+ break; -+ schedule(); -+ continue; -+ } else -+ __set_current_state(TASK_RUNNING); -+ -+ c->need_bgt = 0; -+ err = ubifs_bg_wbufs_sync(c); -+ if (err) -+ ubifs_ro_mode(c, err); -+ -+ run_bg_commit(c); -+ cond_resched(); -+ } -+ -+ dbg_msg("background thread \"%s\" stops", c->bgt_name); -+ return 0; -+} -+ -+/** -+ * ubifs_commit_required - set commit state to "required". -+ * @c: UBIFS file-system description object -+ * -+ * This function is called if a commit is required but cannot be done from the -+ * calling function, so it is just flagged instead. -+ */ -+void ubifs_commit_required(struct ubifs_info *c) -+{ -+ spin_lock(&c->cs_lock); -+ switch (c->cmt_state) { -+ case COMMIT_RESTING: -+ case COMMIT_BACKGROUND: -+ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), -+ dbg_cstate(COMMIT_REQUIRED)); -+ c->cmt_state = COMMIT_REQUIRED; -+ break; -+ case COMMIT_RUNNING_BACKGROUND: -+ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), -+ dbg_cstate(COMMIT_RUNNING_REQUIRED)); -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ break; -+ case COMMIT_REQUIRED: -+ case COMMIT_RUNNING_REQUIRED: -+ case COMMIT_BROKEN: -+ break; -+ } -+ spin_unlock(&c->cs_lock); -+} -+ -+/** -+ * ubifs_request_bg_commit - notify the background thread to do a commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function is called if the journal is full enough to make a commit -+ * worthwhile, so background thread is kicked to start it. -+ */ -+void ubifs_request_bg_commit(struct ubifs_info *c) -+{ -+ spin_lock(&c->cs_lock); -+ if (c->cmt_state == COMMIT_RESTING) { -+ dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), -+ dbg_cstate(COMMIT_BACKGROUND)); -+ c->cmt_state = COMMIT_BACKGROUND; -+ spin_unlock(&c->cs_lock); -+ ubifs_wake_up_bgt(c); -+ } else -+ spin_unlock(&c->cs_lock); -+} -+ -+/** -+ * wait_for_commit - wait for commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function sleeps until the commit operation is no longer running. -+ */ -+static int wait_for_commit(struct ubifs_info *c) -+{ -+ dbg_cmt("pid %d goes sleep", current->pid); -+ -+ /* -+ * The following sleeps if the condition is false, and will be woken -+ * when the commit ends. It is possible, although very unlikely, that we -+ * will wake up and see the subsequent commit running, rather than the -+ * one we were waiting for, and go back to sleep. However, we will be -+ * woken again, so there is no danger of sleeping forever. -+ */ -+ wait_event(c->cmt_wq, c->cmt_state != COMMIT_RUNNING_BACKGROUND && -+ c->cmt_state != COMMIT_RUNNING_REQUIRED); -+ dbg_cmt("commit finished, pid %d woke up", current->pid); -+ return 0; -+} -+ -+/** -+ * ubifs_run_commit - run or wait for commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function runs commit and returns zero in case of success and a negative -+ * error code in case of failure. -+ */ -+int ubifs_run_commit(struct ubifs_info *c) -+{ -+ int err = 0; -+ -+ spin_lock(&c->cs_lock); -+ if (c->cmt_state == COMMIT_BROKEN) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) -+ /* -+ * We set the commit state to 'running required' to indicate -+ * that we want it to complete as quickly as possible. -+ */ -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ -+ if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { -+ spin_unlock(&c->cs_lock); -+ return wait_for_commit(c); -+ } -+ spin_unlock(&c->cs_lock); -+ -+ /* Ok, the commit is indeed needed */ -+ -+ down_write(&c->commit_sem); -+ spin_lock(&c->cs_lock); -+ /* -+ * Since we unlocked 'c->cs_lock', the state may have changed, so -+ * re-check it. -+ */ -+ if (c->cmt_state == COMMIT_BROKEN) { -+ err = -EINVAL; -+ goto out_cmt_unlock; -+ } -+ -+ if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ -+ if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { -+ up_write(&c->commit_sem); -+ spin_unlock(&c->cs_lock); -+ return wait_for_commit(c); -+ } -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ spin_unlock(&c->cs_lock); -+ -+ err = do_commit(c); -+ return err; -+ -+out_cmt_unlock: -+ up_write(&c->commit_sem); -+out: -+ spin_unlock(&c->cs_lock); -+ return err; -+} -+ -+/** -+ * ubifs_recovery_commit - if needed, ensure a commit has run since recovery. -+ * @c: UBIFS file-system description object -+ * -+ * This function ensures that a commit has been run since recovery and before -+ * unmounting cleanly. Errors are ignored because in that case a subsequent -+ * unmount will not be clean. -+ * -+ * The recovery needs a commit when it updates TNC directly without there being -+ * a corresponding record of the change in the journal. In that case, if UBIFS -+ * were to unmount cleanly without having run a commit, the TNC changes would -+ * be lost. -+ */ -+void ubifs_recovery_commit(struct ubifs_info *c) -+{ -+ spin_lock(&c->cs_lock); -+ if (!c->recovery_needs_commit || -+ c->cmt_state == COMMIT_BROKEN || -+ c->cmt_state == COMMIT_RUNNING_BACKGROUND || -+ c->cmt_state == COMMIT_RUNNING_REQUIRED) { -+ spin_unlock(&c->cs_lock); -+ return; -+ } -+ spin_unlock(&c->cs_lock); -+ down_write(&c->commit_sem); -+ spin_lock(&c->cs_lock); -+ if (!c->recovery_needs_commit || -+ c->cmt_state == COMMIT_BROKEN || -+ c->cmt_state == COMMIT_RUNNING_BACKGROUND || -+ c->cmt_state == COMMIT_RUNNING_REQUIRED) { -+ spin_unlock(&c->cs_lock); -+ up_write(&c->commit_sem); -+ return; -+ } -+ c->cmt_state = COMMIT_RUNNING_REQUIRED; -+ spin_unlock(&c->cs_lock); -+ do_commit(c); -+} -+ -+/** -+ * ubifs_gc_should_commit - determine if it is time for GC to run commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function is called by garbage collection to determine if commit should -+ * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal -+ * is full enough to start commit, this function returns true. It is not -+ * absolutely necessary to commit yet, but it feels like this should be better -+ * then to keep doing GC. This function returns %1 if GC has to initiate commit -+ * and %0 if not. -+ */ -+int ubifs_gc_should_commit(struct ubifs_info *c) -+{ -+ int ret = 0; -+ -+ spin_lock(&c->cs_lock); -+ if (c->cmt_state == COMMIT_BACKGROUND) { -+ dbg_cmt("commit required now"); -+ c->cmt_state = COMMIT_REQUIRED; -+ } else -+ dbg_cmt("commit not requested"); -+ if (c->cmt_state == COMMIT_REQUIRED) -+ ret = 1; -+ spin_unlock(&c->cs_lock); -+ return ret; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * struct idx_node - hold index nodes during index tree traversal. -+ * @list: list -+ * @iip: index in parent (slot number of this indexing node in the parent -+ * indexing node) -+ * @upper_key: all keys in this indexing node have to be less or equivalent to -+ * this key -+ * @idx: index node (8-byte aligned because all node structures must be 8-byte -+ * aligned) -+ */ -+struct idx_node { -+ struct list_head list; -+ int iip; -+ union ubifs_key upper_key; -+ struct ubifs_idx_node idx __attribute__((aligned(8))); -+}; -+ -+/** -+ * dbg_old_index_check_init - get information for the next old index check. -+ * @c: UBIFS file-system description object -+ * @zroot: root of the index -+ * -+ * This function records information about the index that will be needed for the -+ * next old index check i.e. 'dbg_check_old_index()'. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot) -+{ -+ struct ubifs_idx_node *idx; -+ int lnum, offs, len, err = 0; -+ -+ c->old_zroot = *zroot; -+ -+ lnum = c->old_zroot.lnum; -+ offs = c->old_zroot.offs; -+ len = c->old_zroot.len; -+ -+ idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); -+ if (!idx) -+ return -ENOMEM; -+ -+ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); -+ if (err) -+ goto out; -+ -+ c->old_zroot_level = le16_to_cpu(idx->level); -+ c->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum); -+out: -+ kfree(idx); -+ return err; -+} -+ -+/** -+ * dbg_check_old_index - check the old copy of the index. -+ * @c: UBIFS file-system description object -+ * @zroot: root of the new index -+ * -+ * In order to be able to recover from an unclean unmount, a complete copy of -+ * the index must exist on flash. This is the "old" index. The commit process -+ * must write the "new" index to flash without overwriting or destroying any -+ * part of the old index. This function is run at commit end in order to check -+ * that the old index does indeed exist completely intact. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot) -+{ -+ int lnum, offs, len, err = 0, uninitialized_var(last_level), child_cnt; -+ int first = 1, iip; -+ union ubifs_key lower_key, upper_key, l_key, u_key; -+ unsigned long long uninitialized_var(last_sqnum); -+ struct ubifs_idx_node *idx; -+ struct list_head list; -+ struct idx_node *i; -+ size_t sz; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX)) -+ goto out; -+ -+ INIT_LIST_HEAD(&list); -+ -+ sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) - -+ UBIFS_IDX_NODE_SZ; -+ -+ /* Start at the old zroot */ -+ lnum = c->old_zroot.lnum; -+ offs = c->old_zroot.offs; -+ len = c->old_zroot.len; -+ iip = 0; -+ -+ /* -+ * Traverse the index tree preorder depth-first i.e. do a node and then -+ * its subtrees from left to right. -+ */ -+ while (1) { -+ struct ubifs_branch *br; -+ -+ /* Get the next index node */ -+ i = kmalloc(sz, GFP_NOFS); -+ if (!i) { -+ err = -ENOMEM; -+ goto out_free; -+ } -+ i->iip = iip; -+ /* Keep the index nodes on our path in a linked list */ -+ list_add_tail(&i->list, &list); -+ /* Read the index node */ -+ idx = &i->idx; -+ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); -+ if (err) -+ goto out_free; -+ /* Validate index node */ -+ child_cnt = le16_to_cpu(idx->child_cnt); -+ if (child_cnt < 1 || child_cnt > c->fanout) { -+ err = 1; -+ goto out_dump; -+ } -+ if (first) { -+ first = 0; -+ /* Check root level and sqnum */ -+ if (le16_to_cpu(idx->level) != c->old_zroot_level) { -+ err = 2; -+ goto out_dump; -+ } -+ if (le64_to_cpu(idx->ch.sqnum) != c->old_zroot_sqnum) { -+ err = 3; -+ goto out_dump; -+ } -+ /* Set last values as though root had a parent */ -+ last_level = le16_to_cpu(idx->level) + 1; -+ last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1; -+ key_read(c, ubifs_idx_key(c, idx), &lower_key); -+ highest_ino_key(c, &upper_key, INUM_WATERMARK); -+ } -+ key_copy(c, &upper_key, &i->upper_key); -+ if (le16_to_cpu(idx->level) != last_level - 1) { -+ err = 3; -+ goto out_dump; -+ } -+ /* -+ * The index is always written bottom up hence a child's sqnum -+ * is always less than the parents. -+ */ -+ if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) { -+ err = 4; -+ goto out_dump; -+ } -+ /* Check key range */ -+ key_read(c, ubifs_idx_key(c, idx), &l_key); -+ br = ubifs_idx_branch(c, idx, child_cnt - 1); -+ key_read(c, &br->key, &u_key); -+ if (keys_cmp(c, &lower_key, &l_key) > 0) { -+ err = 5; -+ goto out_dump; -+ } -+ if (keys_cmp(c, &upper_key, &u_key) < 0) { -+ err = 6; -+ goto out_dump; -+ } -+ if (keys_cmp(c, &upper_key, &u_key) == 0) -+ if (!is_hash_key(c, &u_key)) { -+ err = 7; -+ goto out_dump; -+ } -+ /* Go to next index node */ -+ if (le16_to_cpu(idx->level) == 0) { -+ /* At the bottom, so go up until can go right */ -+ while (1) { -+ /* Drop the bottom of the list */ -+ list_del(&i->list); -+ kfree(i); -+ /* No more list means we are done */ -+ if (list_empty(&list)) -+ goto out; -+ /* Look at the new bottom */ -+ i = list_entry(list.prev, struct idx_node, -+ list); -+ idx = &i->idx; -+ /* Can we go right */ -+ if (iip + 1 < le16_to_cpu(idx->child_cnt)) { -+ iip = iip + 1; -+ break; -+ } else -+ /* Nope, so go up again */ -+ iip = i->iip; -+ } -+ } else -+ /* Go down left */ -+ iip = 0; -+ /* -+ * We have the parent in 'idx' and now we set up for reading the -+ * child pointed to by slot 'iip'. -+ */ -+ last_level = le16_to_cpu(idx->level); -+ last_sqnum = le64_to_cpu(idx->ch.sqnum); -+ br = ubifs_idx_branch(c, idx, iip); -+ lnum = le32_to_cpu(br->lnum); -+ offs = le32_to_cpu(br->offs); -+ len = le32_to_cpu(br->len); -+ key_read(c, &br->key, &lower_key); -+ if (iip + 1 < le16_to_cpu(idx->child_cnt)) { -+ br = ubifs_idx_branch(c, idx, iip + 1); -+ key_read(c, &br->key, &upper_key); -+ } else -+ key_copy(c, &i->upper_key, &upper_key); -+ } -+out: -+ err = dbg_old_index_check_init(c, zroot); -+ if (err) -+ goto out_free; -+ -+ return 0; -+ -+out_dump: -+ dbg_err("dumping index node (iip=%d)", i->iip); -+ dbg_dump_node(c, idx); -+ list_del(&i->list); -+ kfree(i); -+ if (!list_empty(&list)) { -+ i = list_entry(list.prev, struct idx_node, list); -+ dbg_err("dumping parent index node"); -+ dbg_dump_node(c, &i->idx); -+ } -+out_free: -+ while (!list_empty(&list)) { -+ i = list_entry(list.next, struct idx_node, list); -+ list_del(&i->list); -+ kfree(i); -+ } -+ ubifs_err("failed, error %d", err); -+ if (err > 0) -+ err = -EINVAL; -+ return err; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/compat.c linux-2.6.24.7/fs/ubifs/compat.c ---- linux-2.6.24.7.old/fs/ubifs/compat.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/compat.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,480 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ */ -+ -+#include "ubifs.h" -+#include -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) -+#define BYTES_PER_LINE 32 -+ -+/** -+ * ubifs_hexdump - dump a buffer. -+ * @ptr: the buffer to dump -+ * @size: buffer size which must be multiple of 4 bytes -+ */ -+void ubifs_hexdump(const void *ptr, int size) -+{ -+ int i, k = 0, rows, columns; -+ const uint8_t *p = ptr; -+ -+ rows = size / BYTES_PER_LINE + size % BYTES_PER_LINE; -+ for (i = 0; i < rows; i++) { -+ int j; -+ -+ cond_resched(); -+ columns = min(size - k, BYTES_PER_LINE) / 4; -+ if (columns == 0) -+ break; -+ printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE); -+ for (j = 0; j < columns; j++) { -+ int n, N; -+ -+ N = size - k > 4 ? 4 : size - k; -+ for (n = 0; n < N; n++) -+ printk("%02x", p[k++]); -+ printk(" "); -+ } -+ printk("\n"); -+ } -+} -+#endif /* LINUX_VERSION_CODE < 2.6.23 */ -+ -+#ifdef UBIFS_COMPAT_USE_OLD_IGET -+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) -+{ -+ struct inode *inode; -+ -+ inode = iget(sb, inum); -+ if (!inode) { -+ make_bad_inode(inode); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ return inode; -+} -+ -+int validate_inode(struct ubifs_info *c, const struct inode *inode); -+ -+void ubifs_read_inode(struct inode *inode) -+{ -+ int err; -+ union ubifs_key key; -+ struct ubifs_ino_node *ino; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ dbg_gen("inode %lu", inode->i_ino); -+ ubifs_assert(inode->i_state & I_LOCK); -+ -+ ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); -+ if (!ino) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ ino_key_init(c, &key, inode->i_ino); -+ -+ err = ubifs_tnc_lookup(c, &key, ino); -+ if (err) -+ goto out_ino; -+ -+ inode->i_flags |= (S_NOCMTIME | S_NOATIME); -+ inode->i_nlink = le32_to_cpu(ino->nlink); -+ inode->i_uid = le32_to_cpu(ino->uid); -+ inode->i_gid = le32_to_cpu(ino->gid); -+ inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec); -+ inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec); -+ inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec); -+ inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec); -+ inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec); -+ inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec); -+ inode->i_mode = le32_to_cpu(ino->mode); -+ inode->i_size = le64_to_cpu(ino->size); -+ -+ ui->data_len = le32_to_cpu(ino->data_len); -+ ui->flags = le32_to_cpu(ino->flags); -+ ui->compr_type = le16_to_cpu(ino->compr_type); -+ ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum); -+ ui->xattr_cnt = le32_to_cpu(ino->xattr_cnt); -+ ui->xattr_size = le64_to_cpu(ino->xattr_size); -+ ui->xattr_names = le32_to_cpu(ino->xattr_names); -+ -+ err = validate_inode(c, inode); -+ if (err) -+ goto out_invalid; -+ -+ switch (inode->i_mode & S_IFMT) { -+ case S_IFREG: -+ inode->i_mapping->a_ops = &ubifs_file_address_operations; -+ inode->i_op = &ubifs_file_inode_operations; -+ inode->i_fop = &ubifs_file_operations; -+ if (ui->data_len != 0) { -+ err = 10; -+ goto out_invalid; -+ } -+ break; -+ case S_IFDIR: -+ inode->i_op = &ubifs_dir_inode_operations; -+ inode->i_fop = &ubifs_dir_operations; -+ if (ui->data_len != 0) { -+ err = 11; -+ goto out_invalid; -+ } -+ break; -+ case S_IFLNK: -+ inode->i_op = &ubifs_symlink_inode_operations; -+ if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { -+ err = 12; -+ goto out_invalid; -+ } -+ ui->data = kmalloc(ui->data_len + 1, GFP_KERNEL); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_ino; -+ } -+ memcpy(ui->data, ino->data, ui->data_len); -+ ((char *)ui->data)[ui->data_len] = '\0'; -+ break; -+ case S_IFBLK: -+ case S_IFCHR: -+ { -+ dev_t rdev; -+ union ubifs_dev_desc *dev; -+ -+ ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_ino; -+ } -+ -+ dev = (union ubifs_dev_desc *)ino->data; -+ if (ui->data_len == sizeof(dev->new)) { -+ rdev = new_decode_dev(__le32_to_cpu(dev->new)); -+ } else if (ui->data_len == sizeof(dev->huge)) { -+ rdev = huge_decode_dev(__le64_to_cpu(dev->huge)); -+ } else { -+ err = 13; -+ goto out_invalid; -+ } -+ inode->i_op = &ubifs_file_inode_operations; -+ init_special_inode(inode, inode->i_mode, rdev); -+ break; -+ } -+ case S_IFSOCK: -+ case S_IFIFO: -+ inode->i_op = &ubifs_file_inode_operations; -+ init_special_inode(inode, inode->i_mode, 0); -+ if (ui->data_len != 0) { -+ err = 14; -+ goto out_invalid; -+ } -+ break; -+ default: -+ err = 15; -+ goto out_invalid; -+ } -+ -+ ubifs_set_inode_flags(inode); -+ kfree(ino); -+ return; -+ -+out_invalid: -+ ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err); -+ dbg_dump_inode(c, inode); -+ dbg_dump_node(c, ino); -+ err = -EINVAL; -+out_ino: -+ kfree(ino); -+out: -+ ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err); -+ make_bad_inode(inode); -+ return; -+} -+#endif /* UBIFS_COMPAT_USE_OLD_IGET */ -+ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+int ubifs_prepare_write(struct file *file, struct page *page, unsigned from, -+ unsigned to) -+{ -+ struct inode *inode = page->mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; -+ struct ubifs_budget_req req; -+ int err; -+ -+ ubifs_assert(PageLocked(page)); -+ ubifs_assert(mutex_is_locked(&inode->i_mutex)); -+ ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); -+ -+ if (c->ro_media) -+ return -EINVAL; -+ -+ if (!PageUptodate(page)) { -+ /* -+ * The page is not loaded from the flash and has to be loaded -+ * unless we are writing all of it. -+ */ -+ if (from == 0 && to == PAGE_CACHE_SIZE) -+ /* -+ * Set the PG_checked flag to make the further code -+ * allocate full budget, because we do not know whether -+ * the page exists on the flash media or not. -+ */ -+ SetPageChecked(page); -+ else { -+ err = do_readpage(page); -+ if (err) -+ return err; -+ } -+ -+ SetPageUptodate(page); -+ ClearPageError(page); -+ } -+ -+ memset(&req, 0, sizeof(struct ubifs_budget_req)); -+ if (!PagePrivate(page)) { -+ /* -+ * If the PG_Checked flag is set, the page corresponds to a -+ * hole or to a place beyond the inode. In this case we have to -+ * budget for a new page, otherwise for a dirtied page. -+ */ -+ if (PageChecked(page)) -+ req.new_page = 1; -+ else -+ req.dirtied_page = 1; -+ } else -+ req.locked_pg = 1; -+ -+ if (pos > inode->i_size) -+ /* -+ * We are writing beyond the file which means we are going to -+ * change inode size and make the inode dirty. And in turn, -+ * this means we have to budget for making the inode dirty. -+ * -+ * Note, if the inode is already dirty, -+ * 'ubifs_budget_inode_op()' will not allocate any budget, -+ * but will just lock the @budg_mutex of the inode to prevent -+ * it from becoming clean before we have changed its size, -+ * which is going to happen in 'ubifs_write_end()'. -+ */ -+ err = ubifs_budget_inode_op(c, inode, &req); -+ else -+ /* -+ * The inode is not going to be marked as dirty by this write -+ * operation, do do not budget for this. -+ */ -+ err = ubifs_budget_space(c, &req); -+ -+ return err; -+} -+ -+int ubifs_commit_write(struct file *file, struct page *page, unsigned from, -+ unsigned to) -+{ -+ struct inode *inode = page->mapping->host; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; -+ -+ dbg_gen("ino %lu, pg %lu, offs %lld-%lld (in pg: %u-%u, %u bytes) " -+ "flags %#lx", inode->i_ino, page->index, pos - to + from, -+ pos, from, to, to - from, page->flags); -+ ubifs_assert(PageUptodate(page)); -+ ubifs_assert(mutex_is_locked(&inode->i_mutex)); -+ -+ if (!PagePrivate(page)) { -+ SetPagePrivate(page); -+ atomic_long_inc(&c->dirty_pg_cnt); -+ __set_page_dirty_nobuffers(page); -+ } -+ -+ if (pos > inode->i_size) { -+ i_size_write(inode, pos); -+ -+ /* -+ * Note, we do not set 'I_DIRTY_PAGES' (which means that the -+ * inode has dirty pages), this has been done in -+ * '__set_page_dirty_nobuffers()'. -+ */ -+ mark_inode_dirty_sync(inode); -+ -+ /* -+ * The inode has been marked dirty, unlock it. This is a bit -+ * hacky because normally we would have to call -+ * 'ubifs_release_ino_dirty()'. But we know there is nothing -+ * to release because page's budget will be released -+ * in 'ubifs_write_inode()', so just unlock the inode here for -+ * optimization. -+ */ -+ mutex_unlock(&ui->budg_mutex); -+ } -+ -+ return 0; -+} -+ -+#include -+ -+#define MAX_SHRINK_RETRIES 8 -+#define MAX_GC_RETRIES 4 -+#define MAX_CMT_RETRIES 2 -+#define MAX_NOSPC_RETRIES 1 -+#define NR_TO_WRITE 16 -+ -+struct retries_info { -+ long long prev_liability; -+ unsigned int shrink_cnt; -+ unsigned int shrink_retries:5; -+ unsigned int try_gc:1; -+ unsigned int gc_retries:4; -+ unsigned int cmt_retries:3; -+ unsigned int nospc_retries:1; -+}; -+ -+static int shrink_liability(struct ubifs_info *c, int nr_to_write, -+ int locked_pg) -+{ -+ struct writeback_control wbc = { -+ .sync_mode = WB_SYNC_NONE, -+ .range_end = LLONG_MAX, -+ .nr_to_write = nr_to_write, -+ .skip_locked_pages = locked_pg, -+ }; -+ -+ writeback_inodes_sb(c->vfs_sb, &wbc); -+ dbg_budg("%ld pages were written back", nr_to_write - wbc.nr_to_write); -+ return nr_to_write - wbc.nr_to_write; -+} -+ -+static int run_gc(struct ubifs_info *c) -+{ -+ int err, lnum; -+ -+ /* Make some free space by garbage-collecting dirty space */ -+ down_read(&c->commit_sem); -+ lnum = ubifs_garbage_collect(c, 1); -+ up_read(&c->commit_sem); -+ if (lnum < 0) -+ return lnum; -+ -+ /* GC freed one LEB, return it to lprops */ -+ dbg_budg("GC freed LEB %d", lnum); -+ err = ubifs_return_leb(c, lnum); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+int ubifs_make_free_space(struct ubifs_info *c, struct retries_info *ri, -+ int locked_pg) -+{ -+ int err; -+ -+ /* -+ * If we have some dirty pages and inodes (liability), try to write -+ * them back unless this was tried too many times without effect -+ * already. -+ */ -+ if (ri->shrink_retries < MAX_SHRINK_RETRIES && !ri->try_gc) { -+ long long liability; -+ -+ spin_lock(&c->space_lock); -+ liability = c->budg_idx_growth + c->budg_data_growth + -+ c->budg_dd_growth; -+ spin_unlock(&c->space_lock); -+ -+ if (ri->prev_liability >= liability) { -+ /* Liability does not shrink, next time try GC then */ -+ ri->shrink_retries += 1; -+ if (ri->gc_retries < MAX_GC_RETRIES) -+ ri->try_gc = 1; -+ dbg_budg("liability did not shrink: retries %d of %d", -+ ri->shrink_retries, MAX_SHRINK_RETRIES); -+ } -+ -+ dbg_budg("force write-back (count %d)", ri->shrink_cnt); -+ shrink_liability(c, NR_TO_WRITE + ri->shrink_cnt, locked_pg); -+ -+ ri->prev_liability = liability; -+ ri->shrink_cnt += 1; -+ return -EAGAIN; -+ } -+ -+ /* -+ * Try to run garbage collector unless it was already tried too many -+ * times. -+ */ -+ if (ri->gc_retries < MAX_GC_RETRIES) { -+ ri->gc_retries += 1; -+ dbg_budg("run GC, retries %d of %d", -+ ri->gc_retries, MAX_GC_RETRIES); -+ -+ ri->try_gc = 0; -+ err = run_gc(c); -+ if (!err) -+ return -EAGAIN; -+ -+ if (err == -EAGAIN) { -+ dbg_budg("GC asked to commit"); -+ err = ubifs_run_commit(c); -+ if (err) -+ return err; -+ return -EAGAIN; -+ } -+ -+ if (err != -ENOSPC) -+ return err; -+ -+ /* -+ * GC could not make any progress. If this is the first time, -+ * then it makes sense to try to commit, because it might make -+ * some dirty space. -+ */ -+ dbg_budg("GC returned -ENOSPC, retries %d", -+ ri->nospc_retries); -+ if (ri->nospc_retries >= MAX_NOSPC_RETRIES) -+ return err; -+ ri->nospc_retries += 1; -+ } -+ -+ /* Neither GC nor write-back helped, try to commit */ -+ if (ri->cmt_retries < MAX_CMT_RETRIES) { -+ ri->cmt_retries += 1; -+ dbg_budg("run commit, retries %d of %d", -+ ri->cmt_retries, MAX_CMT_RETRIES); -+ err = ubifs_run_commit(c); -+ if (err) -+ return err; -+ return -EAGAIN; -+ } -+ -+ return -ENOSPC; -+} -+ -+#endif /* UBIFS_COMPAT_USE_OLD_PREPARE_WRITE */ -+ -+#ifdef UBIFS_COMPAT_NO_SHARED_MMAP -+int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ return generic_file_readonly_mmap(file, vma); -+} -+#endif /* UBIFS_COMPAT_NO_SHARED_MMAP */ -diff -urN linux-2.6.24.7.old/fs/ubifs/compat.h linux-2.6.24.7/fs/ubifs/compat.h ---- linux-2.6.24.7.old/fs/ubifs/compat.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/compat.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,88 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Author: Artem Bityutskiy -+ * Adrian Hunter -+ */ -+ -+#ifndef __UBIFS_COMPAT_H__ -+#define __UBIFS_COMPAT_H__ -+ -+#include -+ -+struct inode; -+struct file; -+struct page; -+struct ubifs_info; -+struct retries_info; -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) -+/* iget() does not exist since 2.6.25 */ -+#define UBIFS_COMPAT_USE_OLD_IGET -+void ubifs_read_inode(struct inode *inode); -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -+/* -+ * We have write_begin() write_end() instead of prepare_write(), commit_write() -+ * since 2.6.24. -+ */ -+#define UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+#define do_readpage(page) ubifs_do_readpage(page) -+int ubifs_do_readpage(struct page *page); -+int ubifs_prepare_write(struct file *file, struct page *page, unsigned from, -+ unsigned to); -+int ubifs_commit_write(struct file *file, struct page *page, unsigned from, -+ unsigned to); -+int ubifs_make_free_space(struct ubifs_info *c, struct retries_info *ri, -+ int locked_pg); -+#define bdi_init(x) 0 -+#define bdi_destroy(x) -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) -+#define UBIFS_COMPAT_NO_SHRINKER -+#define register_shrinker(x) -+#define unregister_shrinker(x) -+#define dbg_mempressure_init() -+#define dbg_mempressure_exit() -+#define set_freezable() -+#define is_owner_or_cap(inode) \ -+ ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER)) -+/* This is to hide slab cache interface changes - destructor was dropped */ -+#define UBIFSCOMPATNULL ,NULL -+#else -+#define UBIFSCOMPATNULL -+#endif -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)) -+#define uninitialized_var(x) x = x -+/* print_hex_dump() did not exist in kernel prior to 2.6.22 */ -+#define print_hex_dump(a, b, c, f, e, buf, len, g) ubifs_hexdump(buf, len) -+void ubifs_hexdump(const void *ptr, int size); -+/* -+ * Older kernel have no '->page_mkwrite()' call-back in -+ * 'struct vm_operations_struct', so we just do not support writeble mmaps. The -+ * support can be added if someone needs it badly, though. -+ */ -+int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma); -+#define UBIFS_COMPAT_NO_SHARED_MMAP -+#endif -+ -+ -+#endif /* !__UBIFS_COMPAT_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/compress.c linux-2.6.24.7/fs/ubifs/compress.c ---- linux-2.6.24.7.old/fs/ubifs/compress.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/compress.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,253 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * Copyright (C) 2006, 2007 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ * Zoltan Sogor -+ */ -+ -+/* -+ * This file provides a single place to access to compression and -+ * decompression. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/* Fake description object for the "none" compressor */ -+static struct ubifs_compressor none_compr = { -+ .compr_type = UBIFS_COMPR_NONE, -+ .name = "no compression", -+ .capi_name = "", -+}; -+ -+#ifdef CONFIG_UBIFS_FS_LZO -+static DEFINE_MUTEX(lzo_mutex); -+ -+static struct ubifs_compressor lzo_compr = { -+ .compr_type = UBIFS_COMPR_LZO, -+ .comp_mutex = &lzo_mutex, -+ .name = "LZO", -+ .capi_name = "lzo", -+}; -+#else -+static struct ubifs_compressor lzo_compr = { -+ .compr_type = UBIFS_COMPR_LZO, -+ .name = "LZO", -+}; -+#endif -+ -+#ifdef CONFIG_UBIFS_FS_ZLIB -+static DEFINE_MUTEX(deflate_mutex); -+static DEFINE_MUTEX(inflate_mutex); -+ -+static struct ubifs_compressor zlib_compr = { -+ .compr_type = UBIFS_COMPR_ZLIB, -+ .comp_mutex = &deflate_mutex, -+ .decomp_mutex = &inflate_mutex, -+ .name = "zlib", -+ .capi_name = "deflate", -+}; -+#else -+static struct ubifs_compressor zlib_compr = { -+ .compr_type = UBIFS_COMPR_ZLIB, -+ .name = "zlib", -+}; -+#endif -+ -+/* All UBIFS compressors */ -+struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; -+ -+/** -+ * ubifs_compress - compress data. -+ * @in_buf: data to compress -+ * @in_len: length of the data to compress -+ * @out_buf: output buffer where compressed data should be stored -+ * @out_len: output buffer length is returned here -+ * @compr_type: type of compression to use on enter, actually used compression -+ * type on exit -+ * -+ * This function compresses input buffer @in_buf of length @in_len and stores -+ * the result in the output buffer @out_buf and the resulting length in -+ * @out_len. If the input buffer does not compress, it is just copied to the -+ * @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE or if -+ * compression error occurred. -+ * -+ * Note, if the input buffer was not compressed, it is copied to the output -+ * buffer and %UBIFS_COMPR_NONE is returned in @compr_type. -+ * -+ * This functions returns %0 on success or a negative error code on failure. -+ */ -+void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len, -+ int *compr_type) -+{ -+ int err; -+ struct ubifs_compressor *compr = ubifs_compressors[*compr_type]; -+ -+ if (*compr_type == UBIFS_COMPR_NONE) -+ goto no_compr; -+ -+ /* If the input data is small, do not even try to compress it */ -+ if (in_len < UBIFS_MIN_COMPR_LEN) -+ goto no_compr; -+ -+ if (compr->comp_mutex) -+ mutex_lock(compr->comp_mutex); -+ err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf, -+ out_len); -+ if (compr->comp_mutex) -+ mutex_unlock(compr->comp_mutex); -+ if (unlikely(err)) { -+ ubifs_warn("cannot compress %d bytes, compressor %s, " -+ "error %d, leave data uncompressed", -+ in_len, compr->name, err); -+ goto no_compr; -+ } -+ -+ /* -+ * Presently, we just require that compression results in less data, -+ * rather than any defined minimum compression ratio or amount. -+ */ -+ if (ALIGN(*out_len, 8) >= ALIGN(in_len, 8)) -+ goto no_compr; -+ -+ return; -+ -+no_compr: -+ memcpy(out_buf, in_buf, in_len); -+ *out_len = in_len; -+ *compr_type = UBIFS_COMPR_NONE; -+} -+ -+/** -+ * ubifs_decompress - decompress data. -+ * @in_buf: data to decompress -+ * @in_len: length of the data to decompress -+ * @out_buf: output buffer where decompressed data should -+ * @out_len: output length is returned here -+ * @compr_type: type of compression -+ * -+ * This function decompresses data from buffer @in_buf into buffer @out_buf. -+ * The length of the uncompressed data is returned in @out_len. This functions -+ * returns %0 on success or a negative error code on failure. -+ */ -+int ubifs_decompress(const void *in_buf, int in_len, void *out_buf, -+ int *out_len, int compr_type) -+{ -+ int err; -+ struct ubifs_compressor *compr; -+ -+ if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) { -+ ubifs_err("invalid compression type %d", compr_type); -+ return -EINVAL; -+ } -+ -+ compr = ubifs_compressors[compr_type]; -+ -+ if (unlikely(!compr->capi_name)) { -+ ubifs_err("%s compression is not compiled in", compr->name); -+ return -EINVAL; -+ } -+ -+ if (compr_type == UBIFS_COMPR_NONE) { -+ memcpy(out_buf, in_buf, in_len); -+ *out_len = in_len; -+ return 0; -+ } -+ -+ if (compr->decomp_mutex) -+ mutex_lock(compr->decomp_mutex); -+ err = crypto_comp_decompress(compr->cc, in_buf, in_len, out_buf, -+ out_len); -+ if (compr->decomp_mutex) -+ mutex_unlock(compr->decomp_mutex); -+ if (err) -+ ubifs_err("cannot decompress %d bytes, compressor %s, " -+ "error %d", in_len, compr->name, err); -+ -+ return err; -+} -+ -+/** -+ * compr_init - initialize a compressor. -+ * @compr: compressor description object -+ * -+ * This function initializes the requested compressor and returns zero in case -+ * of success or a negative error code in case of failure. -+ */ -+static int __init compr_init(struct ubifs_compressor *compr) -+{ -+ if (compr->capi_name) { -+ compr->cc = crypto_alloc_comp(compr->capi_name, 0, 0); -+ if (IS_ERR(compr->cc)) { -+ ubifs_err("cannot initialize compressor %s, error %ld", -+ compr->name, PTR_ERR(compr->cc)); -+ return PTR_ERR(compr->cc); -+ } -+ } -+ -+ ubifs_compressors[compr->compr_type] = compr; -+ return 0; -+} -+ -+/** -+ * compr_exit - de-initialize a compressor. -+ * @compr: compressor description object -+ */ -+static void compr_exit(struct ubifs_compressor *compr) -+{ -+ if (compr->capi_name) -+ crypto_free_comp(compr->cc); -+ return; -+} -+ -+/** -+ * ubifs_compressors_init - initialize UBIFS compressors. -+ * -+ * This function initializes the compressor which were compiled in. Returns -+ * zero in case of success and a negative error code in case of failure. -+ */ -+int __init ubifs_compressors_init(void) -+{ -+ int err; -+ -+ err = compr_init(&lzo_compr); -+ if (err) -+ return err; -+ -+ err = compr_init(&zlib_compr); -+ if (err) -+ goto out_lzo; -+ -+ ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; -+ return 0; -+ -+out_lzo: -+ compr_exit(&lzo_compr); -+ return err; -+} -+ -+/** -+ * ubifs_compressors_exit - de-initialize UBIFS compressors. -+ */ -+void __exit ubifs_compressors_exit(void) -+{ -+ compr_exit(&lzo_compr); -+ compr_exit(&zlib_compr); -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/debug.c linux-2.6.24.7/fs/ubifs/debug.c ---- linux-2.6.24.7.old/fs/ubifs/debug.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/debug.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1517 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements most of the debugging stuff which is compiled in only -+ * when it is enabled. But some debugging check functions are implemented in -+ * corresponding subsystem, just because they are closely related and utilize -+ * various local functions of those subsystems. -+ */ -+ -+#define UBIFS_DBG_PRESERVE_UBI -+ -+#include "ubifs.h" -+#include -+#include -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+DEFINE_SPINLOCK(dbg_lock); -+ -+static char dbg_key_buf0[128]; -+static char dbg_key_buf1[128]; -+ -+unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT; -+unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT; -+unsigned int ubifs_tst_flags; -+ -+module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR); -+module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR); -+module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR); -+ -+MODULE_PARM_DESC(debug_msgs, "Debug message type flags"); -+MODULE_PARM_DESC(debug_chks, "Debug check flags"); -+MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); -+ -+static const char *get_key_fmt(int fmt) -+{ -+ switch (fmt) { -+ case UBIFS_SIMPLE_KEY_FMT: -+ return "simple"; -+ default: -+ return "unknown/invalid format"; -+ } -+} -+ -+static const char *get_key_hash(int hash) -+{ -+ switch (hash) { -+ case UBIFS_KEY_HASH_R5: -+ return "R5"; -+ case UBIFS_KEY_HASH_TEST: -+ return "test"; -+ default: -+ return "unknown/invalid name hash"; -+ } -+} -+ -+static const char *get_key_type(int type) -+{ -+ switch (type) { -+ case UBIFS_INO_KEY: -+ return "inode"; -+ case UBIFS_DENT_KEY: -+ return "direntry"; -+ case UBIFS_XENT_KEY: -+ return "xentry"; -+ case UBIFS_DATA_KEY: -+ return "data"; -+ case UBIFS_TRUN_KEY: -+ return "truncate"; -+ default: -+ return "unknown/invalid key"; -+ } -+} -+ -+static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key, -+ char *buffer) -+{ -+ char *p = buffer; -+ int type = key_type(c, key); -+ -+ if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) { -+ switch (type) { -+ case UBIFS_INO_KEY: -+ sprintf(p, "(%lu, %s)", key_ino(c, key), -+ get_key_type(type)); -+ break; -+ case UBIFS_DENT_KEY: -+ case UBIFS_XENT_KEY: -+ sprintf(p, "(%lu, %s, %#08x)", key_ino(c, key), -+ get_key_type(type), key_hash(c, key)); -+ break; -+ case UBIFS_DATA_KEY: -+ sprintf(p, "(%lu, %s, %u)", key_ino(c, key), -+ get_key_type(type), key_block(c, key)); -+ break; -+ case UBIFS_TRUN_KEY: -+ sprintf(p, "(%lu, %s)", -+ key_ino(c, key), get_key_type(type)); -+ break; -+ default: -+ sprintf(p, "(bad key type: %#08x, %#08x)", -+ key->u32[0], key->u32[1]); -+ } -+ } else -+ sprintf(p, "bad key format %d", c->key_fmt); -+} -+ -+const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key) -+{ -+ /* dbg_lock must be held */ -+ sprintf_key(c, key, dbg_key_buf0); -+ return dbg_key_buf0; -+} -+ -+const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key) -+{ -+ /* dbg_lock must be held */ -+ sprintf_key(c, key, dbg_key_buf1); -+ return dbg_key_buf1; -+} -+ -+const char *dbg_ntype(int type) -+{ -+ switch (type) { -+ case UBIFS_PAD_NODE: -+ return "padding node"; -+ case UBIFS_SB_NODE: -+ return "superblock node"; -+ case UBIFS_MST_NODE: -+ return "master node"; -+ case UBIFS_REF_NODE: -+ return "reference node"; -+ case UBIFS_INO_NODE: -+ return "inode node"; -+ case UBIFS_DENT_NODE: -+ return "direntry node"; -+ case UBIFS_XENT_NODE: -+ return "xentry node"; -+ case UBIFS_DATA_NODE: -+ return "data node"; -+ case UBIFS_TRUN_NODE: -+ return "truncate node"; -+ case UBIFS_IDX_NODE: -+ return "indexing node"; -+ case UBIFS_CS_NODE: -+ return "commit start node"; -+ case UBIFS_ORPH_NODE: -+ return "orphan node"; -+ default: -+ return "unknown node"; -+ } -+} -+ -+static const char *dbg_gtype(int type) -+{ -+ switch (type) { -+ case UBIFS_NO_NODE_GROUP: -+ return "no node group"; -+ case UBIFS_IN_NODE_GROUP: -+ return "in node group"; -+ case UBIFS_LAST_OF_NODE_GROUP: -+ return "last of node group"; -+ default: -+ return "unknown"; -+ } -+} -+ -+const char *dbg_cstate(int cmt_state) -+{ -+ switch (cmt_state) { -+ case COMMIT_RESTING: -+ return "commit resting"; -+ case COMMIT_BACKGROUND: -+ return "background commit requested"; -+ case COMMIT_REQUIRED: -+ return "commit required"; -+ case COMMIT_RUNNING_BACKGROUND: -+ return "BACKGROUND commit running"; -+ case COMMIT_RUNNING_REQUIRED: -+ return "commit running and required"; -+ case COMMIT_BROKEN: -+ return "broken commit"; -+ default: -+ return "unknown commit state"; -+ } -+} -+ -+static void dump_ch(const struct ubifs_ch *ch) -+{ -+ printk(KERN_DEBUG "\tmagic %#x\n", le32_to_cpu(ch->magic)); -+ printk(KERN_DEBUG "\tcrc %#x\n", le32_to_cpu(ch->crc)); -+ printk(KERN_DEBUG "\tnode_type %d (%s)\n", ch->node_type, -+ dbg_ntype(ch->node_type)); -+ printk(KERN_DEBUG "\tgroup_type %d (%s)\n", ch->group_type, -+ dbg_gtype(ch->group_type)); -+ printk(KERN_DEBUG "\tsqnum %llu\n", -+ (unsigned long long)le64_to_cpu(ch->sqnum)); -+ printk(KERN_DEBUG "\tlen %u\n", le32_to_cpu(ch->len)); -+} -+ -+void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode) -+{ -+ const struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ printk(KERN_DEBUG "inode %lu\n", inode->i_ino); -+ printk(KERN_DEBUG "size %llu\n", -+ (unsigned long long)i_size_read(inode)); -+ printk(KERN_DEBUG "nlink %u\n", inode->i_nlink); -+ printk(KERN_DEBUG "uid %u\n", (unsigned int)inode->i_uid); -+ printk(KERN_DEBUG "gid %u\n", (unsigned int)inode->i_gid); -+ printk(KERN_DEBUG "atime %u.%u\n", -+ (unsigned int)inode->i_atime.tv_sec, -+ (unsigned int)inode->i_atime.tv_nsec); -+ printk(KERN_DEBUG "mtime %u.%u\n", -+ (unsigned int)inode->i_mtime.tv_sec, -+ (unsigned int)inode->i_mtime.tv_nsec); -+ printk(KERN_DEBUG "ctime %u.%u\n", -+ (unsigned int)inode->i_ctime.tv_sec, -+ (unsigned int)inode->i_ctime.tv_nsec); -+ printk(KERN_DEBUG "creat_sqnum %llu\n", ui->creat_sqnum); -+ printk(KERN_DEBUG "xattr_size %lld\n", ui->xattr_size); -+ printk(KERN_DEBUG "xattr_cnt %d\n", ui->xattr_cnt); -+ printk(KERN_DEBUG "xattr_names %d\n", ui->xattr_names); -+ printk(KERN_DEBUG "dirty %u\n", ui->dirty); -+ printk(KERN_DEBUG "xattr %u\n", ui->xattr); -+ printk(KERN_DEBUG "flags %d\n", ui->flags); -+ printk(KERN_DEBUG "compr_type %d\n", ui->compr_type); -+ printk(KERN_DEBUG "data_len %d\n", ui->data_len); -+} -+ -+void dbg_dump_node(const struct ubifs_info *c, const void *node) -+{ -+ int i, n; -+ union ubifs_key key; -+ const struct ubifs_ch *ch = node; -+ -+ if (dbg_failure_mode) -+ return; -+ -+ /* If the magic is incorrect, just hexdump the first bytes */ -+ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { -+ printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ); -+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, -+ (void *)node, UBIFS_CH_SZ, 1); -+ return; -+ } -+ -+ spin_lock(&dbg_lock); -+ dump_ch(node); -+ -+ switch (ch->node_type) { -+ case UBIFS_PAD_NODE: -+ { -+ const struct ubifs_pad_node *pad = node; -+ -+ printk(KERN_DEBUG "\tpad_len %u\n", -+ le32_to_cpu(pad->pad_len)); -+ break; -+ } -+ case UBIFS_SB_NODE: -+ { -+ const struct ubifs_sb_node *sup = node; -+ unsigned int sup_flags = le32_to_cpu(sup->flags); -+ -+ printk(KERN_DEBUG "\tkey_hash %d (%s)\n", -+ (int)sup->key_hash, get_key_hash(sup->key_hash)); -+ printk(KERN_DEBUG "\tkey_fmt %d (%s)\n", -+ (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); -+ printk(KERN_DEBUG "\tflags %#x\n", sup_flags); -+ printk(KERN_DEBUG "\t big_lpt %u\n", -+ !!(sup_flags & UBIFS_FLG_BIGLPT)); -+ printk(KERN_DEBUG "\tmin_io_size %u\n", -+ le32_to_cpu(sup->min_io_size)); -+ printk(KERN_DEBUG "\tleb_size %u\n", -+ le32_to_cpu(sup->leb_size)); -+ printk(KERN_DEBUG "\tleb_cnt %u\n", -+ le32_to_cpu(sup->leb_cnt)); -+ printk(KERN_DEBUG "\tmax_leb_cnt %u\n", -+ le32_to_cpu(sup->max_leb_cnt)); -+ printk(KERN_DEBUG "\tmax_bud_bytes %llu\n", -+ (unsigned long long)le64_to_cpu(sup->max_bud_bytes)); -+ printk(KERN_DEBUG "\tlog_lebs %u\n", -+ le32_to_cpu(sup->log_lebs)); -+ printk(KERN_DEBUG "\tlpt_lebs %u\n", -+ le32_to_cpu(sup->lpt_lebs)); -+ printk(KERN_DEBUG "\torph_lebs %u\n", -+ le32_to_cpu(sup->orph_lebs)); -+ printk(KERN_DEBUG "\tjhead_cnt %u\n", -+ le32_to_cpu(sup->jhead_cnt)); -+ printk(KERN_DEBUG "\tfanout %u\n", -+ le32_to_cpu(sup->fanout)); -+ printk(KERN_DEBUG "\tlsave_cnt %u\n", -+ le32_to_cpu(sup->lsave_cnt)); -+ printk(KERN_DEBUG "\tdefault_compr %u\n", -+ (int)le16_to_cpu(sup->default_compr)); -+ printk(KERN_DEBUG "\trp_size %llu\n", -+ (unsigned long long)le64_to_cpu(sup->rp_size)); -+ printk(KERN_DEBUG "\trp_uid %u\n", -+ le32_to_cpu(sup->rp_uid)); -+ printk(KERN_DEBUG "\trp_gid %u\n", -+ le32_to_cpu(sup->rp_gid)); -+ printk(KERN_DEBUG "\tfmt_version %u\n", -+ le32_to_cpu(sup->fmt_version)); -+ printk(KERN_DEBUG "\ttime_gran %u\n", -+ le32_to_cpu(sup->time_gran)); -+ break; -+ } -+ case UBIFS_MST_NODE: -+ { -+ const struct ubifs_mst_node *mst = node; -+ -+ printk(KERN_DEBUG "\thighest_inum %llu\n", -+ (unsigned long long)le64_to_cpu(mst->highest_inum)); -+ printk(KERN_DEBUG "\tcommit number %llu\n", -+ (unsigned long long)le64_to_cpu(mst->cmt_no)); -+ printk(KERN_DEBUG "\tflags %#x\n", -+ le32_to_cpu(mst->flags)); -+ printk(KERN_DEBUG "\tlog_lnum %u\n", -+ le32_to_cpu(mst->log_lnum)); -+ printk(KERN_DEBUG "\troot_lnum %u\n", -+ le32_to_cpu(mst->root_lnum)); -+ printk(KERN_DEBUG "\troot_offs %u\n", -+ le32_to_cpu(mst->root_offs)); -+ printk(KERN_DEBUG "\troot_len %u\n", -+ le32_to_cpu(mst->root_len)); -+ printk(KERN_DEBUG "\tgc_lnum %u\n", -+ le32_to_cpu(mst->gc_lnum)); -+ printk(KERN_DEBUG "\tihead_lnum %u\n", -+ le32_to_cpu(mst->ihead_lnum)); -+ printk(KERN_DEBUG "\tihead_offs %u\n", -+ le32_to_cpu(mst->ihead_offs)); -+ printk(KERN_DEBUG "\tindex_size %u\n", -+ le32_to_cpu(mst->index_size)); -+ printk(KERN_DEBUG "\tlpt_lnum %u\n", -+ le32_to_cpu(mst->lpt_lnum)); -+ printk(KERN_DEBUG "\tlpt_offs %u\n", -+ le32_to_cpu(mst->lpt_offs)); -+ printk(KERN_DEBUG "\tnhead_lnum %u\n", -+ le32_to_cpu(mst->nhead_lnum)); -+ printk(KERN_DEBUG "\tnhead_offs %u\n", -+ le32_to_cpu(mst->nhead_offs)); -+ printk(KERN_DEBUG "\tltab_lnum %u\n", -+ le32_to_cpu(mst->ltab_lnum)); -+ printk(KERN_DEBUG "\tltab_offs %u\n", -+ le32_to_cpu(mst->ltab_offs)); -+ printk(KERN_DEBUG "\tlsave_lnum %u\n", -+ le32_to_cpu(mst->lsave_lnum)); -+ printk(KERN_DEBUG "\tlsave_offs %u\n", -+ le32_to_cpu(mst->lsave_offs)); -+ printk(KERN_DEBUG "\tlscan_lnum %u\n", -+ le32_to_cpu(mst->lscan_lnum)); -+ printk(KERN_DEBUG "\tleb_cnt %u\n", -+ le32_to_cpu(mst->leb_cnt)); -+ printk(KERN_DEBUG "\tempty_lebs %u\n", -+ le32_to_cpu(mst->empty_lebs)); -+ printk(KERN_DEBUG "\tidx_lebs %u\n", -+ le32_to_cpu(mst->idx_lebs)); -+ printk(KERN_DEBUG "\ttotal_free %llu\n", -+ (unsigned long long)le64_to_cpu(mst->total_free)); -+ printk(KERN_DEBUG "\ttotal_dirty %llu\n", -+ (unsigned long long)le64_to_cpu(mst->total_dirty)); -+ printk(KERN_DEBUG "\ttotal_used %llu\n", -+ (unsigned long long)le64_to_cpu(mst->total_used)); -+ printk(KERN_DEBUG "\ttotal_dead %llu\n", -+ (unsigned long long)le64_to_cpu(mst->total_dead)); -+ printk(KERN_DEBUG "\ttotal_dark %llu\n", -+ (unsigned long long)le64_to_cpu(mst->total_dark)); -+ break; -+ } -+ case UBIFS_REF_NODE: -+ { -+ const struct ubifs_ref_node *ref = node; -+ -+ printk(KERN_DEBUG "\tlnum %u\n", -+ le32_to_cpu(ref->lnum)); -+ printk(KERN_DEBUG "\toffs %u\n", -+ le32_to_cpu(ref->offs)); -+ printk(KERN_DEBUG "\tjhead %u\n", -+ le32_to_cpu(ref->jhead)); -+ break; -+ } -+ case UBIFS_INO_NODE: -+ { -+ const struct ubifs_ino_node *ino = node; -+ -+ key_read(c, &ino->key, &key); -+ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); -+ printk(KERN_DEBUG "\tsize %llu\n", -+ (unsigned long long)le64_to_cpu(ino->size)); -+ printk(KERN_DEBUG "\tnlink %u\n", -+ le32_to_cpu(ino->nlink)); -+ printk(KERN_DEBUG "\tatime %lld.%u\n", -+ (long long)le64_to_cpu(ino->atime_sec), -+ le32_to_cpu(ino->atime_nsec)); -+ printk(KERN_DEBUG "\tmtime %lld.%u\n", -+ (long long)le64_to_cpu(ino->mtime_sec), -+ le32_to_cpu(ino->mtime_nsec)); -+ printk(KERN_DEBUG "\tctime %lld.%u\n", -+ (long long)le64_to_cpu(ino->ctime_sec), -+ le32_to_cpu(ino->ctime_nsec)); -+ printk(KERN_DEBUG "\tuid %u\n", -+ le32_to_cpu(ino->uid)); -+ printk(KERN_DEBUG "\tgid %u\n", -+ le32_to_cpu(ino->gid)); -+ printk(KERN_DEBUG "\tmode %u\n", -+ le32_to_cpu(ino->mode)); -+ printk(KERN_DEBUG "\tflags %#x\n", -+ le32_to_cpu(ino->flags)); -+ printk(KERN_DEBUG "\txattr_cnt %u\n", -+ le32_to_cpu(ino->xattr_cnt)); -+ printk(KERN_DEBUG "\txattr_size %llu\n", -+ (unsigned long long)le64_to_cpu(ino->xattr_size)); -+ printk(KERN_DEBUG "\txattr_names %u\n", -+ le32_to_cpu(ino->xattr_names)); -+ printk(KERN_DEBUG "\tcompr_type %#x\n", -+ (int)le16_to_cpu(ino->compr_type)); -+ printk(KERN_DEBUG "\tdata len %u\n", -+ le32_to_cpu(ino->data_len)); -+ break; -+ } -+ case UBIFS_DENT_NODE: -+ case UBIFS_XENT_NODE: -+ { -+ const struct ubifs_dent_node *dent = node; -+ int nlen = le16_to_cpu(dent->nlen); -+ -+ key_read(c, &dent->key, &key); -+ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); -+ printk(KERN_DEBUG "\tinum %llu\n", -+ (unsigned long long)le64_to_cpu(dent->inum)); -+ printk(KERN_DEBUG "\ttype %d\n", (int)dent->type); -+ printk(KERN_DEBUG "\tnlen %d\n", nlen); -+ printk(KERN_DEBUG "\tname "); -+ -+ if (nlen > UBIFS_MAX_NLEN) { -+ nlen = UBIFS_MAX_NLEN; -+ printk(KERN_DEBUG "\tWarning! Node is corrupted\n"); -+ } -+ -+ for (i = 0; i < nlen && dent->name[i]; i++) -+ printk("%c", dent->name[i]); -+ printk("\n"); -+ -+ break; -+ } -+ case UBIFS_DATA_NODE: -+ { -+ const struct ubifs_data_node *dn = node; -+ int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ; -+ -+ key_read(c, &dn->key, &key); -+ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); -+ printk(KERN_DEBUG "\tsize %u\n", -+ le32_to_cpu(dn->size)); -+ printk(KERN_DEBUG "\tcompr_typ %d\n", -+ (int)le16_to_cpu(dn->compr_type)); -+ printk(KERN_DEBUG "\tdata size %d\n", -+ dlen); -+ printk(KERN_DEBUG "\tdata:\n"); -+ print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1, -+ (void *)&dn->data, dlen, 0); -+ break; -+ } -+ case UBIFS_TRUN_NODE: -+ { -+ const struct ubifs_trun_node *trun = node; -+ -+ key_read(c, &trun->key, &key); -+ printk(KERN_DEBUG "\tkey %s\n", DBGKEY(&key)); -+ printk(KERN_DEBUG "\told_size %llu\n", -+ (unsigned long long)le64_to_cpu(trun->old_size)); -+ printk(KERN_DEBUG "\tnew_size %llu\n", -+ (unsigned long long)le64_to_cpu(trun->new_size)); -+ break; -+ } -+ case UBIFS_IDX_NODE: -+ { -+ const struct ubifs_idx_node *idx = node; -+ -+ n = le16_to_cpu(idx->child_cnt); -+ printk(KERN_DEBUG "\tchild_cnt %d\n", n); -+ printk(KERN_DEBUG "\tlevel %d\n", -+ (int)le16_to_cpu(idx->level)); -+ printk(KERN_DEBUG "\tBranches:\n"); -+ -+ for (i = 0; i < n && i < c->fanout - 1; i++) { -+ const struct ubifs_branch *br; -+ -+ br = ubifs_idx_branch(c, idx, i); -+ key_read(c, &br->key, &key); -+ printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n", -+ i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs), -+ le32_to_cpu(br->len), DBGKEY(&key)); -+ } -+ break; -+ } -+ case UBIFS_CS_NODE: -+ break; -+ case UBIFS_ORPH_NODE: -+ { -+ const struct ubifs_orph_node *orph = node; -+ -+ printk(KERN_DEBUG "\tcommit number %llu\n", -+ (unsigned long long) -+ le64_to_cpu(orph->cmt_no) & LLONG_MAX); -+ printk(KERN_DEBUG "\tlast node flag %llu\n", -+ (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63); -+ n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3; -+ printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n); -+ for (i = 0; i < n; i++) -+ printk(KERN_DEBUG "\t ino %llu\n", -+ le64_to_cpu(orph->inos[i])); -+ break; -+ } -+ default: -+ printk(KERN_DEBUG "node type %d was not recognized\n", -+ (int)ch->node_type); -+ } -+ spin_unlock(&dbg_lock); -+} -+ -+void dbg_dump_budget_req(const struct ubifs_budget_req *req) -+{ -+ spin_lock(&dbg_lock); -+ printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n", -+ req->new_ino, req->dirtied_ino); -+ printk(KERN_DEBUG "\tnew_ino_d %d, dirtied_ino_d %d\n", -+ req->new_ino_d, req->dirtied_ino_d); -+ printk(KERN_DEBUG "\tnew_page %d, dirtied_page %d\n", -+ req->new_page, req->dirtied_page); -+ printk(KERN_DEBUG "\tnew_dent %d, mod_dent %d\n", -+ req->new_dent, req->mod_dent); -+/* TODO: remove compatibility stuff as late as possible */ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+ printk(KERN_DEBUG "\tlocked_pg %d idx_growth %d\n", -+ req->locked_pg, req->idx_growth); -+#else -+ printk(KERN_DEBUG "\tidx_growth %d\n", req->idx_growth); -+#endif -+ printk(KERN_DEBUG "\tdata_growth %d dd_growth %d\n", -+ req->data_growth, req->dd_growth); -+ spin_unlock(&dbg_lock); -+} -+ -+void dbg_dump_lstats(const struct ubifs_lp_stats *lst) -+{ -+ spin_lock(&dbg_lock); -+ printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs %d\n", -+ lst->empty_lebs, lst->idx_lebs); -+ printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, " -+ "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free, -+ lst->total_dirty); -+ printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, " -+ "total_dead %lld\n", lst->total_used, lst->total_dark, -+ lst->total_dead); -+ spin_unlock(&dbg_lock); -+} -+ -+void dbg_dump_budg(struct ubifs_info *c) -+{ -+ int i; -+ struct rb_node *rb; -+ struct ubifs_bud *bud; -+ struct ubifs_gced_idx_leb *idx_gc; -+ -+ spin_lock(&dbg_lock); -+ printk(KERN_DEBUG "Budgeting info: budg_data_growth %lld, " -+ "budg_dd_growth %lld, budg_idx_growth %lld\n", -+ c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); -+ printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " -+ "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, -+ c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth, -+ c->freeable_cnt); -+ printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, " -+ "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs, -+ c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt); -+ printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_ino_cnt %ld, " -+ "dirty_zn_cnt %ld, clean_zn_cnt %ld\n", -+ atomic_long_read(&c->dirty_pg_cnt), -+ atomic_long_read(&c->dirty_ino_cnt), -+ atomic_long_read(&c->dirty_zn_cnt), -+ atomic_long_read(&c->clean_zn_cnt)); -+ printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n", -+ c->dark_wm, c->dead_wm, c->max_idx_node_sz); -+ printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n", -+ c->gc_lnum, c->ihead_lnum); -+ for (i = 0; i < c->jhead_cnt; i++) -+ printk(KERN_DEBUG "\tjhead %d\t LEB %d\n", -+ c->jheads[i].wbuf.jhead, c->jheads[i].wbuf.lnum); -+ for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) { -+ bud = rb_entry(rb, struct ubifs_bud, rb); -+ printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum); -+ } -+ list_for_each_entry(bud, &c->old_buds, list) -+ printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum); -+ list_for_each_entry(idx_gc, &c->idx_gc, list) -+ printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n", -+ idx_gc->lnum, idx_gc->unmap); -+ printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state); -+ spin_unlock(&dbg_lock); -+} -+ -+void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp) -+{ -+ printk(KERN_DEBUG "LEB %d lprops: free %d, dirty %d (used %d), " -+ "flags %#x\n", lp->lnum, lp->free, lp->dirty, -+ c->leb_size - lp->free - lp->dirty, lp->flags); -+} -+ -+void dbg_dump_lprops(struct ubifs_info *c) -+{ -+ int lnum, err; -+ struct ubifs_lprops lp; -+ struct ubifs_lp_stats lst; -+ -+ printk(KERN_DEBUG "Dumping LEB properties\n"); -+ ubifs_get_lp_stats(c, &lst); -+ dbg_dump_lstats(&lst); -+ -+ for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) { -+ err = ubifs_read_one_lp(c, lnum, &lp); -+ if (err) -+ ubifs_err("cannot read lprops for LEB %d", lnum); -+ -+ dbg_dump_lprop(c, &lp); -+ } -+} -+ -+void dbg_dump_leb(const struct ubifs_info *c, int lnum) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ -+ if (dbg_failure_mode) -+ return; -+ -+ printk(KERN_DEBUG "Dumping LEB %d\n", lnum); -+ -+ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); -+ if (IS_ERR(sleb)) { -+ ubifs_err("scan error %d", (int)PTR_ERR(sleb)); -+ return; -+ } -+ -+ printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum, -+ sleb->nodes_cnt, sleb->endpt); -+ -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ cond_resched(); -+ printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum, -+ snod->offs, snod->len); -+ dbg_dump_node(c, snod->node); -+ } -+ -+ ubifs_scan_destroy(sleb); -+ return; -+} -+ -+void dbg_dump_znode(const struct ubifs_info *c, -+ const struct ubifs_znode *znode) -+{ -+ int n; -+ const struct ubifs_zbranch *zbr; -+ -+ spin_lock(&dbg_lock); -+ if (znode->parent) -+ zbr = &znode->parent->zbranch[znode->iip]; -+ else -+ zbr = &c->zroot; -+ -+ printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d" -+ " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs, -+ zbr->len, znode->parent, znode->iip, znode->level, -+ znode->child_cnt, znode->flags); -+ -+ if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) { -+ spin_unlock(&dbg_lock); -+ return; -+ } -+ -+ printk(KERN_DEBUG "zbranches:\n"); -+ for (n = 0; n < znode->child_cnt; n++) { -+ cond_resched(); -+ -+ zbr = &znode->zbranch[n]; -+ if (znode->level > 0) -+ printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key " -+ "%s\n", n, zbr->znode, zbr->lnum, -+ zbr->offs, zbr->len, -+ DBGKEY(&zbr->key)); -+ else -+ printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key " -+ "%s\n", n, zbr->znode, zbr->lnum, -+ zbr->offs, zbr->len, -+ DBGKEY(&zbr->key)); -+ } -+ spin_unlock(&dbg_lock); -+} -+ -+void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) -+{ -+ int i; -+ -+ printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n", -+ cat, heap->cnt); -+ for (i = 0; i < heap->cnt; i++) { -+ struct ubifs_lprops *lprops = heap->arr[i]; -+ -+ printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d " -+ "flags %d\n", i, lprops->lnum, lprops->hpos, -+ lprops->free, lprops->dirty, lprops->flags); -+ } -+} -+ -+void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, -+ struct ubifs_nnode *parent, int iip) -+{ -+ int i; -+ -+ printk(KERN_DEBUG "Dumping pnode:\n"); -+ printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", -+ (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); -+ printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", -+ pnode->flags, iip, pnode->level, pnode->num); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_lprops *lp = &pnode->lprops[i]; -+ -+ printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n", -+ i, lp->free, lp->dirty, lp->flags, lp->lnum); -+ } -+} -+ -+void dbg_dump_tnc(struct ubifs_info *c) -+{ -+ struct ubifs_znode *znode; -+ int level; -+ -+ printk(KERN_DEBUG "\n"); -+ printk(KERN_DEBUG "Dumping the TNC tree\n"); -+ znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); -+ level = znode->level; -+ printk(KERN_DEBUG "== Level %d ==\n", level); -+ while (znode) { -+ if (level != znode->level) { -+ level = znode->level; -+ printk(KERN_DEBUG "== Level %d ==\n", level); -+ } -+ dbg_dump_znode(c, znode); -+ znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); -+ } -+ -+ printk(KERN_DEBUG "\n"); -+} -+ -+/* -+ * dbg_check_dir - check directory inode size. -+ * @c: UBIFS file-system description object -+ * @dir: the directory to calculate size for -+ * @size: the result is returned here -+ * -+ * This function makes sure that directory size is correct. Returns zero -+ * in case of success and a negative error code in case of failure. -+ * -+ * Note, it is good idea to make sure the @dir->i_mutex is locked before -+ * calling this function. -+ */ -+int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) -+{ -+ union ubifs_key key; -+ struct ubifs_dent_node *dent, *pdent = NULL; -+ struct qstr nm = { .name = NULL }; -+ loff_t size = UBIFS_INO_NODE_SZ; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) -+ return 0; -+ -+ if (!S_ISDIR(dir->i_mode)) -+ return 0; -+ -+ lowest_dent_key(c, &key, dir->i_ino); -+ while (1) { -+ int err; -+ -+ dent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (IS_ERR(dent)) { -+ err = PTR_ERR(dent); -+ if (err == -ENOENT) -+ break; -+ return err; -+ } -+ -+ nm.name = dent->name; -+ nm.len = le16_to_cpu(dent->nlen); -+ size += CALC_DENT_SIZE(nm.len); -+ kfree(pdent); -+ pdent = dent; -+ key_read(c, &dent->key, &key); -+ } -+ -+ kfree(pdent); -+ -+ if (i_size_read(dir) != size) { -+ ubifs_err("bad directory dir %lu size %llu, " -+ "calculated %llu", dir->i_ino, -+ (unsigned long long)i_size_read(dir), -+ (unsigned long long)size); -+ dump_stack(); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * dbg_check_key_order - make sure that colliding keys are properly ordered. -+ * @c: UBIFS file-system description object -+ * @zbr1: first zbranch -+ * @zbr1: following zbranch -+ * -+ * In UBIFS indexing B-tree colliding keys has to be sorted in binary order of -+ * names of the direntries/xentries which are referred by the keys. This -+ * function reads direntries/xentries referred by @zbr1 and @zbr2 and makes -+ * sure the name of direntry/xentry referred by @zbr1 is less than -+ * direntry/xentry referred by @zbr2. Returns zero if this is true, %1 if not, -+ * and a negative error code in case of failure. -+ */ -+static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1, -+ struct ubifs_zbranch *zbr2) -+{ -+ int err, nlen1, nlen2, cmp; -+ struct ubifs_dent_node *dent1, *dent2; -+ union ubifs_key key; -+ -+ ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key)); -+ dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); -+ if (!dent1) -+ return -ENOMEM; -+ dent2 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); -+ if (!dent2) { -+ err = -ENOMEM; -+ goto out_free; -+ } -+ -+ err = dbg_read_leaf_nolock(c, zbr1, dent1); -+ if (err) -+ goto out_free; -+ err = ubifs_validate_entry(c, dent1); -+ if (err) -+ goto out_free; -+ -+ err = dbg_read_leaf_nolock(c, zbr2, dent2); -+ if (err) -+ goto out_free; -+ err = ubifs_validate_entry(c, dent2); -+ if (err) -+ goto out_free; -+ -+ /* Make sure node keys are the same as in zbranch */ -+ err = 1; -+ key_read(c, &dent1->key, &key); -+ if (keys_cmp(c, &zbr1->key, &key)) { -+ dbg_err("1st entry at %d:%d has key %s", zbr1->lnum, -+ zbr1->offs, DBGKEY(&key)); -+ dbg_err("but it should have key %s according to tnc", -+ DBGKEY(&zbr1->key)); -+ dbg_dump_node(c, dent1); -+ goto out_free; -+ } -+ -+ key_read(c, &dent2->key, &key); -+ if (keys_cmp(c, &zbr2->key, &key)) { -+ dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum, -+ zbr1->offs, DBGKEY(&key)); -+ dbg_err("but it should have key %s according to tnc", -+ DBGKEY(&zbr2->key)); -+ dbg_dump_node(c, dent2); -+ goto out_free; -+ } -+ -+ nlen1 = le16_to_cpu(dent1->nlen); -+ nlen2 = le16_to_cpu(dent2->nlen); -+ -+ cmp = memcmp(dent1->name, dent2->name, min_t(int, nlen1, nlen2)); -+ if (cmp < 0 || (cmp == 0 && nlen1 < nlen2)) { -+ err = 0; -+ goto out_free; -+ } -+ if (cmp == 0 && nlen1 == nlen2) -+ dbg_err("2 xent/dent nodes with the same name"); -+ else -+ dbg_err("bad order of colliding key %s", -+ DBGKEY(&key)); -+ -+ dbg_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs); -+ dbg_dump_node(c, dent1); -+ dbg_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs); -+ dbg_dump_node(c, dent2); -+ -+out_free: -+ kfree(dent2); -+ kfree(dent1); -+ return err; -+} -+ -+/** -+ * dbg_check_znode - check if znode is all right. -+ * @c: UBIFS file-system description object -+ * @zbr: zbranch which points to this znode -+ * -+ * This function makes sure that znode referred to by @zbr is all right. -+ * Returns zero if it is, and %-EINVAL if it is not. -+ */ -+static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr) -+{ -+ struct ubifs_znode *znode = zbr->znode; -+ struct ubifs_znode *zp = znode->parent; -+ int n, err, cmp; -+ -+ if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) { -+ err = 1; -+ goto out; -+ } -+ if (znode->level < 0) { -+ err = 2; -+ goto out; -+ } -+ if (znode->iip < 0 || znode->iip >= c->fanout) { -+ err = 3; -+ goto out; -+ } -+ -+ if (zbr->len == 0) -+ /* Only dirty zbranch may have no on-flash nodes */ -+ if (!ubifs_zn_dirty(znode)) { -+ err = 4; -+ goto out; -+ } -+ -+ if (ubifs_zn_dirty(znode)) { -+ /* -+ * If znode is dirty, its parent has to be dirty as well. The -+ * order of the operation is important, so we have to have -+ * memory barriers. -+ */ -+ smp_mb(); -+ if (zp && !ubifs_zn_dirty(zp)) { -+ /* -+ * The dirty flag is atomic and is cleared outside the -+ * TNC mutex, so znode's dirty flag may now have -+ * been cleared. The child is always cleared before the -+ * parent, so we just need to check again. -+ */ -+ smp_mb(); -+ if (ubifs_zn_dirty(znode)) { -+ err = 5; -+ goto out; -+ } -+ } -+ } -+ -+ if (zp) { -+ const union ubifs_key *min, *max; -+ -+ if (znode->level != zp->level - 1) { -+ err = 6; -+ goto out; -+ } -+ -+ /* Make sure the 'parent' pointer in our znode is correct */ -+ err = ubifs_search_zbranch(c, zp, &zbr->key, &n); -+ if (!err) { -+ /* This zbranch does not exist in the parent */ -+ err = 7; -+ goto out; -+ } -+ -+ if (znode->iip >= zp->child_cnt) { -+ err = 8; -+ goto out; -+ } -+ -+ if (znode->iip != n) { -+ /* This may happen only in case of collisions */ -+ if (keys_cmp(c, &zp->zbranch[n].key, -+ &zp->zbranch[znode->iip].key)) { -+ err = 9; -+ goto out; -+ } -+ n = znode->iip; -+ } -+ -+ /* -+ * Make sure that the first key in our znode is greater than or -+ * equal to the key in the pointing zbranch. -+ */ -+ min = &zbr->key; -+ cmp = keys_cmp(c, min, &znode->zbranch[0].key); -+ if (cmp == 1) { -+ err = 10; -+ goto out; -+ } -+ -+ if (n + 1 < zp->child_cnt) { -+ max = &zp->zbranch[n + 1].key; -+ -+ /* -+ * Make sure the last key in our znode is less or -+ * equivalent than the the key in zbranch which goes -+ * after our pointing zbranch. -+ */ -+ cmp = keys_cmp(c, max, -+ &znode->zbranch[znode->child_cnt - 1].key); -+ if (cmp == -1) { -+ err = 11; -+ goto out; -+ } -+ } -+ } else { -+ /* This may only be root znode */ -+ if (zbr != &c->zroot) { -+ err = 12; -+ goto out; -+ } -+ } -+ -+ /* -+ * Make sure that next key is greater or equivalent then the previous -+ * one. -+ */ -+ for (n = 1; n < znode->child_cnt; n++) { -+ cmp = keys_cmp(c, &znode->zbranch[n - 1].key, -+ &znode->zbranch[n].key); -+ if (cmp > 0) { -+ err = 13; -+ goto out; -+ } -+ if (cmp == 0) { -+ /* This can only be keys with colliding hash */ -+ if (!is_hash_key(c, &znode->zbranch[n].key)) { -+ err = 14; -+ goto out; -+ } -+ -+ if (znode->level != 0 || c->replaying) -+ continue; -+ -+ /* -+ * Colliding keys should follow binary order of -+ * corresponding xentry/dentry names. -+ */ -+ err = dbg_check_key_order(c, &znode->zbranch[n - 1], -+ &znode->zbranch[n]); -+ if (err < 0) -+ return err; -+ if (err) { -+ err = 15; -+ goto out; -+ } -+ } -+ } -+ -+ for (n = 0; n < znode->child_cnt; n++) { -+ if (!znode->zbranch[n].znode && -+ (znode->zbranch[n].lnum == 0 || -+ znode->zbranch[n].len == 0)) { -+ err = 16; -+ goto out; -+ } -+ -+ if (znode->zbranch[n].lnum != 0 && -+ znode->zbranch[n].len == 0) { -+ err = 17; -+ goto out; -+ } -+ -+ if (znode->zbranch[n].lnum == 0 && -+ znode->zbranch[n].len != 0) { -+ err = 18; -+ goto out; -+ } -+ -+ if (znode->zbranch[n].lnum == 0 && -+ znode->zbranch[n].offs != 0) { -+ err = 19; -+ goto out; -+ } -+ -+ if (znode->level != 0 && znode->zbranch[n].znode) -+ if (znode->zbranch[n].znode->parent != znode) { -+ err = 20; -+ goto out; -+ } -+ } -+ -+ return 0; -+ -+out: -+ ubifs_err("failed, error %d", err); -+ ubifs_msg("dump of the znode"); -+ dbg_dump_znode(c, znode); -+ if (zp) { -+ ubifs_msg("dump of the parent znode"); -+ dbg_dump_znode(c, zp); -+ } -+ dump_stack(); -+ return -EINVAL; -+} -+ -+/** -+ * dbg_check_tnc - check TNC tree. -+ * @c: UBIFS file-system description object -+ * @extra: do extra checks that are possible at start commit -+ * -+ * This function traverses whole TNC tree and checks every znode. Returns zero -+ * if everything is all right and %-EINVAL if something is wrong with TNC. -+ */ -+int dbg_check_tnc(struct ubifs_info *c, int extra) -+{ -+ struct ubifs_znode *znode; -+ long clean_cnt = 0, dirty_cnt = 0; -+ int err, last; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_TNC)) -+ return 0; -+ -+ ubifs_assert(mutex_is_locked(&c->tnc_mutex)); -+ if (!c->zroot.znode) -+ return 0; -+ -+ znode = ubifs_tnc_postorder_first(c->zroot.znode); -+ while (1) { -+ struct ubifs_znode *prev; -+ struct ubifs_zbranch *zbr; -+ -+ if (!znode->parent) -+ zbr = &c->zroot; -+ else -+ zbr = &znode->parent->zbranch[znode->iip]; -+ -+ err = dbg_check_znode(c, zbr); -+ if (err) -+ return err; -+ -+ if (extra) { -+ if (ubifs_zn_dirty(znode)) -+ dirty_cnt += 1; -+ else -+ clean_cnt += 1; -+ } -+ -+ prev = znode; -+ znode = ubifs_tnc_postorder_next(znode); -+ if (!znode) -+ break; -+ -+ /* -+ * If the last key of this znode is equivalent to the first key -+ * of the next znode (collision), then check order of the keys. -+ */ -+ last = prev->child_cnt - 1; -+ if (prev->level == 0 && znode->level == 0 && !c->replaying && -+ !keys_cmp(c, &prev->zbranch[last].key, -+ &znode->zbranch[0].key)) { -+ err = dbg_check_key_order(c, &prev->zbranch[last], -+ &znode->zbranch[0]); -+ if (err < 0) -+ return err; -+ if (err) { -+ ubifs_msg("first znode"); -+ dbg_dump_znode(c, prev); -+ ubifs_msg("second znode"); -+ dbg_dump_znode(c, znode); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ if (extra) { -+ if (clean_cnt != atomic_long_read(&c->clean_zn_cnt)) { -+ ubifs_err("incorrect clean_zn_cnt %ld, calculated %ld", -+ atomic_long_read(&c->clean_zn_cnt), -+ clean_cnt); -+ return -EINVAL; -+ } -+ if (dirty_cnt != atomic_long_read(&c->dirty_zn_cnt)) { -+ ubifs_err("incorrect dirty_zn_cnt %ld, calculated %ld", -+ atomic_long_read(&c->dirty_zn_cnt), -+ dirty_cnt); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static int dbg_add_size(struct ubifs_info *c, struct ubifs_znode *znode, -+ void *priv) -+{ -+ long long *idx_size = priv; -+ int add; -+ -+ add = ubifs_idx_node_sz(c, znode->child_cnt); -+ add = ALIGN(add, 8); -+ *idx_size += add; -+ return 0; -+} -+ -+int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) -+{ -+ int err; -+ long long calc = 0; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ)) -+ return 0; -+ -+ err = dbg_walk_index(c, NULL, dbg_add_size, &calc); -+ if (err) { -+ ubifs_err("error %d while walking the index", err); -+ return err; -+ } -+ -+ if (calc != idx_size) { -+ ubifs_err("index size check failed"); -+ ubifs_err("calculated size is %lld, should be %lld", -+ calc, idx_size); -+ dump_stack(); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int invocation_cnt; -+ -+int dbg_force_in_the_gaps(void) -+{ -+ if (!dbg_force_in_the_gaps_enabled) -+ return 0; -+ /* Force in-the-gaps every 8th commit */ -+ return !((invocation_cnt++) & 0x7); -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -+ -+/* Failure mode for recovery testing */ -+ -+#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d)) -+ -+struct failure_mode_info { -+ struct list_head list; -+ struct ubifs_info *c; -+}; -+ -+static LIST_HEAD(fmi_list); -+static DEFINE_SPINLOCK(fmi_lock); -+ -+static unsigned int next; -+ -+static int simple_rand(void) -+{ -+ if (next == 0) -+ next = current->pid; -+ next = next * 1103515245 + 12345; -+ return (next >> 16) & 32767; -+} -+ -+void dbg_failure_mode_registration(struct ubifs_info *c) -+{ -+ struct failure_mode_info *fmi; -+ -+ fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS); -+ if (!fmi) { -+ dbg_err("Failed to register failure mode - no memory"); -+ return; -+ } -+ fmi->c = c; -+ spin_lock(&fmi_lock); -+ list_add_tail(&fmi->list, &fmi_list); -+ spin_unlock(&fmi_lock); -+} -+ -+void dbg_failure_mode_deregistration(struct ubifs_info *c) -+{ -+ struct failure_mode_info *fmi, *tmp; -+ -+ spin_lock(&fmi_lock); -+ list_for_each_entry_safe(fmi, tmp, &fmi_list, list) -+ if (fmi->c == c) { -+ list_del(&fmi->list); -+ kfree(fmi); -+ } -+ spin_unlock(&fmi_lock); -+} -+ -+static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc) -+{ -+ struct failure_mode_info *fmi; -+ -+ spin_lock(&fmi_lock); -+ list_for_each_entry(fmi, &fmi_list, list) -+ if (fmi->c->ubi == desc) { -+ struct ubifs_info *c = fmi->c; -+ -+ spin_unlock(&fmi_lock); -+ return c; -+ } -+ spin_unlock(&fmi_lock); -+ return NULL; -+} -+ -+static int in_failure_mode(struct ubi_volume_desc *desc) -+{ -+ struct ubifs_info *c = dbg_find_info(desc); -+ -+ if (c) -+ return c->failure_mode; -+ return 0; -+} -+ -+static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) -+{ -+ struct ubifs_info *c = dbg_find_info(desc); -+ -+ if (!c || !dbg_failure_mode) -+ return 0; -+ if (c->failure_mode) -+ return 1; -+ if (!c->fail_cnt) { -+ /* First call - decide delay to failure */ -+ if (chance(1, 2)) { -+ unsigned int delay = 1 << (simple_rand() >> 11); -+ -+ if (chance(1, 2)) { -+ c->fail_delay = 1; -+ c->fail_timeout = jiffies + -+ msecs_to_jiffies(delay); -+ dbg_rcvry("failing after %ums", delay); -+ } else { -+ c->fail_delay = 2; -+ c->fail_cnt_max = delay; -+ dbg_rcvry("failing after %u calls", delay); -+ } -+ } -+ c->fail_cnt += 1; -+ } -+ /* Determine if failure delay has expired */ -+ if (c->fail_delay == 1) { -+ if (time_before(jiffies, c->fail_timeout)) -+ return 0; -+ } else if (c->fail_delay == 2) -+ if (c->fail_cnt++ < c->fail_cnt_max) -+ return 0; -+ if (lnum == UBIFS_SB_LNUM) { -+ if (write) { -+ if (chance(1, 2)) -+ return 0; -+ } else if (chance(19, 20)) -+ return 0; -+ dbg_rcvry("failing in super block LEB %d", lnum); -+ } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) { -+ if (chance(19, 20)) -+ return 0; -+ dbg_rcvry("failing in master LEB %d", lnum); -+ } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) { -+ if (write) { -+ if (chance(99, 100)) -+ return 0; -+ } else if (chance(399, 400)) -+ return 0; -+ dbg_rcvry("failing in log LEB %d", lnum); -+ } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) { -+ if (write) { -+ if (chance(7, 8)) -+ return 0; -+ } else if (chance(19, 20)) -+ return 0; -+ dbg_rcvry("failing in LPT LEB %d", lnum); -+ } else if (lnum >= c->orph_first && lnum <= c->orph_last) { -+ if (write) { -+ if (chance(1, 2)) -+ return 0; -+ } else if (chance(9, 10)) -+ return 0; -+ dbg_rcvry("failing in orphan LEB %d", lnum); -+ } else if (lnum == c->ihead_lnum) { -+ if (chance(99, 100)) -+ return 0; -+ dbg_rcvry("failing in index head LEB %d", lnum); -+ } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) { -+ if (chance(9, 10)) -+ return 0; -+ dbg_rcvry("failing in GC head LEB %d", lnum); -+ } else if (write && !RB_EMPTY_ROOT(&c->buds) && -+ !ubifs_search_bud(c, lnum)) { -+ if (chance(19, 20)) -+ return 0; -+ dbg_rcvry("failing in non-bud LEB %d", lnum); -+ } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND || -+ c->cmt_state == COMMIT_RUNNING_REQUIRED) { -+ if (chance(999, 1000)) -+ return 0; -+ dbg_rcvry("failing in bud LEB %d commit running", lnum); -+ } else { -+ if (chance(9999, 10000)) -+ return 0; -+ dbg_rcvry("failing in bud LEB %d commit not running", lnum); -+ } -+ ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); -+ c->failure_mode = 1; -+ dump_stack(); -+ return 1; -+} -+ -+static void cut_data(const void *buf, int len) -+{ -+ int flen, i; -+ unsigned char *p = (void *)buf; -+ -+ flen = (len * (long long)simple_rand()) >> 15; -+ for (i = flen; i < len; i++) -+ p[i] = 0xff; -+} -+ -+int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, -+ int len, int check) -+{ -+ if (in_failure_mode(desc)) -+ return -EIO; -+ return ubi_leb_read(desc, lnum, buf, offset, len, check); -+} -+ -+int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, -+ int offset, int len, int dtype) -+{ -+ int err; -+ -+ if (in_failure_mode(desc)) -+ return -EIO; -+ if (do_fail(desc, lnum, 1)) -+ cut_data(buf, len); -+ err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); -+ if (err) -+ return err; -+ if (in_failure_mode(desc)) -+ return -EIO; -+ return 0; -+} -+ -+int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, -+ int len, int dtype) -+{ -+ int err; -+ -+ if (do_fail(desc, lnum, 1)) -+ return -EIO; -+ err = ubi_leb_change(desc, lnum, buf, len, dtype); -+ if (err) -+ return err; -+ if (do_fail(desc, lnum, 1)) -+ return -EIO; -+ return 0; -+} -+ -+int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum) -+{ -+ int err; -+ -+ if (do_fail(desc, lnum, 0)) -+ return -EIO; -+ err = ubi_leb_erase(desc, lnum); -+ if (err) -+ return err; -+ if (do_fail(desc, lnum, 0)) -+ return -EIO; -+ return 0; -+} -+ -+int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum) -+{ -+ int err; -+ -+ if (do_fail(desc, lnum, 0)) -+ return -EIO; -+ err = ubi_leb_unmap(desc, lnum); -+ if (err) -+ return err; -+ if (do_fail(desc, lnum, 0)) -+ return -EIO; -+ return 0; -+} -+ -+int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum) -+{ -+ if (in_failure_mode(desc)) -+ return -EIO; -+ return ubi_is_mapped(desc, lnum); -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/debug.h linux-2.6.24.7/fs/ubifs/debug.h ---- linux-2.6.24.7.old/fs/ubifs/debug.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/debug.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,392 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+#ifndef __UBIFS_DEBUG_H__ -+#define __UBIFS_DEBUG_H__ -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+#define UBIFS_DBG(op) op -+ -+#define ubifs_assert(expr) do { \ -+ if (unlikely(!(expr))) { \ -+ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ -+ __func__, __LINE__, current->pid); \ -+ dbg_dump_stack(); \ -+ } \ -+} while (0) -+ -+#define ubifs_assert_cmt_locked(c) do { \ -+ if (unlikely(down_write_trylock(&(c)->commit_sem))) { \ -+ up_write(&(c)->commit_sem); \ -+ printk(KERN_CRIT "commit lock is not locked!\n"); \ -+ ubifs_assert(0); \ -+ } \ -+} while (0) -+ -+#define dbg_dump_stack() do { \ -+ if (!dbg_failure_mode) \ -+ dump_stack(); \ -+} while (0) -+ -+/* Generic debugging messages */ -+#define dbg_msg(fmt, ...) do { \ -+ spin_lock(&dbg_lock); \ -+ printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid, \ -+ __func__, ##__VA_ARGS__); \ -+ spin_unlock(&dbg_lock); \ -+} while (0) -+ -+#define dbg_do_msg(typ, fmt, ...) do { \ -+ if (ubifs_msg_flags & typ) \ -+ dbg_msg(fmt, ##__VA_ARGS__); \ -+} while (0) -+ -+#define dbg_err(fmt, ...) do { \ -+ spin_lock(&dbg_lock); \ -+ ubifs_err(fmt, ##__VA_ARGS__); \ -+ spin_unlock(&dbg_lock); \ -+} while (0) -+ -+const char *dbg_key_str0(const struct ubifs_info *c, -+ const union ubifs_key *key); -+const char *dbg_key_str1(const struct ubifs_info *c, -+ const union ubifs_key *key); -+ -+/* -+ * DBGKEY macros require dbg_lock to be held, which it is in the dbg message -+ * macros. -+ */ -+#define DBGKEY(key) dbg_key_str0(c, (key)) -+#define DBGKEY1(key) dbg_key_str1(c, (key)) -+ -+/* General messages */ -+#define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__) -+ -+/* Additional journal messages */ -+#define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__) -+ -+/* Additional TNC messages */ -+#define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__) -+ -+/* Additional lprops messages */ -+#define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__) -+ -+/* Additional LEB find messages */ -+#define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__) -+ -+/* Additional mount messages */ -+#define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__) -+ -+/* Additional I/O messages */ -+#define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__) -+ -+/* Additional commit messages */ -+#define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__) -+ -+/* Additional budgeting messages */ -+#define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__) -+ -+/* Additional log messages */ -+#define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__) -+ -+/* Additional gc messages */ -+#define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__) -+ -+/* Additional scan messages */ -+#define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__) -+ -+/* Additional recovery messages */ -+#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__) -+ -+/* -+ * Debugging message type flags (must match msg_type_names in debug.c). -+ * -+ * UBIFS_MSG_GEN: general messages -+ * UBIFS_MSG_JNL: journal messages -+ * UBIFS_MSG_MNT: mount messages -+ * UBIFS_MSG_CMT: commit messages -+ * UBIFS_MSG_FIND: LEB find messages -+ * UBIFS_MSG_BUDG: budgeting messages -+ * UBIFS_MSG_GC: garbage collection messages -+ * UBIFS_MSG_TNC: TNC messages -+ * UBIFS_MSG_LP: lprops messages -+ * UBIFS_MSG_IO: I/O messages -+ * UBIFS_MSG_LOG: log messages -+ * UBIFS_MSG_SCAN: scan messages -+ * UBIFS_MSG_RCVRY: recovery messages -+ */ -+enum { -+ UBIFS_MSG_GEN = 0x1, -+ UBIFS_MSG_JNL = 0x2, -+ UBIFS_MSG_MNT = 0x4, -+ UBIFS_MSG_CMT = 0x8, -+ UBIFS_MSG_FIND = 0x10, -+ UBIFS_MSG_BUDG = 0x20, -+ UBIFS_MSG_GC = 0x40, -+ UBIFS_MSG_TNC = 0x80, -+ UBIFS_MSG_LP = 0x100, -+ UBIFS_MSG_IO = 0x200, -+ UBIFS_MSG_LOG = 0x400, -+ UBIFS_MSG_SCAN = 0x800, -+ UBIFS_MSG_RCVRY = 0x1000, -+}; -+ -+/* Debugging message type flags for each default debug message level */ -+#define UBIFS_MSG_LVL_0 0 -+#define UBIFS_MSG_LVL_1 0x1 -+#define UBIFS_MSG_LVL_2 0x7f -+#define UBIFS_MSG_LVL_3 0xffff -+ -+/* -+ * Debugging check flags (must match chk_names in debug.c). -+ * -+ * UBIFS_CHK_GEN: general checks -+ * UBIFS_CHK_TNC: check TNC -+ * UBIFS_CHK_IDX_SZ: check index size -+ * UBIFS_CHK_ORPH: check orphans -+ * UBIFS_CHK_OLD_IDX: check the old index -+ * UBIFS_CHK_LPROPS: check lprops -+ */ -+enum { -+ UBIFS_CHK_GEN = 0x1, -+ UBIFS_CHK_TNC = 0x2, -+ UBIFS_CHK_IDX_SZ = 0x4, -+ UBIFS_CHK_ORPH = 0x8, -+ UBIFS_CHK_OLD_IDX = 0x10, -+ UBIFS_CHK_LPROPS = 0x20, -+}; -+ -+/* -+ * Special testing flags (must match tst_names in debug.c). -+ * -+ * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method -+ * UBIFS_TST_RCVRY: failure mode for recovery testing -+ */ -+enum { -+ UBIFS_TST_FORCE_IN_THE_GAPS = 0x2, -+ UBIFS_TST_RCVRY = 0x4, -+}; -+ -+#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1 -+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1 -+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2 -+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2 -+#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3 -+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3 -+#else -+#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0 -+#endif -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS -+#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff -+#else -+#define UBIFS_CHK_FLAGS_DEFAULT 0 -+#endif -+ -+extern spinlock_t dbg_lock; -+ -+extern unsigned int ubifs_msg_flags; -+extern unsigned int ubifs_chk_flags; -+extern unsigned int ubifs_tst_flags; -+ -+/* Dump functions */ -+ -+const char *dbg_ntype(int type); -+const char *dbg_cstate(int cmt_state); -+const char *dbg_get_key_dump(const struct ubifs_info *c, -+ const union ubifs_key *key); -+void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode); -+void dbg_dump_node(const struct ubifs_info *c, const void *node); -+void dbg_dump_budget_req(const struct ubifs_budget_req *req); -+void dbg_dump_lstats(const struct ubifs_lp_stats *lst); -+void dbg_dump_budg(struct ubifs_info *c); -+void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp); -+void dbg_dump_lprops(struct ubifs_info *c); -+void dbg_dump_leb(const struct ubifs_info *c, int lnum); -+void dbg_dump_znode(const struct ubifs_info *c, -+ const struct ubifs_znode *znode); -+void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat); -+void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, -+ struct ubifs_nnode *parent, int iip); -+void dbg_dump_tnc(struct ubifs_info *c); -+ -+/* Checking helper functions */ -+ -+typedef int (*dbg_leaf_callback)(struct ubifs_info *c, -+ struct ubifs_zbranch *zbr, void *priv); -+typedef int (*dbg_znode_callback)(struct ubifs_info *c, -+ struct ubifs_znode *znode, void *priv); -+ -+int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, -+ dbg_znode_callback znode_cb, void *priv); -+int dbg_read_leaf_nolock(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *node); -+ -+/* Checking functions */ -+ -+int dbg_check_lprops(struct ubifs_info *c); -+ -+int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); -+int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); -+ -+int dbg_check_cats(struct ubifs_info *c); -+ -+int dbg_check_ltab(struct ubifs_info *c); -+ -+int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); -+ -+int dbg_check_tnc(struct ubifs_info *c, int extra); -+ -+int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); -+ -+void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, -+ int add_pos); -+ -+int dbg_check_lprops(struct ubifs_info *c); -+int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, -+ int row, int col); -+ -+/* Force the use of in-the-gaps method for testing */ -+ -+#define dbg_force_in_the_gaps_enabled \ -+ (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS) -+ -+int dbg_force_in_the_gaps(void); -+ -+/* Failure mode for recovery testing */ -+ -+#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY) -+ -+void dbg_failure_mode_registration(struct ubifs_info *c); -+void dbg_failure_mode_deregistration(struct ubifs_info *c); -+ -+#ifndef UBIFS_DBG_PRESERVE_UBI -+ -+#define ubi_leb_read dbg_leb_read -+#define ubi_leb_write dbg_leb_write -+#define ubi_leb_change dbg_leb_change -+#define ubi_leb_erase dbg_leb_erase -+#define ubi_leb_unmap dbg_leb_unmap -+#define ubi_is_mapped dbg_is_mapped -+ -+#endif -+ -+int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, -+ int len, int check); -+int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, -+ int offset, int len, int dtype); -+int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, -+ int len, int dtype); -+int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum); -+int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum); -+int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum); -+ -+static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf, -+ int offset, int len) -+{ -+ return dbg_leb_read(desc, lnum, buf, offset, len, 0); -+} -+ -+static inline int dbg_write(struct ubi_volume_desc *desc, int lnum, -+ const void *buf, int offset, int len) -+{ -+ return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN); -+} -+ -+static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, -+ const void *buf, int len) -+{ -+ return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); -+} -+ -+#else /* !CONFIG_UBIFS_FS_DEBUG */ -+ -+#define UBIFS_DBG(op) -+#define ubifs_assert(expr) ({}) -+#define ubifs_assert_cmt_locked(c) -+#define dbg_dump_stack() -+#define dbg_err(fmt, ...) ({}) -+#define dbg_msg(fmt, ...) ({}) -+#define dbg_key(c, key, fmt, ...) ({}) -+ -+#define dbg_gen(fmt, ...) ({}) -+#define dbg_jnl(fmt, ...) ({}) -+#define dbg_tnc(fmt, ...) ({}) -+#define dbg_lp(fmt, ...) ({}) -+#define dbg_find(fmt, ...) ({}) -+#define dbg_mnt(fmt, ...) ({}) -+#define dbg_io(fmt, ...) ({}) -+#define dbg_cmt(fmt, ...) ({}) -+#define dbg_budg(fmt, ...) ({}) -+#define dbg_log(fmt, ...) ({}) -+#define dbg_gc(fmt, ...) ({}) -+#define dbg_scan(fmt, ...) ({}) -+#define dbg_rcvry(fmt, ...) ({}) -+ -+#define dbg_ntype(type) "" -+#define dbg_cstate(cmt_state) "" -+#define dbg_get_key_dump(c, key) ({}) -+#define dbg_dump_inode(c, inode) ({}) -+#define dbg_dump_node(c, node) ({}) -+#define dbg_dump_budget_req(req) ({}) -+#define dbg_dump_lstats(lst) ({}) -+#define dbg_dump_budg(c) ({}) -+#define dbg_dump_lprop(c, lp) ({}) -+#define dbg_dump_lprops(c) ({}) -+#define dbg_dump_leb(c, lnum) ({}) -+#define dbg_dump_znode(c, znode) ({}) -+#define dbg_dump_heap(c, heap, cat) ({}) -+#define dbg_dump_pnode(c, pnode, parent, iip) ({}) -+#define dbg_dump_tnc(c) ({}) -+ -+#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 -+#define dbg_read_leaf_nolock(c, zbr, node) 0 -+ -+#define dbg_old_index_check_init(c, zroot) 0 -+#define dbg_check_old_index(c, zroot) 0 -+ -+#define dbg_check_cats(c) 0 -+ -+#define dbg_check_ltab(c) 0 -+ -+#define dbg_check_dir_size(c, dir) 0 -+ -+#define dbg_check_tnc(c, x) 0 -+ -+#define dbg_check_idx_size(c, idx_size) 0 -+ -+#define dbg_check_heap(c, heap, cat, add_pos) ({}) -+ -+#define dbg_check_lprops(c) 0 -+#define dbg_check_lpt_nodes(c, cnode, row, col) 0 -+ -+#define dbg_force_in_the_gaps_enabled 0 -+#define dbg_force_in_the_gaps() 0 -+ -+#define dbg_failure_mode 0 -+#define dbg_failure_mode_registration(c) ({}) -+#define dbg_failure_mode_deregistration(c) ({}) -+ -+#endif /* !CONFIG_UBIFS_FS_DEBUG */ -+ -+#endif /* !__UBIFS_DEBUG_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/dir.c linux-2.6.24.7/fs/ubifs/dir.c ---- linux-2.6.24.7.old/fs/ubifs/dir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/dir.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1017 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * Copyright (C) 2006, 2007 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+/* -+ * This file implements directory operations. -+ * -+ * All FS operations in this file allocate budget before writing anything to the -+ * media. If they fail to allocate it, the error is returned. The only -+ * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even -+ * if they unable to allocate the budget, because deletion %-ENOSPC failure is -+ * not what users are usually ready to get. UBIFS budgeting subsystem has some -+ * space reserved for these purposes. -+ * -+ * All operations in this file change the parent inode, e.g., 'ubifs_link()' -+ * changes ctime and nlink of the parent inode. The parent inode is written to -+ * the media straight away - it is not marked as dirty and there is no -+ * write-back for it. This was done to simplify file-system recovery which -+ * would otherwise be very difficult to do. So instead of marking the parent -+ * inode dirty, the operations mark it clean. -+ */ -+ -+#include "ubifs.h" -+ -+/* -+ * Provide backing_dev_info in order to disable readahead. For UBIFS, I/O is -+ * not deferred, it is done immediately in readpage, which means the user would -+ * have to wait not just for their own I/O but the readahead I/O as well i.e. -+ * completely pointless. -+ */ -+struct backing_dev_info ubifs_backing_dev_info = { -+ .ra_pages = 0, /* Set to zero to disable readahead */ -+ .state = 0, -+ .capabilities = BDI_CAP_MAP_COPY, -+ .unplug_io_fn = default_unplug_io_fn, -+}; -+ -+/** -+ * inherit_flags - inherit flags of the parent inode. -+ * @dir: parent inode -+ * @mode: new inode mode flags -+ * -+ * This is a helper function for 'ubifs_new_inode()' which inherits flag of the -+ * parent directory inode @dir. UBIFS inodes inherit the following flags: -+ * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on -+ * sub-directory basis; -+ * o %UBIFS_SYNC_FL - useful for the same reasons; -+ * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. -+ * -+ * This function returns the inherited flags. -+ */ -+static int inherit_flags(const struct inode *dir, int mode) -+{ -+ int flags; -+ const struct ubifs_inode *ui = ubifs_inode(dir); -+ -+ if (!S_ISDIR(dir->i_mode)) -+ /* -+ * The parent is not a directory, which means that an extended -+ * attribute inode is being created. No flags. -+ */ -+ return 0; -+ -+ flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); -+ if (!S_ISDIR(mode)) -+ /* The "DIRSYNC" flag only applies to directories */ -+ flags &= ~UBIFS_DIRSYNC_FL; -+ -+ return flags; -+} -+ -+/** -+ * ubifs_new_inode - allocate new UBIFS inode object. -+ * @c: UBIFS file-system description object -+ * @dir: parent directory inode -+ * @mode: inode mode flags -+ * -+ * This function finds an unused inode number, allocates new inode and -+ * initializes it. Returns new inode in case of success and an error code in -+ * case of failure. -+ */ -+struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, -+ int mode) -+{ -+ struct inode *inode; -+ struct ubifs_inode *ui; -+ -+ inode = new_inode(c->vfs_sb); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ -+ /* -+ * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and -+ * marking them dirty in file write path (see 'file_update_time()'). -+ * UBIFS has to fully control "clean <-> dirty" transitions of inodes -+ * to make budgeting work. -+ */ -+ inode->i_flags |= (S_NOCMTIME); -+ -+ inode->i_uid = current->fsuid; -+ if (dir->i_mode & S_ISGID) { -+ inode->i_gid = dir->i_gid; -+ if (S_ISDIR(mode)) -+ mode |= S_ISGID; -+ } else -+ inode->i_gid = current->fsgid; -+ inode->i_mode = mode; -+ inode->i_mtime = inode->i_atime = inode->i_ctime = -+ ubifs_current_time(inode); -+ inode->i_mapping->nrpages = 0; -+ /* Disable readahead */ -+ inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info; -+ -+ switch (mode & S_IFMT) { -+ case S_IFREG: -+ inode->i_mapping->a_ops = &ubifs_file_address_operations; -+ inode->i_op = &ubifs_file_inode_operations; -+ inode->i_fop = &ubifs_file_operations; -+ break; -+ case S_IFDIR: -+ inode->i_op = &ubifs_dir_inode_operations; -+ inode->i_fop = &ubifs_dir_operations; -+ inode->i_size = UBIFS_INO_NODE_SZ; -+ break; -+ case S_IFLNK: -+ inode->i_op = &ubifs_symlink_inode_operations; -+ break; -+ case S_IFSOCK: -+ case S_IFIFO: -+ case S_IFBLK: -+ case S_IFCHR: -+ inode->i_op = &ubifs_file_inode_operations; -+ break; -+ default: -+ BUG(); -+ } -+ -+ ui = ubifs_inode(inode); -+ ui->flags = inherit_flags(dir, mode); -+ ubifs_set_inode_flags(inode); -+ -+ if (S_ISREG(mode)) -+ ui->compr_type = c->default_compr; -+ else -+ ui->compr_type = UBIFS_COMPR_NONE; -+ -+ spin_lock(&c->cnt_lock); -+ /* Inode number overflow is currently not supported */ -+ if (c->highest_inum >= INUM_WARN_WATERMARK) { -+ if (c->highest_inum >= INUM_WATERMARK) { -+ spin_unlock(&c->cnt_lock); -+ ubifs_err("out of inode numbers"); -+ make_bad_inode(inode); -+ iput(inode); -+ return ERR_PTR(-EINVAL); -+ } -+ ubifs_warn("running out of inode numbers (current %lu, max %d)", -+ c->highest_inum, INUM_WATERMARK); -+ } -+ -+ inode->i_ino = ++c->highest_inum; -+ inode->i_generation = ++c->vfs_gen; -+ /* -+ * The creation sequence number remains with this inode for its -+ * lifetime. All nodes for this inode have a greater sequence number, -+ * and so it is possible to distinguish obsolete nodes belonging to a -+ * previous incarnation of the same inode number - for example, for the -+ * purpose of rebuilding the index. -+ */ -+ ui->creat_sqnum = ++c->max_sqnum; -+ spin_unlock(&c->cnt_lock); -+ -+ return inode; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm) -+{ -+ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) -+ return 0; -+ if (le16_to_cpu(dent->nlen) != nm->len) -+ return -EINVAL; -+ if (memcmp(dent->name, nm->name, nm->len)) -+ return -EINVAL; -+ return 0; -+} -+ -+#else -+ -+#define dbg_check_name(dent, nm) 0 -+ -+#endif -+ -+static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, -+ struct nameidata *nd) -+{ -+ int err; -+ union ubifs_key key; -+ struct inode *inode = NULL; -+ struct ubifs_dent_node *dent; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ -+ dbg_gen("'%.*s' in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, dir->i_ino); -+ -+ if (dentry->d_name.len > UBIFS_MAX_NLEN) -+ return ERR_PTR(-ENAMETOOLONG); -+ -+ dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); -+ if (!dent) -+ return ERR_PTR(-ENOMEM); -+ -+ dent_key_init(c, &key, dir->i_ino, &dentry->d_name); -+ -+ err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); -+ if (err) { -+ if (err == -ENOENT) { -+ dbg_gen("not found"); -+ goto done; -+ } -+ goto out; -+ } -+ -+ if (dbg_check_name(dent, &dentry->d_name)) { -+ err = -EINVAL; -+ goto out; -+ } -+ -+ inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); -+ if (IS_ERR(inode)) { -+ /* -+ * This should not happen. Probably the file-system needs -+ * checking. -+ */ -+ err = PTR_ERR(inode); -+ ubifs_err("dead directory entry '%.*s', error %d", -+ dentry->d_name.len, dentry->d_name.name, err); -+ ubifs_ro_mode(c, err); -+ goto out; -+ } -+ -+done: -+ kfree(dent); -+ /* -+ * Note, d_splice_alias() would be required instead if we supported -+ * NFS. -+ */ -+ d_add(dentry, inode); -+ return NULL; -+ -+out: -+ kfree(dent); -+ return ERR_PTR(err); -+} -+ -+static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode, -+ struct nameidata *nd) -+{ -+ struct inode *inode; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; -+ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ -+ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); -+ -+ inode = ubifs_new_inode(c, dir, mode); -+ if (IS_ERR(inode)) -+ return PTR_ERR(inode); -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) -+ goto out; -+ -+ dir->i_size += sz_change; -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_budg; -+ -+ insert_inode_hash(inode); -+ d_instantiate(dentry, inode); -+ ubifs_release_ino_clean(c, dir, &req); -+ return 0; -+ -+out_budg: -+ dir->i_size -= sz_change; -+ ubifs_cancel_ino_op(c, dir, &req); -+ ubifs_err("cannot create regular file, error %d", err); -+out: -+ make_bad_inode(inode); -+ iput(inode); -+ return err; -+} -+ -+/** -+ * vfs_dent_type - get VFS directory entry type. -+ * @type: UBIFS directory entry type -+ * -+ * This function converts UBIFS directory entry type into VFS directory entry -+ * type. -+ */ -+static unsigned int vfs_dent_type(uint8_t type) -+{ -+ switch (type) { -+ case UBIFS_ITYPE_REG: -+ return DT_REG; -+ case UBIFS_ITYPE_DIR: -+ return DT_DIR; -+ case UBIFS_ITYPE_LNK: -+ return DT_LNK; -+ case UBIFS_ITYPE_BLK: -+ return DT_BLK; -+ case UBIFS_ITYPE_CHR: -+ return DT_CHR; -+ case UBIFS_ITYPE_FIFO: -+ return DT_FIFO; -+ case UBIFS_ITYPE_SOCK: -+ return DT_SOCK; -+ default: -+ BUG(); -+ } -+ return 0; -+} -+ -+/* -+ * The classical Unix view for directory is that it is a linear array of -+ * (name, inode number) entries. Linux/VFS assumes this model as well. -+ * Particularly, 'readdir()' call wants us to return a directory entry offset -+ * which later may be used to continue 'readdir()'ing the directory or to -+ * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this -+ * model because directory entries are identified by keys, which may collide. -+ * -+ * UBIFS uses directory entry hash value for directory offsets, so -+ * 'seekdir()'/'telldir()' may not always work because of possible key -+ * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work -+ * properly by means of saving full directory entry name in the private field -+ * of the file description object. -+ * -+ * This means that UBIFS cannot support NFS which requires full -+ * 'seekdir()'/'telldir()' support. -+ */ -+static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) -+{ -+ int err, over = 0; -+ struct qstr nm; -+ union ubifs_key key; -+ struct ubifs_dent_node *dent; -+ struct inode *dir = file->f_path.dentry->d_inode; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ -+ dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); -+ -+ if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2) -+ /* -+ * The directory was seek'ed to a senseless position or there -+ * are no more entries. -+ */ -+ return 0; -+ -+ /* File positions 0 and 1 correspond to "." and ".." */ -+ if (file->f_pos == 0) { -+ ubifs_assert(!file->private_data); -+ over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR); -+ if (over) -+ return 0; -+ file->f_pos = 1; -+ } -+ -+ if (file->f_pos == 1) { -+ ubifs_assert(!file->private_data); -+ over = filldir(dirent, "..", 2, 1, -+ parent_ino(file->f_path.dentry), DT_DIR); -+ if (over) -+ return 0; -+ -+ /* Find the first entry in TNC and save it */ -+ lowest_dent_key(c, &key, dir->i_ino); -+ nm.name = NULL; -+ dent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (IS_ERR(dent)) { -+ err = PTR_ERR(dent); -+ goto out; -+ } -+ -+ file->f_pos = key_hash_flash(c, &dent->key); -+ file->private_data = dent; -+ } -+ -+ dent = file->private_data; -+ if (!dent) { -+ /* -+ * The directory was seek'ed to and is now readdir'ed. -+ * Find the entry corresponding to @file->f_pos or the -+ * closest one. -+ */ -+ dent_key_init_hash(c, &key, dir->i_ino, file->f_pos); -+ nm.name = NULL; -+ dent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (IS_ERR(dent)) { -+ err = PTR_ERR(dent); -+ goto out; -+ } -+ file->f_pos = key_hash_flash(c, &dent->key); -+ file->private_data = dent; -+ } -+ -+ while (1) { -+ dbg_gen("feed '%s', ino %llu, new f_pos %#x", -+ dent->name, le64_to_cpu(dent->inum), -+ key_hash_flash(c, &dent->key)); -+ ubifs_assert(dent->ch.sqnum > ubifs_inode(dir)->creat_sqnum); -+ -+ nm.len = le16_to_cpu(dent->nlen); -+ over = filldir(dirent, dent->name, nm.len, file->f_pos, -+ le64_to_cpu(dent->inum), -+ vfs_dent_type(dent->type)); -+ if (over) -+ return 0; -+ -+ /* Switch to the next entry */ -+ key_read(c, &dent->key, &key); -+ nm.name = dent->name; -+ dent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (IS_ERR(dent)) { -+ err = PTR_ERR(dent); -+ goto out; -+ } -+ -+ kfree(file->private_data); -+ file->f_pos = key_hash_flash(c, &dent->key); -+ file->private_data = dent; -+ cond_resched(); -+ } -+ -+out: -+ if (err != -ENOENT) { -+ ubifs_err("cannot find next direntry, error %d", err); -+ return err; -+ } -+ -+ kfree(file->private_data); -+ file->private_data = NULL; -+ file->f_pos = 2; -+ return 0; -+} -+ -+/* If a directory is seeked, we have to free saved readdir() state */ -+loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin) -+{ -+ kfree(file->private_data); -+ file->private_data = NULL; -+ return generic_file_llseek(file, offset, origin); -+} -+ -+/* Free saved readdir() state when the directory is closed */ -+static int ubifs_dir_release(struct inode *dir, struct file *file) -+{ -+ kfree(file->private_data); -+ file->private_data = NULL; -+ return 0; -+} -+ -+static int ubifs_link(struct dentry *old_dentry, struct inode *dir, -+ struct dentry *dentry) -+{ -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct inode *inode = old_dentry->d_inode; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 1, -+ .dirtied_ino_d = ui->data_len }; -+ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ -+ dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, inode->i_ino, -+ inode->i_nlink, dir->i_ino); -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) -+ return err; -+ -+ inc_nlink(inode); -+ dir->i_size += sz_change; -+ inode->i_ctime = dir->i_mtime = dir->i_ctime = -+ ubifs_current_time(inode); -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_budg; -+ -+ atomic_inc(&inode->i_count); -+ d_instantiate(dentry, inode); -+ ubifs_release_ino_clean(c, dir, &req); -+ return 0; -+ -+out_budg: -+ dir->i_size -= sz_change; -+ ubifs_cancel_ino_op(c, dir, &req); -+ drop_nlink(inode); -+ iput(inode); -+ return err; -+} -+ -+static int ubifs_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct inode *inode = dentry->d_inode; -+ struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 }; -+ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ int err, budgeted = 1; -+ -+ dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, inode->i_ino, -+ inode->i_nlink, dir->i_ino); -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) { -+ if (err != -ENOSPC) -+ return err; -+ err = 0; -+ budgeted = 0; -+ } -+ -+ dir->i_size -= sz_change; -+ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); -+ -+ inode->i_ctime = dir->i_ctime; -+ drop_nlink(inode); -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_budg; -+ -+ if (budgeted) -+ ubifs_release_ino_clean(c, dir, &req); -+ -+ return 0; -+ -+out_budg: -+ dir->i_size += sz_change; -+ inc_nlink(inode); -+ if (budgeted) -+ ubifs_cancel_ino_op(c, dir, &req); -+ return err; -+} -+ -+/** -+ * check_dir_empty - check if a directory is empty or not. -+ * @c: UBIFS file-system description object -+ * @dir: VFS inode object of the directory to check -+ * -+ * This function checks if directory @dir is empty. Returns zero if the -+ * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes -+ * in case of of errors. -+ */ -+static int check_dir_empty(struct ubifs_info *c, struct inode *dir) -+{ -+ struct qstr nm = { .name = NULL }; -+ struct ubifs_dent_node *dent; -+ union ubifs_key key; -+ int err; -+ -+ lowest_dent_key(c, &key, dir->i_ino); -+ dent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (IS_ERR(dent)) { -+ err = PTR_ERR(dent); -+ if (err == -ENOENT) -+ err = 0; -+ } else { -+ kfree(dent); -+ err = -ENOTEMPTY; -+ } -+ -+ return err; -+} -+ -+static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct inode *inode = dentry->d_inode; -+ struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 1 }; -+ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ int err, budgeted = 0; -+ -+ dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len, -+ dentry->d_name.name, inode->i_ino, dir->i_ino); -+ -+ err = check_dir_empty(c, dentry->d_inode); -+ if (err) -+ return err; -+ -+ budgeted = 1; -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) { -+ if (err != -ENOSPC) -+ return err; -+ budgeted = 0; -+ } -+ -+ dir->i_size -= sz_change; -+ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); -+ drop_nlink(dir); -+ -+ inode->i_size = 0; -+ inode->i_ctime = dir->i_ctime; -+ clear_nlink(inode); -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_budg; -+ -+ if (budgeted) -+ ubifs_release_ino_clean(c, dir, &req); -+ -+ return 0; -+ -+out_budg: -+ dir->i_size += sz_change; -+ inc_nlink(dir); -+ inc_nlink(inode); -+ inc_nlink(inode); -+ if (budgeted) -+ ubifs_cancel_ino_op(c, dir, &req); -+ return err; -+} -+ -+static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -+{ -+ struct inode *inode; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; -+ int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ -+ dbg_gen("dent '%.*s', mode %#x in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino); -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) -+ return err; -+ -+ inode = ubifs_new_inode(c, dir, S_IFDIR | mode); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out_budg; -+ } -+ -+ insert_inode_hash(inode); -+ inc_nlink(inode); -+ -+ dir->i_mtime = dir->i_ctime = ubifs_current_time(dir); -+ dir->i_size += sz_change; -+ inc_nlink(dir); -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, -+ IS_DIRSYNC(dir), 0); -+ if (err) { -+ ubifs_err("cannot create directory, error %d", err); -+ goto out_inode; -+ } -+ -+ d_instantiate(dentry, inode); -+ ubifs_release_ino_clean(c, dir, &req); -+ return 0; -+ -+out_inode: -+ dir->i_size -= sz_change; -+ drop_nlink(dir); -+ make_bad_inode(inode); -+ iput(inode); -+out_budg: -+ ubifs_cancel_ino_op(c, dir, &req); -+ return err; -+} -+ -+static int ubifs_mknod(struct inode *dir, struct dentry *dentry, -+ int mode, dev_t rdev) -+{ -+ struct inode *inode; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; -+ union ubifs_dev_desc *dev = NULL; -+ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ int err, devlen = 0; -+ -+ dbg_gen("dent '%.*s' in dir ino %lu", -+ dentry->d_name.len, dentry->d_name.name, dir->i_ino); -+ -+ if (!new_valid_dev(rdev)) -+ return -EINVAL; -+ -+ if (S_ISBLK(mode) || S_ISCHR(mode)) { -+ dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); -+ if (!dev) -+ return -ENOMEM; -+ devlen = ubifs_encode_dev(dev, rdev); -+ } -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) { -+ kfree(dev); -+ return err; -+ } -+ -+ inode = ubifs_new_inode(c, dir, mode); -+ if (IS_ERR(inode)) { -+ kfree(dev); -+ err = PTR_ERR(inode); -+ goto out_budg; -+ } -+ -+ init_special_inode(inode, inode->i_mode, rdev); -+ -+ inode->i_size = devlen; -+ ubifs_inode(inode)->data = dev; -+ ubifs_inode(inode)->data_len = devlen; -+ -+ dir->i_size += sz_change; -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_inode; -+ -+ insert_inode_hash(inode); -+ d_instantiate(dentry, inode); -+ ubifs_release_ino_clean(c, dir, &req); -+ return 0; -+ -+out_inode: -+ dir->i_size -= sz_change; -+ make_bad_inode(inode); -+ iput(inode); -+out_budg: -+ ubifs_cancel_ino_op(c, dir, &req); -+ return err; -+} -+ -+static int ubifs_symlink(struct inode *dir, struct dentry *dentry, -+ const char *symname) -+{ -+ struct inode *inode; -+ struct ubifs_inode *ui; -+ struct ubifs_info *c = dir->i_sb->s_fs_info; -+ int err, len = strlen(symname); -+ int sz_change = CALC_DENT_SIZE(dentry->d_name.len); -+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, -+ .new_ino_d = len }; -+ -+ dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len, -+ dentry->d_name.name, symname, dir->i_ino); -+ -+ if (len > UBIFS_MAX_INO_DATA) -+ return -ENAMETOOLONG; -+ -+ err = ubifs_budget_inode_op(c, dir, &req); -+ if (err) -+ return err; -+ -+ inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out_budg; -+ } -+ -+ ui = ubifs_inode(inode); -+ ui->data = kmalloc(len + 1, GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_inode; -+ } -+ -+ memcpy(ui->data, symname, len); -+ ((char *)ui->data)[len] = '\0'; -+ /* -+ * The terminating zero byte is not written to the flash media and it -+ * is put just to make later in-memory string processing simpler. Thus, -+ * data length is @len, not @len + %1. -+ */ -+ ui->data_len = len; -+ inode->i_size = len; -+ -+ dir->i_size += sz_change; -+ -+ err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, -+ IS_DIRSYNC(dir), 0); -+ if (err) -+ goto out_dir; -+ -+ insert_inode_hash(inode); -+ d_instantiate(dentry, inode); -+ ubifs_release_ino_clean(c, dir, &req); -+ return 0; -+ -+out_dir: -+ dir->i_size -= sz_change; -+out_inode: -+ make_bad_inode(inode); -+ iput(inode); -+out_budg: -+ ubifs_cancel_ino_op(c, dir, &req); -+ return err; -+} -+ -+static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, -+ struct inode *new_dir, struct dentry *new_dentry) -+{ -+ struct ubifs_info *c = old_dir->i_sb->s_fs_info; -+ struct inode *old_inode = old_dentry->d_inode; -+ struct inode *new_inode = new_dentry->d_inode; -+ int err, move = (new_dir != old_dir); -+ int is_dir = S_ISDIR(old_inode->i_mode); -+ int unlink = !!new_inode; -+ int dirsync = (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)); -+ int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len); -+ int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len); -+ struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1 }; -+ struct timespec time = ubifs_current_time(old_dir); -+ -+ dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in " -+ "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, -+ old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len, -+ new_dentry->d_name.name, new_dir->i_ino); -+ -+ if (unlink && is_dir) { -+ err = check_dir_empty(c, new_inode); -+ if (err) -+ return err; -+ } -+ -+ if (move) { -+ req.dirtied_ino = 1; -+ if (unlink) { -+ req.dirtied_ino += 2; -+ req.dirtied_ino_d = ubifs_inode(new_inode)->data_len; -+ } -+ } -+ -+ /* -+ * Note, rename may write @new_dir inode if the directory entry is -+ * moved there. And if the @new_dir is dirty, we do not bother to make -+ * it clean. It could be done, but requires extra coding which does not -+ * seem to be really worth it. -+ */ -+ err = ubifs_budget_inode_op(c, old_dir, &req); -+ if (err) -+ return err; -+ -+ /* -+ * Like most other Unix systems, set the ctime for inodes on a -+ * rename. -+ */ -+ old_inode->i_ctime = time; -+ -+ /* -+ * If we moved a directory to another parent directory, decrement -+ * 'i_nlink' of the old parent. Also, update 'i_size' of the old parent -+ * as well as its [mc]time. -+ */ -+ if (is_dir && move) -+ drop_nlink(old_dir); -+ old_dir->i_size -= old_sz; -+ old_dir->i_mtime = old_dir->i_ctime = time; -+ new_dir->i_mtime = new_dir->i_ctime = time; -+ -+ /* -+ * If we moved a directory object to new directory, parent's 'i_nlink' -+ * should be adjusted. -+ */ -+ if (move && is_dir) -+ inc_nlink(new_dir); -+ -+ /* -+ * And finally, if we unlinked a direntry which happened to have the -+ * same name as the moved direntry, we have to decrement 'i_nlink' of -+ * the unlinked inode and change its ctime. -+ */ -+ if (unlink) { -+ /* -+ * Directories cannot have hard-links, so if this is a -+ * directory, decrement its 'i_nlink' twice because an empty -+ * directory has 'i_nlink' 2. -+ */ -+ if (is_dir) -+ drop_nlink(new_inode); -+ new_inode->i_ctime = time; -+ drop_nlink(new_inode); -+ } else -+ new_dir->i_size += new_sz; -+ -+ err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, -+ dirsync); -+ if (err) -+ goto out_inode; -+ -+ ubifs_release_ino_clean(c, old_dir, &req); -+ return 0; -+ -+out_inode: -+ if (unlink) { -+ if (is_dir) -+ inc_nlink(new_inode); -+ inc_nlink(new_inode); -+ } else -+ new_dir->i_size -= new_sz; -+ old_dir->i_size += old_sz; -+ if (is_dir && move) { -+ drop_nlink(new_dir); -+ inc_nlink(old_dir); -+ } -+ ubifs_cancel_ino_op(c, old_dir, &req); -+ return err; -+} -+ -+int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, -+ struct kstat *stat) -+{ -+ struct inode *inode = dentry->d_inode; -+ loff_t size; -+ -+ stat->dev = inode->i_sb->s_dev; -+ stat->ino = inode->i_ino; -+ stat->mode = inode->i_mode; -+ stat->nlink = inode->i_nlink; -+ stat->uid = inode->i_uid; -+ stat->gid = inode->i_gid; -+ stat->rdev = inode->i_rdev; -+ stat->atime = inode->i_atime; -+ stat->mtime = inode->i_mtime; -+ stat->ctime = inode->i_ctime; -+ stat->blksize = UBIFS_BLOCK_SIZE; -+ stat->size = i_size_read(inode); -+ -+ spin_lock(&inode->i_lock); -+ size = ubifs_inode(inode)->xattr_size; -+ spin_unlock(&inode->i_lock); -+ -+ /* -+ * Unfortunately, the 'stat()' system call was designed for block -+ * device based file systems, and it is not appropriate for UBIFS, -+ * because UBIFS does not have notion of "block". For example, it is -+ * difficult to tell how many block a directory takes - it actually -+ * takes less than 300 bytes, but we have to round it to block size, -+ * which introduces large mistake. This makes utilities like 'du' to -+ * report completely senseless numbers. This is the reason why UBIFS -+ * goes the same way as JFFS2 - it reports zero blocks for everything -+ * but regular files, which makes more sense than reporting completely -+ * wrong sizes. -+ */ -+ if (S_ISREG(inode->i_mode)) -+ size += stat->size; -+ -+ size = ALIGN(size, UBIFS_BLOCK_SIZE); -+ /* -+ * Note, user-space expects 512-byte blocks count irrespectively of what -+ * was reported in @stat->size. -+ */ -+ stat->blocks = size >> 9; -+ -+ return 0; -+} -+ -+struct inode_operations ubifs_dir_inode_operations = { -+ .lookup = ubifs_lookup, -+ .create = ubifs_create, -+ .link = ubifs_link, -+ .symlink = ubifs_symlink, -+ .unlink = ubifs_unlink, -+ .mkdir = ubifs_mkdir, -+ .rmdir = ubifs_rmdir, -+ .mknod = ubifs_mknod, -+ .rename = ubifs_rename, -+ .setattr = ubifs_setattr, -+ .getattr = ubifs_getattr, -+#ifdef CONFIG_UBIFS_FS_XATTR -+ .setxattr = ubifs_setxattr, -+ .getxattr = ubifs_getxattr, -+ .listxattr = ubifs_listxattr, -+ .removexattr = ubifs_removexattr, -+#endif -+}; -+ -+struct file_operations ubifs_dir_operations = { -+ .llseek = ubifs_dir_llseek, -+ .release = ubifs_dir_release, -+ .read = generic_read_dir, -+ .readdir = ubifs_readdir, -+ .fsync = ubifs_fsync, -+ .unlocked_ioctl = ubifs_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = ubifs_compat_ioctl, -+#endif -+}; -diff -urN linux-2.6.24.7.old/fs/ubifs/file.c linux-2.6.24.7/fs/ubifs/file.c ---- linux-2.6.24.7.old/fs/ubifs/file.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/file.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,983 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements VFS file and inode operations of regular files, device -+ * nodes and symlinks as well as address space operations. -+ * -+ * UBIFS uses 2 page flags: PG_private and PG_checked. PG_private is set if the -+ * page is dirty and is used for budgeting purposes - dirty pages should not be -+ * budgeted. The PG_checked flag is set if full budgeting is required for the -+ * page e.g., when it corresponds to a file hole or it is just beyond the file -+ * size. The budgeting is done in 'ubifs_write_begin()', because it is OK to -+ * fail in this function, and the budget is released in 'ubifs_write_end()'. So -+ * the PG_private and PG_checked flags carry the information about how the page -+ * was budgeted, to make it possible to release the budget properly. -+ * -+ * A thing to keep in mind: inode's 'i_mutex' is locked in most VFS operations -+ * we implement. However, this is not true for '->writepage()', which might be -+ * called with 'i_mutex' unlocked. For example, when pdflush is performing -+ * write-back, it calls 'writepage()' with unlocked 'i_mutex', although the -+ * inode has 'I_LOCK' flag in this case. At "normal" work-paths 'i_mutex' is -+ * locked in '->writepage', e.g. in "sys_write -> alloc_pages -> direct reclaim -+ * path'. So, in '->writepage()' we are only guaranteed that the page is -+ * locked. -+ * -+ * Similarly, 'i_mutex' does not have to be locked in readpage(), e.g., -+ * readahead path does not have it locked ("sys_read -> generic_file_aio_read -+ * -> ondemand_readahead -> readpage"). In case of readahead, 'I_LOCK' flag is -+ * not set as well. -+ * -+ * This, for example means that there might be 2 concurrent '->writepage()' -+ * calls for the same inode, but different inode dirty pages. -+ */ -+ -+#include "ubifs.h" -+#include -+ -+static int read_block(struct inode *inode, void *addr, unsigned int block, -+ struct ubifs_data_node *dn) -+{ -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ int err, len, out_len; -+ union ubifs_key key; -+ unsigned int dlen; -+ -+ data_key_init(c, &key, inode->i_ino, block); -+ err = ubifs_tnc_lookup(c, &key, dn); -+ if (err) { -+ if (err == -ENOENT) -+ /* Not found, so it must be a hole */ -+ memset(addr, 0, UBIFS_BLOCK_SIZE); -+ return err; -+ } -+ -+ ubifs_assert(dn->ch.sqnum > ubifs_inode(inode)->creat_sqnum); -+ -+ len = le32_to_cpu(dn->size); -+ if (len <= 0 || len > UBIFS_BLOCK_SIZE) -+ goto dump; -+ -+ dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; -+ out_len = UBIFS_BLOCK_SIZE; -+ err = ubifs_decompress(&dn->data, dlen, addr, &out_len, -+ le16_to_cpu(dn->compr_type)); -+ if (err || len != out_len) -+ goto dump; -+ -+ /* -+ * Data length can be less than a full block, even for blocks that are -+ * not the last in the file (e.g., as a result of making a hole and -+ * appending data). Ensure that the remainder is zeroed out. -+ */ -+ if (len < UBIFS_BLOCK_SIZE) -+ memset(addr + len, 0, UBIFS_BLOCK_SIZE - len); -+ -+ return 0; -+ -+dump: -+ ubifs_err("bad data node (block %u, inode %lu)", -+ block, inode->i_ino); -+ dbg_dump_node(c, dn); -+ return -EINVAL; -+} -+ -+/* TODO: remove compatibility stuff as late as possible */ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+int ubifs_do_readpage(struct page *page) -+#else -+static int do_readpage(struct page *page) -+#endif -+{ -+ void *addr; -+ int err = 0, i; -+ unsigned int block, beyond; -+ struct ubifs_data_node *dn; -+ struct inode *inode = page->mapping->host; -+ loff_t i_size = i_size_read(inode); -+ -+ dbg_gen("ino %lu, pg %lu, i_size %lld, flags %#lx", -+ inode->i_ino, page->index, i_size, page->flags); -+ ubifs_assert(!PageChecked(page)); -+ ubifs_assert(!PagePrivate(page)); -+ -+ addr = kmap(page); -+ -+ block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; -+ beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; -+ if (block >= beyond) { -+ /* Reading beyond inode */ -+ SetPageChecked(page); -+ memset(addr, 0, PAGE_CACHE_SIZE); -+ goto out; -+ } -+ -+ dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS); -+ if (!dn) { -+ err = -ENOMEM; -+ goto error; -+ } -+ -+ i = 0; -+ while (1) { -+ int ret; -+ -+ if (block >= beyond) { -+ /* Reading beyond inode */ -+ err = -ENOENT; -+ memset(addr, 0, UBIFS_BLOCK_SIZE); -+ } else { -+ ret = read_block(inode, addr, block, dn); -+ if (ret) { -+ err = ret; -+ if (err != -ENOENT) -+ break; -+ } -+ } -+ if (++i >= UBIFS_BLOCKS_PER_PAGE) -+ break; -+ block += 1; -+ addr += UBIFS_BLOCK_SIZE; -+ } -+ if (err) { -+ if (err == -ENOENT) { -+ /* Not found, so it must be a hole */ -+ SetPageChecked(page); -+ dbg_gen("hole"); -+ goto out_free; -+ } -+ ubifs_err("cannot read page %lu of inode %lu, error %d", -+ page->index, inode->i_ino, err); -+ goto error; -+ } -+ -+out_free: -+ kfree(dn); -+out: -+ SetPageUptodate(page); -+ ClearPageError(page); -+ flush_dcache_page(page); -+ kunmap(page); -+ return 0; -+ -+error: -+ kfree(dn); -+ ClearPageUptodate(page); -+ SetPageError(page); -+ flush_dcache_page(page); -+ kunmap(page); -+ return err; -+} -+ -+/* TODO: remove compatibility stuff as late as possible */ -+#ifndef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+ -+static int ubifs_write_begin(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned flags, -+ struct page **pagep, void **fsdata) -+{ -+ struct inode *inode = mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ pgoff_t index = pos >> PAGE_CACHE_SHIFT; -+ struct ubifs_budget_req req = { .new_page = 1 }; -+ loff_t i_size = i_size_read(inode); -+ int uninitialized_var(err); -+ struct page *page; -+ -+ ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); -+ -+ if (unlikely(c->ro_media)) -+ return -EROFS; -+ -+ /* -+ * We are about to have a page of data written and we have to budget for -+ * this. The very important point here is that we have to budget before -+ * locking the page, because budgeting may force write-back, which -+ * would wait on locked pages and deadlock if we had the page locked. -+ * -+ * At this point we do not know anything about the page of data we are -+ * going to change, so assume the biggest budget (i.e., assume that -+ * this is a new page of data and it does not override an older page of -+ * data in the inode). Later the budget will be amended if this is not -+ * true. -+ */ -+ if (pos + len > i_size) -+ /* -+ * We are writing beyond the file which means we are going to -+ * change inode size and make the inode dirty. And in turn, -+ * this means we have to budget for making the inode dirty. -+ * -+ * Note, if the inode is already dirty, -+ * 'ubifs_budget_inode_op()' will not allocate any budget, -+ * but will just lock the @budg_mutex of the inode to prevent -+ * it from becoming clean before we have changed its size, -+ * which is going to happen in 'ubifs_write_end()'. -+ */ -+ err = ubifs_budget_inode_op(c, inode, &req); -+ else -+ /* -+ * The inode is not going to be marked as dirty by this write -+ * operation, do not budget for this. -+ */ -+ err = ubifs_budget_space(c, &req); -+ if (unlikely(err)) -+ return err; -+ -+ page = __grab_cache_page(mapping, index); -+ if (unlikely(!page)) { -+ err = -ENOMEM; -+ goto out_release; -+ } -+ -+ if (!PageUptodate(page)) { -+ /* -+ * The page is not loaded from the flash and has to be loaded -+ * unless we are writing all of it. -+ */ -+ if (!(pos & PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) -+ /* -+ * Set the PG_checked flag to make the further code -+ * assume the page is new. -+ */ -+ SetPageChecked(page); -+ else { -+ err = do_readpage(page); -+ if (err) -+ goto out_unlock; -+ } -+ -+ SetPageUptodate(page); -+ ClearPageError(page); -+ } -+ -+ if (PagePrivate(page)) -+ /* -+ * The page is dirty, which means it was budgeted twice: -+ * o first time the budget was allocated by the task which -+ * made the page dirty and set the PG_private flag; -+ * o and then we budgeted for it for the second time at the -+ * very beginning of this function. -+ * -+ * So what we have to do is to release the page budget we -+ * allocated. -+ * -+ * Note, the page write operation may change the inode length, -+ * which makes it dirty and means the budget should be -+ * allocated. This was done above in the "pos + len > i_size" -+ * case. If this was done, we do not free the the inode budget, -+ * because we cannot as we are really going to mark it dirty in -+ * the 'ubifs_write_end()' function. -+ */ -+ ubifs_release_new_page_budget(c); -+ else if (!PageChecked(page)) -+ /* -+ * The page is not new, which means we are changing the page -+ * which already exists on the media. This means that changing -+ * the page does not make the amount of indexing information -+ * larger, and this part of the budget which we have already -+ * acquired may be released. -+ */ -+ ubifs_convert_page_budget(c); -+ -+ *pagep = page; -+ return 0; -+ -+out_unlock: -+ unlock_page(page); -+ page_cache_release(page); -+out_release: -+ if (pos + len > i_size) -+ ubifs_cancel_ino_op(c, inode, &req); -+ else -+ ubifs_release_budget(c, &req); -+ return err; -+} -+ -+static int ubifs_write_end(struct file *file, struct address_space *mapping, -+ loff_t pos, unsigned len, unsigned copied, -+ struct page *page, void *fsdata) -+{ -+ struct inode *inode = mapping->host; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ loff_t i_size = i_size_read(inode); -+ -+ dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld", -+ inode->i_ino, pos, page->index, len, copied, i_size); -+ -+ if (unlikely(copied < len && len == PAGE_CACHE_SIZE)) { -+ /* -+ * VFS copied less data to the page that it intended and -+ * declared in its '->write_begin()' call via the @len -+ * argument. If the page was not up-to-date, and @len was -+ * @PAGE_CACHE_SIZE, the 'ubifs_write_begin()' function did -+ * not load it from the media (for optimization reasons). This -+ * means that part of the page contains garbage. So read the -+ * page now. -+ */ -+ dbg_gen("copied %d instead of %d, read page and repeat", -+ copied, len); -+ -+ if (pos + len > i_size) -+ /* See a comment below about this hacky unlock */ -+ mutex_unlock(&ui->budg_mutex); -+ -+ copied = do_readpage(page); -+ -+ /* -+ * Return 0 to force VFS to repeat the whole operation, or the -+ * error code if 'do_readpage()' failed. -+ */ -+ goto out; -+ } -+ -+ if (!PagePrivate(page)) { -+ SetPagePrivate(page); -+ atomic_long_inc(&c->dirty_pg_cnt); -+ __set_page_dirty_nobuffers(page); -+ } -+ -+ if (pos + len > i_size) { -+ i_size_write(inode, pos + len); -+ -+ /* -+ * Note, we do not set @I_DIRTY_PAGES (which means that the -+ * inode has dirty pages), this has been done in -+ * '__set_page_dirty_nobuffers()'. -+ */ -+ mark_inode_dirty_sync(inode); -+ -+ /* -+ * The inode has been marked dirty, unlock it. This is a bit -+ * hacky because normally we would have to call -+ * 'ubifs_release_ino_dirty()'. But we know there is nothing -+ * to release because page's budget will be released in -+ * 'ubifs_write_page()' and inode's budget will be released in -+ * 'ubifs_write_inode()', so just unlock the inode here for -+ * optimization. -+ */ -+ mutex_unlock(&ui->budg_mutex); -+ } -+ -+out: -+ unlock_page(page); -+ page_cache_release(page); -+ return copied; -+} -+ -+#endif /* UBIFS_COMPAT_USE_OLD_PREPARE_WRITE */ -+ -+static int ubifs_readpage(struct file *file, struct page *page) -+{ -+ do_readpage(page); -+ unlock_page(page); -+ return 0; -+} -+ -+/** -+ * release_existing_page_budget - release budget of an existing page. -+ * @c: UBIFS file-system description object -+ * -+ * This is a helper function which releases budget corresponding to the budget -+ * of changing one one page of data which already exists on the flash media. -+ * -+ * This function was not moved to "budget.c" because there is only one user. -+ */ -+static void release_existing_page_budget(struct ubifs_info *c) -+{ -+ struct ubifs_budget_req req = { .dd_growth = c->page_budget}; -+ -+ ubifs_release_budget(c, &req); -+} -+ -+static int do_writepage(struct page *page, int len) -+{ -+ int err = 0, i, blen; -+ unsigned int block; -+ void *addr; -+ union ubifs_key key; -+ struct inode *inode = page->mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ -+ /* Update radix tree tags */ -+ set_page_writeback(page); -+ -+ addr = kmap(page); -+ -+ block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT; -+ i = 0; -+ while (len) { -+ blen = min_t(int, len, UBIFS_BLOCK_SIZE); -+ data_key_init(c, &key, inode->i_ino, block); -+ err = ubifs_jnl_write_data(c, inode, &key, addr, blen); -+ if (err) -+ break; -+ if (++i >= UBIFS_BLOCKS_PER_PAGE) -+ break; -+ block += 1; -+ addr += blen; -+ len -= blen; -+ } -+ if (err) { -+ SetPageError(page); -+ ubifs_err("cannot write page %lu of inode %lu, error %d", -+ page->index, inode->i_ino, err); -+ ubifs_ro_mode(c, err); -+ } -+ -+ ubifs_assert(PagePrivate(page)); -+ if (PageChecked(page)) -+ ubifs_release_new_page_budget(c); -+ else -+ release_existing_page_budget(c); -+ -+ atomic_long_dec(&c->dirty_pg_cnt); -+ ClearPagePrivate(page); -+ ClearPageChecked(page); -+ -+ kunmap(page); -+ unlock_page(page); -+ end_page_writeback(page); -+ -+ return err; -+} -+ -+static int ubifs_writepage(struct page *page, struct writeback_control *wbc) -+{ -+ struct inode *inode = page->mapping->host; -+ loff_t i_size = i_size_read(inode); -+ pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; -+ int len; -+ void *kaddr; -+ -+ dbg_gen("ino %lu, pg %lu, pg flags %#lx", -+ inode->i_ino, page->index, page->flags); -+ ubifs_assert(PagePrivate(page)); -+ -+ /* Is the page fully inside i_size? */ -+ if (page->index < end_index) -+ return do_writepage(page, PAGE_CACHE_SIZE); -+ -+ /* Is the page fully outside i_size? (truncate in progress) */ -+ len = i_size & (PAGE_CACHE_SIZE - 1); -+ if (page->index >= end_index + 1 || !len) { -+ unlock_page(page); -+ return 0; -+ } -+ -+ /* -+ * The page straddles i_size. It must be zeroed out on each and every -+ * writepage invocation because it may be mmapped. "A file is mapped -+ * in multiples of the page size. For a file that is not a multiple of -+ * the page size, the remaining memory is zeroed when mapped, and -+ * writes to that region are not written out to the file." -+ */ -+ kaddr = kmap_atomic(page, KM_USER0); -+ memset(kaddr + len, 0, PAGE_CACHE_SIZE - len); -+ flush_dcache_page(page); -+ kunmap_atomic(kaddr, KM_USER0); -+ -+ return do_writepage(page, len); -+} -+ -+static int ubifs_trunc(struct inode *inode, loff_t new_size) -+{ -+ loff_t old_size; -+ int err; -+ -+ dbg_gen("ino %lu, size %lld -> %lld", -+ inode->i_ino, inode->i_size, new_size); -+ old_size = inode->i_size; -+ -+ err = vmtruncate(inode, new_size); -+ if (err) -+ return err; -+ -+ if (new_size < old_size) { -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ int offset = new_size & (UBIFS_BLOCK_SIZE - 1); -+ -+ if (offset) { -+ pgoff_t index = new_size >> PAGE_CACHE_SHIFT; -+ struct page *page; -+ -+ page = find_lock_page(inode->i_mapping, index); -+ if (page) { -+ if (PageDirty(page)) { -+ ubifs_assert(PagePrivate(page)); -+ -+ clear_page_dirty_for_io(page); -+ if (UBIFS_BLOCKS_PER_PAGE_SHIFT) -+ offset = new_size & -+ (PAGE_CACHE_SIZE - 1); -+ err = do_writepage(page, offset); -+ page_cache_release(page); -+ if (err) -+ return err; -+ /* -+ * We could now tell ubifs_jnl_truncate -+ * not to read the last block. -+ */ -+ } else { -+ /* -+ * We could 'kmap()' the page and -+ * pass the data to ubifs_jnl_truncate -+ * to save it from having to read it. -+ */ -+ unlock_page(page); -+ page_cache_release(page); -+ } -+ } -+ } -+ err = ubifs_jnl_truncate(c, inode->i_ino, old_size, new_size); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+int ubifs_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ unsigned int ia_valid = attr->ia_valid; -+ struct inode *inode = dentry->d_inode; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_budget_req req; -+ int truncation, err = 0; -+ -+ dbg_gen("ino %lu, ia_valid %#x", inode->i_ino, ia_valid); -+ err = inode_change_ok(inode, attr); -+ if (err) -+ return err; -+ -+ memset(&req, 0, sizeof(struct ubifs_budget_req)); -+ -+ /* -+ * If this is truncation, and we do not truncate on a block boundary, -+ * budget for changing one data block, because the last block will be -+ * re-written. -+ */ -+ truncation = (ia_valid & ATTR_SIZE) && attr->ia_size != inode->i_size; -+ if (truncation && attr->ia_size < inode->i_size && -+ (attr->ia_size & (UBIFS_BLOCK_SIZE - 1))) -+ req.dirtied_page = 1; -+ -+ err = ubifs_budget_inode_op(c, inode, &req); -+ if (err) -+ return err; -+ -+ if (truncation) { -+ err = ubifs_trunc(inode, attr->ia_size); -+ if (err) { -+ ubifs_cancel_ino_op(c, inode, &req); -+ return err; -+ } -+ -+ inode->i_mtime = inode->i_ctime = ubifs_current_time(inode); -+ } -+ -+ if (ia_valid & ATTR_UID) -+ inode->i_uid = attr->ia_uid; -+ if (ia_valid & ATTR_GID) -+ inode->i_gid = attr->ia_gid; -+ if (ia_valid & ATTR_ATIME) -+ inode->i_atime = timespec_trunc(attr->ia_atime, -+ inode->i_sb->s_time_gran); -+ if (ia_valid & ATTR_MTIME) -+ inode->i_mtime = timespec_trunc(attr->ia_mtime, -+ inode->i_sb->s_time_gran); -+ if (ia_valid & ATTR_CTIME) -+ inode->i_ctime = timespec_trunc(attr->ia_ctime, -+ inode->i_sb->s_time_gran); -+ if (ia_valid & ATTR_MODE) { -+ umode_t mode = attr->ia_mode; -+ -+ if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) -+ mode &= ~S_ISGID; -+ inode->i_mode = mode; -+ } -+ -+ mark_inode_dirty_sync(inode); -+ ubifs_release_ino_dirty(c, inode, &req); -+ -+ if (req.dirtied_page) { -+ /* -+ * Truncation code does not make the reenacted page dirty, it -+ * just changes it on journal level, so we have to release page -+ * change budget. -+ */ -+ memset(&req, 0, sizeof(struct ubifs_budget_req)); -+ req.dd_growth = c->page_budget; -+ ubifs_release_budget(c, &req); -+ } -+ -+ if (IS_SYNC(inode)) -+ err = write_inode_now(inode, 1); -+ -+ return err; -+} -+ -+static void ubifs_invalidatepage(struct page *page, unsigned long offset) -+{ -+ struct inode *inode = page->mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_budget_req req; -+ -+ ubifs_assert(PagePrivate(page)); -+ if (offset) -+ /* Partial page remains dirty */ -+ return; -+ -+ memset(&req, 0, sizeof(struct ubifs_budget_req)); -+ if (PageChecked(page)) { -+ req.new_page = 1; -+ req.idx_growth = -1; -+ req.data_growth = c->page_budget; -+ } else -+ req.dd_growth = c->page_budget; -+ ubifs_release_budget(c, &req); -+ -+ atomic_long_dec(&c->dirty_pg_cnt); -+ ClearPagePrivate(page); -+ ClearPageChecked(page); -+} -+ -+static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) -+{ -+ struct ubifs_inode *ui = ubifs_inode(dentry->d_inode); -+ -+ nd_set_link(nd, ui->data); -+ return NULL; -+} -+ -+int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync) -+{ -+ struct inode *inode = dentry->d_inode; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ int err; -+ -+ dbg_gen("syncing inode %lu", inode->i_ino); -+ -+ /* Synchronize the inode and dirty pages */ -+ err = write_inode_now(inode, 1); -+ if (err) -+ return err; -+ -+ /* -+ * Some data related to this inode may still sit in a write-buffer. -+ * Flush them. -+ */ -+ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/** -+ * mctime_update_needed - check if mtime or ctime update is needed. -+ * @inode: the inode to do the check for -+ * @now: current time -+ * -+ * This helper function checks if the inode mtime/ctime should be updated or -+ * not. If current values of the time-stamps are within the UBIFS inode time -+ * granularity, they are not updated. This is an optimization. -+ */ -+static inline int mctime_update_needed(struct inode *inode, -+ struct timespec *now) -+{ -+ if (!timespec_equal(&inode->i_mtime, now) || -+ !timespec_equal(&inode->i_ctime, now)) -+ return 1; -+ return 0; -+} -+ -+/** -+ * update_ctime - update mtime and ctime of an inode. -+ * @c: UBIFS file-system description object -+ * @inode: inode to update -+ * -+ * This function updates mtime and ctime of the inode if it is not equivalent to -+ * current time. Returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int update_mctime(struct ubifs_info *c, struct inode *inode) -+{ -+ struct timespec now = ubifs_current_time(inode); -+ -+ if (mctime_update_needed(inode, &now)) { -+ struct ubifs_budget_req req; -+ int err; -+ -+ memset(&req, 0, sizeof(struct ubifs_budget_req)); -+ err = ubifs_budget_inode_op(c, inode, &req); -+ if (err) -+ return err; -+ -+ inode->i_mtime = inode->i_ctime = now; -+ mark_inode_dirty_sync(inode); -+ mutex_unlock(&ubifs_inode(inode)->budg_mutex); -+ } -+ -+ return 0; -+} -+ -+static ssize_t ubifs_write(struct file *file, const char __user *buf, -+ size_t len, loff_t *ppos) -+{ -+ int err; -+ ssize_t ret; -+ struct inode *inode = file->f_mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ -+ err = update_mctime(c, inode); -+ if (err) -+ return err; -+ -+ ret = do_sync_write(file, buf, len, ppos); -+ if (ret < 0) -+ return ret; -+ -+ if (ret > 0 && IS_SYNC(inode)) { -+ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); -+ if (err) -+ return err; -+ } -+ -+ return ret; -+} -+ -+static ssize_t ubifs_aio_write(struct kiocb *iocb, const struct iovec *iov, -+ unsigned long nr_segs, loff_t pos) -+{ -+ int err; -+ ssize_t ret; -+ struct inode *inode = iocb->ki_filp->f_mapping->host; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ -+ err = update_mctime(c, inode); -+ if (err) -+ return err; -+ -+ ret = generic_file_aio_write(iocb, iov, nr_segs, pos); -+ if (ret < 0) -+ return ret; -+ -+ if (ret > 0 && IS_SYNC(inode)) { -+ err = ubifs_sync_wbufs_by_inodes(c, &inode, 1); -+ if (err) -+ return err; -+ } -+ -+ return ret; -+} -+ -+static int ubifs_set_page_dirty(struct page *page) -+{ -+ int ret; -+ -+ ret = __set_page_dirty_nobuffers(page); -+ /* -+ * An attempt to dirty a page without budgeting for it - should not -+ * happen. -+ */ -+ ubifs_assert(ret == 0); -+ return ret; -+} -+ -+static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags) -+{ -+ /* -+ * An attempt to release a dirty page without budgeting for it - should -+ * not happen. -+ */ -+ if (PageWriteback(page)) -+ return 0; -+ ubifs_assert(PagePrivate(page)); -+ ubifs_assert(0); -+ ClearPagePrivate(page); -+ ClearPageChecked(page); -+ return 1; -+} -+ -+#ifndef UBIFS_COMPAT_NO_SHARED_MMAP -+ -+/* -+ * mmap()d file has taken write protection fault and is being made -+ * writable. UBIFS must ensure page is budgeted for. -+ */ -+static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct page *page) -+{ -+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct timespec now = ubifs_current_time(inode); -+ struct ubifs_budget_req req = { .new_page = 1 }; -+ int err, update_time; -+ -+ dbg_gen("ino %lu, pg %lu, i_size %lld", inode->i_ino, page->index, -+ i_size_read(inode)); -+ ubifs_assert(!(inode->i_sb->s_flags & MS_RDONLY)); -+ -+ if (unlikely(c->ro_media)) -+ return -EROFS; -+ -+ /* -+ * We have not locked @page so far so we may budget for changing the -+ * page. Note, we cannot do this after we locked the page, because -+ * budgeting may cause write-back which would cause deadlock. -+ * -+ * At the moment we do not know whether the page is dirty or not, so we -+ * assume that it is not and budget for a new page. We could look at -+ * the @PG_private flag and figure this out, but we may race with write -+ * back and the page state may change by the time we lock it, so this -+ * would need additional care. We do not bother with this at the -+ * moment, although it might be good idea to do. Instead, we allocate -+ * budget for a new page and amend it later on if the page was in fact -+ * dirty. -+ * -+ * The budgeting-related logic of this function is similar to what we -+ * do in 'ubifs_write_begin()' and 'ubifs_write_end()'. Glance there -+ * for more comments. -+ */ -+ if (mctime_update_needed(inode, &now)) { -+ /* -+ * We have to change inode time stamp which requires extra -+ * budgeting. -+ */ -+ update_time = 1; -+ err = ubifs_budget_inode_op(c, inode, &req); -+ } else { -+ update_time = 0; -+ err = ubifs_budget_space(c, &req); -+ } -+ if (unlikely(err)) { -+ if (err == -ENOSPC) -+ ubifs_warn("out of space for mmapped file " -+ "(inode number %lu)", inode->i_ino); -+ return err; -+ } -+ -+ lock_page(page); -+ if (unlikely(page->mapping != inode->i_mapping || -+ page_offset(page) > i_size_read(inode))) { -+ /* Page got truncated out from underneath us */ -+ err = -EINVAL; -+ goto out_unlock; -+ } -+ -+ if (PagePrivate(page)) -+ ubifs_release_new_page_budget(c); -+ else { -+ if (!PageChecked(page)) -+ ubifs_convert_page_budget(c); -+ SetPagePrivate(page); -+ atomic_long_inc(&c->dirty_pg_cnt); -+ __set_page_dirty_nobuffers(page); -+ } -+ -+ if (update_time) { -+ inode->i_mtime = inode->i_ctime = now; -+ mark_inode_dirty_sync(inode); -+ mutex_unlock(&ubifs_inode(inode)->budg_mutex); -+ } -+ -+ unlock_page(page); -+ return 0; -+ -+out_unlock: -+ unlock_page(page); -+ if (update_time) -+ ubifs_cancel_ino_op(c, inode, &req); -+ else -+ ubifs_release_budget(c, &req); -+ return err; -+} -+ -+struct vm_operations_struct ubifs_file_vm_ops = { -+#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,22)) -+ .nopage = filemap_nopage, -+#else -+ .fault = filemap_fault, -+#endif -+ .page_mkwrite = ubifs_vm_page_mkwrite, -+}; -+ -+static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ int err; -+ -+ /* 'generic_file_mmap()' takes care of NOMMU case */ -+ err = generic_file_mmap(file, vma); -+ if (err) -+ return err; -+ vma->vm_ops = &ubifs_file_vm_ops; -+ return 0; -+} -+#endif -+ -+struct address_space_operations ubifs_file_address_operations = { -+ .readpage = ubifs_readpage, -+ .writepage = ubifs_writepage, -+/* TODO: remove compatibility stuff as late as possible */ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+ .prepare_write = ubifs_prepare_write, -+ .commit_write = ubifs_commit_write, -+#else -+ .write_begin = ubifs_write_begin, -+ .write_end = ubifs_write_end, -+#endif -+ .invalidatepage = ubifs_invalidatepage, -+ .set_page_dirty = ubifs_set_page_dirty, -+ .releasepage = ubifs_releasepage, -+}; -+ -+struct inode_operations ubifs_file_inode_operations = { -+ .setattr = ubifs_setattr, -+ .getattr = ubifs_getattr, -+#ifdef CONFIG_UBIFS_FS_XATTR -+ .setxattr = ubifs_setxattr, -+ .getxattr = ubifs_getxattr, -+ .listxattr = ubifs_listxattr, -+ .removexattr = ubifs_removexattr, -+#endif -+}; -+ -+struct inode_operations ubifs_symlink_inode_operations = { -+ .readlink = generic_readlink, -+ .follow_link = ubifs_follow_link, -+ .setattr = ubifs_setattr, -+ .getattr = ubifs_getattr, -+}; -+ -+struct file_operations ubifs_file_operations = { -+ .llseek = generic_file_llseek, -+ .read = do_sync_read, -+ .write = ubifs_write, -+ .aio_read = generic_file_aio_read, -+ .aio_write = ubifs_aio_write, -+ .mmap = ubifs_file_mmap, -+ .fsync = ubifs_fsync, -+ .unlocked_ioctl = ubifs_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = ubifs_compat_ioctl, -+#endif -+}; -diff -urN linux-2.6.24.7.old/fs/ubifs/find.c linux-2.6.24.7/fs/ubifs/find.c ---- linux-2.6.24.7.old/fs/ubifs/find.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/find.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,971 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file contains functions for finding LEBs for various purposes e.g. -+ * garbage collection. In general, lprops category heaps and lists are used -+ * for fast access, falling back on scanning the LPT as a last resort. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/** -+ * struct scan_data - data provided to scan callback functions -+ * @min_space: minimum number of bytes for which to scan -+ * @pick_free: whether it is OK to scan for empty LEBs -+ * @lnum: LEB number found is returned here -+ * @exclude_index: whether to exclude index LEBs -+ */ -+struct scan_data { -+ int min_space; -+ int pick_free; -+ int lnum; -+ int exclude_index; -+}; -+ -+/** -+ * valuable - determine whether LEB properties are valuable. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties -+ * -+ * This function return %1 if the LEB properties should be added to the LEB -+ * properties tree in memory. Otherwise %0 is returned. -+ */ -+static int valuable(struct ubifs_info *c, const struct ubifs_lprops *lprops) -+{ -+ int n, cat = lprops->flags & LPROPS_CAT_MASK; -+ struct ubifs_lpt_heap *heap; -+ -+ switch (cat) { -+ case LPROPS_DIRTY: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FREE: -+ heap = &c->lpt_heap[cat - 1]; -+ if (heap->cnt < heap->max_cnt) -+ return 1; -+ if (lprops->free + lprops->dirty >= c->dark_wm) -+ return 1; -+ return 0; -+ case LPROPS_EMPTY: -+ n = c->lst.empty_lebs + c->freeable_cnt - -+ c->lst.taken_empty_lebs; -+ if (n < c->lsave_cnt) -+ return 1; -+ return 0; -+ case LPROPS_FREEABLE: -+ return 1; -+ case LPROPS_FRDI_IDX: -+ return 1; -+ } -+ return 0; -+} -+ -+/** -+ * scan_for_dirty_cb - dirty space scan callback. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties to scan -+ * @in_tree: whether the LEB properties are in main memory -+ * @data: information passed to and from the caller of the scan -+ * -+ * This function returns a code that indicates whether the scan should continue -+ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree -+ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop -+ * (%LPT_SCAN_STOP). -+ */ -+static int scan_for_dirty_cb(struct ubifs_info *c, -+ const struct ubifs_lprops *lprops, int in_tree, -+ struct scan_data *data) -+{ -+ int ret = LPT_SCAN_CONTINUE; -+ -+ /* Exclude LEBs that are currently in use */ -+ if (lprops->flags & LPROPS_TAKEN) -+ return LPT_SCAN_CONTINUE; -+ /* Determine whether to add these LEB properties to the tree */ -+ if (!in_tree && valuable(c, lprops)) -+ ret |= LPT_SCAN_ADD; -+ /* Exclude LEBs with too little space */ -+ if (lprops->free + lprops->dirty < data->min_space) -+ return ret; -+ /* If specified, exclude index LEBs */ -+ if (data->exclude_index && lprops->flags & LPROPS_INDEX) -+ return ret; -+ /* If specified, exclude empty or freeable LEBs */ -+ if (!data->pick_free && lprops->free + lprops->dirty == c->leb_size) -+ return ret; -+ /* Exclude LEBs with too little dirty space (unless it is empty) */ -+ if (lprops->dirty < c->dead_wm && lprops->free != c->leb_size) -+ return ret; -+ /* Finally we found space */ -+ data->lnum = lprops->lnum; -+ return LPT_SCAN_ADD | LPT_SCAN_STOP; -+} -+ -+/** -+ * scan_for_dirty - find a data LEB with free space. -+ * @c: the UBIFS file-system description object -+ * @min_space: minimum amount free plus dirty space the returned LEB has to -+ * have -+ * @pick_free: if it is OK to return a free or freeable LEB -+ * @exclude_index: whether to exclude index LEBs -+ * -+ * This function returns a pointer to the LEB properties found or a negative -+ * error code. -+ */ -+static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c, -+ int min_space, int pick_free, -+ int exclude_index) -+{ -+ const struct ubifs_lprops *lprops; -+ struct ubifs_lpt_heap *heap; -+ struct scan_data data; -+ int err, i; -+ -+ /* There may be an LEB with enough dirty space on the free heap */ -+ heap = &c->lpt_heap[LPROPS_FREE - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ lprops = heap->arr[i]; -+ if (lprops->free + lprops->dirty < min_space) -+ continue; -+ if (lprops->dirty < c->dead_wm) -+ continue; -+ return lprops; -+ } -+ /* -+ * A LEB may have fallen off of the bottom of the dirty heap, and ended -+ * up as uncategorized even though it has enough dirty space for us now, -+ * so check the uncategorized list. N.B. neither empty nor freeable LEBs -+ * can end up as uncategorized because they are kept on lists not -+ * finite-sized heaps. -+ */ -+ list_for_each_entry(lprops, &c->uncat_list, list) { -+ if (lprops->flags & LPROPS_TAKEN) -+ continue; -+ if (lprops->free + lprops->dirty < min_space) -+ continue; -+ if (exclude_index && (lprops->flags & LPROPS_INDEX)) -+ continue; -+ if (lprops->dirty < c->dead_wm) -+ continue; -+ return lprops; -+ } -+ /* We have looked everywhere in main memory, now scan the flash */ -+ if (c->pnodes_have >= c->pnode_cnt) -+ /* All pnodes are in memory, so skip scan */ -+ return ERR_PTR(-ENOSPC); -+ data.min_space = min_space; -+ data.pick_free = pick_free; -+ data.lnum = -1; -+ data.exclude_index = exclude_index; -+ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, -+ (ubifs_lpt_scan_callback)scan_for_dirty_cb, -+ &data); -+ if (err) -+ return ERR_PTR(err); -+ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); -+ c->lscan_lnum = data.lnum; -+ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); -+ if (IS_ERR(lprops)) -+ return lprops; -+ ubifs_assert(lprops->lnum == data.lnum); -+ ubifs_assert(lprops->free + lprops->dirty >= min_space); -+ ubifs_assert(lprops->dirty >= c->dead_wm); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ return lprops; -+} -+ -+/** -+ * ubifs_find_dirty_leb - find a dirty LEB for the Garbage Collector. -+ * @c: the UBIFS file-system description object -+ * @ret_lp: LEB properties are returned here on exit -+ * @min_space: minimum amount free plus dirty space the returned LEB has to -+ * have -+ * @pick_free: controls whether it is OK to pick empty or index LEBs -+ * -+ * This function tries to find a dirty logical eraseblock which has at least -+ * @min_space free and dirty space. It prefers to take an LEB from the dirty or -+ * dirty index heap, and it falls-back to LPT scanning if the heaps are empty -+ * or do not have an LEB which satisfies the @min_space criteria. -+ * -+ * Note: -+ * o LEBs which have less than dead watermark of dirty space are never picked -+ * by this function; -+ * -+ * Returns zero and the LEB properties of -+ * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a -+ * negative error code in case of other failures. The returned LEB is marked as -+ * "taken". -+ * -+ * The additional @pick_free argument controls if this function has to return a -+ * free or freeable LEB if one is present. For example, GC must to set it to %1, -+ * when called from the journal space reservation function, because the -+ * appearance of free space may coincide with the loss of enough dirty space -+ * for GC to succeed anyway. -+ * -+ * In contrast, if the Garbage Collector is called from budgeting, it should -+ * just make free space, not return LEBs which are already free or freeable. -+ * -+ * In addition @pick_free is set to %2 by the recovery process in order to -+ * recover gc_lnum in which case an index LEB must not be returned. -+ */ -+int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, -+ int min_space, int pick_free) -+{ -+ int err = 0, sum, exclude_index = pick_free == 2 ? 1 : 0; -+ const struct ubifs_lprops *lp = NULL, *idx_lp = NULL; -+ struct ubifs_lpt_heap *heap, *idx_heap; -+ -+ ubifs_get_lprops(c); -+ -+ if (pick_free) { -+ int lebs, rsvd_idx_lebs = 0; -+ -+ spin_lock(&c->space_lock); -+ lebs = c->lst.empty_lebs; -+ lebs += c->freeable_cnt - c->lst.taken_empty_lebs; -+ -+ /* -+ * Note, the index may consume more LEBs than have been reserved -+ * for it. It is OK because it might be consolidated by GC. -+ * But if the index takes fewer LEBs than it is reserved for it, -+ * this function must avoid picking those reserved LEBs. -+ */ -+ if (c->min_idx_lebs >= c->lst.idx_lebs) { -+ rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs; -+ exclude_index = 1; -+ } -+ spin_unlock(&c->space_lock); -+ -+ /* Check if there are enough free LEBs for the index */ -+ if (rsvd_idx_lebs < lebs) { -+ /* OK, try to find an empty LEB */ -+ lp = ubifs_fast_find_empty(c); -+ if (lp) -+ goto found; -+ -+ /* Or a freeable LEB */ -+ lp = ubifs_fast_find_freeable(c); -+ if (lp) -+ goto found; -+ } else -+ /* -+ * We cannot pick free/freeable LEBs in the below code. -+ */ -+ pick_free = 0; -+ } else { -+ spin_lock(&c->space_lock); -+ exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs); -+ spin_unlock(&c->space_lock); -+ } -+ -+ /* Look on the dirty and dirty index heaps */ -+ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; -+ idx_heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; -+ -+ if (idx_heap->cnt && !exclude_index) { -+ idx_lp = idx_heap->arr[0]; -+ sum = idx_lp->free + idx_lp->dirty; -+ /* -+ * Since we reserve twice as more space for the index than it -+ * actually takes, it does not make sense to pick indexing LEBs -+ * with less than half LEB of dirty space. -+ */ -+ if (sum < min_space || sum < c->half_leb_size) -+ idx_lp = NULL; -+ } -+ -+ if (heap->cnt) { -+ lp = heap->arr[0]; -+ if (lp->dirty + lp->free < min_space) -+ lp = NULL; -+ } -+ -+ /* Pick the LEB with most space */ -+ if (idx_lp && lp) { -+ if (idx_lp->free + idx_lp->dirty >= lp->free + lp->dirty) -+ lp = idx_lp; -+ } else if (idx_lp && !lp) -+ lp = idx_lp; -+ -+ if (lp) { -+ ubifs_assert(lp->dirty >= c->dead_wm); -+ goto found; -+ } -+ -+ /* Did not find a dirty LEB on the dirty heaps, have to scan */ -+ dbg_find("scanning LPT for a dirty LEB"); -+ lp = scan_for_dirty(c, min_space, pick_free, exclude_index); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ ubifs_assert(lp->dirty >= c->dead_wm); -+ -+found: -+ dbg_find("found LEB %d, free %d, dirty %d, flags %#x", -+ lp->lnum, lp->free, lp->dirty, lp->flags); -+ -+ lp = ubifs_change_lp(c, lp, -1, -1, lp->flags | LPROPS_TAKEN, 0); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ memcpy(ret_lp, lp, sizeof(struct ubifs_lprops)); -+ -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * scan_for_free_cb - free space scan callback. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties to scan -+ * @in_tree: whether the LEB properties are in main memory -+ * @data: information passed to and from the caller of the scan -+ * -+ * This function returns a code that indicates whether the scan should continue -+ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree -+ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop -+ * (%LPT_SCAN_STOP). -+ */ -+static int scan_for_free_cb(struct ubifs_info *c, -+ const struct ubifs_lprops *lprops, int in_tree, -+ struct scan_data *data) -+{ -+ int ret = LPT_SCAN_CONTINUE; -+ -+ /* Exclude LEBs that are currently in use */ -+ if (lprops->flags & LPROPS_TAKEN) -+ return LPT_SCAN_CONTINUE; -+ /* Determine whether to add these LEB properties to the tree */ -+ if (!in_tree && valuable(c, lprops)) -+ ret |= LPT_SCAN_ADD; -+ /* Exclude index LEBs */ -+ if (lprops->flags & LPROPS_INDEX) -+ return ret; -+ /* Exclude LEBs with too little space */ -+ if (lprops->free < data->min_space) -+ return ret; -+ /* If specified, exclude empty LEBs */ -+ if (!data->pick_free && lprops->free == c->leb_size) -+ return ret; -+ /* -+ * LEBs that have only free and dirty space must not be allocated -+ * because they may have been unmapped already or they may have data -+ * that is obsolete only because of nodes that are still sitting in a -+ * wbuf. -+ */ -+ if (lprops->free + lprops->dirty == c->leb_size && lprops->dirty > 0) -+ return ret; -+ /* Finally we found space */ -+ data->lnum = lprops->lnum; -+ return LPT_SCAN_ADD | LPT_SCAN_STOP; -+} -+ -+/** -+ * do_find_free_space - find a data LEB with free space. -+ * @c: the UBIFS file-system description object -+ * @min_space: minimum amount of free space required -+ * @pick_free: whether it is OK to scan for empty LEBs -+ * @squeeze: whether to try to find space in a non-empty LEB first -+ * -+ * This function returns a pointer to the LEB properties found or a negative -+ * error code. -+ */ -+static -+const struct ubifs_lprops *do_find_free_space(struct ubifs_info *c, -+ int min_space, int pick_free, -+ int squeeze) -+{ -+ const struct ubifs_lprops *lprops; -+ struct ubifs_lpt_heap *heap; -+ struct scan_data data; -+ int err, i; -+ -+ if (squeeze) { -+ lprops = ubifs_fast_find_free(c); -+ if (lprops && lprops->free >= min_space) -+ return lprops; -+ } -+ if (pick_free) { -+ lprops = ubifs_fast_find_empty(c); -+ if (lprops) -+ return lprops; -+ } -+ if (!squeeze) { -+ lprops = ubifs_fast_find_free(c); -+ if (lprops && lprops->free >= min_space) -+ return lprops; -+ } -+ /* There may be an LEB with enough free space on the dirty heap */ -+ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ lprops = heap->arr[i]; -+ if (lprops->free >= min_space) -+ return lprops; -+ } -+ /* -+ * A LEB may have fallen off of the bottom of the free heap, and ended -+ * up as uncategorized even though it has enough free space for us now, -+ * so check the uncategorized list. N.B. neither empty nor freeable LEBs -+ * can end up as uncategorized because they are kept on lists not -+ * finite-sized heaps. -+ */ -+ list_for_each_entry(lprops, &c->uncat_list, list) { -+ if (lprops->flags & LPROPS_TAKEN) -+ continue; -+ if (lprops->flags & LPROPS_INDEX) -+ continue; -+ if (lprops->free >= min_space) -+ return lprops; -+ } -+ /* We have looked everywhere in main memory, now scan the flash */ -+ if (c->pnodes_have >= c->pnode_cnt) -+ /* All pnodes are in memory, so skip scan */ -+ return ERR_PTR(-ENOSPC); -+ data.min_space = min_space; -+ data.pick_free = pick_free; -+ data.lnum = -1; -+ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, -+ (ubifs_lpt_scan_callback)scan_for_free_cb, -+ &data); -+ if (err) -+ return ERR_PTR(err); -+ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); -+ c->lscan_lnum = data.lnum; -+ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); -+ if (IS_ERR(lprops)) -+ return lprops; -+ ubifs_assert(lprops->lnum == data.lnum); -+ ubifs_assert(lprops->free >= min_space); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ return lprops; -+} -+ -+/** -+ * ubifs_find_free_space - find a data LEB with free space. -+ * @c: the UBIFS file-system description object -+ * @min_space: minimum amount of required free space -+ * @free: contains amount of free space in the LEB on exit -+ * @squeeze: whether to try to find space in a non-empty LEB first -+ * -+ * This function looks for an LEB with at least @min_space bytes of free space. -+ * It tries to find an empty LEB if possible. If no empty LEBs are available, -+ * this function searches for a non-empty data LEB. The returned LEB is marked -+ * as "taken". -+ * -+ * This function returns found LEB number in case of success, %-ENOSPC if it -+ * failed to find a LEB with @min_space bytes of free space and other a negative -+ * error codes in case of failure. -+ */ -+int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free, -+ int squeeze) -+{ -+ const struct ubifs_lprops *lprops; -+ int lebs, rsvd_idx_lebs, pick_free = 0, err, lnum, flags; -+ -+ dbg_find("min_space %d", min_space); -+ ubifs_assert(min_space > 0 && min_space <= c->dark_wm); -+ -+ ubifs_get_lprops(c); -+ -+ /* Check if there are enough empty LEBs for commit */ -+ spin_lock(&c->space_lock); -+ if (c->min_idx_lebs > c->lst.idx_lebs) -+ rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs; -+ else -+ rsvd_idx_lebs = 0; -+ lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - -+ c->lst.taken_empty_lebs; -+ ubifs_assert(lebs + c->lst.idx_lebs >= c->min_idx_lebs); -+ if (rsvd_idx_lebs < lebs) -+ /* -+ * OK to allocate an empty LEB, but we still don't want to go -+ * looking for one if there aren't any. -+ */ -+ if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { -+ pick_free = 1; -+ /* -+ * Because we release the space lock, we must account -+ * for this allocation here. After the LEB properties -+ * flags have been updated, we subtract one. Note, the -+ * result of this is that lprops also decreases -+ * @taken_empty_lebs in 'ubifs_change_lp()', so it is -+ * off by one for a short period of time which may -+ * introduce a small disturbance to budgeting -+ * calculations, but this is harmless because at the -+ * worst case this would make the budgeting subsystem -+ * be more pessimistic than needed. -+ * -+ * Fundamentally, this is about serialization of the -+ * budgeting and lprops subsystems. We could make the -+ * @space_lock a mutex and avoid dropping it before -+ * calling 'ubifs_change_lp()', but mutex is more -+ * heavy-weight, and we want budgeting to be as fast as -+ * possible. -+ */ -+ c->lst.taken_empty_lebs += 1; -+ } -+ spin_unlock(&c->space_lock); -+ -+ lprops = do_find_free_space(c, min_space, pick_free, squeeze); -+ if (IS_ERR(lprops)) { -+ err = PTR_ERR(lprops); -+ goto out; -+ } -+ -+ lnum = lprops->lnum; -+ flags = lprops->flags | LPROPS_TAKEN; -+ -+ lprops = ubifs_change_lp(c, lprops, -1, -1, flags, 0); -+ if (IS_ERR(lprops)) { -+ err = PTR_ERR(lprops); -+ goto out; -+ } -+ -+ if (pick_free) { -+ spin_lock(&c->space_lock); -+ c->lst.taken_empty_lebs -= 1; -+ spin_unlock(&c->space_lock); -+ } -+ -+ *free = lprops->free; -+ ubifs_release_lprops(c); -+ -+ if (*free == c->leb_size) { -+ /* -+ * Ensure that empty LEBs have been unmapped. They may not have -+ * been, for example, because of an unclean unmount. Also -+ * LEBs that were freeable LEBs (free + dirty == leb_size) will -+ * not have been unmapped. -+ */ -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ -+ dbg_find("found LEB %d, free %d", lnum, *free); -+ ubifs_assert(*free >= min_space); -+ return lnum; -+ -+out: -+ if (pick_free) { -+ spin_lock(&c->space_lock); -+ c->lst.taken_empty_lebs -= 1; -+ spin_unlock(&c->space_lock); -+ } -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * scan_for_idx_cb - callback used by the scan for a free LEB for the index. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties to scan -+ * @in_tree: whether the LEB properties are in main memory -+ * @data: information passed to and from the caller of the scan -+ * -+ * This function returns a code that indicates whether the scan should continue -+ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree -+ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop -+ * (%LPT_SCAN_STOP). -+ */ -+static int scan_for_idx_cb(struct ubifs_info *c, -+ const struct ubifs_lprops *lprops, int in_tree, -+ struct scan_data *data) -+{ -+ int ret = LPT_SCAN_CONTINUE; -+ -+ /* Exclude LEBs that are currently in use */ -+ if (lprops->flags & LPROPS_TAKEN) -+ return LPT_SCAN_CONTINUE; -+ /* Determine whether to add these LEB properties to the tree */ -+ if (!in_tree && valuable(c, lprops)) -+ ret |= LPT_SCAN_ADD; -+ /* Exclude index LEBS */ -+ if (lprops->flags & LPROPS_INDEX) -+ return ret; -+ /* Exclude LEBs that cannot be made empty */ -+ if (lprops->free + lprops->dirty != c->leb_size) -+ return ret; -+ /* -+ * We are allocating for the index so it is safe to allocate LEBs with -+ * only free and dirty space, because write buffers are sync'd at commit -+ * start. -+ */ -+ data->lnum = lprops->lnum; -+ return LPT_SCAN_ADD | LPT_SCAN_STOP; -+} -+ -+/** -+ * scan_for_leb_for_idx - scan for a free LEB for the index. -+ * @c: the UBIFS file-system description object -+ */ -+static const struct ubifs_lprops *scan_for_leb_for_idx(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ struct scan_data data; -+ int err; -+ -+ data.lnum = -1; -+ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, -+ (ubifs_lpt_scan_callback)scan_for_idx_cb, -+ &data); -+ if (err) -+ return ERR_PTR(err); -+ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); -+ c->lscan_lnum = data.lnum; -+ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); -+ if (IS_ERR(lprops)) -+ return lprops; -+ ubifs_assert(lprops->lnum == data.lnum); -+ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ return lprops; -+} -+ -+/** -+ * ubifs_find_free_leb_for_idx - find a free LEB for the index. -+ * @c: the UBIFS file-system description object -+ * -+ * This function looks for a free LEB and returns that LEB number. The returned -+ * LEB is marked as "taken", "index". -+ * -+ * Only empty LEBs are allocated. This is for two reasons. First, the commit -+ * calculates the number of LEBs to allocate based on the assumption that they -+ * will be empty. Secondly, free space at the end of an index LEB is not -+ * guaranteed to be empty because it may have been used by the in-the-gaps -+ * method prior to an unclean unmount. -+ * -+ * If no LEB is found %-ENOSPC is returned. For other failures another negative -+ * error code is returned. -+ */ -+int ubifs_find_free_leb_for_idx(struct ubifs_info *c) -+{ -+ const struct ubifs_lprops *lprops; -+ int lnum = -1, err, flags; -+ -+ ubifs_get_lprops(c); -+ -+ lprops = ubifs_fast_find_empty(c); -+ if (!lprops) { -+ lprops = ubifs_fast_find_freeable(c); -+ if (!lprops) { -+ ubifs_assert(c->freeable_cnt == 0); -+ if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) { -+ lprops = scan_for_leb_for_idx(c); -+ if (IS_ERR(lprops)) { -+ err = PTR_ERR(lprops); -+ goto out; -+ } -+ } -+ } -+ } -+ -+ if (!lprops) { -+ err = -ENOSPC; -+ goto out; -+ } -+ -+ lnum = lprops->lnum; -+ -+ dbg_find("found LEB %d, free %d, dirty %d, flags %#x", -+ lnum, lprops->free, lprops->dirty, lprops->flags); -+ -+ flags = lprops->flags | LPROPS_TAKEN | LPROPS_INDEX; -+ lprops = ubifs_change_lp(c, lprops, c->leb_size, 0, flags, 0); -+ if (IS_ERR(lprops)) { -+ err = PTR_ERR(lprops); -+ goto out; -+ } -+ -+ ubifs_release_lprops(c); -+ -+ /* -+ * Ensure that empty LEBs have been unmapped. They may not have been, -+ * for example, because of an unclean unmount. Also LEBs that were -+ * freeable LEBs (free + dirty == leb_size) will not have been unmapped. -+ */ -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) { -+ ubifs_change_one_lp(c, lnum, -1, -1, 0, -+ LPROPS_TAKEN | LPROPS_INDEX, 0); -+ return err; -+ } -+ -+ return lnum; -+ -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+static int cmp_dirty_idx(const struct ubifs_lprops **a, -+ const struct ubifs_lprops **b) -+{ -+ const struct ubifs_lprops *lpa = *a; -+ const struct ubifs_lprops *lpb = *b; -+ -+ return lpa->dirty + lpa->free - lpb->dirty - lpb->free; -+} -+ -+static void swap_dirty_idx(struct ubifs_lprops **a, struct ubifs_lprops **b, -+ int size) -+{ -+ struct ubifs_lprops *t = *a; -+ -+ *a = *b; -+ *b = t; -+} -+ -+/** -+ * ubifs_save_dirty_idx_lnums - save an array of the most dirty index LEB nos. -+ * @c: the UBIFS file-system description object -+ * -+ * This function is called each commit to create an array of LEB numbers of -+ * dirty index LEBs sorted in order of dirty and free space. This is used by -+ * the in-the-gaps method of TNC commit. -+ */ -+int ubifs_save_dirty_idx_lnums(struct ubifs_info *c) -+{ -+ int i; -+ -+ ubifs_get_lprops(c); -+ /* Copy the LPROPS_DIRTY_IDX heap */ -+ c->dirty_idx.cnt = c->lpt_heap[LPROPS_DIRTY_IDX - 1].cnt; -+ memcpy(c->dirty_idx.arr, c->lpt_heap[LPROPS_DIRTY_IDX - 1].arr, -+ sizeof(void *) * c->dirty_idx.cnt); -+ /* Sort it so that the dirtiest is now at the end */ -+ sort(c->dirty_idx.arr, c->dirty_idx.cnt, sizeof(void *), -+ (int (*)(const void *, const void *))cmp_dirty_idx, -+ (void (*)(void *, void *, int))swap_dirty_idx); -+ dbg_find("found %d dirty index LEBs", c->dirty_idx.cnt); -+ if (c->dirty_idx.cnt) -+ dbg_find("dirtiest index LEB is %d with dirty %d and free %d", -+ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->lnum, -+ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->dirty, -+ c->dirty_idx.arr[c->dirty_idx.cnt - 1]->free); -+ /* Replace the lprops pointers with LEB numbers */ -+ for (i = 0; i < c->dirty_idx.cnt; i++) -+ c->dirty_idx.arr[i] = (void *)(size_t)c->dirty_idx.arr[i]->lnum; -+ ubifs_release_lprops(c); -+ return 0; -+} -+ -+/** -+ * scan_dirty_idx_cb - callback used by the scan for a dirty index LEB. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties to scan -+ * @in_tree: whether the LEB properties are in main memory -+ * @data: information passed to and from the caller of the scan -+ * -+ * This function returns a code that indicates whether the scan should continue -+ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree -+ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop -+ * (%LPT_SCAN_STOP). -+ */ -+static int scan_dirty_idx_cb(struct ubifs_info *c, -+ const struct ubifs_lprops *lprops, int in_tree, -+ struct scan_data *data) -+{ -+ int ret = LPT_SCAN_CONTINUE; -+ -+ /* Exclude LEBs that are currently in use */ -+ if (lprops->flags & LPROPS_TAKEN) -+ return LPT_SCAN_CONTINUE; -+ /* Determine whether to add these LEB properties to the tree */ -+ if (!in_tree && valuable(c, lprops)) -+ ret |= LPT_SCAN_ADD; -+ /* Exclude non-index LEBs */ -+ if (!(lprops->flags & LPROPS_INDEX)) -+ return ret; -+ /* Exclude LEBs with too little space */ -+ if (lprops->free + lprops->dirty < c->min_idx_node_sz) -+ return ret; -+ /* Finally we found space */ -+ data->lnum = lprops->lnum; -+ return LPT_SCAN_ADD | LPT_SCAN_STOP; -+} -+ -+/** -+ * find_dirty_idx_leb - find a dirty index LEB. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns LEB number upon success and a negative error code upon -+ * failure. In particular, -ENOSPC is returned if a dirty index LEB is not -+ * found. -+ * -+ * Note that this function scans the entire LPT but it is called very rarely. -+ */ -+static int find_dirty_idx_leb(struct ubifs_info *c) -+{ -+ const struct ubifs_lprops *lprops; -+ struct ubifs_lpt_heap *heap; -+ struct scan_data data; -+ int err, i, ret; -+ -+ /* Check all structures in memory first */ -+ data.lnum = -1; -+ heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ lprops = heap->arr[i]; -+ ret = scan_dirty_idx_cb(c, lprops, 1, &data); -+ if (ret & LPT_SCAN_STOP) -+ goto found; -+ } -+ list_for_each_entry(lprops, &c->frdi_idx_list, list) { -+ ret = scan_dirty_idx_cb(c, lprops, 1, &data); -+ if (ret & LPT_SCAN_STOP) -+ goto found; -+ } -+ list_for_each_entry(lprops, &c->uncat_list, list) { -+ ret = scan_dirty_idx_cb(c, lprops, 1, &data); -+ if (ret & LPT_SCAN_STOP) -+ goto found; -+ } -+ if (c->pnodes_have >= c->pnode_cnt) -+ /* All pnodes are in memory, so skip scan */ -+ return -ENOSPC; -+ err = ubifs_lpt_scan_nolock(c, -1, c->lscan_lnum, -+ (ubifs_lpt_scan_callback)scan_dirty_idx_cb, -+ &data); -+ if (err) -+ return err; -+found: -+ ubifs_assert(data.lnum >= c->main_first && data.lnum < c->leb_cnt); -+ c->lscan_lnum = data.lnum; -+ lprops = ubifs_lpt_lookup_dirty(c, data.lnum); -+ if (IS_ERR(lprops)) -+ return PTR_ERR(lprops); -+ ubifs_assert(lprops->lnum == data.lnum); -+ ubifs_assert(lprops->free + lprops->dirty >= c->min_idx_node_sz); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert((lprops->flags & LPROPS_INDEX)); -+ -+ dbg_find("found dirty LEB %d, free %d, dirty %d, flags %#x", -+ lprops->lnum, lprops->free, lprops->dirty, lprops->flags); -+ -+ lprops = ubifs_change_lp(c, lprops, -1, -1, -+ lprops->flags | LPROPS_TAKEN, 0); -+ if (IS_ERR(lprops)) -+ return PTR_ERR(lprops); -+ -+ return lprops->lnum; -+} -+ -+/** -+ * get_idx_gc_leb - try to get a LEB number from trivial GC. -+ * @c: the UBIFS file-system description object -+ */ -+static int get_idx_gc_leb(struct ubifs_info *c) -+{ -+ const struct ubifs_lprops *lp; -+ int err, lnum; -+ -+ err = ubifs_get_idx_gc_leb(c); -+ if (err < 0) -+ return err; -+ lnum = err; -+ /* -+ * The LEB was due to be unmapped after the commit but -+ * it is needed now for this commit. -+ */ -+ lp = ubifs_lpt_lookup_dirty(c, lnum); -+ if (unlikely(IS_ERR(lp))) -+ return PTR_ERR(lp); -+ lp = ubifs_change_lp(c, lp, -1, -1, lp->flags | LPROPS_INDEX, -1); -+ if (unlikely(IS_ERR(lp))) -+ return PTR_ERR(lp); -+ dbg_find("LEB %d, dirty %d and free %d flags %#x", -+ lp->lnum, lp->dirty, lp->free, lp->flags); -+ return lnum; -+} -+ -+/** -+ * find_dirtiest_idx_leb - find dirtiest index LEB from dirtiest array. -+ * @c: the UBIFS file-system description object -+ */ -+static int find_dirtiest_idx_leb(struct ubifs_info *c) -+{ -+ const struct ubifs_lprops *lp; -+ int lnum; -+ -+ while (1) { -+ if (!c->dirty_idx.cnt) -+ return -ENOSPC; -+ /* The lprops pointers were replaced by LEB numbers */ -+ lnum = (size_t)c->dirty_idx.arr[--c->dirty_idx.cnt]; -+ lp = ubifs_lpt_lookup(c, lnum); -+ if (IS_ERR(lp)) -+ return PTR_ERR(lp); -+ if ((lp->flags & LPROPS_TAKEN) || !(lp->flags & LPROPS_INDEX)) -+ continue; -+ lp = ubifs_change_lp(c, lp, -1, -1, -+ lp->flags | LPROPS_TAKEN, 0); -+ if (IS_ERR(lp)) -+ return PTR_ERR(lp); -+ break; -+ } -+ dbg_find("LEB %d, dirty %d and free %d flags %#x", lp->lnum, lp->dirty, -+ lp->free, lp->flags); -+ ubifs_assert(lp->flags | LPROPS_TAKEN); -+ ubifs_assert(lp->flags | LPROPS_INDEX); -+ return lnum; -+} -+ -+/** -+ * ubifs_find_dirty_idx_leb - try to find dirtiest index LEB as at last commit. -+ * @c: the UBIFS file-system description object -+ * -+ * This function attempts to find an untaken index LEB with the most free and -+ * dirty space that can be used without overwriting index nodes that were in the -+ * last index committed. -+ */ -+int ubifs_find_dirty_idx_leb(struct ubifs_info *c) -+{ -+ int err; -+ -+ ubifs_get_lprops(c); -+ -+ /* -+ * We made an array of the dirtiest index LEB numbers as at the start of -+ * last commit. Try that array first. -+ */ -+ err = find_dirtiest_idx_leb(c); -+ -+ /* Next try scanning the entire LPT */ -+ if (err == -ENOSPC) -+ err = find_dirty_idx_leb(c); -+ -+ /* Finally take any index LEBs awaiting trivial GC */ -+ if (err == -ENOSPC) -+ err = get_idx_gc_leb(c); -+ -+ ubifs_release_lprops(c); -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/gc.c linux-2.6.24.7/fs/ubifs/gc.c ---- linux-2.6.24.7.old/fs/ubifs/gc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/gc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,762 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements garbage collection. The procedure for garbage collection -+ * is different depending on whether a LEB as an index LEB (contains index -+ * nodes) or not. For non-index LEBs, garbage collection finds a LEB which -+ * contains a lot of dirty space (obsolete nodes), and copies the non-obsolete -+ * nodes to the journal, at which point the garbage-collected LEB is free to be -+ * reused. For index LEBs, garbage collection marks the non-obsolete index nodes -+ * dirty in the TNC, and after the next commit, the garbage-collected LEB is -+ * to be reused. Garbage collection will cause the number of dirty index nodes -+ * to grow, however sufficient space is reserved for the index to ensure the -+ * commit will never run out of space. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/* -+ * GC tries to optimize the way it fit nodes to available space, and it sorts -+ * nodes a little. The below constants are watermarks which define "large", -+ * "medium", and "small" nodes. -+ */ -+#define MEDIUM_NODE_WM (UBIFS_BLOCK_SIZE / 4) -+#define SMALL_NODE_WM UBIFS_MAX_DENT_NODE_SZ -+ -+/* -+ * GC may need to move more then one LEB to make progress. The below constants -+ * define "soft" and "hard" limits on the number of LEBs the garbage collector -+ * may move. -+ */ -+#define SOFT_LEBS_LIMIT 4 -+#define HARD_LEBS_LIMIT 32 -+ -+/** -+ * switch_gc_head - switch the garbage collection journal head. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to write -+ * @len: length of the buffer to write -+ * @lnum: LEB number written is returned here -+ * @offs: offset written is returned here -+ * -+ * This function switch the GC head to the next LEB which is reserved in -+ * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required, -+ * and other negative error code in case of failures. -+ */ -+static int switch_gc_head(struct ubifs_info *c) -+{ -+ int err, gc_lnum = c->gc_lnum; -+ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; -+ -+ ubifs_assert(gc_lnum != -1); -+ dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)", -+ wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum, -+ c->leb_size - wbuf->offs - wbuf->used); -+ -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ if (err) -+ return err; -+ -+ /* -+ * The GC write-buffer was synchronized, we may safely unmap -+ * 'c->gc_lnum'. -+ */ -+ err = ubifs_leb_unmap(c, gc_lnum); -+ if (err) -+ return err; -+ -+ err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); -+ if (err) -+ return err; -+ -+ c->gc_lnum = -1; -+ err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM); -+ return err; -+} -+ -+/** -+ * move_nodes - move nodes. -+ * @c: UBIFS file-system description object -+ * @sleb: describes nodes to move -+ * -+ * This function moves valid nodes from data LEB described by @sleb to the GC -+ * journal head. The obsolete nodes are dropped. -+ * -+ * When moving nodes we have to deal with classical bin-packing problem: the -+ * space in the current GC journal head LEB and in @c->gc_lnum are the "bins", -+ * where the nodes in the @sleb->nodes list are the elements which should be -+ * fit optimally to the bins. This function uses the "first fit decreasing" -+ * strategy, although it does not really sort the nodes but just split them on -+ * 3 classes - large, medium, and small, so they are roughly sorted. -+ * -+ * This function returns zero in case of success, %-EAGAIN if commit is -+ * required, and other negative error codes in case of other failures. -+ */ -+static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) -+{ -+ struct ubifs_scan_node *snod, *tmp; -+ struct list_head large, medium, small; -+ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; -+ int avail, err, min = INT_MAX; -+ -+ INIT_LIST_HEAD(&large); -+ INIT_LIST_HEAD(&medium); -+ INIT_LIST_HEAD(&small); -+ -+ list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { -+ struct list_head *lst; -+ -+ ubifs_assert(snod->type != UBIFS_IDX_NODE); -+ ubifs_assert(snod->type != UBIFS_REF_NODE); -+ ubifs_assert(snod->type != UBIFS_CS_NODE); -+ -+ err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum, -+ snod->offs, 0); -+ if (err < 0) -+ goto out; -+ -+ lst = &snod->list; -+ list_del(lst); -+ if (!err) { -+ /* The node is obsolete, remove it from the list */ -+ kfree(snod); -+ continue; -+ } -+ -+ /* -+ * Sort the list of nodes so that large nodes go first, and -+ * small nodes go last. -+ */ -+ if (snod->len > MEDIUM_NODE_WM) -+ list_add(lst, &large); -+ else if (snod->len > SMALL_NODE_WM) -+ list_add(lst, &medium); -+ else -+ list_add(lst, &small); -+ -+ /* And find the smallest node */ -+ if (snod->len < min) -+ min = snod->len; -+ } -+ -+ /* -+ * Join the tree lists so that we'd have one roughly sorted list -+ * ('large' will be the head of the joined list). -+ */ -+ list_splice(&medium, large.prev); -+ list_splice(&small, large.prev); -+ -+ if (wbuf->lnum == -1) { -+ /* -+ * The GC journal head is not set, because it is the first GC -+ * invocation since mount. -+ */ -+ err = switch_gc_head(c); -+ if (err) -+ goto out; -+ } -+ -+ /* Write nodes to their new location. Use the first-fit strategy */ -+ while (1) { -+ avail = c->leb_size - wbuf->offs - wbuf->used; -+ list_for_each_entry_safe(snod, tmp, &large, list) { -+ int new_lnum, new_offs; -+ -+ if (avail < min) -+ break; -+ -+ if (snod->len > avail) -+ /* This node does not fit */ -+ continue; -+ -+ cond_resched(); -+ -+ new_lnum = wbuf->lnum; -+ new_offs = wbuf->offs + wbuf->used; -+ err = ubifs_wbuf_write_nolock(wbuf, snod->node, -+ snod->len); -+ -+ err = ubifs_tnc_replace(c, &snod->key, sleb->lnum, -+ snod->offs, new_lnum, new_offs, -+ snod->len); -+ if (err) -+ goto out; -+ -+ avail = c->leb_size - wbuf->offs - wbuf->used; -+ list_del(&snod->list); -+ kfree(snod); -+ } -+ -+ if (list_empty(&large)) -+ break; -+ -+ /* -+ * Waste the rest of the space in the LEB and switch to the -+ * next LEB. -+ */ -+ err = switch_gc_head(c); -+ if (err) -+ goto out; -+ } -+ -+ return 0; -+ -+out: -+ list_for_each_entry_safe(snod, tmp, &large, list) { -+ list_del(&snod->list); -+ kfree(snod); -+ } -+ return err; -+} -+ -+/** -+ * gc_sync_wbufs - sync write-buffers for GC. -+ * @c: UBIFS file-system description object -+ * -+ * We must guarantee that obsoleting nodes are on flash. Unfortunately they may -+ * be in a write-buffer instead. That is, a node could be written to a -+ * write-buffer, obsoleting another node in a LEB that is GC'd. If that LEB is -+ * erased before the write-buffer is sync'd and then there is an unclean -+ * unmount, then an existing node is lost. To avoid this, we sync all -+ * write-buffers. -+ * -+ * This function returns %0 on success or a negative error code on failure. -+ */ -+static int gc_sync_wbufs(struct ubifs_info *c) -+{ -+ int err, i; -+ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ if (i == GCHD) -+ continue; -+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ if (err) -+ return err; -+ } -+ return 0; -+} -+ -+/** -+ * ubifs_garbage_collect_leb - garbage-collect a logical eraseblock. -+ * @c: UBIFS file-system description object -+ * @lp: describes the LEB to garbage collect -+ * -+ * This function garbage-collects an LEB and returns one of the @LEB_FREED, -+ * @LEB_RETAINED, etc positive codes in case of success, %-EAGAIN if commit is -+ * required, and other negative error codes in case of failures. -+ */ -+int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; -+ int err = 0, lnum = lp->lnum; -+ -+ ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 || -+ c->need_recovery); -+ ubifs_assert(c->gc_lnum != lnum); -+ ubifs_assert(wbuf->lnum != lnum); -+ -+ /* -+ * We scan the entire LEB even though we only really need to scan up to -+ * (c->leb_size - lp->free). -+ */ -+ sleb = ubifs_scan(c, lnum, 0, c->sbuf); -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ -+ ubifs_assert(!list_empty(&sleb->nodes)); -+ snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); -+ -+ if (snod->type == UBIFS_IDX_NODE) { -+ struct ubifs_gced_idx_leb *idx_gc; -+ -+ dbg_gc("indexing LEB %d (free %d, dirty %d)", -+ lnum, lp->free, lp->dirty); -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ struct ubifs_idx_node *idx = snod->node; -+ int level = le16_to_cpu(idx->level); -+ -+ ubifs_assert(snod->type == UBIFS_IDX_NODE); -+ key_read(c, ubifs_idx_key(c, idx), &snod->key); -+ err = ubifs_dirty_idx_node(c, &snod->key, level, lnum, -+ snod->offs); -+ if (err) -+ goto out; -+ } -+ -+ idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); -+ if (!idx_gc) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ idx_gc->lnum = lnum; -+ idx_gc->unmap = 0; -+ list_add(&idx_gc->list, &c->idx_gc); -+ -+ /* -+ * Don't release the LEB until after the next commit, because -+ * it may contain date which is needed for recovery. So -+ * although we freed this LEB, it will become usable only after -+ * the commit. -+ */ -+ err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, -+ LPROPS_INDEX, 1); -+ if (err) -+ goto out; -+ err = LEB_FREED_IDX; -+ } else { -+ dbg_gc("data LEB %d (free %d, dirty %d)", -+ lnum, lp->free, lp->dirty); -+ -+ err = move_nodes(c, sleb); -+ if (err) -+ goto out; -+ -+ err = gc_sync_wbufs(c); -+ if (err) -+ goto out; -+ -+ err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0); -+ if (err) -+ goto out; -+ -+ if (c->gc_lnum == -1) { -+ c->gc_lnum = lnum; -+ err = LEB_RETAINED; -+ } else { -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ if (err) -+ goto out; -+ -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ goto out; -+ -+ err = LEB_FREED; -+ } -+ } -+ -+out: -+ ubifs_scan_destroy(sleb); -+ return err; -+} -+ -+/** -+ * ubifs_garbage_collect - UBIFS garbage collector. -+ * @c: UBIFS file-system description object -+ * @anyway: do GC even if there are free LEBs -+ * -+ * This function does out-of-place garbage collection. The return codes are: -+ * o positive LEB number if the LEB has been freed and may be used; -+ * o %-EAGAIN if the caller has to run commit; -+ * o %-ENOSPC if GC failed to make any progress; -+ * o other negative error codes in case of other errors. -+ * -+ * Garbage collector writes data to the journal when GC'ing data LEBs, and just -+ * marking indexing nodes dirty when GC'ing indexing LEBs. Thus, at some point -+ * commit may be required. But commit cannot be run from inside GC, because the -+ * caller might be holding the commit lock, so %-EAGAIN is returned instead; -+ * And this error code means that the caller has to run commit, and re-run GC -+ * if there is still no free space. -+ * -+ * There are many reasons why this function may return %-EAGAIN: -+ * o the log is full and there is no space to write an LEB reference for -+ * @c->gc_lnum; -+ * o the journal is too large and exceeds size limitations; -+ * o GC moved indexing LEBs, but they can be used only after the commit; -+ * o the shrinker fails to find clean znodes to free and requests the commit; -+ * o etc. -+ * -+ * Note, if the file-system is close to be full, this function may return -+ * %-EAGAIN infinitely, so the caller has to limit amount of re-invocations of -+ * the function. E.g., this happens if the limits on the journal size are too -+ * tough and GC writes too much to the journal before an LEB is freed. This -+ * might also mean that the journal is too large, and the TNC becomes to big, -+ * so that the shrinker is constantly called, finds not clean znodes to free, -+ * and requests commit. Well, this may also happen if the journal is all right, -+ * but another kernel process consumes too much memory. Anyway, infinite -+ * %-EAGAIN may happen, but in some extreme/misconfiguration cases. -+ */ -+int ubifs_garbage_collect(struct ubifs_info *c, int anyway) -+{ -+ int i, err, ret, min_space = c->dead_wm; -+ struct ubifs_lprops lp; -+ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; -+ -+ ubifs_assert_cmt_locked(c); -+ -+ if (ubifs_gc_should_commit(c)) -+ return -EAGAIN; -+ -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ /* We expect the write-buffer to be empty on entry */ -+ ubifs_assert(!wbuf->used); -+ -+ for (i = 0; ; i++) { -+ int space_before = c->leb_size - wbuf->offs - wbuf->used; -+ int space_after; -+ -+ cond_resched(); -+ -+ /* Give the commit an opportunity to run */ -+ if (ubifs_gc_should_commit(c)) { -+ ret = -EAGAIN; -+ break; -+ } -+ -+ if (i > SOFT_LEBS_LIMIT && !list_empty(&c->idx_gc)) { -+ /* -+ * We've done enough iterations. Indexing LEBs were -+ * moved and will be available after the commit. -+ */ -+ dbg_gc("soft limit, some index LEBs GC'ed, -EAGAIN"); -+ ubifs_commit_required(c); -+ ret = -EAGAIN; -+ break; -+ } -+ -+ if (i > HARD_LEBS_LIMIT) { -+ /* -+ * We've moved too many LEBs and have not made -+ * progress, give up. -+ */ -+ dbg_gc("hard limit, -ENOSPC"); -+ ret = -ENOSPC; -+ break; -+ } -+ -+ /* -+ * Empty and freeable LEBs can turn up while we waited for -+ * the wbuf lock, or while we have been running GC. In that -+ * case, we should just return one of those instead of -+ * continuing to GC dirty LEBs. Hence we request -+ * 'ubifs_find_dirty_leb()' to return an empty LEB if it can. -+ */ -+ ret = ubifs_find_dirty_leb(c, &lp, min_space, anyway ? 0 : 1); -+ if (ret) { -+ if (ret == -ENOSPC) -+ dbg_gc("no more dirty LEBs"); -+ break; -+ } -+ -+ dbg_gc("found LEB %d: free %d, dirty %d, sum %d " -+ "(min. space %d)", lp.lnum, lp.free, lp.dirty, -+ lp.free + lp.dirty, min_space); -+ -+ if (lp.free + lp.dirty == c->leb_size) { -+ /* An empty LEB was returned */ -+ dbg_gc("LEB %d is free, return it", lp.lnum); -+ /* -+ * ubifs_find_dirty_leb() doesn't return freeable index -+ * LEBs. -+ */ -+ ubifs_assert(!(lp.flags & LPROPS_INDEX)); -+ if (lp.free != c->leb_size) { -+ /* -+ * Write buffers must be sync'd before -+ * unmapping freeable LEBs, because one of them -+ * may contain data which obsoletes something -+ * in 'lp.pnum'. -+ */ -+ ret = gc_sync_wbufs(c); -+ if (ret) -+ goto out; -+ ret = ubifs_change_one_lp(c, lp.lnum, -+ c->leb_size, 0, 0, 0, -+ 0); -+ if (ret) -+ goto out; -+ } -+ ret = ubifs_leb_unmap(c, lp.lnum); -+ if (ret) -+ goto out; -+ ret = lp.lnum; -+ break; -+ } -+ -+ space_before = c->leb_size - wbuf->offs - wbuf->used; -+ if (wbuf->lnum == -1) -+ space_before = 0; -+ -+ ret = ubifs_garbage_collect_leb(c, &lp); -+ if (ret < 0) { -+ if (ret == -EAGAIN || ret == -ENOSPC) { -+ /* -+ * These codes are not errors, so we have to -+ * return the LEB to lprops. But if the -+ * 'ubifs_return_leb()' function fails, its -+ * failure code is propagated to the caller -+ * instead of the original '-EAGAIN' or -+ * '-ENOSPC'. -+ */ -+ err = ubifs_return_leb(c, lp.lnum); -+ if (err) -+ ret = err; -+ break; -+ } -+ goto out; -+ } -+ -+ if (ret == LEB_FREED) { -+ /* An LEB has been freed and is ready for use */ -+ dbg_gc("LEB %d freed, return", lp.lnum); -+ ret = lp.lnum; -+ break; -+ } -+ -+ if (ret == LEB_FREED_IDX) { -+ /* -+ * This was an indexing LEB and it cannot be -+ * immediately used. And instead of requesting the -+ * commit straight away, we try to garbage collect some -+ * more. -+ */ -+ dbg_gc("indexing LEB %d freed, continue", lp.lnum); -+ continue; -+ } -+ -+ ubifs_assert(ret == LEB_RETAINED); -+ space_after = c->leb_size - wbuf->offs - wbuf->used; -+ dbg_gc("LEB %d retained, freed %d bytes", lp.lnum, -+ space_after - space_before); -+ -+ if (space_after > space_before) { -+ /* GC makes progress, keep working */ -+ min_space >>= 1; -+ if (min_space < c->dead_wm) -+ min_space = c->dead_wm; -+ continue; -+ } -+ -+ dbg_gc("did not make progress"); -+ -+ /* -+ * GC moved an LEB bud have not done any progress. This means -+ * that the previous GC head LEB contained too few free space -+ * and the LEB which was GC'ed contained only large nodes which -+ * did not fit that space. -+ * -+ * We can do 2 things: -+ * 1. pick another LEB in a hope it'll contain a small node -+ * which will fit the space we have at the end of current GC -+ * head LEB, but there is no guarantee, so we try this out -+ * unless we have already been working for too long; -+ * 2. request an LEB with more dirty space, which will force -+ * 'ubifs_find_dirty_leb()' to start scanning the lprops -+ * table, instead of just picking one from the heap -+ * (previously it already picked the dirtiest LEB). -+ */ -+ if (i < SOFT_LEBS_LIMIT) { -+ dbg_gc("try again"); -+ continue; -+ } -+ -+ min_space <<= 1; -+ if (min_space > c->dark_wm) -+ min_space = c->dark_wm; -+ dbg_gc("set min. space to %d", min_space); -+ } -+ -+ if (ret == -ENOSPC && !list_empty(&c->idx_gc)) { -+ dbg_gc("no space, some index LEBs GC'ed, -EAGAIN"); -+ ubifs_commit_required(c); -+ ret = -EAGAIN; -+ } -+ -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ if (!err) -+ err = ubifs_leb_unmap(c, c->gc_lnum); -+ if (err) -+ ret = err; -+ mutex_unlock(&wbuf->io_mutex); -+ return ret; -+ -+out: -+ ubifs_assert(ret < 0); -+ ubifs_assert(ret != -ENOSPC && ret != -EAGAIN); -+ ubifs_wbuf_sync_nolock(wbuf); -+ mutex_unlock(&wbuf->io_mutex); -+ ubifs_return_leb(c, lp.lnum); -+ return ret; -+} -+ -+/** -+ * ubifs_gc_start_commit - garbage collection at start of commit. -+ * @c: UBIFS file-system description object -+ * -+ * If a LEB has only dirty and free space, then we may safely unmap it and make -+ * it free. Note, we cannot do this with indexing LEBs because dirty space may -+ * correspond index nodes that are required for recovery. In that case, the -+ * LEB cannot be unmapped until after the next commit. -+ * -+ * This function returns %0 upon success and a negative error code upon failure. -+ */ -+int ubifs_gc_start_commit(struct ubifs_info *c) -+{ -+ struct ubifs_gced_idx_leb *idx_gc; -+ const struct ubifs_lprops *lp; -+ int err = 0, flags; -+ -+ ubifs_get_lprops(c); -+ -+ /* -+ * Unmap (non-index) freeable LEBs. Note that recovery requires that all -+ * wbufs are sync'd before this, which is done in 'do_commit()'. -+ */ -+ while (1) { -+ lp = ubifs_fast_find_freeable(c); -+ if (unlikely(IS_ERR(lp))) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ if (!lp) -+ break; -+ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lp->flags & LPROPS_INDEX)); -+ err = ubifs_leb_unmap(c, lp->lnum); -+ if (err) -+ goto out; -+ lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0); -+ if (unlikely(IS_ERR(lp))) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lp->flags & LPROPS_INDEX)); -+ } -+ -+ /* Mark GC'd index LEBs OK to unmap after this commit finishes */ -+ list_for_each_entry(idx_gc, &c->idx_gc, list) -+ idx_gc->unmap = 1; -+ -+ /* Record index freeable LEBs for unmapping after commit */ -+ while (1) { -+ lp = ubifs_fast_find_frdi_idx(c); -+ if (unlikely(IS_ERR(lp))) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ if (!lp) -+ break; -+ idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); -+ if (!idx_gc) { -+ err = -ENOMEM; -+ goto out; -+ } -+ ubifs_assert(!(lp->flags & LPROPS_TAKEN)); -+ ubifs_assert(lp->flags & LPROPS_INDEX); -+ /* Don't release the LEB until after the next commit */ -+ flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX; -+ lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1); -+ if (unlikely(IS_ERR(lp))) { -+ err = PTR_ERR(lp); -+ kfree(idx_gc); -+ goto out; -+ } -+ ubifs_assert(lp->flags & LPROPS_TAKEN); -+ ubifs_assert(!(lp->flags & LPROPS_INDEX)); -+ idx_gc->lnum = lp->lnum; -+ idx_gc->unmap = 1; -+ list_add(&idx_gc->list, &c->idx_gc); -+ } -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * ubifs_gc_end_commit - garbage collection at end of commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function completes out-of-place garbage collection of index LEBs. -+ */ -+int ubifs_gc_end_commit(struct ubifs_info *c) -+{ -+ struct ubifs_gced_idx_leb *idx_gc, *tmp; -+ struct ubifs_wbuf *wbuf; -+ int err = 0; -+ -+ wbuf = &c->jheads[GCHD].wbuf; -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ list_for_each_entry_safe(idx_gc, tmp, &c->idx_gc, list) -+ if (idx_gc->unmap) { -+ dbg_gc("LEB %d", idx_gc->lnum); -+ err = ubifs_leb_unmap(c, idx_gc->lnum); -+ if (err) -+ goto out; -+ err = ubifs_change_one_lp(c, idx_gc->lnum, -1, -1, 0, -+ LPROPS_TAKEN, -1); -+ if (err) -+ goto out; -+ list_del(&idx_gc->list); -+ kfree(idx_gc); -+ } -+out: -+ mutex_unlock(&wbuf->io_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_destroy_idx_gc - destroy idx_gc list. -+ * @c: UBIFS file-system description object -+ * -+ * This function destroys the idx_gc list. It is called when unmounting or -+ * remounting read-only so locks are not needed. -+ */ -+void ubifs_destroy_idx_gc(struct ubifs_info *c) -+{ -+ while (!list_empty(&c->idx_gc)) { -+ struct ubifs_gced_idx_leb *idx_gc; -+ -+ idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, -+ list); -+ c->idx_gc_cnt -= 1; -+ list_del(&idx_gc->list); -+ kfree(idx_gc); -+ } -+ -+} -+ -+/** -+ * ubifs_get_idx_gc_leb - get a LEB from GC'd index LEB list. -+ * @c: UBIFS file-system description object -+ * -+ * Called during start commit so locks are not needed. -+ */ -+int ubifs_get_idx_gc_leb(struct ubifs_info *c) -+{ -+ struct ubifs_gced_idx_leb *idx_gc; -+ int lnum; -+ -+ if (list_empty(&c->idx_gc)) -+ return -ENOSPC; -+ idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, list); -+ lnum = idx_gc->lnum; -+ /* c->idx_gc_cnt is updated by the caller when lprops are updated */ -+ list_del(&idx_gc->list); -+ kfree(idx_gc); -+ return lnum; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/io.c linux-2.6.24.7/fs/ubifs/io.c ---- linux-2.6.24.7.old/fs/ubifs/io.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/io.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,921 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * Copyright (C) 2006, 2007 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+/* -+ * This file implements UBIFS I/O subsystem which provides various I/O-related -+ * helper functions (reading/writing/checking/validating nodes) and implements -+ * write-buffering support. Write buffers help to save space which otherwise -+ * would have been wasted for padding to the nearest minimal I/O unit boundary. -+ * Instead, data first goes to the write-buffer and is flushed when the -+ * buffer is full or when it is not used for some time (by timer). This is -+ * similarto the mechanism is used by JFFS2. -+ * -+ * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by -+ * mutexes defined inside these objects. Since sometimes upper-level code -+ * has to lock the write-buffer (e.g. journal space reservation code), many -+ * functions related to write-buffers have "nolock" suffix which means that the -+ * caller has to lock the write-buffer before calling this function. -+ * -+ * UBIFS stores nodes at 64 bit-aligned addresses. If the node length is not -+ * aligned, UBIFS starts the next node from the aligned address, and the padded -+ * bytes may contain any rubbish. In other words, UBIFS does not put padding -+ * bytes in those small gaps. Common headers of nodes store real node lengths, -+ * not aligned lengths. Indexing nodes also store real lengths in branches. -+ * -+ * UBIFS uses padding when it pads to the next min. I/O unit. In this case it -+ * uses padding nodes or padding bytes, if the padding node does not fit. -+ * -+ * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes -+ * every time they are read from the flash media. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/** -+ * ubifs_check_node - check node. -+ * @c: UBIFS file-system description object -+ * @buf: node to check -+ * @lnum: logical eraseblock number -+ * @offs: offset within the logical eraseblock -+ * @quiet: print no messages -+ * -+ * This function checks node magic number and CRC checksum. This function also -+ * validates node length to prevent UBIFS from becoming crazy when an attacker -+ * feeds it a file-system image with incorrect nodes. For example, too large -+ * node length in the common header could cause UBIFS to read memory outside of -+ * allocated buffer when checking the CRC checksum. -+ * -+ * This function returns zero in case of success %-EUCLEAN in case of bad CRC -+ * or magic. -+ */ -+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, -+ int offs, int quiet) -+{ -+ int err = -EINVAL, type, node_len; -+ uint32_t crc, node_crc, magic; -+ const struct ubifs_ch *ch = buf; -+ -+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); -+ ubifs_assert(!(offs & 7) && offs < c->leb_size); -+ -+ magic = le32_to_cpu(ch->magic); -+ if (magic != UBIFS_NODE_MAGIC) { -+ if (!quiet) -+ ubifs_err("bad magic %#08x, expected %#08x", -+ magic, UBIFS_NODE_MAGIC); -+ err = -EUCLEAN; -+ goto out; -+ } -+ -+ type = ch->node_type; -+ if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) { -+ if (!quiet) -+ ubifs_err("bad node type %d", type); -+ goto out; -+ } -+ -+ node_len = le32_to_cpu(ch->len); -+ if (node_len + offs > c->leb_size) -+ goto out_len; -+ -+ if (c->ranges[type].max_len == 0) { -+ if (node_len != c->ranges[type].len) -+ goto out_len; -+ } else if (node_len < c->ranges[type].min_len || -+ node_len > c->ranges[type].max_len) -+ goto out_len; -+ -+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); -+ node_crc = le32_to_cpu(ch->crc); -+ if (crc != node_crc) { -+ if (!quiet) -+ ubifs_err("bad CRC: calculated %#08x, read %#08x", -+ crc, node_crc); -+ err = -EUCLEAN; -+ goto out; -+ } -+ -+ return 0; -+ -+out_len: -+ if (!quiet) -+ ubifs_err("bad node length %d", node_len); -+out: -+ if (!quiet) { -+ ubifs_err("bad node at LEB %d:%d", lnum, offs); -+ dbg_dump_node(c, buf); -+ dbg_dump_stack(); -+ } -+ return err; -+} -+ -+/** -+ * ubifs_pad - pad flash space. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to put padding to -+ * @pad: how many bytes to pad -+ * -+ * The flash media obliges us to write only in chunks of %c->min_io_size and -+ * when we have to write less data we add padding node to the write-buffer and -+ * pad it to the next minimal I/O unit's boundary. Padding nodes help when the -+ * media is being scanned. If the amount of wasted space is not enough to fit a -+ * padding node which takes %UBIFS_PAD_NODE_SZ bytes, we write padding bytes -+ * pattern (%UBIFS_PADDING_BYTE). -+ * -+ * Padding nodes are also used to fill gaps when the "commit-in-gaps" method is -+ * used. -+ */ -+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad) -+{ -+ uint32_t crc; -+ -+ ubifs_assert(pad >= 0 && !(pad & 7)); -+ -+ if (pad >= UBIFS_PAD_NODE_SZ) { -+ struct ubifs_ch *ch = buf; -+ struct ubifs_pad_node *pad_node = buf; -+ -+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); -+ ch->node_type = UBIFS_PAD_NODE; -+ ch->group_type = UBIFS_NO_NODE_GROUP; -+ ch->padding[0] = ch->padding[1] = 0; -+ ch->sqnum = 0; -+ ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ); -+ pad -= UBIFS_PAD_NODE_SZ; -+ pad_node->pad_len = cpu_to_le32(pad); -+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8); -+ ch->crc = cpu_to_le32(crc); -+ memset(buf + UBIFS_PAD_NODE_SZ, 0, pad); -+ } else if (pad > 0) -+ /* Too little space, padding node won't fit */ -+ memset(buf, UBIFS_PADDING_BYTE, pad); -+} -+ -+/** -+ * next_sqnum - get next sequence number. -+ * @c: UBIFS file-system description object -+ */ -+static unsigned long long next_sqnum(struct ubifs_info *c) -+{ -+ unsigned long long sqnum; -+ -+ spin_lock(&c->cnt_lock); -+ sqnum = ++c->max_sqnum; -+ spin_unlock(&c->cnt_lock); -+ -+ if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) { -+ if (sqnum >= SQNUM_WATERMARK) { -+ ubifs_err("sequence number overflow %llu, end of life", -+ sqnum); -+ ubifs_ro_mode(c, -EINVAL); -+ } -+ ubifs_warn("running out of sequence numbers, end of life soon"); -+ } -+ -+ return sqnum; -+} -+ -+/** -+ * ubifs_prepare_node - prepare node to be written to flash. -+ * @c: UBIFS file-system description object -+ * @node: the node to pad -+ * @len: node length -+ * @pad: if the buffer has to be padded -+ * -+ * This function prepares node at @node to be written to the media - it -+ * calculates node CRC, fills the common header, and adds proper padding up to -+ * the next minimum I/O unit if @pad is not zero. -+ */ -+void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) -+{ -+ uint32_t crc; -+ struct ubifs_ch *ch = node; -+ unsigned long long sqnum = next_sqnum(c); -+ -+ ubifs_assert(len >= UBIFS_CH_SZ); -+ -+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); -+ ch->len = cpu_to_le32(len); -+ ch->group_type = UBIFS_NO_NODE_GROUP; -+ ch->sqnum = cpu_to_le64(sqnum); -+ ch->padding[0] = ch->padding[1] = 0; -+ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); -+ ch->crc = cpu_to_le32(crc); -+ -+ if (pad) { -+ len = ALIGN(len, 8); -+ pad = ALIGN(len, c->min_io_size) - len; -+ ubifs_pad(c, node + len, pad); -+ } -+} -+ -+/** -+ * ubifs_prep_grp_node - prepare node of a group to be written to flash. -+ * @c: UBIFS file-system description object -+ * @node: the node to pad -+ * @len: node length -+ * @last: indicates the last node of the group -+ * -+ * This function prepares node at @node to be written to the media - it -+ * calculates node CRC and fills the common header. -+ */ -+void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last) -+{ -+ uint32_t crc; -+ struct ubifs_ch *ch = node; -+ unsigned long long sqnum = next_sqnum(c); -+ -+ ubifs_assert(len >= UBIFS_CH_SZ); -+ -+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); -+ ch->len = cpu_to_le32(len); -+ if (last) -+ ch->group_type = UBIFS_LAST_OF_NODE_GROUP; -+ else -+ ch->group_type = UBIFS_IN_NODE_GROUP; -+ ch->sqnum = cpu_to_le64(sqnum); -+ ch->padding[0] = ch->padding[1] = 0; -+ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); -+ ch->crc = cpu_to_le32(crc); -+} -+ -+/** -+ * wbuf_timer_callback - write-buffer timer callback function. -+ * @data: timer data (write-buffer descriptor) -+ * -+ * This function is called when the write-buffer timer expires. -+ */ -+static void wbuf_timer_callback_nolock(unsigned long data) -+{ -+ struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data; -+ -+ wbuf->need_sync = 1; -+ wbuf->c->need_wbuf_sync = 1; -+ ubifs_wake_up_bgt(wbuf->c); -+} -+ -+/** -+ * new_wbuf_timer - start new write-buffer timer. -+ * @wbuf: write-buffer descriptor -+ */ -+static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) -+{ -+ ubifs_assert(!timer_pending(&wbuf->timer)); -+ -+ if (!wbuf->timeout) -+ return; -+ -+ wbuf->timer.expires = jiffies + wbuf->timeout; -+ add_timer(&wbuf->timer); -+} -+ -+/** -+ * cancel_wbuf_timer - cancel write-buffer timer. -+ * @wbuf: write-buffer descriptor -+ */ -+static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) -+{ -+ /* -+ * If the syncer is waiting for the lock (from the background thread's -+ * context) and another task is changing write-buffer then the syncing -+ * should be canceled. -+ */ -+ wbuf->need_sync = 0; -+ del_timer(&wbuf->timer); -+} -+ -+/** -+ * ubifs_wbuf_sync_nolock - synchronize write-buffer. -+ * @wbuf: write-buffer to synchronize -+ * -+ * This function synchronizes write-buffer @buf and returns zero in case of -+ * success or a negative error code in case of failure. -+ */ -+int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) -+{ -+ struct ubifs_info *c = wbuf->c; -+ int err, dirt; -+ -+ cancel_wbuf_timer_nolock(wbuf); -+ if (!wbuf->used || wbuf->lnum == -1) -+ /* Write-buffer is empty or not seeked */ -+ return 0; -+ -+ dbg_io("LEB %d:%d, %d bytes", -+ wbuf->lnum, wbuf->offs, wbuf->used); -+ ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); -+ ubifs_assert(!(wbuf->avail & 7)); -+ ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); -+ -+ if (c->ro_media) -+ return -EROFS; -+ -+ ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail); -+ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, -+ c->min_io_size, wbuf->dtype); -+ if (err) { -+ ubifs_err("cannot write %d bytes to LEB %d:%d", -+ c->min_io_size, wbuf->lnum, wbuf->offs); -+ dbg_dump_stack(); -+ return err; -+ } -+ -+ dirt = wbuf->avail; -+ -+ spin_lock(&wbuf->lock); -+ wbuf->offs += c->min_io_size; -+ wbuf->avail = c->min_io_size; -+ wbuf->used = 0; -+ wbuf->next_ino = 0; -+ spin_unlock(&wbuf->lock); -+ -+ if (wbuf->sync_callback) -+ err = wbuf->sync_callback(c, wbuf->lnum, -+ c->leb_size - wbuf->offs, dirt); -+ return err; -+} -+ -+/** -+ * ubifs_wbuf_seek_nolock - seek write-buffer. -+ * @wbuf: write-buffer -+ * @lnum: logical eraseblock number to seek to -+ * @offs: logical eraseblock offset to seek to -+ * @dtype: data type -+ * -+ * This function targets the write buffer to logical eraseblock @lnum:@offs. -+ * The write-buffer is synchronized if it is not empty. Returns zero in case of -+ * success and a negative error code in case of failure. -+ */ -+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, -+ int dtype) -+{ -+ const struct ubifs_info *c = wbuf->c; -+ -+ dbg_io("LEB %d:%d", lnum, offs); -+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); -+ ubifs_assert(offs >= 0 && offs <= c->leb_size); -+ ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); -+ ubifs_assert(lnum != wbuf->lnum); -+ -+ if (wbuf->used > 0) { -+ int err = ubifs_wbuf_sync_nolock(wbuf); -+ -+ if (err) -+ return err; -+ } -+ -+ spin_lock(&wbuf->lock); -+ wbuf->lnum = lnum; -+ wbuf->offs = offs; -+ wbuf->avail = c->min_io_size; -+ wbuf->used = 0; -+ spin_unlock(&wbuf->lock); -+ wbuf->dtype = dtype; -+ -+ return 0; -+} -+ -+/** -+ * ubifs_bg_wbufs_sync - synchronize write-buffers. -+ * @c: UBIFS file-system description object -+ * -+ * This function is called by background thread to synchronize write-buffers. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+int ubifs_bg_wbufs_sync(struct ubifs_info *c) -+{ -+ int err, i; -+ -+ if (!c->need_wbuf_sync) -+ return 0; -+ c->need_wbuf_sync = 0; -+ -+ if (c->ro_media) { -+ err = -EROFS; -+ goto out_timers; -+ } -+ -+ dbg_io("synchronize"); -+ for (i = 0; i < c->jhead_cnt; i++) { -+ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; -+ -+ cond_resched(); -+ -+ /* -+ * If the mutex is locked then wbuf is being changed, so -+ * synchronization is not necessary. -+ */ -+ if (mutex_is_locked(&wbuf->io_mutex)) -+ continue; -+ -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ if (!wbuf->need_sync) { -+ mutex_unlock(&wbuf->io_mutex); -+ continue; -+ } -+ -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ mutex_unlock(&wbuf->io_mutex); -+ if (err) { -+ ubifs_err("cannot sync write-buffer, error %d", err); -+ ubifs_ro_mode(c, err); -+ goto out_timers; -+ } -+ } -+ -+ return 0; -+ -+out_timers: -+ /* Cancel all timers to prevent repeated errors */ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; -+ -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ cancel_wbuf_timer_nolock(wbuf); -+ mutex_unlock(&wbuf->io_mutex); -+ } -+ return err; -+} -+ -+/** -+ * ubifs_wbuf_write_nolock - write data to flash via write-buffer. -+ * @wbuf: write-buffer -+ * @buf: node to write -+ * @len: node length -+ * -+ * This function writes data to flash via write-buffer @wbuf. This means that -+ * the last piece of the node won't reach the flash media immediately if it -+ * does not take whole minimal I/O unit. Instead, the node will sit in RAM -+ * until the write-buffer is synchronized (e.g., by timer). -+ * -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. If the node cannot be written because there is no more -+ * space in this logical eraseblock, %-ENOSPC is returned. -+ */ -+int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) -+{ -+ struct ubifs_info *c = wbuf->c; -+ int err, written, n, aligned_len = ALIGN(len, 8), offs; -+ -+ dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len, -+ dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum, -+ wbuf->offs + wbuf->used); -+ ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); -+ ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); -+ ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); -+ ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size); -+ ubifs_assert(mutex_is_locked(&wbuf->io_mutex)); -+ -+ if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) { -+ err = -ENOSPC; -+ goto out; -+ } -+ -+ cancel_wbuf_timer_nolock(wbuf); -+ -+ if (c->ro_media) -+ return -EROFS; -+ -+ if (aligned_len <= wbuf->avail) { -+ /* -+ * The node is not very large and fits entirely within -+ * write-buffer. -+ */ -+ memcpy(wbuf->buf + wbuf->used, buf, len); -+ -+ if (aligned_len == wbuf->avail) { -+ dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, -+ wbuf->offs); -+ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, -+ wbuf->offs, c->min_io_size, -+ wbuf->dtype); -+ if (err) -+ goto out; -+ -+ spin_lock(&wbuf->lock); -+ wbuf->offs += c->min_io_size; -+ wbuf->avail = c->min_io_size; -+ wbuf->used = 0; -+ wbuf->next_ino = 0; -+ spin_unlock(&wbuf->lock); -+ } else { -+ spin_lock(&wbuf->lock); -+ wbuf->avail -= aligned_len; -+ wbuf->used += aligned_len; -+ spin_unlock(&wbuf->lock); -+ } -+ -+ goto exit; -+ } -+ -+ /* -+ * The node is large enough and does not fit entirely within current -+ * minimal I/O unit. We have to fill and flush write-buffer and switch -+ * to the next min. I/O unit. -+ */ -+ dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs); -+ memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); -+ err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, -+ c->min_io_size, wbuf->dtype); -+ if (err) -+ goto out; -+ -+ offs = wbuf->offs + c->min_io_size; -+ len -= wbuf->avail; -+ aligned_len -= wbuf->avail; -+ written = wbuf->avail; -+ -+ /* -+ * The remaining data may take more whole min. I/O units, so write the -+ * remains multiple to min. I/O unit size directly to the flash media. -+ * We align node length to 8-byte boundary because we anyway flash wbuf -+ * if the remaining space is less than 8 bytes. -+ */ -+ n = aligned_len >> c->min_io_shift; -+ if (n) { -+ n <<= c->min_io_shift; -+ dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs); -+ err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n, -+ wbuf->dtype); -+ if (err) -+ goto out; -+ offs += n; -+ aligned_len -= n; -+ len -= n; -+ written += n; -+ } -+ -+ spin_lock(&wbuf->lock); -+ if (aligned_len) -+ /* -+ * And now we have what's left and what does not take whole -+ * min. I/O unit, so write it to the write-buffer and we are -+ * done. -+ */ -+ memcpy(wbuf->buf, buf + written, len); -+ -+ wbuf->offs = offs; -+ wbuf->used = aligned_len; -+ wbuf->avail = c->min_io_size - aligned_len; -+ wbuf->next_ino = 0; -+ spin_unlock(&wbuf->lock); -+ -+exit: -+ if (wbuf->sync_callback) { -+ int free = c->leb_size - wbuf->offs - wbuf->used; -+ -+ err = wbuf->sync_callback(c, wbuf->lnum, free, 0); -+ if (err) -+ goto out; -+ } -+ -+ if (wbuf->used) -+ new_wbuf_timer_nolock(wbuf); -+ -+ return 0; -+ -+out: -+ ubifs_err("cannot write %d bytes to LEB %d:%d, error %d", -+ len, wbuf->lnum, wbuf->offs, err); -+ dbg_dump_node(c, buf); -+ dbg_dump_stack(); -+ dbg_dump_leb(c, wbuf->lnum); -+ return err; -+} -+ -+/** -+ * ubifs_write_node - write node to the media. -+ * @c: UBIFS file-system description object -+ * @buf: the node to write -+ * @len: node length -+ * @lnum: logical eraseblock number -+ * @offs: offset within the logical eraseblock -+ * @dtype: node life-time hint (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * -+ * This function automatically fills node magic number, assigns sequence -+ * number, and calculates node CRC checksum. The length of the @buf buffer has -+ * to be aligned to the minimal I/O unit size. This function automatically -+ * appends padding node and padding bytes if needed. Returns zero in case of -+ * success and a negative error code in case of failure. -+ */ -+int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, -+ int offs, int dtype) -+{ -+ int err, buf_len = ALIGN(len, c->min_io_size); -+ -+ dbg_io("LEB %d:%d, %s, length %d (aligned %d)", -+ lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len, -+ buf_len); -+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); -+ ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size); -+ -+ if (c->ro_media) -+ return -EROFS; -+ -+ ubifs_prepare_node(c, buf, len, 1); -+ err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype); -+ if (err) { -+ ubifs_err("cannot write %d bytes to LEB %d:%d, error %d", -+ buf_len, lnum, offs, err); -+ dbg_dump_node(c, buf); -+ dbg_dump_stack(); -+ } -+ -+ return err; -+} -+ -+/** -+ * ubifs_read_node_wbuf - read node from the media or write-buffer. -+ * @wbuf: wbuf to check for un-written data -+ * @buf: buffer to read to -+ * @type: node type -+ * @len: node length -+ * @lnum: logical eraseblock number -+ * @offs: offset within the logical eraseblock -+ * -+ * This function reads a node of known type and length, checks it and stores -+ * in @buf. If the node partially or fully sits in the write-buffer, this -+ * function takes data from the buffer, otherwise it reads the flash media. -+ * Returns zero in case of success, %-EUCLEAN if CRC mismatched and a negative -+ * error code in case of failure. -+ */ -+int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, -+ int lnum, int offs) -+{ -+ const struct ubifs_info *c = wbuf->c; -+ int err, rlen, overlap; -+ struct ubifs_ch *ch = buf; -+ -+ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); -+ ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); -+ ubifs_assert(!(offs & 7) && offs < c->leb_size); -+ ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); -+ -+ spin_lock(&wbuf->lock); -+ overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs); -+ if (!overlap) { -+ /* We may safely unlock the write-buffer and read the data */ -+ spin_unlock(&wbuf->lock); -+ return ubifs_read_node(c, buf, type, len, lnum, offs); -+ } -+ -+ /* Don't read under wbuf */ -+ rlen = wbuf->offs - offs; -+ if (rlen < 0) -+ rlen = 0; -+ -+ /* Copy the rest from the write-buffer */ -+ memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen); -+ spin_unlock(&wbuf->lock); -+ -+ if (rlen > 0) { -+ /* Read everything that goes before write-buffer */ -+ err = ubi_read(c->ubi, lnum, buf, offs, rlen); -+ if (err && err != -EBADMSG) { -+ ubifs_err("failed to read node %d from LEB %d:%d, " -+ "error %d", type, lnum, offs, err); -+ dbg_dump_stack(); -+ return err; -+ } -+ } -+ -+ err = ubifs_check_node(c, buf, lnum, offs, 0); -+ if (err) { -+ ubifs_err("expected node type %d", type); -+ return err; -+ } -+ -+ if (type != ch->node_type) { -+ ubifs_err("bad node type (%d but expected %d)", -+ ch->node_type, type); -+ goto out; -+ } -+ -+ rlen = le32_to_cpu(ch->len); -+ if (rlen != len) { -+ ubifs_err("bad node length %d, expected %d", rlen, len); -+ goto out; -+ } -+ -+ return 0; -+ -+out: -+ ubifs_err("bad node at LEB %d:%d", lnum, offs); -+ dbg_dump_node(c, buf); -+ dbg_dump_stack(); -+ return -EINVAL; -+} -+ -+/** -+ * ubifs_read_node - read node. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to read to -+ * @type: node type -+ * @len: node length (not aligned) -+ * @lnum: logical eraseblock number -+ * @offs: offset within the logical eraseblock -+ * -+ * This function reads a node of known type and and length, checks it and -+ * stores in @buf. Returns zero in case of success, %-EUCLEAN if CRC mismatched -+ * and a negative error code in case of failure. -+ */ -+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, -+ int lnum, int offs) -+{ -+ int err, l; -+ struct ubifs_ch *ch = buf; -+ -+ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); -+ ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0); -+ ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size); -+ ubifs_assert(!(offs & 7) && offs < c->leb_size); -+ ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); -+ -+ err = ubi_read(c->ubi, lnum, buf, offs, len); -+ if (err && err != -EBADMSG) { -+ ubifs_err("cannot read node %d from LEB %d:%d, error %d", -+ type, lnum, offs, err); -+ return err; -+ } -+ -+ err = ubifs_check_node(c, buf, lnum, offs, 0); -+ if (err) { -+ ubifs_err("expected node type %d", type); -+ return err; -+ } -+ -+ if (type != ch->node_type) { -+ ubifs_err("bad node type (%d but expected %d)", -+ ch->node_type, type); -+ goto out; -+ } -+ -+ l = le32_to_cpu(ch->len); -+ if (l != len) { -+ ubifs_err("bad node length %d, expected %d", l, len); -+ goto out; -+ } -+ -+ return 0; -+ -+out: -+ ubifs_err("bad node at LEB %d:%d", lnum, offs); -+ dbg_dump_node(c, buf); -+ dbg_dump_stack(); -+ return -EINVAL; -+} -+ -+/** -+ * ubifs_wbuf_init - initialize write-buffer. -+ * @c: UBIFS file-system description object -+ * @wbuf: write-buffer to initialize -+ * -+ * This function initializes write buffer. Returns zero in case of success -+ * %-ENOMEM in case of failure. -+ */ -+int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) -+{ -+ size_t size; -+ -+ wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL); -+ if (!wbuf->buf) -+ return -ENOMEM; -+ -+ size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t); -+ wbuf->inodes = kmalloc(size, GFP_KERNEL); -+ if (!wbuf->inodes) { -+ kfree(wbuf->buf); -+ wbuf->buf = NULL; -+ return -ENOMEM; -+ } -+ -+ wbuf->used = 0; -+ wbuf->lnum = wbuf->offs = -1; -+ wbuf->avail = c->min_io_size; -+ wbuf->dtype = UBI_UNKNOWN; -+ wbuf->sync_callback = NULL; -+ mutex_init(&wbuf->io_mutex); -+ spin_lock_init(&wbuf->lock); -+ -+ wbuf->c = c; -+ init_timer(&wbuf->timer); -+ wbuf->timer.function = wbuf_timer_callback_nolock; -+ wbuf->timer.data = (unsigned long)wbuf; -+ wbuf->timeout = DEFAULT_WBUF_TIMEOUT; -+ wbuf->next_ino = 0; -+ -+ return 0; -+} -+ -+/** -+ * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. -+ * @wbuf: the write-buffer whereto add -+ * @inum: the inode number -+ * -+ * This function adds an inode number to the inode array of the write-buffer. -+ */ -+void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum) -+{ -+ if (!wbuf->buf) -+ /* NOR flash or something similar */ -+ return; -+ -+ spin_lock(&wbuf->lock); -+ if (wbuf->used) -+ wbuf->inodes[wbuf->next_ino++] = inum; -+ spin_unlock(&wbuf->lock); -+} -+ -+/** -+ * wbuf_has_ino - returns if the wbuf contains data from the inode. -+ * @wbuf: the write-buffer -+ * @inum: the inode number -+ * -+ * This function returns with %1 if the write-buffer contains some data from the -+ * given inode otherwise it returns with %0. -+ */ -+static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum) -+{ -+ int i, ret = 0; -+ -+ spin_lock(&wbuf->lock); -+ for (i = 0; i < wbuf->next_ino; i++) -+ if (inum == wbuf->inodes[i]) { -+ ret = 1; -+ break; -+ } -+ spin_unlock(&wbuf->lock); -+ -+ return ret; -+} -+ -+/** -+ * ubifs_sync_wbufs_by_inodes - synchronize write-buffers which have data. -+ * belonging to specified inodes. -+ * @c: UBIFS file-system description object -+ * @inodes: array of inodes -+ * @count: number of elements in @inodes -+ * -+ * This function synchronizes write-buffers which contain nodes belonging to -+ * any inode specified in @inodes array. Returns zero in case of success and a -+ * negative error code in case of failure. -+ */ -+int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c, -+ struct inode * const *inodes, int count) -+{ -+ int i, j, err = 0; -+ -+ ubifs_assert(count); -+ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf; -+ -+ if (i == GCHD) -+ /* -+ * GC head is special, do not look at it. Even if the -+ * head contains something related to this inode, it is -+ * a _copy_ of corresponding on-flash node which sits -+ * somewhere else. -+ */ -+ continue; -+ -+ for (j = 0; j < count && !err; j++) -+ if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) { -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ if (wbuf_has_ino(wbuf, inodes[j]->i_ino)) -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ mutex_unlock(&wbuf->io_mutex); -+ break; -+ } -+ -+ if (err) { -+ ubifs_ro_mode(c, err); -+ break; -+ } -+ } -+ -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/ioctl.c linux-2.6.24.7/fs/ubifs/ioctl.c ---- linux-2.6.24.7.old/fs/ubifs/ioctl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/ioctl.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,204 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * Copyright (C) 2006, 2007 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Zoltan Sogor -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* This file implements EXT2-compatible extended attribute ioctl() calls */ -+ -+#include -+#include -+#include "ubifs.h" -+ -+/** -+ * ubifs_set_inode_flags - set VFS inode flags. -+ * @inode: VFS inode to set flags for -+ * -+ * This function propagates flags from UBIFS inode object to VFS inode object. -+ */ -+void ubifs_set_inode_flags(struct inode *inode) -+{ -+ unsigned int flags = ubifs_inode(inode)->flags; -+ -+ inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_DIRSYNC); -+ if (flags & UBIFS_SYNC_FL) -+ inode->i_flags |= S_SYNC; -+ if (flags & UBIFS_APPEND_FL) -+ inode->i_flags |= S_APPEND; -+ if (flags & UBIFS_IMMUTABLE_FL) -+ inode->i_flags |= S_IMMUTABLE; -+ if (flags & UBIFS_DIRSYNC_FL) -+ inode->i_flags |= S_DIRSYNC; -+} -+ -+/* -+ * ioctl2ubifs - convert ioctl inode flags to UBIFS inode flags. -+ * @ioctl_flags: flags to convert -+ * -+ * This function convert ioctl flags (@FS_COMPR_FL, etc) to UBIFS inode flags -+ * (@UBIFS_COMPR_FL, etc). -+ */ -+static int ioctl2ubifs(int ioctl_flags) -+{ -+ int ubifs_flags = 0; -+ -+ if (ioctl_flags & FS_COMPR_FL) -+ ubifs_flags |= UBIFS_COMPR_FL; -+ if (ioctl_flags & FS_SYNC_FL) -+ ubifs_flags |= UBIFS_SYNC_FL; -+ if (ioctl_flags & FS_APPEND_FL) -+ ubifs_flags |= UBIFS_APPEND_FL; -+ if (ioctl_flags & FS_IMMUTABLE_FL) -+ ubifs_flags |= UBIFS_IMMUTABLE_FL; -+ if (ioctl_flags & FS_DIRSYNC_FL) -+ ubifs_flags |= UBIFS_DIRSYNC_FL; -+ -+ return ubifs_flags; -+} -+ -+/* -+ * ubifs2ioctl - convert UBIFS inode flags to ioctl inode flags. -+ * @ubifs_flags: flags to convert -+ * -+ * This function convert UBIFS (@UBIFS_COMPR_FL, etc) to ioctl flags -+ * (@FS_COMPR_FL, etc). -+ */ -+static int ubifs2ioctl(int ubifs_flags) -+{ -+ int ioctl_flags = 0; -+ -+ if (ubifs_flags & UBIFS_COMPR_FL) -+ ioctl_flags |= FS_COMPR_FL; -+ if (ubifs_flags & UBIFS_SYNC_FL) -+ ioctl_flags |= FS_SYNC_FL; -+ if (ubifs_flags & UBIFS_APPEND_FL) -+ ioctl_flags |= FS_APPEND_FL; -+ if (ubifs_flags & UBIFS_IMMUTABLE_FL) -+ ioctl_flags |= FS_IMMUTABLE_FL; -+ if (ubifs_flags & UBIFS_DIRSYNC_FL) -+ ioctl_flags |= FS_DIRSYNC_FL; -+ -+ return ioctl_flags; -+} -+ -+static int setflags(struct inode *inode, int flags) -+{ -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_budget_req req; -+ int oldflags, err; -+ -+ mutex_lock(&inode->i_mutex); -+ -+ memset(&req, 0 , sizeof(struct ubifs_budget_req)); -+ err = ubifs_budget_inode_op(c, inode, &req); -+ if (err) -+ goto out; -+ -+ /* -+ * The IMMUTABLE and APPEND_ONLY flags can only be changed by -+ * the relevant capability. -+ */ -+ oldflags = ubifs2ioctl(ui->flags); -+ if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { -+ if (!capable(CAP_LINUX_IMMUTABLE)) { -+ err = -EPERM; -+ goto out_budg; -+ } -+ } -+ -+ ui->flags = ioctl2ubifs(flags); -+ ubifs_set_inode_flags(inode); -+ -+ inode->i_ctime = ubifs_current_time(inode); -+ mark_inode_dirty_sync(inode); -+ -+ ubifs_release_ino_dirty(c, inode, &req); -+ -+ if (IS_SYNC(inode)) -+ err = write_inode_now(inode, 1); -+ -+ mutex_unlock(&inode->i_mutex); -+ return err; -+ -+out_budg: -+ ubifs_cancel_ino_op(c, inode, &req); -+out: -+ ubifs_err("can't modify inode %lu attributes", inode->i_ino); -+ mutex_unlock(&inode->i_mutex); -+ return err; -+} -+ -+long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ int flags; -+ struct inode *inode = file->f_path.dentry->d_inode; -+ -+ switch (cmd) { -+ case FS_IOC_GETFLAGS: -+ flags = ubifs2ioctl(ubifs_inode(inode)->flags); -+ -+ return put_user(flags, (int __user *) arg); -+ -+ case FS_IOC_SETFLAGS: { -+ if (IS_RDONLY(inode)) -+ return -EROFS; -+ -+ if (!is_owner_or_cap(inode)) -+ return -EACCES; -+ -+ if (get_user(flags, (int __user *) arg)) -+ return -EFAULT; -+ -+ if (!S_ISDIR(inode->i_mode)) -+ flags &= ~FS_DIRSYNC_FL; -+ -+ return setflags(inode, flags); -+ } -+ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+#ifdef CONFIG_COMPAT -+long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ int err; -+ -+ switch (cmd) { -+ case FS_IOC32_GETFLAGS: -+ cmd = FS_IOC_GETFLAGS; -+ break; -+ case FS_IOC32_SETFLAGS: -+ cmd = FS_IOC_SETFLAGS; -+ break; -+ default: -+ return -ENOIOCTLCMD; -+ } -+ -+ lock_kernel(); -+ err = ubifs_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); -+ unlock_kernel(); -+ -+ return err; -+} -+#endif -diff -urN linux-2.6.24.7.old/fs/ubifs/journal.c linux-2.6.24.7/fs/ubifs/journal.c ---- linux-2.6.24.7.old/fs/ubifs/journal.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/journal.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1275 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS journal. -+ * -+ * The journal consists of 2 parts - the log and bud LEBs. The log has fixed -+ * length and position, while a bud logical eraseblock is any LEB in the main -+ * area. Buds contain file system data - data nodes, inode nodes, etc. The log -+ * contains only references to buds and some other stuff like commit -+ * start node. The idea is that when we commit the journal, we do -+ * not copy the data, the buds just become indexed. Since after the commit the -+ * nodes in bud eraseblocks become leaf nodes of the file system index tree, we -+ * use term "bud". Analogy is obvious, bud eraseblocks contain nodes which will -+ * become leafs in the future. -+ * -+ * The journal is multi-headed because we want to write data to the journal as -+ * optimally as possible. It is nice to have nodes belonging to the same inode -+ * in one LEB, so we may write data owned by different inodes to different -+ * journal heads, although at present only one data head is used. -+ * -+ * For recovery reasons, the base head contains all inode nodes, all directory -+ * entry nodes and all truncate nodes. This means that the other heads contain -+ * only data nodes. -+ * -+ * Bud LEBs may be half-indexed. For example, if the bud was not full at the -+ * time of commit, the bud is retained to continue to be used in the journal, -+ * even though the "front" of the LEB is now indexed. In that case, the log -+ * reference contains the offset where the bud starts for the purposes of the -+ * journal. -+ * -+ * The journal size has to be limited, because the larger is the journal, the -+ * longer it takes to mount UBIFS (scanning the journal) and the more memory it -+ * takes (indexing in the TNC). -+ * -+ * Note, all the journal write operations like 'ubifs_jnl_update()' here, which -+ * write multiple UBIFS nodes to the journal at one go, are atomic with respect -+ * to unclean reboots. Should the unclean reboot happen, the recovery code drops -+ * all the nodes. -+ */ -+ -+#include "ubifs.h" -+ -+/** -+ * zero_ino_node_unused - zero out unused fields of an on-flash inode node. -+ * @ino: the inode to zero out -+ */ -+static inline void zero_ino_node_unused(struct ubifs_ino_node *ino) -+{ -+ memset(ino->padding, 0, 26); -+} -+ -+/** -+ * zero_dent_node_unused - zero out unused fields of an on-flash directory -+ * entry node. -+ * @ino: the directory entry to zero out -+ */ -+static inline void zero_dent_node_unused(struct ubifs_dent_node *dent) -+{ -+ dent->padding1 = 0; -+ memset(dent->padding2, 0, 4); -+} -+ -+/** -+ * zero_data_node_unused - zero out unused fields of an on-flash data node. -+ * @ino: the data node to zero out -+ */ -+static inline void zero_data_node_unused(struct ubifs_data_node *data) -+{ -+ memset(data->padding, 0, 2); -+} -+ -+/** -+ * reserve_space - reserve space in the journal. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head number -+ * @len: node length -+ * -+ * This function reserves space in journal head @head. If the reservation -+ * succeeded, the journal head stays locked and later has to be unlocked using -+ * 'release_head()'. 'write_node()' and 'write_head()' functions also unlock -+ * it. Returns zero in case of success, %-EAGAIN if commit has to be done, and -+ * other negative error codes in case of other failures. -+ */ -+static int reserve_space(struct ubifs_info *c, int jhead, int len) -+{ -+ int err = 0, err1, retries = 0, avail, lnum, offs, free, squeeze; -+ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; -+ -+ /* -+ * Typically, the base head has smaller nodes written to it, so it is -+ * better to try to allocate space at the ends of eraseblocks. This is -+ * what the squeeze parameter does. -+ */ -+ squeeze = (jhead == BASEHD); -+again: -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ avail = c->leb_size - wbuf->offs - wbuf->used; -+ -+ if (wbuf->lnum != -1 && avail >= len) -+ return 0; -+ -+ /* -+ * Write buffer wasn't seek'ed or there is no enough space - look for an -+ * LEB with some empty space. -+ */ -+ lnum = ubifs_find_free_space(c, len, &free, squeeze); -+ if (lnum >= 0) { -+ /* Found an LEB, add it to the journal head */ -+ offs = c->leb_size - free; -+ err = ubifs_add_bud_to_log(c, jhead, lnum, offs); -+ if (err) -+ goto out_return; -+ /* A new bud was successfully allocated and added to the log */ -+ goto out; -+ } -+ -+ err = lnum; -+ if (err != -ENOSPC) -+ goto out_unlock; -+ -+ /* -+ * No free space, we have to run garbage collector to make -+ * some. But the write-buffer mutex has to be unlocked because -+ * GC have to sync write buffers, which may lead a deadlock. -+ */ -+ dbg_jnl("no free space jhead %d, run GC", jhead); -+ mutex_unlock(&wbuf->io_mutex); -+ -+ lnum = ubifs_garbage_collect(c, 0); -+ if (lnum < 0) { -+ err = lnum; -+ if (err != -ENOSPC) -+ return err; -+ -+ /* -+ * GC could not make a free LEB. But someone else may -+ * have allocated new bud for this journal head, -+ * because we dropped the 'io_mutex', so try once -+ * again. -+ */ -+ dbg_jnl("GC couldn't make a free LEB for jhead %d", jhead); -+ if (retries++ < 2) { -+ dbg_jnl("retry (%d)", retries); -+ goto again; -+ } -+ -+ dbg_jnl("return -ENOSPC"); -+ return err; -+ } -+ -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ dbg_jnl("got LEB %d for jhead %d", lnum, jhead); -+ avail = c->leb_size - wbuf->offs - wbuf->used; -+ -+ if (wbuf->lnum != -1 && avail >= len) { -+ /* -+ * Someone else has switched the journal head and we have -+ * enough space now. This happens when more then one process is -+ * trying to write to the same journal head at the same time. -+ */ -+ dbg_jnl("return LEB %d back, already have LEB %d:%d", -+ lnum, wbuf->lnum, wbuf->offs + wbuf->used); -+ err = ubifs_return_leb(c, lnum); -+ if (err) -+ goto out_unlock; -+ return 0; -+ } -+ -+ err = ubifs_add_bud_to_log(c, jhead, lnum, 0); -+ if (err) -+ goto out_return; -+ offs = 0; -+ -+out: -+ err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, UBI_SHORTTERM); -+ if (err) -+ goto out_unlock; -+ -+ return 0; -+ -+out_unlock: -+ mutex_unlock(&wbuf->io_mutex); -+ return err; -+ -+out_return: -+ /* An error occurred and the LEB has to be returned to lprops */ -+ ubifs_assert(err < 0); -+ err1 = ubifs_return_leb(c, lnum); -+ if (err1 && err == -EAGAIN) -+ /* -+ * Return original error code 'err' only if it is not -+ * '-EAGAIN', which is not really an error. Otherwise, return -+ * the error code of 'ubifs_return_leb()'. -+ */ -+ err = err1; -+ mutex_unlock(&wbuf->io_mutex); -+ return err; -+} -+ -+/** -+ * write_node - write node to a journal head. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head -+ * @node: node to write -+ * @len: node length -+ * @lnum: LEB number written is returned here -+ * @offs: offset written is returned here -+ * -+ * This function writes a node to reserved space of journal head @jhead. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int write_node(struct ubifs_info *c, int jhead, void *node, int len, -+ int *lnum, int *offs) -+{ -+ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; -+ -+ ubifs_assert(jhead != GCHD); -+ -+ *lnum = c->jheads[jhead].wbuf.lnum; -+ *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; -+ -+ dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len); -+ ubifs_prepare_node(c, node, len, 0); -+ -+ return ubifs_wbuf_write_nolock(wbuf, node, len); -+} -+ -+/** -+ * write_head - write data to a journal head. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head -+ * @buf: buffer to write -+ * @len: length to write -+ * @lnum: LEB number written is returned here -+ * @offs: offset written is returned here -+ * @sync: non-zero if the write-buffer has to by synchronized -+ * -+ * This function is the same as 'write_node()' but it does not assume the -+ * buffer it is writing is a node, so it does not prepare it (which means -+ * initializing common header and calculating CRC). -+ */ -+static int write_head(struct ubifs_info *c, int jhead, void *buf, int len, -+ int *lnum, int *offs, int sync) -+{ -+ int err; -+ struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; -+ -+ ubifs_assert(jhead != GCHD); -+ -+ *lnum = c->jheads[jhead].wbuf.lnum; -+ *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; -+ dbg_jnl("jhead %d, LEB %d:%d, len %d", jhead, *lnum, *offs, len); -+ -+ err = ubifs_wbuf_write_nolock(wbuf, buf, len); -+ if (err) -+ return err; -+ if (sync) -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ return err; -+} -+ -+/** -+ * make_reservation - reserve journal space. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head -+ * @len: how many bytes to reserve -+ * -+ * This function makes space reservation in journal head @jhead. The function -+ * takes the commit lock and locks the journal head, and the caller has to -+ * unlock the head and finish the reservation with 'finish_reservation()'. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ * -+ * Note, the journal head may be unlocked as soon as the data is written, while -+ * the commit lock has to be released after the data has been added to the -+ * TNC. -+ */ -+static int make_reservation(struct ubifs_info *c, int jhead, int len) -+{ -+ int err, cmt_retries = 0, nospc_retries = 0; -+ -+ ubifs_assert(len <= c->dark_wm); -+ -+again: -+ down_read(&c->commit_sem); -+ err = reserve_space(c, jhead, len); -+ if (!err) -+ return 0; -+ up_read(&c->commit_sem); -+ -+ if (err == -ENOSPC) { -+ /* -+ * GC could not make any progress. We should try to commit -+ * once because it could make some dirty space and GC would -+ * make progress, so make the error -EAGAIN so that the below -+ * will commit and re-try. -+ */ -+ if (nospc_retries++ < 2) { -+ dbg_jnl("no space, retry"); -+ err = -EAGAIN; -+ } -+ -+ /* -+ * This means that the budgeting is incorrect. We always have -+ * to be able to write to the media, because all operations are -+ * budgeted. Deletions are not budgeted, though, but we reserve -+ * an extra LEB for them. -+ */ -+ } -+ -+ if (err != -EAGAIN) -+ goto out; -+ -+ /* -+ * -EAGAIN means that the journal is full or too large, or the above -+ * code wants to do one commit. Do this and re-try. -+ */ -+ if (cmt_retries > 128) { -+ /* -+ * This should not happen unless the journal size limitations -+ * are too tough. -+ */ -+ ubifs_err("stuck in space allocation"); -+ err = -ENOSPC; -+ goto out; -+ } else if (cmt_retries > 32) -+ ubifs_warn("too many space allocation re-tries (%d)", -+ cmt_retries); -+ -+ dbg_jnl("-EAGAIN, commit and retry (retried %d times)", -+ cmt_retries); -+ cmt_retries += 1; -+ -+ err = ubifs_run_commit(c); -+ if (err) -+ return err; -+ goto again; -+ -+out: -+ ubifs_err("cannot reserve %d bytes in jhead %d, error %d", -+ len, jhead, err); -+ if (err == -ENOSPC) { -+ /* This are some budgeting problems, print useful information */ -+ down_write(&c->commit_sem); -+ spin_lock(&c->space_lock); -+ dbg_dump_stack(); -+ dbg_dump_budg(c); -+ spin_unlock(&c->space_lock); -+ dbg_dump_lprops(c); -+ cmt_retries = dbg_check_lprops(c); -+ up_write(&c->commit_sem); -+ } -+ -+ return err; -+} -+ -+/** -+ * release_head - release a journal head. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head -+ * -+ * This function releases journal head @jhead which was locked by -+ * the 'make_reservation()' function. It has to be called after each successful -+ * 'make_reservation()' invocation. -+ */ -+static inline void release_head(struct ubifs_info *c, int jhead) -+{ -+ mutex_unlock(&c->jheads[jhead].wbuf.io_mutex); -+} -+ -+/** -+ * finish_reservation - finish a reservation. -+ * @c: UBIFS file-system description object -+ * -+ * This function finishes journal space reservation. It must be called after -+ * 'make_reservation()'. -+ */ -+static void finish_reservation(struct ubifs_info *c) -+{ -+ up_read(&c->commit_sem); -+} -+ -+/** -+ * get_dent_type - translate VFS inode mode to UBIFS directory entry type. -+ * @mode: inode mode -+ */ -+static int get_dent_type(int mode) -+{ -+ switch (mode & S_IFMT) { -+ case S_IFREG: -+ return UBIFS_ITYPE_REG; -+ case S_IFDIR: -+ return UBIFS_ITYPE_DIR; -+ case S_IFLNK: -+ return UBIFS_ITYPE_LNK; -+ case S_IFBLK: -+ return UBIFS_ITYPE_BLK; -+ case S_IFCHR: -+ return UBIFS_ITYPE_CHR; -+ case S_IFIFO: -+ return UBIFS_ITYPE_FIFO; -+ case S_IFSOCK: -+ return UBIFS_ITYPE_SOCK; -+ default: -+ BUG(); -+ } -+ return 0; -+} -+ -+/** -+ * pack_inode - pack an inode node. -+ * @c: UBIFS file-system description object -+ * @ino: buffer in which to pack inode node -+ * @inode: inode to pack -+ * @last: indicates the last node of the group -+ * @last_reference: non-zero if this is a deletion inode -+ */ -+static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, -+ const struct inode *inode, int last, int last_reference) -+{ -+ int data_len = 0; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ ino->ch.node_type = UBIFS_INO_NODE; -+ ino_key_init_flash(c, &ino->key, inode->i_ino); -+ ino->creat_sqnum = cpu_to_le64(ui->creat_sqnum); -+ ino->size = cpu_to_le64(i_size_read(inode)); -+ ino->nlink = cpu_to_le32(inode->i_nlink); -+ ino->atime_sec = cpu_to_le64(inode->i_atime.tv_sec); -+ ino->atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); -+ ino->ctime_sec = cpu_to_le64(inode->i_ctime.tv_sec); -+ ino->ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec); -+ ino->mtime_sec = cpu_to_le64(inode->i_mtime.tv_sec); -+ ino->mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec); -+ ino->uid = cpu_to_le32(inode->i_uid); -+ ino->gid = cpu_to_le32(inode->i_gid); -+ ino->mode = cpu_to_le32(inode->i_mode); -+ ino->flags = cpu_to_le32(ui->flags); -+ ino->compr_type = cpu_to_le16(ui->compr_type); -+ ino->xattr_cnt = cpu_to_le32(ui->xattr_cnt); -+ ino->xattr_size = cpu_to_le64(ui->xattr_size); -+ ino->xattr_names = cpu_to_le32(ui->xattr_names); -+ ino->data_len = cpu_to_le32(ui->data_len); -+ zero_ino_node_unused(ino); -+ -+ /* -+ * Drop the attached data if this is a deletion inode, the data is not -+ * needed anymore. -+ */ -+ if (!last_reference) { -+ memcpy(ino->data, ui->data, ui->data_len); -+ data_len = ui->data_len; -+ } -+ -+ ubifs_prep_grp_node(c, ino, UBIFS_INO_NODE_SZ + data_len, last); -+} -+ -+/** -+ * ubifs_jnl_update - update inode. -+ * @c: UBIFS file-system description object -+ * @dir: parent inode or host inode in case of extended attributes -+ * @nm: directory entry name -+ * @inode: inode -+ * @deletion: indicates a directory entry deletion i.e unlink or rmdir -+ * @sync: non-zero if the write-buffer has to be synchronized -+ * @xent: non-zero if the directory entry is an extended attribute entry -+ * -+ * This function updates an inode by writing a directory entry (or extended -+ * attribute entry), the inode itself, and the parent directory inode (or the -+ * host inode) to the journal. -+ * -+ * The function writes the host inode @dir last, which is important in case of -+ * extended attributes. Indeed, then we guarantee that if the host inode gets -+ * synchronized, and the write-buffer it sits in gets flushed, the extended -+ * attribute inode gets flushed too. And this is exactly what the user expects - -+ * synchronizing the host inode synchronizes its extended attributes. -+ * Similarly, this guarantees that if @dir is synchronized, its directory entry -+ * corresponding to @nm gets synchronized too. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, -+ const struct qstr *nm, const struct inode *inode, -+ int deletion, int sync, int xent) -+{ -+ int err, dlen, ilen, len, lnum, ino_offs, dent_offs; -+ int aligned_dlen, aligned_ilen; -+ int last_reference = !!(deletion && inode->i_nlink == 0); -+ struct ubifs_dent_node *dent; -+ struct ubifs_ino_node *ino; -+ union ubifs_key dent_key, ino_key; -+ -+ dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu", -+ inode->i_ino, nm->len, nm->name, ubifs_inode(inode)->data_len, -+ dir->i_ino); -+ ubifs_assert(ubifs_inode(dir)->data_len == 0); -+ -+ dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; -+ ilen = UBIFS_INO_NODE_SZ; -+ -+ /* -+ * If the last reference to the inode is being deleted, then there is no -+ * need to attach and write inode data, it is being deleted anyway. -+ */ -+ if (!last_reference) -+ ilen += ubifs_inode(inode)->data_len; -+ -+ aligned_dlen = ALIGN(dlen, 8); -+ aligned_ilen = ALIGN(ilen, 8); -+ -+ len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; -+ -+ dent = kmalloc(len, GFP_NOFS); -+ if (!dent) -+ return -ENOMEM; -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, len); -+ if (err) -+ goto out_free; -+ -+ if (!xent) { -+ dent->ch.node_type = UBIFS_DENT_NODE; -+ dent_key_init(c, &dent_key, dir->i_ino, nm); -+ } else { -+ dent->ch.node_type = UBIFS_XENT_NODE; -+ xent_key_init(c, &dent_key, dir->i_ino, nm); -+ } -+ -+ key_write(c, &dent_key, dent->key); -+ dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino); -+ dent->type = get_dent_type(inode->i_mode); -+ dent->nlen = cpu_to_le16(nm->len); -+ memcpy(dent->name, nm->name, nm->len); -+ dent->name[nm->len] = '\0'; -+ zero_dent_node_unused(dent); -+ ubifs_prep_grp_node(c, dent, dlen, 0); -+ -+ ino = (void *)dent + aligned_dlen; -+ pack_inode(c, ino, inode, 0, last_reference); -+ -+ ino = (void *)ino + aligned_ilen; -+ pack_inode(c, ino, dir, 1, 0); -+ -+ if (last_reference) { -+ err = ubifs_add_orphan(c, inode->i_ino); -+ if (err) { -+ release_head(c, BASEHD); -+ goto out_finish; -+ } -+ } -+ -+ err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); -+ if (!sync && !err) { -+ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; -+ -+ ubifs_wbuf_add_ino_nolock(wbuf, inode->i_ino); -+ ubifs_wbuf_add_ino_nolock(wbuf, dir->i_ino); -+ } -+ release_head(c, BASEHD); -+ kfree(dent); -+ if (err) -+ goto out_ro; -+ -+ if (deletion) { -+ err = ubifs_tnc_remove_nm(c, &dent_key, nm); -+ if (err) -+ goto out_ro; -+ err = ubifs_add_dirt(c, lnum, dlen); -+ } else -+ err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm); -+ if (err) -+ goto out_ro; -+ -+ /* -+ * Note, we do not remove the inode from TNC even if the last reference -+ * to it has just been deleted, because the inode may still be opened. -+ * Instead, the inode has been added to orphan lists and the orphan -+ * subsystem will take further care about it. -+ */ -+ ino_key_init(c, &ino_key, inode->i_ino); -+ ino_offs = dent_offs + aligned_dlen; -+ err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen); -+ if (err) -+ goto out_ro; -+ -+ ino_key_init(c, &ino_key, dir->i_ino); -+ ino_offs += aligned_ilen; -+ err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ); -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ return 0; -+ -+out_finish: -+ finish_reservation(c); -+out_free: -+ kfree(dent); -+ return err; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ if (last_reference) -+ ubifs_delete_orphan(c, inode->i_ino); -+ finish_reservation(c); -+ return err; -+} -+ -+/** -+ * ubifs_jnl_write_data - write a data node to the journal. -+ * @c: UBIFS file-system description object -+ * @inode: inode the data node belongs to -+ * @key: node key -+ * @buf: buffer to write -+ * @len: data length (must not exceed %UBIFS_BLOCK_SIZE) -+ * -+ * This function writes a data node to the journal. Returns %0 if the data node -+ * was successfully written, and a negative error code in case of failure. -+ */ -+int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, -+ const union ubifs_key *key, const void *buf, int len) -+{ -+ int err, lnum, offs, compr_type, out_len; -+ int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR; -+ const struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_data_node *data; -+ -+ dbg_jnl("ino %lu, blk %u, len %d, key %s", key_ino(c, key), -+ key_block(c, key), len, DBGKEY(key)); -+ ubifs_assert(len <= UBIFS_BLOCK_SIZE); -+ -+ data = kmalloc(dlen, GFP_NOFS); -+ if (!data) -+ return -ENOMEM; -+ -+ data->ch.node_type = UBIFS_DATA_NODE; -+ key_write(c, key, &data->key); -+ data->size = cpu_to_le32(len); -+ zero_data_node_unused(data); -+ -+ if (!(ui->flags && UBIFS_COMPR_FL)) -+ /* Compression is disabled for this inode */ -+ compr_type = UBIFS_COMPR_NONE; -+ else -+ compr_type = ui->compr_type; -+ -+ out_len = dlen - UBIFS_DATA_NODE_SZ; -+ ubifs_compress(buf, len, &data->data, &out_len, &compr_type); -+ ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); -+ -+ dlen = UBIFS_DATA_NODE_SZ + out_len; -+ data->compr_type = cpu_to_le16(compr_type); -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, DATAHD, dlen); -+ if (err) -+ goto out_free; -+ -+ err = write_node(c, DATAHD, data, dlen, &lnum, &offs); -+ if (!err) -+ ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, -+ key_ino(c, key)); -+ release_head(c, DATAHD); -+ if (err) -+ goto out_ro; -+ -+ err = ubifs_tnc_add(c, key, lnum, offs, dlen); -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ kfree(data); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ finish_reservation(c); -+out_free: -+ kfree(data); -+ return err; -+} -+ -+/** -+ * ubifs_jnl_write_inode - flush inode to the journal. -+ * @c: UBIFS file-system description object -+ * @inode: inode to flush -+ * @last_reference: inode has been deleted -+ * @sync: non-zero if the write-buffer has to be synchronized -+ * -+ * This function writes inode @inode to the journal (to the base head). Returns -+ * zero in case of success and a negative error code in case of failure. -+ */ -+int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, -+ int last_reference, int sync) -+{ -+ int err, len, lnum, offs; -+ struct ubifs_ino_node *ino; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ dbg_jnl("ino %lu%s", inode->i_ino, -+ last_reference ? " (last reference)" : ""); -+ if (last_reference) -+ ubifs_assert(inode->i_nlink == 0); -+ -+ /* If the inode is deleted, do not write the attached data */ -+ len = UBIFS_INO_NODE_SZ; -+ if (!last_reference) -+ len += ui->data_len; -+ ino = kmalloc(len, GFP_NOFS); -+ if (!ino) -+ return -ENOMEM; -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, len); -+ if (err) -+ goto out_free; -+ -+ pack_inode(c, ino, inode, 1, last_reference); -+ -+ err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); -+ if (!sync && !err) -+ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, -+ inode->i_ino); -+ release_head(c, BASEHD); -+ if (err) -+ goto out_ro; -+ -+ if (last_reference) { -+ err = ubifs_tnc_remove_ino(c, inode->i_ino); -+ if (err) -+ goto out_ro; -+ ubifs_delete_orphan(c, inode->i_ino); -+ err = ubifs_add_dirt(c, lnum, len); -+ } else { -+ union ubifs_key key; -+ -+ ino_key_init(c, &key, inode->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs, len); -+ } -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ kfree(ino); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ finish_reservation(c); -+out_free: -+ kfree(ino); -+ return err; -+} -+ -+/** -+ * ubifs_jnl_rename - rename a directory entry. -+ * @c: UBIFS file-system description object -+ * @old_dir: parent inode of directory entry to rename -+ * @old_dentry: directory entry to rename -+ * @new_dir: parent inode of directory entry to rename -+ * @new_dentry: new directory entry (or directory entry to replace) -+ * @sync: non-zero if the write-buffer has to be synchronized -+ * -+ * Returns zero in case of success and a negative error code in case of failure. -+ */ -+int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, -+ const struct dentry *old_dentry, -+ const struct inode *new_dir, -+ const struct dentry *new_dentry, int sync) -+{ -+ const struct inode *old_inode = old_dentry->d_inode; -+ const struct inode *new_inode = new_dentry->d_inode; -+ int err, dlen1, dlen2, ilen, lnum, offs, len; -+ int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; -+ int last_reference = !!(new_inode && new_inode->i_nlink == 0); -+ struct ubifs_dent_node *dent, *dent2; -+ void *p; -+ union ubifs_key key; -+ -+ dbg_jnl("dent '%.*s' in dir ino %lu to dent '%.*s' in dir ino %lu", -+ old_dentry->d_name.len, old_dentry->d_name.name, -+ old_dir->i_ino, new_dentry->d_name.len, -+ new_dentry->d_name.name, new_dir->i_ino); -+ -+ ubifs_assert(ubifs_inode(old_dir)->data_len == 0); -+ ubifs_assert(ubifs_inode(new_dir)->data_len == 0); -+ -+ dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1; -+ dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1; -+ if (new_inode) { -+ ilen = UBIFS_INO_NODE_SZ; -+ if (!last_reference) -+ ilen += ubifs_inode(new_inode)->data_len; -+ } else -+ ilen = 0; -+ -+ aligned_dlen1 = ALIGN(dlen1, 8); -+ aligned_dlen2 = ALIGN(dlen2, 8); -+ -+ len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); -+ if (old_dir != new_dir) -+ len += plen; -+ -+ dent = kmalloc(len, GFP_NOFS); -+ if (!dent) -+ return -ENOMEM; -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, len); -+ if (err) -+ goto out_free; -+ -+ /* Make new dent */ -+ dent->ch.node_type = UBIFS_DENT_NODE; -+ dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name); -+ dent->inum = cpu_to_le64(old_inode->i_ino); -+ dent->type = get_dent_type(old_inode->i_mode); -+ dent->nlen = cpu_to_le16(new_dentry->d_name.len); -+ memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len); -+ dent->name[new_dentry->d_name.len] = '\0'; -+ zero_dent_node_unused(dent); -+ ubifs_prep_grp_node(c, dent, dlen1, 0); -+ -+ dent2 = (void *)dent + aligned_dlen1; -+ -+ /* Make deletion dent */ -+ dent2->ch.node_type = UBIFS_DENT_NODE; -+ dent_key_init_flash(c, &dent2->key, old_dir->i_ino, -+ &old_dentry->d_name); -+ dent2->inum = 0; -+ dent2->type = DT_UNKNOWN; -+ dent2->nlen = cpu_to_le16(old_dentry->d_name.len); -+ memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len); -+ dent2->name[old_dentry->d_name.len] = '\0'; -+ zero_dent_node_unused(dent2); -+ ubifs_prep_grp_node(c, dent2, dlen2, 0); -+ -+ p = (void *)dent2 + aligned_dlen2; -+ if (new_inode) { -+ pack_inode(c, p, new_inode, 0, last_reference); -+ p += ALIGN(ilen, 8); -+ } -+ -+ if (old_dir == new_dir) -+ pack_inode(c, p, old_dir, 1, 0); -+ else { -+ pack_inode(c, p, old_dir, 0, 0); -+ p += ALIGN(plen, 8); -+ pack_inode(c, p, new_dir, 1, 0); -+ } -+ -+ if (last_reference) { -+ err = ubifs_add_orphan(c, new_inode->i_ino); -+ if (err) { -+ release_head(c, BASEHD); -+ goto out_finish; -+ } -+ } -+ -+ err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); -+ if (!sync && !err) { -+ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; -+ -+ ubifs_wbuf_add_ino_nolock(wbuf, new_dir->i_ino); -+ ubifs_wbuf_add_ino_nolock(wbuf, old_dir->i_ino); -+ if (new_inode) -+ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, -+ new_inode->i_ino); -+ } -+ release_head(c, BASEHD); -+ if (err) -+ goto out_ro; -+ -+ dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name); -+ err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name); -+ if (err) -+ goto out_ro; -+ -+ err = ubifs_add_dirt(c, lnum, dlen2); -+ if (err) -+ goto out_ro; -+ -+ dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name); -+ err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name); -+ if (err) -+ goto out_ro; -+ -+ offs += aligned_dlen1 + aligned_dlen2; -+ if (new_inode) { -+ ino_key_init(c, &key, new_inode->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs, ilen); -+ if (err) -+ goto out_ro; -+ offs += ALIGN(ilen, 8); -+ } -+ -+ ino_key_init(c, &key, old_dir->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs, plen); -+ if (err) -+ goto out_ro; -+ -+ if (old_dir != new_dir) { -+ offs += ALIGN(plen, 8); -+ ino_key_init(c, &key, new_dir->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs, plen); -+ if (err) -+ goto out_ro; -+ } -+ -+ finish_reservation(c); -+ kfree(dent); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ if (last_reference) -+ ubifs_delete_orphan(c, new_inode->i_ino); -+out_finish: -+ finish_reservation(c); -+out_free: -+ kfree(dent); -+ return err; -+} -+ -+/** -+ * recomp_data_node - re-compress a truncated data node. -+ * @dn: data node to re-compress -+ * @new_len: new length -+ * -+ * This function is used when an inode is truncated and the last data node of -+ * the inode has to be re-compressed and re-written. -+ */ -+static int recomp_data_node(struct ubifs_data_node *dn, int *new_len) -+{ -+ void *buf; -+ int err, len, compr_type, out_len; -+ -+ out_len = le32_to_cpu(dn->size); -+ buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); -+ if (!buf) -+ return -ENOMEM; -+ -+ len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; -+ compr_type = le16_to_cpu(dn->compr_type); -+ err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type); -+ if (err) -+ goto out; -+ -+ ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type); -+ ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); -+ dn->compr_type = cpu_to_le16(compr_type); -+ dn->size = cpu_to_le32(*new_len); -+ *new_len = UBIFS_DATA_NODE_SZ + out_len; -+out: -+ kfree(buf); -+ return err; -+} -+ -+/** -+ * ubifs_jnl_truncate - update the journal for a truncation. -+ * @c: UBIFS file-system description object -+ * @inum: inode number of inode being truncated -+ * @old_size: old size -+ * @new_size: new size -+ * -+ * When the size of a file decreases due to truncation, a truncation node is -+ * written, the journal tree is updated, and the last data block is re-written -+ * if it has been affected. -+ * -+ * This function returns %0 in the case of success, and a negative error code in -+ * case of failure. -+ */ -+int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum, -+ loff_t old_size, loff_t new_size) -+{ -+ union ubifs_key key, to_key; -+ struct ubifs_trun_node *trun; -+ struct ubifs_data_node *uninitialized_var(dn); -+ int err, dlen, len, lnum, offs, bit, sz; -+ unsigned int blk; -+ -+ dbg_jnl("ino %lu, size %lld -> %lld", inum, old_size, new_size); -+ -+ sz = UBIFS_TRUN_NODE_SZ + UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR; -+ trun = kmalloc(sz, GFP_NOFS); -+ if (!trun) -+ return -ENOMEM; -+ -+ trun->ch.node_type = UBIFS_TRUN_NODE; -+ trun_key_init_flash(c, &trun->key, inum); -+ trun->old_size = cpu_to_le64(old_size); -+ trun->new_size = cpu_to_le64(new_size); -+ -+ dlen = new_size & (UBIFS_BLOCK_SIZE - 1); -+ -+ if (dlen) { -+ /* Get last data block so it can be truncated */ -+ dn = (void *)trun + ALIGN(UBIFS_TRUN_NODE_SZ, 8); -+ blk = new_size / UBIFS_BLOCK_SIZE; -+ data_key_init(c, &key, inum, blk); -+ dbg_jnl("last block key %s", DBGKEY(&key)); -+ err = ubifs_tnc_lookup(c, &key, dn); -+ if (err == -ENOENT) -+ dlen = 0; /* Not found (so it is a hole) */ -+ else if (err) -+ goto out_free; -+ else { -+ if (le32_to_cpu(dn->size) <= dlen) -+ dlen = 0; /* Nothing to do */ -+ else { -+ int compr_type = le16_to_cpu(dn->compr_type); -+ -+ if (compr_type != UBIFS_COMPR_NONE) { -+ err = recomp_data_node(dn, &dlen); -+ if (err) -+ goto out_free; -+ } else { -+ dn->size = cpu_to_le32(dlen); -+ dlen += UBIFS_DATA_NODE_SZ; -+ } -+ zero_data_node_unused(dn); -+ } -+ } -+ } -+ -+ if (dlen) -+ len = ALIGN(UBIFS_TRUN_NODE_SZ, 8) + dlen; -+ else -+ len = UBIFS_TRUN_NODE_SZ; -+ -+ /* Must make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, len); -+ if (err) -+ goto out_free; -+ -+ ubifs_prepare_node(c, trun, UBIFS_TRUN_NODE_SZ, 0); -+ if (dlen) -+ ubifs_prepare_node(c, dn, dlen, 0); -+ -+ err = write_head(c, BASEHD, trun, len, &lnum, &offs, 0); -+ if (!err) -+ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum); -+ release_head(c, BASEHD); -+ if (err) -+ goto out_ro; -+ -+ if (dlen) { -+ offs += ALIGN(UBIFS_TRUN_NODE_SZ, 8); -+ err = ubifs_tnc_add(c, &key, lnum, offs, dlen); -+ if (err) -+ goto out_ro; -+ } -+ -+ err = ubifs_add_dirt(c, lnum, UBIFS_TRUN_NODE_SZ); -+ if (err) -+ goto out_ro; -+ -+ bit = new_size & (UBIFS_BLOCK_SIZE - 1); -+ -+ blk = new_size / UBIFS_BLOCK_SIZE + (bit ? 1 : 0); -+ data_key_init(c, &key, inum, blk); -+ -+ bit = old_size & (UBIFS_BLOCK_SIZE - 1); -+ -+ blk = old_size / UBIFS_BLOCK_SIZE - (bit ? 0: 1); -+ data_key_init(c, &to_key, inum, blk); -+ -+ err = ubifs_tnc_remove_range(c, &key, &to_key); -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ kfree(trun); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ finish_reservation(c); -+out_free: -+ kfree(trun); -+ return err; -+} -+ -+#ifdef CONFIG_UBIFS_FS_XATTR -+ -+int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, -+ const struct inode *inode, const struct qstr *nm, -+ int sync) -+{ -+ int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; -+ struct ubifs_dent_node *xent; -+ struct ubifs_ino_node *ino; -+ union ubifs_key xent_key, key1, key2; -+ -+ dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d", -+ host->i_ino, inode->i_ino, nm->name, -+ ubifs_inode(inode)->data_len); -+ ubifs_assert(inode->i_nlink == 0); -+ -+ /* -+ * Since we are deleting the inode, we do not bother to attach any data -+ * to it and assume its length is %UBIFS_INO_NODE_SZ. -+ */ -+ xlen = UBIFS_DENT_NODE_SZ + nm->len + 1; -+ aligned_xlen = ALIGN(xlen, 8); -+ hlen = ubifs_inode(host)->data_len + UBIFS_INO_NODE_SZ; -+ len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); -+ -+ xent = kmalloc(len, GFP_NOFS); -+ if (!xent) -+ return -ENOMEM; -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, len); -+ if (err) { -+ kfree(xent); -+ return err; -+ } -+ -+ xent->ch.node_type = UBIFS_XENT_NODE; -+ xent_key_init(c, &xent_key, host->i_ino, nm); -+ key_write(c, &xent_key, xent->key); -+ xent->inum = 0; -+ xent->type = get_dent_type(inode->i_mode); -+ xent->nlen = cpu_to_le16(nm->len); -+ memcpy(xent->name, nm->name, nm->len); -+ xent->name[nm->len] = '\0'; -+ zero_dent_node_unused(xent); -+ ubifs_prep_grp_node(c, xent, xlen, 0); -+ -+ ino = (void *)xent + aligned_xlen; -+ pack_inode(c, ino, inode, 0, 1); -+ -+ ino = (void *)ino + UBIFS_INO_NODE_SZ; -+ pack_inode(c, ino, host, 1, 0); -+ -+ err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); -+ if (!sync && !err) -+ ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino); -+ release_head(c, BASEHD); -+ kfree(xent); -+ if (err) -+ goto out_ro; -+ -+ /* Remove the extended attribute entry from TNC */ -+ err = ubifs_tnc_remove_nm(c, &xent_key, nm); -+ if (err) -+ goto out_ro; -+ err = ubifs_add_dirt(c, lnum, xlen); -+ if (err) -+ goto out_ro; -+ -+ /* -+ * Remove all nodes belonging to the extended attribute inode from TNC. -+ * Well, there actually must be only one node - the inode itself. -+ */ -+ lowest_ino_key(c, &key1, inode->i_ino); -+ highest_ino_key(c, &key2, inode->i_ino); -+ err = ubifs_tnc_remove_range(c, &key1, &key2); -+ if (err) -+ goto out_ro; -+ err = ubifs_add_dirt(c, lnum, UBIFS_INO_NODE_SZ); -+ if (err) -+ goto out_ro; -+ -+ /* And update TNC with the new host inode position */ -+ ino_key_init(c, &key1, host->i_ino); -+ err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen); -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ finish_reservation(c); -+ return err; -+} -+ -+/** -+ * ubifs_jnl_write_2_inodes - write 2 inodes to the journal. -+ * @c: UBIFS file-system description object -+ * @inode1: first inode to write -+ * @inode2: second inode to write -+ * @sync: non-zero if the write-buffer has to be synchronized -+ * -+ * This function writes 2 inodes @inode1 and @inode2 to the journal (to the -+ * base head - first @inode1, then @inode2). Returns zero in case of success -+ * and a negative error code in case of failure. -+ */ -+int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1, -+ const struct inode *inode2, int sync) -+{ -+ int err, len1, len2, aligned_len, aligned_len1, lnum, offs; -+ struct ubifs_ino_node *ino; -+ union ubifs_key key; -+ -+ dbg_jnl("ino %lu, ino %lu", inode1->i_ino, inode2->i_ino); -+ ubifs_assert(inode1->i_nlink > 0); -+ ubifs_assert(inode2->i_nlink > 0); -+ -+ len1 = UBIFS_INO_NODE_SZ + ubifs_inode(inode1)->data_len; -+ len2 = UBIFS_INO_NODE_SZ + ubifs_inode(inode2)->data_len; -+ aligned_len1 = ALIGN(len1, 8); -+ aligned_len = aligned_len1 + ALIGN(len2, 8); -+ -+ ino = kmalloc(aligned_len, GFP_NOFS); -+ if (!ino) -+ return -ENOMEM; -+ -+ /* Make reservation before allocating sequence numbers */ -+ err = make_reservation(c, BASEHD, aligned_len); -+ if (err) -+ goto out_free; -+ -+ pack_inode(c, ino, inode1, 0, 0); -+ pack_inode(c, (void *)ino + aligned_len1, inode2, 1, 0); -+ -+ err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); -+ if (!sync && !err) { -+ struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; -+ -+ ubifs_wbuf_add_ino_nolock(wbuf, inode1->i_ino); -+ ubifs_wbuf_add_ino_nolock(wbuf, inode2->i_ino); -+ } -+ release_head(c, BASEHD); -+ if (err) -+ goto out_ro; -+ -+ ino_key_init(c, &key, inode1->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs, len1); -+ if (err) -+ goto out_ro; -+ -+ ino_key_init(c, &key, inode2->i_ino); -+ err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2); -+ if (err) -+ goto out_ro; -+ -+ finish_reservation(c); -+ kfree(ino); -+ return 0; -+ -+out_ro: -+ ubifs_ro_mode(c, err); -+ finish_reservation(c); -+out_free: -+ kfree(ino); -+ return err; -+} -+ -+#endif /* CONFIG_UBIFS_FS_XATTR */ -diff -urN linux-2.6.24.7.old/fs/ubifs/key.h linux-2.6.24.7/fs/ubifs/key.h ---- linux-2.6.24.7.old/fs/ubifs/key.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/key.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,566 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This header contains various key-related definitions and helper function. -+ * UBIFS allows several key schemes, so we access key fields only via these -+ * helpers. At the moment only one key scheme is supported. -+ * -+ * Simple key scheme -+ * ~~~~~~~~~~~~~~~~~ -+ * -+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number -+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are -+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry -+ * node. We use "r5" hash borrowed from reiserfs. -+ */ -+ -+#ifndef __UBIFS_KEY_H__ -+#define __UBIFS_KEY_H__ -+ -+/** -+ * key_r5_hash - R5 hash function (borrowed from reiserfs). -+ * @s: direntry name -+ * @len: name length -+ */ -+static inline uint32_t key_r5_hash(const char *s, int len) -+{ -+ uint32_t a = 0; -+ const signed char *str = (const signed char *)s; -+ -+ while (*str) { -+ a += *str << 4; -+ a += *str >> 4; -+ a *= 11; -+ str++; -+ } -+ -+ /* TODO: change this to -+ * a &= UBIFS_S_KEY_HASH_MASK; */ -+ a &= 0x1FFFFFFF; -+ -+ /* -+ * We use hash values as offset in directories, so values %0 and %1 are -+ * reserved for "." and "..". %2 is reserved for "end of readdir" -+ * marker. -+ */ -+ if (unlikely(a >= 0 && a <= 2)) -+ a += 3; -+ return a; -+} -+ -+/** -+ * tmp_key_r5_hash - R5 hash function (borrowed from reiserfs). -+ * @s: direntry name -+ * @len: name length -+ * TODO: this should die soon -+ */ -+static inline uint32_t tmp_key_r5_hash(const char *s, int len) -+{ -+ uint32_t a = 0; -+ const signed char *str = (const signed char *)s; -+ -+ while (*str) { -+ a += *str << 4; -+ a += *str >> 4; -+ a *= 11; -+ str++; -+ } -+ -+ a &= 0x01FFFFFF; -+ -+ /* -+ * We use hash values as offset in directories, so values %0 and %1 are -+ * reserved for "." and "..". %2 is reserved for possible future use. -+ */ -+ if (unlikely(a >= 0 && a <= 2)) -+ a += 3; -+ return a; -+} -+ -+/** -+ * key_test_hash - testing hash function. -+ * @str: direntry name -+ * @len: name length -+ */ -+static inline uint32_t key_test_hash(const char *str, int len) -+{ -+ uint32_t a = 0; -+ -+ len = min_t(uint32_t, len, 4); -+ memcpy(&a, str, len); -+ /* TODO: change this to -+ * a &= UBIFS_S_KEY_HASH_MASK; */ -+ a &= 0x1FFFFFFF; -+ if (unlikely(a >= 0 && a <= 2)) -+ a += 3; -+ return a; -+} -+ -+/** -+ * ino_key_init - initialize inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void ino_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * ino_key_init_flash - initialize on-flash inode key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ */ -+static inline void ino_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum) -+{ -+ union ubifs_key *key = k; -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_ino_key - get the lowest possible inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void lowest_ino_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = 0; -+} -+ -+/** -+ * highest_ino_key - get the highest possible inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void highest_ino_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = 0xffffffff; -+} -+ -+/** -+ * dent_key_init - initialize directory entry key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: parent inode number -+ * @nm: direntry name and length -+ */ -+static inline void dent_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ const struct qstr *nm) -+{ -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * dent_key_init_hash - initialize directory entry key without re-calculating -+ * hash function. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: parent inode number -+ * @hash: direntry name hash -+ */ -+static inline void dent_key_init_hash(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ uint32_t hash) -+{ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * dent_key_init_flash - initialize on-flash directory entry key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: parent inode number -+ * @nm: direntry name and length -+ */ -+static inline void dent_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, const struct qstr *nm) -+{ -+ union ubifs_key *key = k; -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(hash | -+ (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_dent_key - get the lowest possible directory entry key. -+ * @c: UBIFS file-system description object -+ * @key: where to store the lowest key -+ * @inum: parent inode number -+ */ -+static inline void lowest_dent_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS; -+} -+ -+/** -+ * xent_key_init - initialize extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: host inode number -+ * @nm: extended attribute entry name and length -+ */ -+static inline void xent_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ const struct qstr *nm) -+{ -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * xent_key_init_hash - initialize extended attribute entry key without -+ * re-calculating hash function. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: host inode number -+ * @hash: extended attribute entry name hash -+ */ -+static inline void xent_key_init_hash(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ uint32_t hash) -+{ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * xent_key_init_flash - initialize on-flash extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: host inode number -+ * @nm: extended attribute entry name and length -+ */ -+static inline void xent_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, const struct qstr *nm) -+{ -+ union ubifs_key *key = k; -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(hash | -+ (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_xent_key - get the lowest possible extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @key: where to store the lowest key -+ * @inum: host inode number -+ */ -+static inline void lowest_xent_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS; -+} -+ -+/** -+ * data_key_init - initialize data key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ * @block: block number -+ */ -+static inline void data_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ unsigned int block) -+{ -+ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK)); -+ key->u32[0] = inum; -+ key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS); -+} -+ -+/** -+ * data_key_init_flash - initialize on-flash data key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ * @block: block number -+ */ -+static inline void data_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, unsigned int block) -+{ -+ union ubifs_key *key = k; -+ -+ ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK)); -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(block | -+ (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * trun_key_init - initialize truncation node key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void trun_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * trun_key_init_flash - initialize on-flash truncation node key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ */ -+static inline void trun_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum) -+{ -+ union ubifs_key *key = k; -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * key_type - get key type. -+ * @c: UBIFS file-system description object -+ * @key: key to get type of -+ */ -+static inline int key_type(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * key_type_flash - get type of a on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: key to get type of -+ */ -+static inline int key_type_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->u32[1]) >> UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * key_ino - fetch inode number from key. -+ * @c: UBIFS file-system description object -+ * @k: key to fetch inode number from -+ */ -+static inline ino_t key_ino(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return key->u32[0]; -+} -+ -+/** -+ * key_ino_flash - fetch inode number from an on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: key to fetch inode number from -+ */ -+static inline ino_t key_ino_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->j32[0]); -+} -+ -+/** -+ * key_hash - get directory entry hash. -+ * @c: UBIFS file-system description object -+ * @key: the key to get hash from -+ */ -+static inline int key_hash(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] & UBIFS_S_KEY_HASH_MASK; -+} -+ -+/** -+ * key_hash_flash - get directory entry hash from an on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: the key to get hash from -+ */ -+static inline int key_hash_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK; -+} -+ -+/** -+ * key_block - get data block number. -+ * @c: UBIFS file-system description object -+ * @key: the key to get the block number from -+ */ -+static inline unsigned int key_block(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK; -+} -+ -+/** -+ * key_read - transform a key to in-memory format. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_read(const struct ubifs_info *c, const void *from, -+ union ubifs_key *to) -+{ -+ const union ubifs_key *f = from; -+ -+ to->u32[0] = le32_to_cpu(f->j32[0]); -+ to->u32[1] = le32_to_cpu(f->j32[1]); -+} -+ -+/** -+ * key_write - transform a key from in-memory format. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_write(const struct ubifs_info *c, -+ const union ubifs_key *from, void *to) -+{ -+ union ubifs_key *t = to; -+ -+ t->j32[0] = cpu_to_le32(from->u32[0]); -+ t->j32[1] = cpu_to_le32(from->u32[1]); -+ memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * key_write_idx - transform a key from in-memory format for the index. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_write_idx(const struct ubifs_info *c, -+ const union ubifs_key *from, void *to) -+{ -+ union ubifs_key *t = to; -+ -+ t->j32[0] = cpu_to_le32(from->u32[0]); -+ t->j32[1] = cpu_to_le32(from->u32[1]); -+} -+ -+/** -+ * key_copy - copy a key. -+ * @c: UBIFS file-system description object -+ * @from: the key to copy from -+ * @to: the key to copy to -+ */ -+static inline void key_copy(const struct ubifs_info *c, -+ const union ubifs_key *from, union ubifs_key *to) -+{ -+ to->u64[0] = from->u64[0]; -+} -+ -+/** -+ * keys_cmp - compare keys. -+ * @c: UBIFS file-system description object -+ * @key1: the first key to compare -+ * @key2: the second key to compare -+ * -+ * This function compares 2 keys and returns %-1 if @key1 is less than -+ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2. -+ */ -+static inline int keys_cmp(const struct ubifs_info *c, -+ const union ubifs_key *key1, -+ const union ubifs_key *key2) -+{ -+ if (key1->u32[0] < key2->u32[0]) -+ return -1; -+ if (key1->u32[0] > key2->u32[0]) -+ return 1; -+ if (key1->u32[1] < key2->u32[1]) -+ return -1; -+ if (key1->u32[1] > key2->u32[1]) -+ return 1; -+ -+ return 0; -+} -+ -+/** -+ * is_hash_key - is a key vulnerable to hash collisions. -+ * @c: UBIFS file-system description object -+ * @key: key -+ * -+ * This function returns %1 if @key is a hashed key or %0 otherwise. -+ */ -+static inline int is_hash_key(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ int type = key_type(c, key); -+ -+ return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY; -+} -+ -+/** -+ * key_max_inode_size - get maximum file size allowed by current key format. -+ * @c: UBIFS file-system description object -+ */ -+static inline unsigned long long key_max_inode_size(const struct ubifs_info *c) -+{ -+ switch (c->key_fmt) { -+ case UBIFS_SIMPLE_KEY_FMT: -+ return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE; -+ default: -+ return 0; -+ } -+} -+#endif /* !__UBIFS_KEY_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/log.c linux-2.6.24.7/fs/ubifs/log.c ---- linux-2.6.24.7.old/fs/ubifs/log.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/log.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,803 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file is a part of UBIFS journal implementation and contains various -+ * functions which manipulate the log. The log is a fixed area on the flash -+ * which does not contain any data but refers to buds. The log is a part of the -+ * journal. -+ */ -+ -+#include "ubifs.h" -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+static int dbg_check_bud_bytes(struct ubifs_info *c); -+#else -+#define dbg_check_bud_bytes(c) 0 -+#endif -+ -+/** -+ * ubifs_search_bud - search bud LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: logical eraseblock number to search -+ * -+ * This function searches bud LEB @lnum. Returns bud description object in case -+ * of success and %NULL if there is no bud with this LEB number. -+ */ -+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum) -+{ -+ struct rb_node *p; -+ struct ubifs_bud *bud; -+ -+ spin_lock(&c->buds_lock); -+ p = c->buds.rb_node; -+ while (p) { -+ bud = rb_entry(p, struct ubifs_bud, rb); -+ if (lnum < bud->lnum) -+ p = p->rb_left; -+ else if (lnum > bud->lnum) -+ p = p->rb_right; -+ else { -+ spin_unlock(&c->buds_lock); -+ return bud; -+ } -+ } -+ spin_unlock(&c->buds_lock); -+ return NULL; -+} -+ -+/** -+ * ubifs_get_wbuf - get the wbuf associated with a LEB, if there is one. -+ * @c: UBIFS file-system description object -+ * @lnum: logical eraseblock number to search -+ * -+ * This functions returns the wbuf for @lnum or %NULL if there is not one. -+ */ -+struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum) -+{ -+ struct rb_node *p; -+ struct ubifs_bud *bud; -+ int jhead; -+ -+ if (!c->jheads) -+ return NULL; -+ -+ spin_lock(&c->buds_lock); -+ p = c->buds.rb_node; -+ while (p) { -+ bud = rb_entry(p, struct ubifs_bud, rb); -+ if (lnum < bud->lnum) -+ p = p->rb_left; -+ else if (lnum > bud->lnum) -+ p = p->rb_right; -+ else { -+ jhead = bud->jhead; -+ spin_unlock(&c->buds_lock); -+ return &c->jheads[jhead].wbuf; -+ } -+ } -+ spin_unlock(&c->buds_lock); -+ return NULL; -+} -+ -+/** -+ * next_log_lnum - switch to the next log LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: current log LEB -+ */ -+static inline int next_log_lnum(const struct ubifs_info *c, int lnum) -+{ -+ lnum += 1; -+ if (lnum > c->log_last) -+ lnum = UBIFS_LOG_LNUM; -+ -+ return lnum; -+} -+ -+/** -+ * empty_log_bytes - calculate amount of empty space in the log. -+ * @c: UBIFS file-system description object -+ */ -+static inline long long empty_log_bytes(const struct ubifs_info *c) -+{ -+ long long h, t; -+ -+ h = c->lhead_lnum * c->leb_size + c->lhead_offs; -+ t = c->ltail_lnum * c->leb_size; -+ -+ if (h >= t) -+ return c->log_bytes - h + t; -+ else -+ return t - h; -+} -+ -+/** -+ * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list. -+ * @c: UBIFS file-system description object -+ * @bud: the bud to add -+ */ -+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud) -+{ -+ struct rb_node **p, *parent = NULL; -+ struct ubifs_bud *b; -+ struct ubifs_jhead *jhead; -+ -+ spin_lock(&c->buds_lock); -+ p = &c->buds.rb_node; -+ while (*p) { -+ parent = *p; -+ b = rb_entry(parent, struct ubifs_bud, rb); -+ ubifs_assert(bud->lnum != b->lnum); -+ if (bud->lnum < b->lnum) -+ p = &(*p)->rb_left; -+ else -+ p = &(*p)->rb_right; -+ } -+ -+ rb_link_node(&bud->rb, parent, p); -+ rb_insert_color(&bud->rb, &c->buds); -+ if (c->jheads) { -+ jhead = &c->jheads[bud->jhead]; -+ list_add_tail(&bud->list, &jhead->buds_list); -+ } else -+ ubifs_assert(c->replaying && (c->vfs_sb->s_flags & MS_RDONLY)); -+ -+ /* -+ * Note, although this is a new bud, we anyway account this space now, -+ * before any data has been written to it, because this is about to -+ * guarantee fixed mount time, and this bud will anyway be read and -+ * scanned. -+ */ -+ c->bud_bytes += c->leb_size - bud->start; -+ -+ dbg_log("LEB %d:%d, jhead %d, bud_bytes %lld", bud->lnum, -+ bud->start, bud->jhead, c->bud_bytes); -+ spin_unlock(&c->buds_lock); -+} -+ -+/** -+ * ubifs_create_buds_lists - create journal head buds lists for remount rw. -+ * @c: UBIFS file-system description object -+ */ -+void ubifs_create_buds_lists(struct ubifs_info *c) -+{ -+ struct rb_node *p; -+ -+ spin_lock(&c->buds_lock); -+ p = rb_first(&c->buds); -+ while (p) { -+ struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb); -+ struct ubifs_jhead *jhead = &c->jheads[bud->jhead]; -+ -+ list_add_tail(&bud->list, &jhead->buds_list); -+ p = rb_next(p); -+ } -+ spin_unlock(&c->buds_lock); -+} -+ -+/** -+ * ubifs_add_bud_to_log - add a new bud to the log. -+ * @c: UBIFS file-system description object -+ * @jhead: journal head the bud belongs to -+ * @lnum: LEB number of the bud -+ * @offs: starting offset of the bud -+ * -+ * This function writes reference node for the new bud LEB @lnum it to the log, -+ * and adds it to the buds tress. It also makes sure that log size does not -+ * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success, -+ * %-EAGAIN if commit is required, and a negative error codes in case of -+ * failure. -+ */ -+int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) -+{ -+ int err; -+ struct ubifs_bud *bud; -+ struct ubifs_ref_node *ref; -+ -+ bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS); -+ if (!bud) -+ return -ENOMEM; -+ ref = kzalloc(c->ref_node_alsz, GFP_NOFS); -+ if (!ref) { -+ kfree(bud); -+ return -ENOMEM; -+ } -+ -+ mutex_lock(&c->log_mutex); -+ /* Make sure we have enough space in the log */ -+ if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) { -+ dbg_log("not enough log space - %lld, required %d", -+ empty_log_bytes(c), c->min_log_bytes); -+ ubifs_commit_required(c); -+ err = -EAGAIN; -+ goto out_unlock; -+ } -+ -+ /* -+ * Make sure the the amount of space in buds will not exceed -+ * 'c->max_bud_bytes' limit, because we want to guarantee mount time -+ * limits. -+ * -+ * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes -+ * because we are holding @c->log_mutex. All @c->bud_bytes take place -+ * when both @c->log_mutex and @c->bud_bytes are locked. -+ */ -+ if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) { -+ dbg_log("bud bytes %lld (%lld max), require commit", -+ c->bud_bytes, c->max_bud_bytes); -+ ubifs_commit_required(c); -+ err = -EAGAIN; -+ goto out_unlock; -+ } -+ -+ /* -+ * If the journal is full enough - start background commit. Note, it is -+ * OK to read 'c->cmt_state' without spinlock because integer reads -+ * are atomic in the kernel. -+ */ -+ if (c->bud_bytes >= c->bg_bud_bytes && -+ c->cmt_state == COMMIT_RESTING) { -+ dbg_log("bud bytes %lld (%lld max), initiate BG commit", -+ c->bud_bytes, c->max_bud_bytes); -+ ubifs_request_bg_commit(c); -+ } -+ -+ bud->lnum = lnum; -+ bud->start = offs; -+ bud->jhead = jhead; -+ -+ ref->ch.node_type = UBIFS_REF_NODE; -+ ref->lnum = cpu_to_le32(bud->lnum); -+ ref->offs = cpu_to_le32(bud->start); -+ ref->jhead = cpu_to_le32(jhead); -+ -+ if (c->lhead_offs > c->leb_size - c->ref_node_alsz) { -+ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); -+ c->lhead_offs = 0; -+ } -+ -+ if (c->lhead_offs == 0) { -+ /* Must ensure next log LEB has been unmapped */ -+ err = ubifs_leb_unmap(c, c->lhead_lnum); -+ if (err) -+ goto out_unlock; -+ } -+ -+ if (bud->start == 0) { -+ /* -+ * Before writing the LEB reference which refers an empty LEB -+ * to the log, we have to make sure it is mapped, because -+ * otherwise we'd risk to refer an LEB with garbage in case of -+ * an unclean reboot, because the target LEB might have been -+ * unmapped, but not yet physically erased. -+ */ -+ err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM); -+ if (err) -+ goto out_unlock; -+ } -+ -+ dbg_log("write ref LEB %d:%d", -+ c->lhead_lnum, c->lhead_offs); -+ err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum, -+ c->lhead_offs, UBI_SHORTTERM); -+ c->lhead_offs += c->ref_node_alsz; -+ if (err) -+ goto out_unlock; -+ -+ ubifs_add_bud(c, bud); -+ -+ mutex_unlock(&c->log_mutex); -+ kfree(ref); -+ return 0; -+ -+out_unlock: -+ mutex_unlock(&c->log_mutex); -+ kfree(ref); -+ kfree(bud); -+ return err; -+} -+ -+/** -+ * remove_buds - remove used buds. -+ * @c: UBIFS file-system description object -+ * -+ * This function removes use buds from the buds tree. It does not remove the -+ * buds which are pointed to by journal heads. -+ */ -+static void remove_buds(struct ubifs_info *c) -+{ -+ struct rb_node *p; -+ -+ ubifs_assert(list_empty(&c->old_buds)); -+ c->cmt_bud_bytes = 0; -+ spin_lock(&c->buds_lock); -+ p = rb_first(&c->buds); -+ while (p) { -+ struct rb_node *p1 = p; -+ struct ubifs_bud *bud; -+ struct ubifs_wbuf *wbuf; -+ -+ p = rb_next(p); -+ bud = rb_entry(p1, struct ubifs_bud, rb); -+ wbuf = &c->jheads[bud->jhead].wbuf; -+ -+ if (wbuf->lnum == bud->lnum) { -+ /* -+ * Do not remove buds which are pointed to by journal -+ * heads (non-closed buds). -+ */ -+ c->cmt_bud_bytes += wbuf->offs - bud->start; -+ dbg_log("preserve %d:%d, jhead %d, bud bytes %d, " -+ "cmt_bud_bytes %lld", bud->lnum, bud->start, -+ bud->jhead, wbuf->offs - bud->start, -+ c->cmt_bud_bytes); -+ bud->start = wbuf->offs; -+ } else { -+ c->cmt_bud_bytes += c->leb_size - bud->start; -+ dbg_log("remove %d:%d, jhead %d, bud bytes %d, " -+ "cmt_bud_bytes %lld", bud->lnum, bud->start, -+ bud->jhead, c->leb_size - bud->start, -+ c->cmt_bud_bytes); -+ rb_erase(p1, &c->buds); -+ list_del(&bud->list); -+ /* -+ * If the commit does not finish, the recovery will need -+ * to replay the journal, in which case the old buds -+ * must be unchanged. Do not release them until post -+ * commit i.e. do not allow them to be garbage -+ * collected. -+ */ -+ list_add(&bud->list, &c->old_buds); -+ } -+ } -+ spin_unlock(&c->buds_lock); -+} -+ -+/** -+ * ubifs_log_start_commit - start commit. -+ * @c: UBIFS file-system description object -+ * @ltail_lnum: return new log tail LEB number -+ * -+ * The commit operation starts with writing "commit start" node to the log and -+ * reference nodes for all journal heads which will define new journal after -+ * the commit has been finished. The commit start and reference nodes are -+ * written in one go to the nearest empty log LEB (hence, when commit is -+ * finished UBIFS may safely unmap all the previous log LEBs). This function -+ * returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) -+{ -+ void *buf; -+ struct ubifs_cs_node *cs; -+ struct ubifs_ref_node *ref; -+ int err, i, max_len, len; -+ -+ err = dbg_check_bud_bytes(c); -+ if (err) -+ return err; -+ -+ max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ; -+ max_len = ALIGN(max_len, c->min_io_size); -+ buf = cs = kmalloc(max_len, GFP_NOFS); -+ if (!buf) -+ return -ENOMEM; -+ -+ cs->ch.node_type = UBIFS_CS_NODE; -+ cs->cmt_no = cpu_to_le64(c->cmt_no + 1); -+ ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); -+ -+ /* -+ * Note, we do not lock 'c->log_mutex' because this is the commit start -+ * phase and we are exclusively using the log. And we do not lock -+ * write-buffer because nobody can write to the file-system at this -+ * phase. -+ */ -+ -+ len = UBIFS_CS_NODE_SZ; -+ for (i = 0; i < c->jhead_cnt; i++) { -+ int lnum = c->jheads[i].wbuf.lnum; -+ int offs = c->jheads[i].wbuf.offs; -+ -+ if (lnum == -1 || offs == c->leb_size) -+ continue; -+ -+ dbg_log("add ref to LEB %d:%d for jhead %d", lnum, offs, i); -+ ref = buf + len; -+ ref->ch.node_type = UBIFS_REF_NODE; -+ ref->lnum = cpu_to_le32(lnum); -+ ref->offs = cpu_to_le32(offs); -+ ref->jhead = cpu_to_le32(i); -+ -+ ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); -+ len += UBIFS_REF_NODE_SZ; -+ } -+ -+ ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); -+ -+ /* Switch to the next log LEB */ -+ if (c->lhead_offs) { -+ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); -+ c->lhead_offs = 0; -+ } -+ -+ if (c->lhead_offs == 0) { -+ /* Must ensure next LEB has been unmapped */ -+ err = ubifs_leb_unmap(c, c->lhead_lnum); -+ if (err) -+ goto out; -+ } -+ -+ len = ALIGN(len, c->min_io_size); -+ dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len); -+ err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len, UBI_SHORTTERM); -+ if (err) -+ goto out; -+ -+ *ltail_lnum = c->lhead_lnum; -+ -+ c->lhead_offs += len; -+ if (c->lhead_offs == c->leb_size) { -+ c->lhead_lnum = next_log_lnum(c, c->lhead_lnum); -+ c->lhead_offs = 0; -+ } -+ -+ remove_buds(c); -+ -+ /* -+ * We have started the commit and now users may use the rest of the log -+ * for new writes. -+ */ -+ c->min_log_bytes = 0; -+ -+out: -+ kfree(buf); -+ return err; -+} -+ -+/** -+ * ubifs_log_end_commit - end commit. -+ * @c: UBIFS file-system description object -+ * @ltail_lnum: new log tail LEB number -+ * -+ * This function is called on when the commit operation was finished. It -+ * moves log tail to new position and unmaps LEBs which contain obsolete data. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum) -+{ -+ int err; -+ -+ /* -+ * At this phase we have to lock 'c->log_mutex' because UBIFS allows FS -+ * writes during commit. Its only short "commit" start phase when -+ * writers are blocked. -+ */ -+ mutex_lock(&c->log_mutex); -+ -+ dbg_log("old tail was LEB %d:0, new tail is LEB %d:0", -+ c->ltail_lnum, ltail_lnum); -+ -+ c->ltail_lnum = ltail_lnum; -+ /* -+ * The commit is finished and from now on it must be guaranteed that -+ * there is always enough space for the next commit. -+ */ -+ c->min_log_bytes = c->leb_size; -+ -+ spin_lock(&c->buds_lock); -+ c->bud_bytes -= c->cmt_bud_bytes; -+ spin_unlock(&c->buds_lock); -+ -+ err = dbg_check_bud_bytes(c); -+ -+ mutex_unlock(&c->log_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_log_post_commit - things to do after commit is completed. -+ * @c: UBIFS file-system description object -+ * @old_ltail_lnum: old log tail LEB number -+ * -+ * Release buds only after commit is completed, because they must be unchanged -+ * if recovery is needed. -+ * -+ * Unmap log LEBs only after commit is completed, because they may be needed for -+ * recovery. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) -+{ -+ int lnum, err = 0; -+ -+ while (!list_empty(&c->old_buds)) { -+ struct ubifs_bud *bud; -+ -+ bud = list_entry(c->old_buds.next, struct ubifs_bud, list); -+ err = ubifs_return_leb(c, bud->lnum); -+ if (err) -+ return err; -+ list_del(&bud->list); -+ kfree(bud); -+ } -+ mutex_lock(&c->log_mutex); -+ for (lnum = old_ltail_lnum; lnum != c->ltail_lnum; -+ lnum = next_log_lnum(c, lnum)) { -+ dbg_log("unmap log LEB %d", lnum); -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ goto out; -+ } -+out: -+ mutex_unlock(&c->log_mutex); -+ return err; -+} -+ -+/** -+ * struct done_ref - references that have been done. -+ * @rb: rb-tree node -+ * @lnum: LEB number -+ */ -+struct done_ref { -+ struct rb_node rb; -+ int lnum; -+}; -+ -+/** -+ * done_already - determine if a reference has been done already. -+ * @done_tree: rb-tree to store references that have been done -+ * @lnum: LEB number of reference -+ * -+ * This function returns %1 if the reference has been done, %0 if not, otherwise -+ * a negative error code is returned. -+ */ -+static int done_already(struct rb_root *done_tree, int lnum) -+{ -+ struct rb_node **p = &done_tree->rb_node, *parent = NULL; -+ struct done_ref *dr; -+ -+ while (*p) { -+ parent = *p; -+ dr = rb_entry(parent, struct done_ref, rb); -+ if (lnum < dr->lnum) -+ p = &(*p)->rb_left; -+ else if (lnum > dr->lnum) -+ p = &(*p)->rb_right; -+ else -+ return 1; -+ } -+ -+ dr = kzalloc(sizeof(struct done_ref), GFP_NOFS); -+ if (!dr) -+ return -ENOMEM; -+ -+ dr->lnum = lnum; -+ -+ rb_link_node(&dr->rb, parent, p); -+ rb_insert_color(&dr->rb, done_tree); -+ -+ return 0; -+} -+ -+/** -+ * destroy_done_tree - destroy the done tree. -+ * @done_tree: done tree to destroy -+ */ -+static void destroy_done_tree(struct rb_root *done_tree) -+{ -+ struct rb_node *this = done_tree->rb_node; -+ struct done_ref *dr; -+ -+ while (this) { -+ if (this->rb_left) { -+ this = this->rb_left; -+ continue; -+ } else if (this->rb_right) { -+ this = this->rb_right; -+ continue; -+ } -+ dr = rb_entry(this, struct done_ref, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &dr->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(dr); -+ } -+} -+ -+/** -+ * add_node - add a node to the consolidated log. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to which to add -+ * @lnum: LEB number to which to write is passed and returned here -+ * @offs: offset to where to write is passed and returned here -+ * @node: node to add -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs, -+ void *node) -+{ -+ struct ubifs_ch *ch = node; -+ int len = le32_to_cpu(ch->len), remains = c->leb_size - *offs; -+ -+ if (len > remains) { -+ int sz = ALIGN(*offs, c->min_io_size), err; -+ -+ ubifs_pad(c, buf + *offs, sz - *offs); -+ err = ubi_leb_change(c->ubi, *lnum, buf, sz, UBI_SHORTTERM); -+ if (err) -+ return err; -+ *lnum = next_log_lnum(c, *lnum); -+ *offs = 0; -+ } -+ memcpy(buf + *offs, node, len); -+ *offs += ALIGN(len, 8); -+ return 0; -+} -+ -+/** -+ * ubifs_consolidate_log - consolidate the log. -+ * @c: UBIFS file-system description object -+ * -+ * Repeated failed commits could cause the log to be full, but at least 1 LEB is -+ * needed for commit. This function rewrites the reference nodes in the log -+ * omitting duplicates, and failed CS nodes, and leaving no gaps. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_consolidate_log(struct ubifs_info *c) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ struct rb_root done_tree = RB_ROOT; -+ int lnum, err, first = 1, write_lnum, offs = 0; -+ void *buf; -+ -+ dbg_rcvry("log tail LEB %d, log head LEB %d", c->ltail_lnum, -+ c->lhead_lnum); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ buf = vmalloc(c->leb_size); -+#endif -+ if (!buf) -+ return -ENOMEM; -+ lnum = c->ltail_lnum; -+ write_lnum = lnum; -+ while (1) { -+ sleb = ubifs_scan(c, lnum, 0, c->sbuf); -+ if (IS_ERR(sleb)) { -+ err = PTR_ERR(sleb); -+ goto out_free; -+ } -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ switch (snod->type) { -+ case UBIFS_REF_NODE: { -+ struct ubifs_ref_node *ref = snod->node; -+ int ref_lnum = le32_to_cpu(ref->lnum); -+ -+ err = done_already(&done_tree, ref_lnum); -+ if (err < 0) -+ goto out_scan; -+ if (err != 1) { -+ err = add_node(c, buf, &write_lnum, -+ &offs, snod->node); -+ if (err) -+ goto out_scan; -+ } -+ break; -+ } -+ case UBIFS_CS_NODE: -+ if (!first) -+ break; -+ err = add_node(c, buf, &write_lnum, &offs, -+ snod->node); -+ if (err) -+ goto out_scan; -+ first = 0; -+ break; -+ } -+ } -+ ubifs_scan_destroy(sleb); -+ if (lnum == c->lhead_lnum) -+ break; -+ lnum = next_log_lnum(c, lnum); -+ } -+ if (offs) { -+ int sz = ALIGN(offs, c->min_io_size); -+ -+ ubifs_pad(c, buf + offs, sz - offs); -+ err = ubi_leb_change(c->ubi, write_lnum, buf, sz, -+ UBI_SHORTTERM); -+ if (err) -+ goto out_free; -+ offs = ALIGN(offs, c->min_io_size); -+ } -+ destroy_done_tree(&done_tree); -+ vfree(buf); -+ if (write_lnum == c->lhead_lnum) { -+ ubifs_err("log is too full"); -+ return -EINVAL; -+ } -+ /* Unmap remaining LEBs */ -+ lnum = write_lnum; -+ do { -+ lnum = next_log_lnum(c, lnum); -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } while (lnum != c->lhead_lnum); -+ c->lhead_lnum = write_lnum; -+ c->lhead_offs = offs; -+ dbg_rcvry("new log head at %d:%d", c->lhead_lnum, c->lhead_offs); -+ return 0; -+ -+out_scan: -+ ubifs_scan_destroy(sleb); -+out_free: -+ destroy_done_tree(&done_tree); -+ vfree(buf); -+ return err; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * dbg_check_bud_bytes - make sure bud bytes calculation are all right. -+ * @c: UBIFS file-system description object -+ * -+ * This function makes sure the amount of flash space used by closed buds -+ * ('c->bud_bytes' is correct). Returns zero in case of success and %-EINVAL in -+ * case of failure. -+ */ -+static int dbg_check_bud_bytes(struct ubifs_info *c) -+{ -+ int i, err = 0; -+ struct ubifs_bud *bud; -+ long long bud_bytes = 0; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) -+ return 0; -+ -+ spin_lock(&c->buds_lock); -+ for (i = 0; i < c->jhead_cnt; i++) -+ list_for_each_entry(bud, &c->jheads[i].buds_list, list) -+ bud_bytes += c->leb_size - bud->start; -+ -+ if (c->bud_bytes != bud_bytes) { -+ ubifs_err("bad bud_bytes %lld, calculated %lld", -+ c->bud_bytes, bud_bytes); -+ err = -EINVAL; -+ } -+ spin_unlock(&c->buds_lock); -+ -+ return err; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/lprops.c linux-2.6.24.7/fs/ubifs/lprops.c ---- linux-2.6.24.7.old/fs/ubifs/lprops.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/lprops.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1353 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements the functions that access LEB properties and their -+ * categories. LEBs are categorized based on the needs of UBIFS, and the -+ * categories are stored as either heaps or lists to provide a fast way of -+ * finding a LEB in a particular category. For example, UBIFS may need to find -+ * an empty LEB for the journal, or a very dirty LEB for garbage collection. -+ */ -+ -+#include "ubifs.h" -+ -+/** -+ * get_heap_comp_val - get the LEB properties value for heap comparisons. -+ * @lprops: LEB properties -+ * @cat: LEB category -+ */ -+static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat) -+{ -+ switch (cat) { -+ case LPROPS_FREE: -+ return lprops->free; -+ case LPROPS_DIRTY_IDX: -+ return lprops->free + lprops->dirty; -+ default: -+ return lprops->dirty; -+ } -+} -+ -+/** -+ * move_up_lpt_heap - move a new heap entry up as far as possible. -+ * @c: UBIFS file-system description object -+ * @heap: LEB category heap -+ * @lprops: LEB properties to move -+ * @cat: LEB category -+ * -+ * New entries to a heap are added at the bottom and then moved up until the -+ * parent's value is greater. In the case of LPT's category heaps, the value -+ * is either the amount of free space or the amount of dirty space, depending -+ * on the category. -+ */ -+static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, -+ struct ubifs_lprops *lprops, int cat) -+{ -+ int val1, val2, hpos; -+ -+ hpos = lprops->hpos; -+ if (!hpos) -+ return; /* Already top of the heap */ -+ val1 = get_heap_comp_val(lprops, cat); -+ /* Compare to parent and, if greater, move up the heap */ -+ do { -+ int ppos = (hpos - 1) / 2; -+ -+ val2 = get_heap_comp_val(heap->arr[ppos], cat); -+ if (val2 >= val1) -+ return; -+ /* Greater than parent so move up */ -+ heap->arr[ppos]->hpos = hpos; -+ heap->arr[hpos] = heap->arr[ppos]; -+ heap->arr[ppos] = lprops; -+ lprops->hpos = ppos; -+ hpos = ppos; -+ } while (hpos); -+} -+ -+/** -+ * adjust_lpt_heap - move a changed heap entry up or down the heap. -+ * @c: UBIFS file-system description object -+ * @heap: LEB category heap -+ * @lprops: LEB properties to move -+ * @hpos: heap position of @lprops -+ * @cat: LEB category -+ * -+ * Changed entries in a heap are moved up or down until the parent's value is -+ * greater. In the case of LPT's category heaps, the value is either the amount -+ * of free space or the amount of dirty space, depending on the category. -+ */ -+static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, -+ struct ubifs_lprops *lprops, int hpos, int cat) -+{ -+ int val1, val2, val3, cpos; -+ -+ val1 = get_heap_comp_val(lprops, cat); -+ /* Compare to parent and, if greater than parent, move up the heap */ -+ if (hpos) { -+ int ppos = (hpos - 1) / 2; -+ -+ val2 = get_heap_comp_val(heap->arr[ppos], cat); -+ if (val1 > val2) { -+ /* Greater than parent so move up */ -+ while (1) { -+ heap->arr[ppos]->hpos = hpos; -+ heap->arr[hpos] = heap->arr[ppos]; -+ heap->arr[ppos] = lprops; -+ lprops->hpos = ppos; -+ hpos = ppos; -+ if (!hpos) -+ return; -+ ppos = (hpos - 1) / 2; -+ val2 = get_heap_comp_val(heap->arr[ppos], cat); -+ if (val1 <= val2) -+ return; -+ /* Still greater than parent so keep going */ -+ } -+ } -+ } -+ /* Not greater than parent, so compare to children */ -+ while (1) { -+ /* Compare to left child */ -+ cpos = hpos * 2 + 1; -+ if (cpos >= heap->cnt) -+ return; -+ val2 = get_heap_comp_val(heap->arr[cpos], cat); -+ if (val1 < val2) { -+ /* Less than left child, so promote biggest child */ -+ if (cpos + 1 < heap->cnt) { -+ val3 = get_heap_comp_val(heap->arr[cpos + 1], -+ cat); -+ if (val3 > val2) -+ cpos += 1; /* Right child is bigger */ -+ } -+ heap->arr[cpos]->hpos = hpos; -+ heap->arr[hpos] = heap->arr[cpos]; -+ heap->arr[cpos] = lprops; -+ lprops->hpos = cpos; -+ hpos = cpos; -+ continue; -+ } -+ /* Compare to right child */ -+ cpos += 1; -+ if (cpos >= heap->cnt) -+ return; -+ val3 = get_heap_comp_val(heap->arr[cpos], cat); -+ if (val1 < val3) { -+ /* Less than right child, so promote right child */ -+ heap->arr[cpos]->hpos = hpos; -+ heap->arr[hpos] = heap->arr[cpos]; -+ heap->arr[cpos] = lprops; -+ lprops->hpos = cpos; -+ hpos = cpos; -+ continue; -+ } -+ return; -+ } -+} -+ -+/** -+ * add_to_lpt_heap - add LEB properties to a LEB category heap. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to add -+ * @cat: LEB category -+ * -+ * This function returns %1 if @lprops is added to the heap for LEB category -+ * @cat, otherwise %0 is returned because the heap is full. -+ */ -+static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops, -+ int cat) -+{ -+ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; -+ -+ if (heap->cnt >= heap->max_cnt) { -+ const int b = LPT_HEAP_SZ / 2 - 1; -+ int cpos, val1, val2; -+ -+ /* Compare to some other LEB on the bottom of heap */ -+ /* Pick a position kind of randomly */ -+ cpos = (((size_t)lprops >> 4) & b) + b; -+ ubifs_assert(cpos >= b); -+ ubifs_assert(cpos < LPT_HEAP_SZ); -+ ubifs_assert(cpos < heap->cnt); -+ -+ val1 = get_heap_comp_val(lprops, cat); -+ val2 = get_heap_comp_val(heap->arr[cpos], cat); -+ if (val1 > val2) { -+ struct ubifs_lprops *lp; -+ -+ lp = heap->arr[cpos]; -+ lp->flags &= ~LPROPS_CAT_MASK; -+ lp->flags |= LPROPS_UNCAT; -+ list_add(&lp->list, &c->uncat_list); -+ lprops->hpos = cpos; -+ heap->arr[cpos] = lprops; -+ move_up_lpt_heap(c, heap, lprops, cat); -+ dbg_check_heap(c, heap, cat, lprops->hpos); -+ return 1; /* Added to heap */ -+ } -+ dbg_check_heap(c, heap, cat, -1); -+ return 0; /* Not added to heap */ -+ } else { -+ lprops->hpos = heap->cnt++; -+ heap->arr[lprops->hpos] = lprops; -+ move_up_lpt_heap(c, heap, lprops, cat); -+ dbg_check_heap(c, heap, cat, lprops->hpos); -+ return 1; /* Added to heap */ -+ } -+} -+ -+/** -+ * remove_from_lpt_heap - remove LEB properties from a LEB category heap. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to remove -+ * @cat: LEB category -+ */ -+static void remove_from_lpt_heap(struct ubifs_info *c, -+ struct ubifs_lprops *lprops, int cat) -+{ -+ struct ubifs_lpt_heap *heap; -+ int hpos = lprops->hpos; -+ -+ heap = &c->lpt_heap[cat - 1]; -+ ubifs_assert(hpos >= 0 && hpos < heap->cnt); -+ ubifs_assert(heap->arr[hpos] == lprops); -+ heap->cnt -= 1; -+ if (hpos < heap->cnt) { -+ heap->arr[hpos] = heap->arr[heap->cnt]; -+ heap->arr[hpos]->hpos = hpos; -+ adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat); -+ } -+ dbg_check_heap(c, heap, cat, -1); -+} -+ -+/** -+ * lpt_heap_replace - replace lprops in a category heap. -+ * @c: UBIFS file-system description object -+ * @old_lprops: LEB properties to replace -+ * @new_lprops: LEB properties with which to replace -+ * @cat: LEB category -+ * -+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode) -+ * and the lprops that the pnode contains. When that happens, references in -+ * the category heaps to those lprops must be updated to point to the new -+ * lprops. This function does that. -+ */ -+static void lpt_heap_replace(struct ubifs_info *c, -+ struct ubifs_lprops *old_lprops, -+ struct ubifs_lprops *new_lprops, int cat) -+{ -+ struct ubifs_lpt_heap *heap; -+ int hpos = new_lprops->hpos; -+ -+ heap = &c->lpt_heap[cat - 1]; -+ heap->arr[hpos] = new_lprops; -+} -+ -+/** -+ * ubifs_add_to_cat - add LEB properties to a category list or heap. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to add -+ * @cat: LEB category to which to add -+ * -+ * LEB properties are categorized to enable fast find operations. -+ */ -+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, -+ int cat) -+{ -+ switch (cat) { -+ case LPROPS_DIRTY: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FREE: -+ if (add_to_lpt_heap(c, lprops, cat)) -+ break; -+ /* No more room on heap so make it uncategorized */ -+ cat = LPROPS_UNCAT; -+ /* Fall through */ -+ case LPROPS_UNCAT: -+ list_add(&lprops->list, &c->uncat_list); -+ break; -+ case LPROPS_EMPTY: -+ list_add(&lprops->list, &c->empty_list); -+ break; -+ case LPROPS_FREEABLE: -+ list_add(&lprops->list, &c->freeable_list); -+ c->freeable_cnt += 1; -+ break; -+ case LPROPS_FRDI_IDX: -+ list_add(&lprops->list, &c->frdi_idx_list); -+ break; -+ default: -+ ubifs_assert(0); -+ } -+ lprops->flags &= ~LPROPS_CAT_MASK; -+ lprops->flags |= cat; -+} -+ -+/** -+ * ubifs_remove_from_cat - remove LEB properties from a category list or heap. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to remove -+ * @cat: LEB category from which to remove -+ * -+ * LEB properties are categorized to enable fast find operations. -+ */ -+static void ubifs_remove_from_cat(struct ubifs_info *c, -+ struct ubifs_lprops *lprops, int cat) -+{ -+ switch (cat) { -+ case LPROPS_DIRTY: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FREE: -+ remove_from_lpt_heap(c, lprops, cat); -+ break; -+ case LPROPS_FREEABLE: -+ c->freeable_cnt -= 1; -+ ubifs_assert(c->freeable_cnt >= 0); -+ /* Fall through */ -+ case LPROPS_UNCAT: -+ case LPROPS_EMPTY: -+ case LPROPS_FRDI_IDX: -+ ubifs_assert(!list_empty(&lprops->list)); -+ list_del(&lprops->list); -+ break; -+ default: -+ ubifs_assert(0); -+ } -+} -+ -+/** -+ * ubifs_replace_cat - replace lprops in a category list or heap. -+ * @c: UBIFS file-system description object -+ * @old_lprops: LEB properties to replace -+ * @new_lprops: LEB properties with which to replace -+ * -+ * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode) -+ * and the lprops that the pnode contains. When that happens, references in -+ * category lists and heaps must be replaced. This function does that. -+ */ -+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops, -+ struct ubifs_lprops *new_lprops) -+{ -+ int cat; -+ -+ cat = new_lprops->flags & LPROPS_CAT_MASK; -+ switch (cat) { -+ case LPROPS_DIRTY: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FREE: -+ lpt_heap_replace(c, old_lprops, new_lprops, cat); -+ break; -+ case LPROPS_UNCAT: -+ case LPROPS_EMPTY: -+ case LPROPS_FREEABLE: -+ case LPROPS_FRDI_IDX: -+ list_replace(&old_lprops->list, &new_lprops->list); -+ break; -+ default: -+ ubifs_assert(0); -+ } -+} -+ -+/** -+ * ubifs_ensure_cat - ensure LEB properties are categorized. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties -+ * -+ * A LEB may have fallen off of the bottom of a heap, and ended up as -+ * uncategorized even though it has enough space for us now. If that is the case -+ * this function will put the LEB back onto a heap. -+ */ -+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops) -+{ -+ int cat = lprops->flags & LPROPS_CAT_MASK; -+ -+ if (cat != LPROPS_UNCAT) -+ return; -+ cat = ubifs_categorize_lprops(c, lprops); -+ if (cat == LPROPS_UNCAT) -+ return; -+ ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT); -+ ubifs_add_to_cat(c, lprops, cat); -+} -+ -+/** -+ * ubifs_categorize_lprops - categorize LEB properties. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to categorize -+ * -+ * LEB properties are categorized to enable fast find operations. This function -+ * returns the LEB category to which the LEB properties belong. Note however -+ * that if the LEB category is stored as a heap and the heap is full, the -+ * LEB properties may have their category changed to %LPROPS_UNCAT. -+ */ -+int ubifs_categorize_lprops(const struct ubifs_info *c, -+ const struct ubifs_lprops *lprops) -+{ -+ if (lprops->flags & LPROPS_TAKEN) -+ return LPROPS_UNCAT; -+ -+ if (lprops->free == c->leb_size) { -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ return LPROPS_EMPTY; -+ } -+ -+ if (lprops->free + lprops->dirty == c->leb_size) { -+ if (lprops->flags & LPROPS_INDEX) -+ return LPROPS_FRDI_IDX; -+ else -+ return LPROPS_FREEABLE; -+ } -+ -+ if (lprops->flags & LPROPS_INDEX) { -+ if (lprops->dirty + lprops->free >= c->min_idx_node_sz) -+ return LPROPS_DIRTY_IDX; -+ } else { -+ if (lprops->dirty >= c->dead_wm && -+ lprops->dirty > lprops->free) -+ return LPROPS_DIRTY; -+ if (lprops->free > 0) -+ return LPROPS_FREE; -+ } -+ -+ return LPROPS_UNCAT; -+} -+ -+/** -+ * change_category - change LEB properties category. -+ * @c: UBIFS file-system description object -+ * @lprops: LEB properties to recategorize -+ * -+ * LEB properties are categorized to enable fast find operations. When the LEB -+ * properties change they must be recategorized. -+ */ -+static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops) -+{ -+ int old_cat = lprops->flags & LPROPS_CAT_MASK; -+ int new_cat = ubifs_categorize_lprops(c, lprops); -+ -+ if (old_cat == new_cat) { -+ struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1]; -+ -+ /* lprops on a heap now must be moved up or down */ -+ if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT) -+ return; /* Not on a heap */ -+ heap = &c->lpt_heap[new_cat - 1]; -+ adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat); -+ } else { -+ ubifs_remove_from_cat(c, lprops, old_cat); -+ ubifs_add_to_cat(c, lprops, new_cat); -+ } -+} -+ -+/** -+ * ubifs_get_lprops - get reference to LEB properties. -+ * @c: the UBIFS file-system description object -+ * -+ * This function locks lprops. Lprops have to be unlocked by -+ * 'ubifs_release_lprops()'. -+ */ -+void ubifs_get_lprops(struct ubifs_info *c) -+{ -+ mutex_lock(&c->lp_mutex); -+} -+ -+/** -+ * calc_dark - calculate LEB dark space size. -+ * @c: the UBIFS file-system description object -+ * @spc: amount of free and dirty space in the LEB -+ * -+ * This function calculates amount of dark space in an LEB which has @spc bytes -+ * of free and dirty space. Returns the calculations result. -+ * -+ * Dark space is the space which is not always usable - it depends on which -+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes, -+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot -+ * count on this LEB and treat these 512 bytes as usable because it is not true -+ * if, for example, only big chunks of uncompressible data will be written to -+ * the FS. -+ */ -+static int calc_dark(struct ubifs_info *c, int spc) -+{ -+ ubifs_assert(!(spc & 7)); -+ -+ if (spc < c->dark_wm) -+ return spc; -+ -+ /* -+ * If we have slightly more space then the dark space watermark, we can -+ * anyway safely assume it we'll be able to write a node of the -+ * smallest size there. -+ */ -+ if (spc - c->dark_wm < MIN_WRITE_SZ) -+ return spc - MIN_WRITE_SZ; -+ -+ return c->dark_wm; -+} -+ -+/** -+ * is_lprops_dirty - determine if LEB properties are dirty. -+ * @c: the UBIFS file-system description object -+ * @lprops: LEB properties to test -+ */ -+static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops) -+{ -+ struct ubifs_pnode *pnode; -+ int pos; -+ -+ pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1); -+ pnode = (struct ubifs_pnode *)container_of(lprops - pos, -+ struct ubifs_pnode, -+ lprops[0]); -+ return !test_bit(COW_ZNODE, &pnode->flags) && -+ test_bit(DIRTY_CNODE, &pnode->flags); -+} -+ -+/** -+ * ubifs_change_lp - change LEB properties. -+ * @c: the UBIFS file-system description object -+ * @lp: LEB properties to change -+ * @free: new free space amount -+ * @dirty: new dirty space amount -+ * @flags: new flags -+ * @idx_gc_cnt: change to the count of idx_gc list -+ * -+ * This function changes LEB properties. This function does not change a LEB -+ * property (@free, @dirty or @flag) if the value passed is %-1. -+ * -+ * This function returns a pointer to the updated LEB properties on success -+ * and a negative error code on failure. N.B. the LEB properties may have had to -+ * be copied (due to COW) and consequently the pointer returned may not be the -+ * same as the pointer passed. -+ */ -+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, -+ const struct ubifs_lprops *lp, -+ int free, int dirty, int flags, -+ int idx_gc_cnt) -+{ -+ /* -+ * This is the only function that is allowed to change lprops, so we -+ * discard the const qualifier. -+ */ -+ struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp; -+ -+ dbg_lp("LEB %d, free %d, dirty %d, flags %d", -+ lprops->lnum, free, dirty, flags); -+ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ ubifs_assert(c->lst.empty_lebs >= 0 && -+ c->lst.empty_lebs <= c->main_lebs); -+ ubifs_assert(c->freeable_cnt >= 0); -+ ubifs_assert(c->freeable_cnt <= c->main_lebs); -+ ubifs_assert(c->lst.taken_empty_lebs >= 0); -+ ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs); -+ ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7)); -+ ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7)); -+ ubifs_assert(!(c->lst.total_used & 7)); -+ -+ if (!is_lprops_dirty(c, lprops)) { -+ lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum); -+ if (IS_ERR(lprops)) -+ return lprops; -+ } else -+ ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum)); -+ -+ ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7)); -+ -+ spin_lock(&c->space_lock); -+ -+ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size) -+ c->lst.taken_empty_lebs -= 1; -+ -+ if (!(lprops->flags & LPROPS_INDEX)) { -+ int old_spc; -+ -+ old_spc = lprops->free + lprops->dirty; -+ if (old_spc < c->dead_wm) -+ c->lst.total_dead -= old_spc; -+ else -+ c->lst.total_dark -= calc_dark(c, old_spc); -+ -+ c->lst.total_used -= c->leb_size - old_spc; -+ } -+ -+ if (free != -1) { -+ free = ALIGN(free, 8); -+ c->lst.total_free += free - lprops->free; -+ -+ /* Increase or decrease empty LEBs counter if needed */ -+ if (free == c->leb_size) { -+ if (lprops->free != c->leb_size) -+ c->lst.empty_lebs += 1; -+ } else if (lprops->free == c->leb_size) -+ c->lst.empty_lebs -= 1; -+ lprops->free = free; -+ } -+ -+ if (dirty != -1) { -+ dirty = ALIGN(dirty, 8); -+ c->lst.total_dirty += dirty - lprops->dirty; -+ lprops->dirty = dirty; -+ } -+ -+ if (flags != -1) { -+ /* Take care about indexing LEBs counter if needed */ -+ if ((lprops->flags & LPROPS_INDEX)) { -+ if (!(flags & LPROPS_INDEX)) -+ c->lst.idx_lebs -= 1; -+ } else if (flags & LPROPS_INDEX) -+ c->lst.idx_lebs += 1; -+ lprops->flags = flags; -+ } -+ -+ if (!(lprops->flags & LPROPS_INDEX)) { -+ int new_spc; -+ -+ new_spc = lprops->free + lprops->dirty; -+ if (new_spc < c->dead_wm) -+ c->lst.total_dead += new_spc; -+ else -+ c->lst.total_dark += calc_dark(c, new_spc); -+ -+ c->lst.total_used += c->leb_size - new_spc; -+ } -+ -+ if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size) -+ c->lst.taken_empty_lebs += 1; -+ -+ change_category(c, lprops); -+ -+ c->idx_gc_cnt += idx_gc_cnt; -+ -+ spin_unlock(&c->space_lock); -+ -+ return lprops; -+} -+ -+/** -+ * ubifs_release_lprops - release lprops lock. -+ * @c: the UBIFS file-system description object -+ * -+ * This function has to be called after each 'ubifs_get_lprops()' call to -+ * unlock lprops. -+ */ -+void ubifs_release_lprops(struct ubifs_info *c) -+{ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ ubifs_assert(c->lst.empty_lebs >= 0 && -+ c->lst.empty_lebs <= c->main_lebs); -+ -+ mutex_unlock(&c->lp_mutex); -+} -+ -+/** -+ * ubifs_get_lp_stats - get lprops statistics. -+ * @c: UBIFS file-system description object -+ * @st: return statistics -+ */ -+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *st) -+{ -+ spin_lock(&c->space_lock); -+ memcpy(st, &c->lst, sizeof(struct ubifs_lp_stats)); -+ spin_unlock(&c->space_lock); -+} -+ -+/** -+ * ubifs_change_one_lp - change LEB properties. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB to change properties for -+ * @free: amount of free space -+ * @dirty: amount of dirty space -+ * @flags_set: flags to set -+ * @flags_clean: flags to clean -+ * @idx_gc_cnt: change to the count of idx_gc list -+ * -+ * This function changes properties of LEB @lnum. It is a helper wrapper over -+ * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the -+ * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and -+ * a negative error code in case of failure. -+ */ -+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, -+ int flags_set, int flags_clean, int idx_gc_cnt) -+{ -+ int err = 0, flags; -+ const struct ubifs_lprops *lp; -+ -+ ubifs_get_lprops(c); -+ -+ lp = ubifs_lpt_lookup_dirty(c, lnum); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ flags = (lp->flags | flags_set) & ~flags_clean; -+ lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt); -+ if (IS_ERR(lp)) -+ err = PTR_ERR(lp); -+ -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * ubifs_update_one_lp - update LEB properties. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB to change properties for -+ * @free: amount of free space -+ * @dirty: amount of dirty space to add -+ * @flags_set: flags to set -+ * @flags_clean: flags to clean -+ * -+ * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to -+ * current dirty space, not substitutes it. -+ */ -+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, -+ int flags_set, int flags_clean) -+{ -+ int err = 0, flags; -+ const struct ubifs_lprops *lp; -+ -+ ubifs_get_lprops(c); -+ -+ lp = ubifs_lpt_lookup_dirty(c, lnum); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ flags = (lp->flags | flags_set) & ~flags_clean; -+ lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0); -+ if (IS_ERR(lp)) -+ err = PTR_ERR(lp); -+ -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * ubifs_read_one_lp - read LEB properties. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB to read properties for -+ * @lp: where to store read properties -+ * -+ * This helper function reads properties of a LEB @lnum and stores them in @lp. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp) -+{ -+ int err = 0; -+ const struct ubifs_lprops *lpp; -+ -+ ubifs_get_lprops(c); -+ -+ lpp = ubifs_lpt_lookup(c, lnum); -+ if (IS_ERR(lpp)) { -+ err = PTR_ERR(lpp); -+ goto out; -+ } -+ -+ memcpy(lp, lpp, sizeof(struct ubifs_lprops)); -+ -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * ubifs_fast_find_free - try to find a LEB with free space quickly. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns LEB properties for a LEB with free space or %NULL if -+ * the function is unable to find a LEB quickly. -+ */ -+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ struct ubifs_lpt_heap *heap; -+ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ -+ heap = &c->lpt_heap[LPROPS_FREE - 1]; -+ if (heap->cnt == 0) -+ return NULL; -+ -+ lprops = heap->arr[0]; -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ return lprops; -+} -+ -+/** -+ * ubifs_fast_find_empty - try to find an empty LEB quickly. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns LEB properties for an empty LEB or %NULL if the -+ * function is unable to find an empty LEB quickly. -+ */ -+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ -+ if (list_empty(&c->empty_list)) -+ return NULL; -+ -+ lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ ubifs_assert(lprops->free == c->leb_size); -+ return lprops; -+} -+ -+/** -+ * ubifs_fast_find_freeable - try to find a freeable LEB quickly. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns LEB properties for a freeable LEB or %NULL if the -+ * function is unable to find a freeable LEB quickly. -+ */ -+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ -+ if (list_empty(&c->freeable_list)) -+ return NULL; -+ -+ lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert(!(lprops->flags & LPROPS_INDEX)); -+ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); -+ ubifs_assert(c->freeable_cnt > 0); -+ return lprops; -+} -+ -+/** -+ * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns LEB properties for a freeable index LEB or %NULL if the -+ * function is unable to find a freeable index LEB quickly. -+ */ -+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ -+ ubifs_assert(mutex_is_locked(&c->lp_mutex)); -+ -+ if (list_empty(&c->frdi_idx_list)) -+ return NULL; -+ -+ lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list); -+ ubifs_assert(!(lprops->flags & LPROPS_TAKEN)); -+ ubifs_assert((lprops->flags & LPROPS_INDEX)); -+ ubifs_assert(lprops->free + lprops->dirty == c->leb_size); -+ return lprops; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * dbg_check_cats - check category heaps and lists. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int dbg_check_cats(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ struct list_head *pos; -+ int i, cat; -+ -+ if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) -+ return 0; -+ -+ list_for_each_entry(lprops, &c->empty_list, list) { -+ if (lprops->free != c->leb_size) { -+ ubifs_err("non-empty LEB %d on empty list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ if (lprops->flags & LPROPS_TAKEN) { -+ ubifs_err("taken LEB %d on empty list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ } -+ -+ i = 0; -+ list_for_each_entry(lprops, &c->freeable_list, list) { -+ if (lprops->free + lprops->dirty != c->leb_size) { -+ ubifs_err("non-freeable LEB %d on freeable list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ if (lprops->flags & LPROPS_TAKEN) { -+ ubifs_err("taken LEB %d on freeable list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ i += 1; -+ } -+ if (i != c->freeable_cnt) { -+ ubifs_err("freeable list count %d expected %d", i, -+ c->freeable_cnt); -+ return -EINVAL; -+ } -+ -+ i = 0; -+ list_for_each(pos, &c->idx_gc) -+ i += 1; -+ if (i != c->idx_gc_cnt) { -+ ubifs_err("idx_gc list count %d expected %d", i, -+ c->idx_gc_cnt); -+ return -EINVAL; -+ } -+ -+ list_for_each_entry(lprops, &c->frdi_idx_list, list) { -+ if (lprops->free + lprops->dirty != c->leb_size) { -+ ubifs_err("non-freeable LEB %d on frdi_idx list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ if (lprops->flags & LPROPS_TAKEN) { -+ ubifs_err("taken LEB %d on frdi_idx list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ if (!(lprops->flags & LPROPS_INDEX)) { -+ ubifs_err("non-index LEB %d on frdi_idx list " -+ "(free %d dirty %d flags %d)", lprops->lnum, -+ lprops->free, lprops->dirty, lprops->flags); -+ return -EINVAL; -+ } -+ } -+ -+ for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) { -+ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; -+ -+ for (i = 0; i < heap->cnt; i++) { -+ lprops = heap->arr[i]; -+ if (!lprops) { -+ ubifs_err("null ptr in LPT heap cat %d", cat); -+ return -EINVAL; -+ } -+ if (lprops->hpos != i) { -+ ubifs_err("bad ptr in LPT heap cat %d", cat); -+ return -EINVAL; -+ } -+ if (lprops->flags & LPROPS_TAKEN) { -+ ubifs_err("taken LEB in LPT heap cat %d", cat); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, -+ int add_pos) -+{ -+ int i = 0, j, err = 0; -+ -+ if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) -+ return; -+ -+ for (i = 0; i < heap->cnt; i++) { -+ struct ubifs_lprops *lprops = heap->arr[i]; -+ struct ubifs_lprops *lp; -+ -+ if (i != add_pos) -+ if ((lprops->flags & LPROPS_CAT_MASK) != cat) { -+ err = 1; -+ goto out; -+ } -+ if (lprops->hpos != i) { -+ err = 2; -+ goto out; -+ } -+ lp = ubifs_lpt_lookup(c, lprops->lnum); -+ if (IS_ERR(lp)) { -+ err = 3; -+ goto out; -+ } -+ if (lprops != lp) { -+ dbg_msg("lprops %zx lp %zx lprops->lnum %d lp->lnum %d", -+ (size_t)lprops, (size_t)lp, lprops->lnum, -+ lp->lnum); -+ err = 4; -+ goto out; -+ } -+ for (j = 0; j < i; j++) { -+ lp = heap->arr[j]; -+ if (lp == lprops) { -+ err = 5; -+ goto out; -+ } -+ if (lp->lnum == lprops->lnum) { -+ err = 6; -+ goto out; -+ } -+ } -+ } -+out: -+ if (err) { -+ dbg_msg("failed cat %d hpos %d err %d", cat, i, err); -+ dbg_dump_stack(); -+ dbg_dump_heap(c, heap, cat); -+ } -+} -+ -+/** -+ * struct scan_check_data - data provided to scan callback function. -+ * @lst: LEB properties statistics -+ * @err: error code -+ */ -+struct scan_check_data { -+ struct ubifs_lp_stats lst; -+ int err; -+}; -+ -+/** -+ * scan_check_cb - scan callback. -+ * @c: the UBIFS file-system description object -+ * @lp: LEB properties to scan -+ * @in_tree: whether the LEB properties are in main memory -+ * @data: information passed to and from the caller of the scan -+ * -+ * This function returns a code that indicates whether the scan should continue -+ * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree -+ * in main memory (%LPT_SCAN_ADD), or whether the scan should stop -+ * (%LPT_SCAN_STOP). -+ */ -+static int scan_check_cb(struct ubifs_info *c, -+ const struct ubifs_lprops *lp, int in_tree, -+ struct scan_check_data *data) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ struct ubifs_lp_stats *lst = &data->lst; -+ int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty; -+ -+ cat = lp->flags & LPROPS_CAT_MASK; -+ if (cat != LPROPS_UNCAT) { -+ cat = ubifs_categorize_lprops(c, lp); -+ if (cat != (lp->flags & LPROPS_CAT_MASK)) { -+ ubifs_err("bad LEB category %d expected %d", -+ (lp->flags & LPROPS_CAT_MASK), cat); -+ goto out; -+ } -+ } -+ -+ /* Check lp is on its category list (if it has one) */ -+ if (in_tree) { -+ struct list_head *list = NULL; -+ -+ switch (cat) { -+ case LPROPS_EMPTY: -+ list = &c->empty_list; -+ break; -+ case LPROPS_FREEABLE: -+ list = &c->freeable_list; -+ break; -+ case LPROPS_FRDI_IDX: -+ list = &c->frdi_idx_list; -+ break; -+ case LPROPS_UNCAT: -+ list = &c->uncat_list; -+ break; -+ } -+ if (list) { -+ struct ubifs_lprops *lprops; -+ int found = 0; -+ -+ list_for_each_entry(lprops, list, list) { -+ if (lprops == lp) { -+ found = 1; -+ break; -+ } -+ } -+ if (!found) { -+ ubifs_err("bad LPT list (category %d)", cat); -+ goto out; -+ } -+ } -+ } -+ -+ /* Check lp is on its category heap (if it has one) */ -+ if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) { -+ struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1]; -+ -+ if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) || -+ lp != heap->arr[lp->hpos]) { -+ ubifs_err("bad LPT heap (category %d)", cat); -+ goto out; -+ } -+ } -+ -+ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); -+ if (IS_ERR(sleb)) { -+ /* -+ * After an unclean unmount, empty and freeable LEBs -+ * may contain garbage. -+ */ -+ if (lp->free == c->leb_size) { -+ ubifs_err("scan errors were in empty LEB " -+ "- continuing checking"); -+ lst->empty_lebs += 1; -+ lst->total_free += c->leb_size; -+ lst->total_dark += calc_dark(c, c->leb_size); -+ return LPT_SCAN_CONTINUE; -+ } -+ -+ if (lp->free + lp->dirty == c->leb_size && -+ !(lp->flags & LPROPS_INDEX)) { -+ ubifs_err("scan errors were in freeable LEB " -+ "- continuing checking"); -+ lst->total_free += lp->free; -+ lst->total_dirty += lp->dirty; -+ lst->total_dark += calc_dark(c, c->leb_size); -+ return LPT_SCAN_CONTINUE; -+ } -+ data->err = PTR_ERR(sleb); -+ return LPT_SCAN_STOP; -+ } -+ -+ is_idx = -1; -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ int found, level = 0; -+ -+ cond_resched(); -+ -+ if (is_idx == -1) -+ is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0; -+ -+ if (is_idx && snod->type != UBIFS_IDX_NODE) { -+ ubifs_err("indexing node in data LEB %d:%d", -+ lnum, snod->offs); -+ goto out_destroy; -+ } -+ -+ if (snod->type == UBIFS_IDX_NODE) { -+ struct ubifs_idx_node *idx = snod->node; -+ -+ key_read(c, ubifs_idx_key(c, idx), &snod->key); -+ level = le16_to_cpu(idx->level); -+ } -+ -+ found = ubifs_tnc_has_node(c, &snod->key, level, lnum, -+ snod->offs, is_idx); -+ if (found) { -+ if (found < 0) -+ goto out_destroy; -+ used += ALIGN(snod->len, 8); -+ } -+ } -+ -+ free = c->leb_size - sleb->endpt; -+ dirty = sleb->endpt - used; -+ -+ if (free > c->leb_size || free < 0 || dirty > c->leb_size || -+ dirty < 0) { -+ ubifs_err("bad calculated accounting for LEB %d: " -+ "free %d, dirty %d", lnum, free, dirty); -+ goto out_destroy; -+ } -+ -+ if (lp->free + lp->dirty == c->leb_size && -+ free + dirty == c->leb_size) -+ if ((is_idx && !(lp->flags & LPROPS_INDEX)) || -+ (!is_idx && free == c->leb_size)) { -+ /* -+ * Empty or freeable LEBs could contain index -+ * nodes from an uncompleted commit due to an -+ * unclean unmount. Or they could be empty for -+ * the same reason. -+ */ -+ free = lp->free; -+ dirty = lp->dirty; -+ is_idx = 0; -+ } -+ -+ if (is_idx && lp->free + lp->dirty == free + dirty && -+ lnum != c->ihead_lnum) { -+ /* -+ * After an unclean unmount, an index LEB could have a different -+ * amount of free space than the value recorded by lprops. That -+ * is because the in-the-gaps method may use free space or -+ * create free space (as a side-effect of using ubi_leb_change -+ * and not writing the whole LEB). The incorrect free space -+ * value is not a problem because the index is only ever -+ * allocated empty LEBs, so there will never be an attempt to -+ * write to the free space at the end of an index LEB - except -+ * by the in-the-gaps method for which it is not a problem. -+ */ -+ free = lp->free; -+ dirty = lp->dirty; -+ } -+ -+ if (lp->free != free || lp->dirty != dirty) -+ goto out_print; -+ -+ if (is_idx && !(lp->flags & LPROPS_INDEX)) { -+ if (free == c->leb_size) -+ /* Free but not unmapped LEB, it's fine */ -+ is_idx = 0; -+ else { -+ ubifs_err("indexing node without indexing " -+ "flag"); -+ goto out_print; -+ } -+ } -+ -+ if (!is_idx && (lp->flags & LPROPS_INDEX)) { -+ ubifs_err("data node with indexing flag"); -+ goto out_print; -+ } -+ -+ if (free == c->leb_size) -+ lst->empty_lebs += 1; -+ -+ if (is_idx) -+ lst->idx_lebs += 1; -+ -+ if (!(lp->flags & LPROPS_INDEX)) -+ lst->total_used += c->leb_size - free - dirty; -+ lst->total_free += free; -+ lst->total_dirty += dirty; -+ -+ if (!(lp->flags & LPROPS_INDEX)) { -+ int spc = free + dirty; -+ -+ if (spc < c->dead_wm) -+ lst->total_dead += spc; -+ else -+ lst->total_dark += calc_dark(c, spc); -+ } -+ -+ ubifs_scan_destroy(sleb); -+ -+ return LPT_SCAN_CONTINUE; -+ -+out_print: -+ ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, " -+ "should be free %d, dirty %d", -+ lnum, lp->free, lp->dirty, lp->flags, free, dirty); -+ dbg_dump_leb(c, lnum); -+out_destroy: -+ ubifs_scan_destroy(sleb); -+out: -+ data->err = -EINVAL; -+ return LPT_SCAN_STOP; -+} -+ -+/** -+ * dbg_check_lprops - check all LEB properties. -+ * @c: UBIFS file-system description object -+ * -+ * This function checks all LEB properties and makes sure they are all correct. -+ * It returns zero if everything is fine, %-EINVAL if there is an inconsistency -+ * and other negative error codes in case of other errors. This function is -+ * called while the file system is locked (because of commit start), so no -+ * additional locking is required. Note that locking the LPT mutex would cause -+ * a circular lock dependency with the TNC mutex. -+ */ -+int dbg_check_lprops(struct ubifs_info *c) -+{ -+ int i, err; -+ struct scan_check_data data; -+ struct ubifs_lp_stats *lst = &data.lst; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) -+ return 0; -+ -+ /* -+ * As we are going to scan the media, the write buffers have to be -+ * synchronized. -+ */ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ if (err) -+ return err; -+ } -+ -+ memset(lst, 0, sizeof(struct ubifs_lp_stats)); -+ -+ data.err = 0; -+ err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1, -+ (ubifs_lpt_scan_callback)scan_check_cb, -+ &data); -+ if (err && err != -ENOSPC) -+ goto out; -+ if (data.err) { -+ err = data.err; -+ goto out; -+ } -+ -+ if (lst->empty_lebs != c->lst.empty_lebs || -+ lst->idx_lebs != c->lst.idx_lebs || -+ lst->total_free != c->lst.total_free || -+ lst->total_dirty != c->lst.total_dirty || -+ lst->total_used != c->lst.total_used) { -+ ubifs_err("bad overall accounting"); -+ ubifs_err("calculated: empty_lebs %d, idx_lebs %d, " -+ "total_free %lld, total_dirty %lld, total_used %lld", -+ lst->empty_lebs, lst->idx_lebs, lst->total_free, -+ lst->total_dirty, lst->total_used); -+ ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, " -+ "total_free %lld, total_dirty %lld, total_used %lld", -+ c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free, -+ c->lst.total_dirty, c->lst.total_used); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (lst->total_dead != c->lst.total_dead || -+ lst->total_dark != c->lst.total_dark) { -+ ubifs_err("bad dead/dark space accounting"); -+ ubifs_err("calculated: total_dead %lld, total_dark %lld", -+ lst->total_dead, lst->total_dark); -+ ubifs_err("read from lprops: total_dead %lld, total_dark %lld", -+ c->lst.total_dead, c->lst.total_dark); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ err = dbg_check_cats(c); -+out: -+ return err; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/lpt.c linux-2.6.24.7/fs/ubifs/lpt.c ---- linux-2.6.24.7.old/fs/ubifs/lpt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/lpt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2279 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements the LEB properties tree (LPT) area. The LPT area -+ * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and -+ * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits -+ * between the log and the orphan area. -+ * -+ * The LPT area is like a miniature self-contained file system. It is required -+ * that it never runs out of space, is fast to access and update, and scales -+ * logarithmically. The LEB properties tree is implemented as a wandering tree -+ * much like the TNC, and the LPT area has its own garbage collection. -+ * -+ * The LPT has two slightly different forms called the "small model" and the -+ * "big model". The small model is used when the entire LEB properties table -+ * can be written into a single eraseblock. In that case, garbage collection -+ * consists of just writing the whole table, which therefore makes all other -+ * eraseblocks reusable. In the case of the big model, dirty eraseblocks are -+ * selected for garbage collection, which consists are marking the nodes in -+ * that LEB as dirty, and then only the dirty nodes are written out. Also, in -+ * the case of the big model, a table of LEB numbers is saved so that the entire -+ * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first -+ * mounted. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/** -+ * do_calc_lpt_geom - calculate sizes for the LPT area. -+ * @c: the UBIFS file-system description object -+ * -+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the -+ * properties of the flash and whether LPT is "big" (c->big_lpt). -+ */ -+static void do_calc_lpt_geom(struct ubifs_info *c) -+{ -+ int i, n, bits, per_leb_wastage, max_pnode_cnt; -+ long long sz, tot_wastage; -+ -+ n = c->main_lebs + c->max_leb_cnt - c->leb_cnt; -+ max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); -+ -+ c->lpt_hght = 1; -+ n = UBIFS_LPT_FANOUT; -+ while (n < max_pnode_cnt) { -+ c->lpt_hght += 1; -+ n <<= UBIFS_LPT_FANOUT_SHIFT; -+ } -+ -+ c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); -+ -+ n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT); -+ c->nnode_cnt = n; -+ for (i = 1; i < c->lpt_hght; i++) { -+ n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT); -+ c->nnode_cnt += n; -+ } -+ -+ c->space_bits = fls(c->leb_size) - 3; -+ c->lpt_lnum_bits = fls(c->lpt_lebs); -+ c->lpt_offs_bits = fls(c->leb_size - 1); -+ c->lpt_spc_bits = fls(c->leb_size); -+ -+ n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT); -+ c->pcnt_bits = fls(n - 1); -+ -+ c->lnum_bits = fls(c->max_leb_cnt - 1); -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ (c->big_lpt ? c->pcnt_bits : 0) + -+ (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT; -+ c->pnode_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ (c->big_lpt ? c->pcnt_bits : 0) + -+ (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT; -+ c->nnode_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ c->lpt_lebs * c->lpt_spc_bits * 2; -+ c->ltab_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ c->lnum_bits * c->lsave_cnt; -+ c->lsave_sz = (bits + 7) / 8; -+ -+ /* Calculate the minimum LPT size */ -+ c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; -+ c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; -+ c->lpt_sz += c->ltab_sz; -+ c->lpt_sz += c->lsave_sz; -+ -+ /* Add wastage */ -+ sz = c->lpt_sz; -+ per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz); -+ sz += per_leb_wastage; -+ tot_wastage = per_leb_wastage; -+ while (sz > c->leb_size) { -+ sz += per_leb_wastage; -+ sz -= c->leb_size; -+ tot_wastage += per_leb_wastage; -+ } -+ tot_wastage += ALIGN(sz, c->min_io_size) - sz; -+ c->lpt_sz += tot_wastage; -+} -+ -+/** -+ * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_calc_lpt_geom(struct ubifs_info *c) -+{ -+ int lebs_needed; -+ uint64_t sz; -+ -+ do_calc_lpt_geom(c); -+ -+ /* Verify that lpt_lebs is big enough */ -+ sz = c->lpt_sz * 2; /* Must have at least 2 times the size */ -+ sz += c->leb_size - 1; -+ do_div(sz, c->leb_size); -+ lebs_needed = sz; -+ if (lebs_needed > c->lpt_lebs) { -+ ubifs_err("too few LPT LEBs"); -+ return -EINVAL; -+ } -+ -+ /* Verify that ltab fits in a single LEB (since ltab is a single node */ -+ if (c->ltab_sz > c->leb_size) { -+ ubifs_err("LPT ltab too big"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * calc_dflt_lpt_geom - calculate default LPT geometry. -+ * @c: the UBIFS file-system description object -+ * @main_lebs: number of main area LEBs is passed and returned here -+ * @big_lpt: whether the LPT area is "big" is returned here -+ * -+ * The size of the LPT area depends on parameters that themselves are dependent -+ * on the size of the LPT area. This function, successively recalculates the LPT -+ * area geometry until the parameters and resultant geometry are consistent. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, -+ int *big_lpt) -+{ -+ int i, lebs_needed; -+ uint64_t sz; -+ -+ /* Start by assuming the minimum number of LPT LEBs */ -+ c->lpt_lebs = UBIFS_MIN_LPT_LEBS; -+ c->main_lebs = *main_lebs - c->lpt_lebs; -+ if (c->main_lebs <= 0) -+ return -EINVAL; -+ -+ /* And assume we will use the small LPT model */ -+ c->big_lpt = 0; -+ -+ /* -+ * Calculate the geometry based on assumptions above and then see if it -+ * makes sense -+ */ -+ do_calc_lpt_geom(c); -+ -+ /* Small LPT model must have lpt_sz < leb_size */ -+ if (c->lpt_sz > c->leb_size) { -+ /* Nope, so try again using big LPT model */ -+ c->big_lpt = 1; -+ do_calc_lpt_geom(c); -+ } -+ -+ /* Now check there are enough LPT LEBs */ -+ for (i = 0; i < 64 ; i++) { -+ sz = c->lpt_sz * 4; /* Allow 4 times the size */ -+ sz += c->leb_size - 1; -+ do_div(sz, c->leb_size); -+ lebs_needed = sz; -+ if (lebs_needed > c->lpt_lebs) { -+ /* Not enough LPT LEBs so try again with more */ -+ c->lpt_lebs = lebs_needed; -+ c->main_lebs = *main_lebs - c->lpt_lebs; -+ if (c->main_lebs <= 0) -+ return -EINVAL; -+ do_calc_lpt_geom(c); -+ continue; -+ } -+ if (c->ltab_sz > c->leb_size) { -+ ubifs_err("LPT ltab too big"); -+ return -EINVAL; -+ } -+ *main_lebs = c->main_lebs; -+ *big_lpt = c->big_lpt; -+ return 0; -+ } -+ return -EINVAL; -+} -+ -+/** -+ * pack_bits - pack bit fields end-to-end. -+ * @addr: address at which to pack (passed and next address returned) -+ * @pos: bit position at which to pack (passed and next position returned) -+ * @val: value to pack -+ * @nrbits: number of bits of value to pack (1-32) -+ */ -+static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits) -+{ -+ uint8_t *p = *addr; -+ int b = *pos; -+ -+ ubifs_assert(nrbits > 0); -+ ubifs_assert(nrbits <= 32); -+ ubifs_assert(*pos >= 0); -+ ubifs_assert(*pos < 8); -+ ubifs_assert((val >> nrbits) == 0 || nrbits == 32); -+ if (b) { -+ *p |= ((uint8_t)val) << b; -+ nrbits += b; -+ if (nrbits > 8) { -+ *++p = (uint8_t)(val >>= (8 - b)); -+ if (nrbits > 16) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 24) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 32) -+ *++p = (uint8_t)(val >>= 8); -+ } -+ } -+ } -+ } else { -+ *p = (uint8_t)val; -+ if (nrbits > 8) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 16) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 24) -+ *++p = (uint8_t)(val >>= 8); -+ } -+ } -+ } -+ b = nrbits & 7; -+ if (b == 0) -+ p++; -+ *addr = p; -+ *pos = b; -+} -+ -+/** -+ * ubifs_unpack_bits - unpack bit fields. -+ * @addr: address at which to unpack (passed and next address returned) -+ * @pos: bit position at which to unpack (passed and next position returned) -+ * @nrbits: number of bits of value to unpack (1-32) -+ * -+ * This functions returns the value unpacked. -+ */ -+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits) -+{ -+ const int k = 32 - nrbits; -+ uint8_t *p = *addr; -+ int b = *pos; -+ uint32_t val; -+ -+ ubifs_assert(nrbits > 0); -+ ubifs_assert(nrbits <= 32); -+ ubifs_assert(*pos >= 0); -+ ubifs_assert(*pos < 8); -+ if (b) { -+ val = p[1] | ((uint32_t)p[2] << 8) | ((uint32_t)p[3] << 16) | -+ ((uint32_t)p[4] << 24); -+ val <<= (8 - b); -+ val |= *p >> b; -+ nrbits += b; -+ } else -+ val = p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | -+ ((uint32_t)p[3] << 24); -+ val <<= k; -+ val >>= k; -+ b = nrbits & 7; -+ p += nrbits / 8; -+ *addr = p; -+ *pos = b; -+ ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32); -+ return val; -+} -+ -+/** -+ * ubifs_pack_pnode - pack all the bit fields of a pnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @pnode: pnode to pack -+ */ -+void ubifs_pack_pnode(struct ubifs_info *c, void *buf, -+ struct ubifs_pnode *pnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS); -+ if (c->big_lpt) -+ pack_bits(&addr, &pos, pnode->num, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ pack_bits(&addr, &pos, pnode->lprops[i].free >> 3, -+ c->space_bits); -+ pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3, -+ c->space_bits); -+ if (pnode->lprops[i].flags & LPROPS_INDEX) -+ pack_bits(&addr, &pos, 1, 1); -+ else -+ pack_bits(&addr, &pos, 0, 1); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->pnode_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * ubifs_pack_nnode - pack all the bit fields of a nnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @nnode: nnode to pack -+ */ -+void ubifs_pack_nnode(struct ubifs_info *c, void *buf, -+ struct ubifs_nnode *nnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS); -+ if (c->big_lpt) -+ pack_bits(&addr, &pos, nnode->num, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int lnum = nnode->nbranch[i].lnum; -+ -+ if (lnum == 0) -+ lnum = c->lpt_last + 1; -+ pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits); -+ pack_bits(&addr, &pos, nnode->nbranch[i].offs, -+ c->lpt_offs_bits); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->nnode_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * ubifs_pack_ltab - pack the LPT's own lprops table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @ltab: LPT's own lprops table to pack -+ */ -+void ubifs_pack_ltab(struct ubifs_info *c, void *buf, -+ struct ubifs_lpt_lprops *ltab) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS); -+ for (i = 0; i < c->lpt_lebs; i++) { -+ pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits); -+ pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->ltab_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * ubifs_pack_lsave - pack the LPT's save table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @lsave: LPT's save table to pack -+ */ -+void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS); -+ for (i = 0; i < c->lsave_cnt; i++) -+ pack_bits(&addr, &pos, lsave[i], c->lnum_bits); -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->lsave_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to which to add dirty space -+ * @dirty: amount of dirty space to add -+ */ -+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty) -+{ -+ if (!dirty || !lnum) -+ return; -+ dbg_lp("LEB %d add %d to %d", -+ lnum, dirty, c->ltab[lnum - c->lpt_first].dirty); -+ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); -+ c->ltab[lnum - c->lpt_first].dirty += dirty; -+} -+ -+/** -+ * set_ltab - set LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @free: amount of free space -+ * @dirty: amount of dirty space -+ */ -+static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty) -+{ -+ dbg_lp("LEB %d free %d dirty %d to %d %d", -+ lnum, c->ltab[lnum - c->lpt_first].free, -+ c->ltab[lnum - c->lpt_first].dirty, free, dirty); -+ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); -+ c->ltab[lnum - c->lpt_first].free = free; -+ c->ltab[lnum - c->lpt_first].dirty = dirty; -+} -+ -+/** -+ * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @nnode: nnode for which to add dirt -+ */ -+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode) -+{ -+ struct ubifs_nnode *np = nnode->parent; -+ -+ if (np) -+ ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum, -+ c->nnode_sz); -+ else { -+ ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz); -+ if (!(c->lpt_drty_flgs & LTAB_DIRTY)) { -+ c->lpt_drty_flgs |= LTAB_DIRTY; -+ ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz); -+ } -+ } -+} -+ -+/** -+ * add_pnode_dirt - add dirty space to LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode for which to add dirt -+ */ -+static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode) -+{ -+ ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum, -+ c->pnode_sz); -+} -+ -+/** -+ * calc_nnode_num - calculate nnode number. -+ * @row: the row in the tree (root is zero) -+ * @col: the column in the row (leftmost is zero) -+ * -+ * The nnode number is a number that uniquely identifies a nnode and can be used -+ * easily to traverse the tree from the root to that nnode. -+ * -+ * This function calculates and returns the nnode number for the nnode at @row -+ * and @col. -+ */ -+static int calc_nnode_num(int row, int col) -+{ -+ int num, bits; -+ -+ num = 1; -+ while (row--) { -+ bits = (col & (UBIFS_LPT_FANOUT - 1)); -+ col >>= UBIFS_LPT_FANOUT_SHIFT; -+ num <<= UBIFS_LPT_FANOUT_SHIFT; -+ num |= bits; -+ } -+ return num; -+} -+ -+/** -+ * calc_nnode_num_from_parent - calculate nnode number. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode -+ * @iip: index in parent -+ * -+ * The nnode number is a number that uniquely identifies a nnode and can be used -+ * easily to traverse the tree from the root to that nnode. -+ * -+ * This function calculates and returns the nnode number based on the parent's -+ * nnode number and the index in parent. -+ */ -+static int calc_nnode_num_from_parent(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip) -+{ -+ int num, shft; -+ -+ if (!parent) -+ return 1; -+ shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT; -+ num = parent->num ^ (1 << shft); -+ num |= (UBIFS_LPT_FANOUT + iip) << shft; -+ return num; -+} -+ -+/** -+ * calc_pnode_num_from_parent - calculate pnode number. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode -+ * @iip: index in parent -+ * -+ * The pnode number is a number that uniquely identifies a pnode and can be used -+ * easily to traverse the tree from the root to that pnode. -+ * -+ * This function calculates and returns the pnode number based on the parent's -+ * nnode number and the index in parent. -+ */ -+static int calc_pnode_num_from_parent(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip) -+{ -+ int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0; -+ -+ for (i = 0; i < n; i++) { -+ num <<= UBIFS_LPT_FANOUT_SHIFT; -+ num |= pnum & (UBIFS_LPT_FANOUT - 1); -+ pnum >>= UBIFS_LPT_FANOUT_SHIFT; -+ } -+ num <<= UBIFS_LPT_FANOUT_SHIFT; -+ num |= iip; -+ return num; -+} -+ -+/** -+ * ubifs_create_dflt_lpt - create default LPT. -+ * @c: UBIFS file-system description object -+ * @main_lebs: number of main area LEBs is passed and returned here -+ * @lpt_first: LEB number of first LPT LEB -+ * @lpt_lebs: number of LEBs for LPT is passed and returned here -+ * @big_lpt: use big LPT model is passed and returned here -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, -+ int *lpt_lebs, int *big_lpt) -+{ -+ int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; -+ int blnum, boffs, bsz, bcnt; -+ struct ubifs_pnode *pnode = NULL; -+ struct ubifs_nnode *nnode = NULL; -+ void *buf = NULL, *p; -+ struct ubifs_lpt_lprops *ltab = NULL; -+ int *lsave = NULL; -+ -+ err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); -+ if (err) -+ return err; -+ *lpt_lebs = c->lpt_lebs; -+ -+ /* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */ -+ c->lpt_first = lpt_first; -+ /* Needed by 'set_ltab()' */ -+ c->lpt_last = lpt_first + c->lpt_lebs - 1; -+ /* Needed by 'ubifs_pack_lsave()' */ -+ c->main_first = c->leb_cnt - *main_lebs; -+ -+ lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_KERNEL); -+ pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL); -+ nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(c->leb_size, GFP_KERNEL); -+ ltab = kmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs, GFP_KERNEL); -+#else -+ buf = vmalloc(c->leb_size); -+ ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); -+#endif -+ if (!pnode || !nnode || !buf || !ltab || !lsave) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ ubifs_assert(!c->ltab); -+ c->ltab = ltab; /* Needed by set_ltab */ -+ -+ /* Initialize LPT's own lprops */ -+ for (i = 0; i < c->lpt_lebs; i++) { -+ ltab[i].free = c->leb_size; -+ ltab[i].dirty = 0; -+ ltab[i].tgc = 0; -+ ltab[i].cmt = 0; -+ } -+ -+ lnum = lpt_first; -+ p = buf; -+ /* Number of leaf nodes (pnodes) */ -+ cnt = c->pnode_cnt; -+ -+ /* -+ * The first pnode contains the LEB properties for the LEBs that contain -+ * the root inode node and the root index node of the index tree. -+ */ -+ node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8); -+ iopos = ALIGN(node_sz, c->min_io_size); -+ pnode->lprops[0].free = c->leb_size - iopos; -+ pnode->lprops[0].dirty = iopos - node_sz; -+ pnode->lprops[0].flags = LPROPS_INDEX; -+ -+ node_sz = UBIFS_INO_NODE_SZ; -+ iopos = ALIGN(node_sz, c->min_io_size); -+ pnode->lprops[1].free = c->leb_size - iopos; -+ pnode->lprops[1].dirty = iopos - node_sz; -+ -+ for (i = 2; i < UBIFS_LPT_FANOUT; i++) -+ pnode->lprops[i].free = c->leb_size; -+ -+ /* Add first pnode */ -+ ubifs_pack_pnode(c, p, pnode); -+ p += c->pnode_sz; -+ len = c->pnode_sz; -+ pnode->num += 1; -+ -+ /* Reset pnode values for remaining pnodes */ -+ pnode->lprops[0].free = c->leb_size; -+ pnode->lprops[0].dirty = 0; -+ pnode->lprops[0].flags = 0; -+ -+ pnode->lprops[1].free = c->leb_size; -+ pnode->lprops[1].dirty = 0; -+ -+ /* -+ * To calculate the internal node branches, we keep information about -+ * the level below. -+ */ -+ blnum = lnum; /* LEB number of level below */ -+ boffs = 0; /* Offset of level below */ -+ bcnt = cnt; /* Number of nodes in level below */ -+ bsz = c->pnode_sz; /* Size of nodes in level below */ -+ -+ /* Add all remaining pnodes */ -+ for (i = 1; i < cnt; i++) { -+ if (len + c->pnode_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = ubi_leb_change(c->ubi, lnum++, buf, alen, -+ UBI_SHORTTERM); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ ubifs_pack_pnode(c, p, pnode); -+ p += c->pnode_sz; -+ len += c->pnode_sz; -+ /* -+ * pnodes are simply numbered left to right starting at zero, -+ * which means the pnode number can be used easily to traverse -+ * down the tree to the corresponding pnode. -+ */ -+ pnode->num += 1; -+ } -+ -+ row = 0; -+ for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT) -+ row += 1; -+ /* Add all nnodes, one level at a time */ -+ while (1) { -+ /* Number of internal nodes (nnodes) at next level */ -+ cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT); -+ for (i = 0; i < cnt; i++) { -+ if (len + c->nnode_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, -+ alen - len); -+ memset(p, 0xff, alen - len); -+ err = ubi_leb_change(c->ubi, lnum++, buf, alen, -+ UBI_SHORTTERM); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ /* Only 1 nnode at this level, so it is the root */ -+ if (cnt == 1) { -+ c->lpt_lnum = lnum; -+ c->lpt_offs = len; -+ } -+ /* Set branches to the level below */ -+ for (j = 0; j < UBIFS_LPT_FANOUT; j++) { -+ if (bcnt) { -+ if (boffs + bsz > c->leb_size) { -+ blnum += 1; -+ boffs = 0; -+ } -+ nnode->nbranch[j].lnum = blnum; -+ nnode->nbranch[j].offs = boffs; -+ boffs += bsz; -+ bcnt--; -+ } else { -+ nnode->nbranch[j].lnum = 0; -+ nnode->nbranch[j].offs = 0; -+ } -+ } -+ nnode->num = calc_nnode_num(row, i); -+ ubifs_pack_nnode(c, p, nnode); -+ p += c->nnode_sz; -+ len += c->nnode_sz; -+ } -+ /* Only 1 nnode at this level, so it is the root */ -+ if (cnt == 1) -+ break; -+ /* Update the information about the level below */ -+ bcnt = cnt; -+ bsz = c->nnode_sz; -+ row -= 1; -+ } -+ -+ if (*big_lpt) { -+ /* Need to add LPT's save table */ -+ if (len + c->lsave_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = ubi_leb_change(c->ubi, lnum++, buf, alen, -+ UBI_SHORTTERM); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ -+ c->lsave_lnum = lnum; -+ c->lsave_offs = len; -+ -+ for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++) -+ lsave[i] = c->main_first + i; -+ for (; i < c->lsave_cnt; i++) -+ lsave[i] = c->main_first; -+ -+ ubifs_pack_lsave(c, p, lsave); -+ p += c->lsave_sz; -+ len += c->lsave_sz; -+ } -+ -+ /* Need to add LPT's own LEB properties table */ -+ if (len + c->ltab_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ -+ c->ltab_lnum = lnum; -+ c->ltab_offs = len; -+ -+ /* Update ltab before packing it */ -+ len += c->ltab_sz; -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ -+ ubifs_pack_ltab(c, p, ltab); -+ p += c->ltab_sz; -+ -+ /* Write remaining buffer */ -+ memset(p, 0xff, alen - len); -+ err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM); -+ if (err) -+ goto out; -+ -+ c->nhead_lnum = lnum; -+ c->nhead_offs = ALIGN(len, c->min_io_size); -+ -+ dbg_lp("space_bits %d", c->space_bits); -+ dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); -+ dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); -+ dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits); -+ dbg_lp("pcnt_bits %d", c->pcnt_bits); -+ dbg_lp("lnum_bits %d", c->lnum_bits); -+ dbg_lp("pnode_sz %d", c->pnode_sz); -+ dbg_lp("nnode_sz %d", c->nnode_sz); -+ dbg_lp("ltab_sz %d", c->ltab_sz); -+ dbg_lp("lsave_sz %d", c->lsave_sz); -+ dbg_lp("lsave_cnt %d", c->lsave_cnt); -+ dbg_lp("lpt_hght %d", c->lpt_hght); -+ dbg_lp("big_lpt %d", c->big_lpt); -+ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); -+ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); -+ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); -+ if (c->big_lpt) -+ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); -+out: -+ c->ltab = NULL; -+ kfree(lsave); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(ltab); -+ kfree(buf); -+#else -+ vfree(ltab); -+ vfree(buf); -+#endif -+ kfree(nnode); -+ kfree(pnode); -+ return err; -+} -+ -+/** -+ * update_cats - add LEB properties of a pnode to LEB category lists and heaps. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode -+ * -+ * When a pnode is loaded into memory, the LEB properties it contains are added, -+ * by this function, to the LEB category lists and heaps. -+ */ -+static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode) -+{ -+ int i; -+ -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK; -+ int lnum = pnode->lprops[i].lnum; -+ -+ if (!lnum) -+ return; -+ ubifs_add_to_cat(c, &pnode->lprops[i], cat); -+ } -+} -+ -+/** -+ * replace_cats - add LEB properties of a pnode to LEB category lists and heaps. -+ * @c: UBIFS file-system description object -+ * @old_pnode: pnode copied -+ * @new_pnode: pnode copy -+ * -+ * During commit it is sometimes necessary to copy a pnode -+ * (see dirty_cow_pnode). When that happens, references in -+ * category lists and heaps must be replaced. This function does that. -+ */ -+static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode, -+ struct ubifs_pnode *new_pnode) -+{ -+ int i; -+ -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ if (!new_pnode->lprops[i].lnum) -+ return; -+ ubifs_replace_cat(c, &old_pnode->lprops[i], -+ &new_pnode->lprops[i]); -+ } -+} -+ -+/** -+ * check_lpt_crc - check LPT node crc is correct. -+ * @c: UBIFS file-system description object -+ * @buf: buffer containing node -+ * @len: length of node -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int check_lpt_crc(void *buf, int len) -+{ -+ int pos = 0; -+ uint8_t *addr = buf; -+ uint16_t crc, calc_crc; -+ -+ crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS); -+ calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ len - UBIFS_LPT_CRC_BYTES); -+ if (crc != calc_crc) { -+ ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc, -+ calc_crc); -+ dbg_dump_stack(); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** -+ * check_lpt_type - check LPT node type is correct. -+ * @c: UBIFS file-system description object -+ * @addr: address of type bit field is passed and returned updated here -+ * @pos: position of type bit field is passed and returned updated here -+ * @type: expected type -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int check_lpt_type(uint8_t **addr, int *pos, int type) -+{ -+ int node_type; -+ -+ node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS); -+ if (node_type != type) { -+ ubifs_err("invalid type (%d) in LPT node type %d", node_type, -+ type); -+ dbg_dump_stack(); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** -+ * unpack_pnode - unpack a pnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer containing packed pnode to unpack -+ * @pnode: pnode structure to fill -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int unpack_pnode(struct ubifs_info *c, void *buf, -+ struct ubifs_pnode *pnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0, err; -+ -+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_PNODE); -+ if (err) -+ return err; -+ if (c->big_lpt) -+ pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_lprops * const lprops = &pnode->lprops[i]; -+ -+ lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits); -+ lprops->free <<= 3; -+ lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits); -+ lprops->dirty <<= 3; -+ -+ if (ubifs_unpack_bits(&addr, &pos, 1)) -+ lprops->flags = LPROPS_INDEX; -+ else -+ lprops->flags = 0; -+ lprops->flags |= ubifs_categorize_lprops(c, lprops); -+ } -+ err = check_lpt_crc(buf, c->pnode_sz); -+ return err; -+} -+ -+/** -+ * unpack_nnode - unpack a nnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer containing packed nnode to unpack -+ * @nnode: nnode structure to fill -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int unpack_nnode(struct ubifs_info *c, void *buf, -+ struct ubifs_nnode *nnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0, err; -+ -+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_NNODE); -+ if (err) -+ return err; -+ if (c->big_lpt) -+ nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int lnum; -+ -+ lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) + -+ c->lpt_first; -+ if (lnum == c->lpt_last + 1) -+ lnum = 0; -+ nnode->nbranch[i].lnum = lnum; -+ nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos, -+ c->lpt_offs_bits); -+ } -+ err = check_lpt_crc(buf, c->nnode_sz); -+ return err; -+} -+ -+/** -+ * unpack_ltab - unpack the LPT's own lprops table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer from which to unpack -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int unpack_ltab(struct ubifs_info *c, void *buf) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0, err; -+ -+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_LTAB); -+ if (err) -+ return err; -+ for (i = 0; i < c->lpt_lebs; i++) { -+ int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits); -+ int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits); -+ -+ if (free < 0 || free > c->leb_size || dirty < 0 || -+ dirty > c->leb_size || free + dirty > c->leb_size) -+ return -EINVAL; -+ -+ c->ltab[i].free = free; -+ c->ltab[i].dirty = dirty; -+ c->ltab[i].tgc = 0; -+ c->ltab[i].cmt = 0; -+ } -+ err = check_lpt_crc(buf, c->ltab_sz); -+ return err; -+} -+ -+/** -+ * unpack_lsave - unpack the LPT's save table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer from which to unpack -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int unpack_lsave(struct ubifs_info *c, void *buf) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0, err; -+ -+ err = check_lpt_type(&addr, &pos, UBIFS_LPT_LSAVE); -+ if (err) -+ return err; -+ for (i = 0; i < c->lsave_cnt; i++) { -+ int lnum = ubifs_unpack_bits(&addr, &pos, c->lnum_bits); -+ -+ if (lnum < c->main_first || lnum >= c->leb_cnt) -+ return -EINVAL; -+ c->lsave[i] = lnum; -+ } -+ err = check_lpt_crc(buf, c->lsave_sz); -+ return err; -+} -+ -+/** -+ * validate_nnode - validate a nnode. -+ * @c: UBIFS file-system description object -+ * @nnode: nnode to validate -+ * @parent: parent nnode (or NULL for the root nnode) -+ * @iip: index in parent -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int validate_nnode(struct ubifs_info *c, struct ubifs_nnode *nnode, -+ struct ubifs_nnode *parent, int iip) -+{ -+ int i, lvl, max_offs; -+ -+ if (c->big_lpt) { -+ int num = calc_nnode_num_from_parent(c, parent, iip); -+ -+ if (nnode->num != num) -+ return -EINVAL; -+ } -+ lvl = parent ? parent->level - 1 : c->lpt_hght; -+ if (lvl < 1) -+ return -EINVAL; -+ if (lvl == 1) -+ max_offs = c->leb_size - c->pnode_sz; -+ else -+ max_offs = c->leb_size - c->nnode_sz; -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int lnum = nnode->nbranch[i].lnum; -+ int offs = nnode->nbranch[i].offs; -+ -+ if (lnum == 0) { -+ if (offs != 0) -+ return -EINVAL; -+ continue; -+ } -+ if (lnum < c->lpt_first || lnum > c->lpt_last) -+ return -EINVAL; -+ if (offs < 0 || offs > max_offs) -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** -+ * validate_pnode - validate a pnode. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode to validate -+ * @parent: parent nnode -+ * @iip: index in parent -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int validate_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, -+ struct ubifs_nnode *parent, int iip) -+{ -+ int i; -+ -+ if (c->big_lpt) { -+ int num = calc_pnode_num_from_parent(c, parent, iip); -+ -+ if (pnode->num != num) -+ return -EINVAL; -+ } -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int free = pnode->lprops[i].free; -+ int dirty = pnode->lprops[i].dirty; -+ -+ if (free < 0 || free > c->leb_size || free % c->min_io_size || -+ (free & 7)) -+ return -EINVAL; -+ if (dirty < 0 || dirty > c->leb_size || (dirty & 7)) -+ return -EINVAL; -+ if (dirty + free > c->leb_size) -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+/** -+ * set_pnode_lnum - set LEB numbers on a pnode. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode to update -+ * -+ * This function calculates the LEB numbers for the LEB properties it contains -+ * based on the pnode number. -+ */ -+static void set_pnode_lnum(struct ubifs_info *c, struct ubifs_pnode *pnode) -+{ -+ int i, lnum; -+ -+ lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first; -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ if (lnum >= c->leb_cnt) -+ return; -+ pnode->lprops[i].lnum = lnum++; -+ } -+} -+ -+/** -+ * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode (or NULL for the root) -+ * @iip: index in parent -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch = NULL; -+ struct ubifs_nnode *nnode = NULL; -+ void *buf = c->lpt_nod_buf; -+ int err, lnum, offs; -+ -+ if (parent) { -+ branch = &parent->nbranch[iip]; -+ lnum = branch->lnum; -+ offs = branch->offs; -+ } else { -+ lnum = c->lpt_lnum; -+ offs = c->lpt_offs; -+ } -+ nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS); -+ if (!nnode) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (lnum == 0) { -+ /* -+ * This nnode was not written which just means that the LEB -+ * properties in the subtree below it describe empty LEBs. We -+ * make the nnode as though we had read it, which in fact means -+ * doing almost nothing. -+ */ -+ if (c->big_lpt) -+ nnode->num = calc_nnode_num_from_parent(c, parent, iip); -+ } else { -+ err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz); -+ if (err) -+ goto out; -+ err = unpack_nnode(c, buf, nnode); -+ if (err) -+ goto out; -+ } -+ err = validate_nnode(c, nnode, parent, iip); -+ if (err) -+ goto out; -+ if (!c->big_lpt) -+ nnode->num = calc_nnode_num_from_parent(c, parent, iip); -+ if (parent) { -+ branch->nnode = nnode; -+ nnode->level = parent->level - 1; -+ } else { -+ c->nroot = nnode; -+ nnode->level = c->lpt_hght; -+ } -+ nnode->parent = parent; -+ nnode->iip = iip; -+ return 0; -+ -+out: -+ ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs); -+ kfree(nnode); -+ return err; -+} -+ -+/** -+ * read_pnode - read a pnode from flash and link it to the tree in memory. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode -+ * @iip: index in parent -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch; -+ struct ubifs_pnode *pnode = NULL; -+ void *buf = c->lpt_nod_buf; -+ int err, lnum, offs; -+ -+ branch = &parent->nbranch[iip]; -+ lnum = branch->lnum; -+ offs = branch->offs; -+ pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS); -+ if (!pnode) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (lnum == 0) { -+ /* -+ * This pnode was not written which just means that the LEB -+ * properties in it describe empty LEBs. We make the pnode as -+ * though we had read it. -+ */ -+ int i; -+ -+ if (c->big_lpt) -+ pnode->num = calc_pnode_num_from_parent(c, parent, iip); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_lprops * const lprops = &pnode->lprops[i]; -+ -+ lprops->free = c->leb_size; -+ lprops->flags = ubifs_categorize_lprops(c, lprops); -+ } -+ } else { -+ err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz); -+ if (err) -+ goto out; -+ err = unpack_pnode(c, buf, pnode); -+ if (err) -+ goto out; -+ } -+ err = validate_pnode(c, pnode, parent, iip); -+ if (err) -+ goto out; -+ if (!c->big_lpt) -+ pnode->num = calc_pnode_num_from_parent(c, parent, iip); -+ branch->pnode = pnode; -+ pnode->parent = parent; -+ pnode->iip = iip; -+ set_pnode_lnum(c, pnode); -+ c->pnodes_have += 1; -+ return 0; -+ -+out: -+ ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs); -+ dbg_dump_pnode(c, pnode, parent, iip); -+ dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip)); -+ kfree(pnode); -+ return err; -+} -+ -+/** -+ * read_ltab - read LPT's own lprops table. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int read_ltab(struct ubifs_info *c) -+{ -+ int err; -+ void *buf; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(c->ltab_sz, GFP_KERNEL); -+#else -+ buf = vmalloc(c->ltab_sz); -+#endif -+ if (!buf) -+ return -ENOMEM; -+ err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz); -+ if (err) -+ goto out; -+ err = unpack_ltab(c, buf); -+out: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else -+ vfree(buf); -+#endif -+ return err; -+} -+ -+/** -+ * read_lsave - read LPT's save table. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int read_lsave(struct ubifs_info *c) -+{ -+ int err, i; -+ void *buf; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ buf = kmalloc(c->lsave_sz, GFP_KERNEL); -+#else -+ buf = vmalloc(c->lsave_sz); -+#endif -+ if (!buf) -+ return -ENOMEM; -+ err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz); -+ if (err) -+ goto out; -+ err = unpack_lsave(c, buf); -+ if (err) -+ goto out; -+ for (i = 0; i < c->lsave_cnt; i++) { -+ int lnum = c->lsave[i]; -+ -+ /* -+ * Due to automatic resizing, the values in the lsave table -+ * could be beyond the volume size - just ignore them. -+ */ -+ if (lnum >= c->leb_cnt) -+ continue; -+ ubifs_lpt_lookup(c, lnum); -+ } -+out: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(buf); -+#else -+ vfree(buf); -+#endif -+ return err; -+} -+ -+/** -+ * ubifs_get_nnode - get a nnode. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode (or NULL for the root) -+ * @iip: index in parent -+ * -+ * This function returns a pointer to the nnode on success or a negative error -+ * code on failure. -+ */ -+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch; -+ struct ubifs_nnode *nnode; -+ int err; -+ -+ branch = &parent->nbranch[iip]; -+ nnode = branch->nnode; -+ if (nnode) -+ return nnode; -+ err = ubifs_read_nnode(c, parent, iip); -+ if (err) -+ return ERR_PTR(err); -+ return branch->nnode; -+} -+ -+/** -+ * ubifs_get_pnode - get a pnode. -+ * @c: UBIFS file-system description object -+ * @parent: parent nnode -+ * @iip: index in parent -+ * -+ * This function returns a pointer to the pnode on success or a negative error -+ * code on failure. -+ */ -+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch; -+ struct ubifs_pnode *pnode; -+ int err; -+ -+ branch = &parent->nbranch[iip]; -+ pnode = branch->pnode; -+ if (pnode) -+ return pnode; -+ err = read_pnode(c, parent, iip); -+ if (err) -+ return ERR_PTR(err); -+ update_cats(c, branch->pnode); -+ return branch->pnode; -+} -+ -+/** -+ * ubifs_lpt_lookup - lookup LEB properties in the LPT. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to lookup -+ * -+ * This function returns a pointer to the LEB properties on success or a -+ * negative error code on failure. -+ */ -+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) -+{ -+ int err, i, h, iip, shft; -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ -+ if (!c->nroot) { -+ err = ubifs_read_nnode(c, NULL, 0); -+ if (err) -+ return ERR_PTR(err); -+ } -+ nnode = c->nroot; -+ i = lnum - c->main_first; -+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; -+ for (h = 1; h < c->lpt_hght; h++) { -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ nnode = ubifs_get_nnode(c, nnode, iip); -+ if (IS_ERR(nnode)) -+ return ERR_PTR(PTR_ERR(nnode)); -+ } -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ pnode = ubifs_get_pnode(c, nnode, iip); -+ if (IS_ERR(pnode)) -+ return ERR_PTR(PTR_ERR(pnode)); -+ iip = (i & (UBIFS_LPT_FANOUT - 1)); -+ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum, -+ pnode->lprops[iip].free, pnode->lprops[iip].dirty, -+ pnode->lprops[iip].flags); -+ return &pnode->lprops[iip]; -+} -+ -+/** -+ * dirty_cow_nnode - ensure a nnode is not being committed. -+ * @c: UBIFS file-system description object -+ * @nnode: nnode to check -+ * -+ * Returns dirtied nnode on success or negative error code on failure. -+ */ -+static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c, -+ struct ubifs_nnode *nnode) -+{ -+ struct ubifs_nnode *n; -+ int i; -+ -+ if (!test_bit(COW_CNODE, &nnode->flags)) { -+ /* nnode is not being committed */ -+ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { -+ c->dirty_nn_cnt += 1; -+ ubifs_add_nnode_dirt(c, nnode); -+ } -+ return nnode; -+ } -+ -+ /* nnode is being committed, so copy it */ -+ n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS); -+ if (unlikely(!n)) -+ return ERR_PTR(-ENOMEM); -+ -+ memcpy(n, nnode, sizeof(struct ubifs_nnode)); -+ n->cnext = NULL; -+ __set_bit(DIRTY_CNODE, &n->flags); -+ __clear_bit(COW_CNODE, &n->flags); -+ -+ /* The children now have new parent */ -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_nbranch *branch = &n->nbranch[i]; -+ -+ if (branch->cnode) -+ branch->cnode->parent = n; -+ } -+ -+ ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags)); -+ __set_bit(OBSOLETE_CNODE, &nnode->flags); -+ -+ c->dirty_nn_cnt += 1; -+ ubifs_add_nnode_dirt(c, nnode); -+ if (nnode->parent) -+ nnode->parent->nbranch[n->iip].nnode = n; -+ else -+ c->nroot = n; -+ return n; -+} -+ -+/** -+ * dirty_cow_pnode - ensure a pnode is not being committed. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode to check -+ * -+ * Returns dirtied pnode on success or negative error code on failure. -+ */ -+static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c, -+ struct ubifs_pnode *pnode) -+{ -+ struct ubifs_pnode *p; -+ -+ if (!test_bit(COW_CNODE, &pnode->flags)) { -+ /* pnode is not being committed */ -+ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) { -+ c->dirty_pn_cnt += 1; -+ add_pnode_dirt(c, pnode); -+ } -+ return pnode; -+ } -+ -+ /* pnode is being committed, so copy it */ -+ p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS); -+ if (unlikely(!p)) -+ return ERR_PTR(-ENOMEM); -+ -+ memcpy(p, pnode, sizeof(struct ubifs_pnode)); -+ p->cnext = NULL; -+ __set_bit(DIRTY_CNODE, &p->flags); -+ __clear_bit(COW_CNODE, &p->flags); -+ replace_cats(c, pnode, p); -+ -+ ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags)); -+ __set_bit(OBSOLETE_CNODE, &pnode->flags); -+ -+ c->dirty_pn_cnt += 1; -+ add_pnode_dirt(c, pnode); -+ pnode->parent->nbranch[p->iip].pnode = p; -+ return p; -+} -+ -+/** -+ * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to lookup -+ * -+ * This function returns a pointer to the LEB properties on success or a -+ * negative error code on failure. -+ */ -+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum) -+{ -+ int err, i, h, iip, shft; -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ -+ if (!c->nroot) { -+ err = ubifs_read_nnode(c, NULL, 0); -+ if (err) -+ return ERR_PTR(err); -+ } -+ nnode = c->nroot; -+ nnode = dirty_cow_nnode(c, nnode); -+ if (IS_ERR(nnode)) -+ return ERR_PTR(PTR_ERR(nnode)); -+ i = lnum - c->main_first; -+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; -+ for (h = 1; h < c->lpt_hght; h++) { -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ nnode = ubifs_get_nnode(c, nnode, iip); -+ if (IS_ERR(nnode)) -+ return ERR_PTR(PTR_ERR(nnode)); -+ nnode = dirty_cow_nnode(c, nnode); -+ if (IS_ERR(nnode)) -+ return ERR_PTR(PTR_ERR(nnode)); -+ } -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ pnode = ubifs_get_pnode(c, nnode, iip); -+ if (IS_ERR(pnode)) -+ return ERR_PTR(PTR_ERR(pnode)); -+ pnode = dirty_cow_pnode(c, pnode); -+ if (IS_ERR(pnode)) -+ return ERR_PTR(PTR_ERR(pnode)); -+ iip = (i & (UBIFS_LPT_FANOUT - 1)); -+ dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum, -+ pnode->lprops[iip].free, pnode->lprops[iip].dirty, -+ pnode->lprops[iip].flags); -+ ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags)); -+ return &pnode->lprops[iip]; -+} -+ -+/** -+ * lpt_init_rd - initialize the LPT for reading. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int lpt_init_rd(struct ubifs_info *c) -+{ -+ int err, i; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ltab = kmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs, GFP_KERNEL); -+#else -+ c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); -+#endif -+ if (!c->ltab) -+ return -ENOMEM; -+ -+ i = max_t(int, c->nnode_sz, c->pnode_sz); -+ c->lpt_nod_buf = kmalloc(i, GFP_KERNEL); -+ if (!c->lpt_nod_buf) -+ return -ENOMEM; -+ -+ for (i = 0; i < LPROPS_HEAP_CNT; i++) { -+ c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, -+ GFP_KERNEL); -+ if (!c->lpt_heap[i].arr) -+ return -ENOMEM; -+ c->lpt_heap[i].cnt = 0; -+ c->lpt_heap[i].max_cnt = LPT_HEAP_SZ; -+ } -+ -+ c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL); -+ if (!c->dirty_idx.arr) -+ return -ENOMEM; -+ c->dirty_idx.cnt = 0; -+ c->dirty_idx.max_cnt = LPT_HEAP_SZ; -+ -+ err = read_ltab(c); -+ if (err) -+ return err; -+ -+ dbg_lp("space_bits %d", c->space_bits); -+ dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); -+ dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); -+ dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits); -+ dbg_lp("pcnt_bits %d", c->pcnt_bits); -+ dbg_lp("lnum_bits %d", c->lnum_bits); -+ dbg_lp("pnode_sz %d", c->pnode_sz); -+ dbg_lp("nnode_sz %d", c->nnode_sz); -+ dbg_lp("ltab_sz %d", c->ltab_sz); -+ dbg_lp("lsave_sz %d", c->lsave_sz); -+ dbg_lp("lsave_cnt %d", c->lsave_cnt); -+ dbg_lp("lpt_hght %d", c->lpt_hght); -+ dbg_lp("big_lpt %d", c->big_lpt); -+ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); -+ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); -+ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); -+ if (c->big_lpt) -+ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); -+ -+ return 0; -+} -+ -+/** -+ * lpt_init_wr - initialize the LPT for writing. -+ * @c: UBIFS file-system description object -+ * -+ * 'lpt_init_rd()' must have been called already. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int lpt_init_wr(struct ubifs_info *c) -+{ -+ int err, i; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ltab_cmt = kmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs, GFP_KERNEL); -+ if (!c->ltab_cmt) -+ return -ENOMEM; -+ c->lpt_buf = kmalloc(c->leb_size, GFP_KERNEL); -+ if (!c->lpt_buf) -+ return -ENOMEM; -+#else -+ c->ltab_cmt = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); -+ if (!c->ltab_cmt) -+ return -ENOMEM; -+ c->lpt_buf = vmalloc(c->leb_size); -+ if (!c->lpt_buf) -+ return -ENOMEM; -+#endif -+ -+ if (c->big_lpt) { -+ c->lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_NOFS); -+ if (!c->lsave) -+ return -ENOMEM; -+ err = read_lsave(c); -+ if (err) -+ return err; -+ } -+ -+ for (i = 0; i < c->lpt_lebs; i++) -+ if (c->ltab[i].free == c->leb_size) { -+ err = ubifs_leb_unmap(c, i + c->lpt_first); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubifs_lpt_init - initialize the LPT. -+ * @c: UBIFS file-system description object -+ * @rd: whether to initialize lpt for reading -+ * @wr: whether to initialize lpt for writing -+ * -+ * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true -+ * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is -+ * true. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr) -+{ -+ int err; -+ -+ if (rd) { -+ err = lpt_init_rd(c); -+ if (err) -+ return err; -+ } -+ -+ if (wr) { -+ err = lpt_init_wr(c); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * struct lpt_scan_node - somewhere to put nodes while we scan LPT. -+ * @nnode: where to keep a nnode -+ * @pnode: where to keep a pnode -+ * @cnode: where to keep a cnode -+ * @in_tree: is the node in the tree in memory -+ * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in -+ * the tree -+ * @ptr.pnode: ditto for pnode -+ * @ptr.cnode: ditto for cnode -+ */ -+struct lpt_scan_node { -+ union { -+ struct ubifs_nnode nnode; -+ struct ubifs_pnode pnode; -+ struct ubifs_cnode cnode; -+ }; -+ int in_tree; -+ union { -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ struct ubifs_cnode *cnode; -+ } ptr; -+}; -+ -+/** -+ * scan_get_nnode - for the scan, get a nnode from either the tree or flash. -+ * @c: the UBIFS file-system description object -+ * @path: where to put the nnode -+ * @parent: parent of the nnode -+ * @iip: index in parent of the nnode -+ * -+ * This function returns a pointer to the nnode on success or a negative error -+ * code on failure. -+ */ -+static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c, -+ struct lpt_scan_node *path, -+ struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch; -+ struct ubifs_nnode *nnode; -+ void *buf = c->lpt_nod_buf; -+ int err; -+ -+ branch = &parent->nbranch[iip]; -+ nnode = branch->nnode; -+ if (nnode) { -+ path->in_tree = 1; -+ path->ptr.nnode = nnode; -+ return nnode; -+ } -+ nnode = &path->nnode; -+ path->in_tree = 0; -+ path->ptr.nnode = nnode; -+ memset(nnode, 0, sizeof(struct ubifs_nnode)); -+ if (branch->lnum == 0) { -+ /* -+ * This nnode was not written which just means that the LEB -+ * properties in the subtree below it describe empty LEBs. We -+ * make the nnode as though we had read it, which in fact means -+ * doing almost nothing. -+ */ -+ if (c->big_lpt) -+ nnode->num = calc_nnode_num_from_parent(c, parent, iip); -+ } else { -+ err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, -+ c->nnode_sz); -+ if (err) -+ return ERR_PTR(err); -+ err = unpack_nnode(c, buf, nnode); -+ if (err) -+ return ERR_PTR(err); -+ } -+ err = validate_nnode(c, nnode, parent, iip); -+ if (err) -+ return ERR_PTR(err); -+ if (!c->big_lpt) -+ nnode->num = calc_nnode_num_from_parent(c, parent, iip); -+ nnode->level = parent->level - 1; -+ nnode->parent = parent; -+ nnode->iip = iip; -+ return nnode; -+} -+ -+/** -+ * scan_get_pnode - for the scan, get a pnode from either the tree or flash. -+ * @c: the UBIFS file-system description object -+ * @path: where to put the pnode -+ * @parent: parent of the pnode -+ * @iip: index in parent of the pnode -+ * -+ * This function returns a pointer to the pnode on success or a negative error -+ * code on failure. -+ */ -+static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c, -+ struct lpt_scan_node *path, -+ struct ubifs_nnode *parent, int iip) -+{ -+ struct ubifs_nbranch *branch; -+ struct ubifs_pnode *pnode; -+ void *buf = c->lpt_nod_buf; -+ int err; -+ -+ branch = &parent->nbranch[iip]; -+ pnode = branch->pnode; -+ if (pnode) { -+ path->in_tree = 1; -+ path->ptr.pnode = pnode; -+ return pnode; -+ } -+ pnode = &path->pnode; -+ path->in_tree = 0; -+ path->ptr.pnode = pnode; -+ memset(pnode, 0, sizeof(struct ubifs_pnode)); -+ if (branch->lnum == 0) { -+ /* -+ * This pnode was not written which just means that the LEB -+ * properties in it describe empty LEBs. We make the pnode as -+ * though we had read it. -+ */ -+ int i; -+ -+ if (c->big_lpt) -+ pnode->num = calc_pnode_num_from_parent(c, parent, iip); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_lprops * const lprops = &pnode->lprops[i]; -+ -+ lprops->free = c->leb_size; -+ lprops->flags = ubifs_categorize_lprops(c, lprops); -+ } -+ } else { -+ ubifs_assert(branch->lnum >= c->lpt_first && -+ branch->lnum <= c->lpt_last); -+ ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size); -+ err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, -+ c->pnode_sz); -+ if (err) -+ return ERR_PTR(err); -+ err = unpack_pnode(c, buf, pnode); -+ if (err) -+ return ERR_PTR(err); -+ } -+ err = validate_pnode(c, pnode, parent, iip); -+ if (err) -+ return ERR_PTR(err); -+ if (!c->big_lpt) -+ pnode->num = calc_pnode_num_from_parent(c, parent, iip); -+ pnode->parent = parent; -+ pnode->iip = iip; -+ set_pnode_lnum(c, pnode); -+ return pnode; -+} -+ -+/** -+ * ubifs_lpt_scan_nolock - scan the LPT. -+ * @c: the UBIFS file-system description object -+ * @start_lnum: LEB number from which to start scanning -+ * @end_lnum: LEB number at which to stop scanning -+ * @scan_cb: callback function called for each lprops -+ * @data: data to be passed to the callback function -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum, -+ ubifs_lpt_scan_callback scan_cb, void *data) -+{ -+ int err = 0, i, h, iip, shft; -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ struct lpt_scan_node *path; -+ -+ if (start_lnum == -1) { -+ start_lnum = end_lnum + 1; -+ if (start_lnum >= c->leb_cnt) -+ start_lnum = c->main_first; -+ } -+ -+ ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt); -+ ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt); -+ -+ if (!c->nroot) { -+ err = ubifs_read_nnode(c, NULL, 0); -+ if (err) -+ return err; -+ } -+ -+ path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1), -+ GFP_NOFS); -+ if (!path) -+ return -ENOMEM; -+ -+ path[0].ptr.nnode = c->nroot; -+ path[0].in_tree = 1; -+again: -+ /* Descend to the pnode containing start_lnum */ -+ nnode = c->nroot; -+ i = start_lnum - c->main_first; -+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; -+ for (h = 1; h < c->lpt_hght; h++) { -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ nnode = scan_get_nnode(c, path + h, nnode, iip); -+ if (IS_ERR(nnode)) { -+ err = PTR_ERR(nnode); -+ goto out; -+ } -+ } -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ pnode = scan_get_pnode(c, path + h, nnode, iip); -+ if (IS_ERR(pnode)) { -+ err = PTR_ERR(pnode); -+ goto out; -+ } -+ iip = (i & (UBIFS_LPT_FANOUT - 1)); -+ -+ /* Loop for each lprops */ -+ while (1) { -+ struct ubifs_lprops *lprops = &pnode->lprops[iip]; -+ int ret, lnum = lprops->lnum; -+ -+ ret = scan_cb(c, lprops, path[h].in_tree, data); -+ if (ret < 0) { -+ err = ret; -+ goto out; -+ } -+ if (ret & LPT_SCAN_ADD) { -+ /* Add all the nodes in path to the tree in memory */ -+ for (h = 1; h < c->lpt_hght; h++) { -+ const size_t sz = sizeof(struct ubifs_nnode); -+ struct ubifs_nnode *parent; -+ -+ if (path[h].in_tree) -+ continue; -+ nnode = kmalloc(sz, GFP_NOFS); -+ if (!nnode) { -+ err = -ENOMEM; -+ goto out; -+ } -+ memcpy(nnode, &path[h].nnode, sz); -+ parent = nnode->parent; -+ parent->nbranch[nnode->iip].nnode = nnode; -+ path[h].ptr.nnode = nnode; -+ path[h].in_tree = 1; -+ path[h + 1].cnode.parent = nnode; -+ } -+ if (path[h].in_tree) -+ ubifs_ensure_cat(c, lprops); -+ else { -+ const size_t sz = sizeof(struct ubifs_pnode); -+ struct ubifs_nnode *parent; -+ -+ pnode = kmalloc(sz, GFP_NOFS); -+ if (!pnode) { -+ err = -ENOMEM; -+ goto out; -+ } -+ memcpy(pnode, &path[h].pnode, sz); -+ parent = pnode->parent; -+ parent->nbranch[pnode->iip].pnode = pnode; -+ path[h].ptr.pnode = pnode; -+ path[h].in_tree = 1; -+ update_cats(c, pnode); -+ c->pnodes_have += 1; -+ } -+ err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *) -+ c->nroot, 0, 0); -+ if (err) -+ goto out; -+ err = dbg_check_cats(c); -+ if (err) -+ goto out; -+ } -+ if (ret & LPT_SCAN_STOP) { -+ err = 0; -+ break; -+ } -+ /* Get the next lprops */ -+ if (lnum == end_lnum) { -+ /* -+ * We got to the end without finding what we were -+ * looking for -+ */ -+ err = -ENOSPC; -+ goto out; -+ } -+ if (lnum + 1 >= c->leb_cnt) { -+ /* Wrap-around to the beginning */ -+ start_lnum = c->main_first; -+ goto again; -+ } -+ if (iip + 1 < UBIFS_LPT_FANOUT) { -+ /* Next lprops is in the same pnode */ -+ iip += 1; -+ continue; -+ } -+ /* We need to get the next pnode. Go up until we can go right */ -+ iip = pnode->iip; -+ while (1) { -+ h -= 1; -+ ubifs_assert(h >= 0); -+ nnode = path[h].ptr.nnode; -+ if (iip + 1 < UBIFS_LPT_FANOUT) -+ break; -+ iip = nnode->iip; -+ } -+ /* Go right */ -+ iip += 1; -+ /* Descend to the pnode */ -+ h += 1; -+ for (; h < c->lpt_hght; h++) { -+ nnode = scan_get_nnode(c, path + h, nnode, iip); -+ if (IS_ERR(nnode)) { -+ err = PTR_ERR(nnode); -+ goto out; -+ } -+ iip = 0; -+ } -+ pnode = scan_get_pnode(c, path + h, nnode, iip); -+ if (IS_ERR(pnode)) { -+ err = PTR_ERR(pnode); -+ goto out; -+ } -+ iip = 0; -+ } -+out: -+ kfree(path); -+ return err; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * dbg_chk_pnode - check a pnode. -+ * @c: the UBIFS file-system description object -+ * @pnode: pnode to check -+ * @col: pnode column -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, -+ int col) -+{ -+ int i; -+ -+ if (pnode->num != col) { -+ dbg_err("pnode num %d expected %d parent num %d iip %d", -+ pnode->num, col, pnode->parent->num, pnode->iip); -+ return -EINVAL; -+ } -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_lprops *lp, *lprops = &pnode->lprops[i]; -+ int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i + -+ c->main_first; -+ int found, cat = lprops->flags & LPROPS_CAT_MASK; -+ struct ubifs_lpt_heap *heap; -+ struct list_head *list = NULL; -+ -+ if (lnum >= c->leb_cnt) -+ continue; -+ if (lprops->lnum != lnum) { -+ dbg_err("bad LEB number %d expected %d", -+ lprops->lnum, lnum); -+ return -EINVAL; -+ } -+ if (lprops->flags & LPROPS_TAKEN) { -+ if (cat != LPROPS_UNCAT) { -+ dbg_err("LEB %d taken but not uncat %d", -+ lprops->lnum, cat); -+ return -EINVAL; -+ } -+ continue; -+ } -+ if (lprops->flags & LPROPS_INDEX) { -+ switch (cat) { -+ case LPROPS_UNCAT: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FRDI_IDX: -+ break; -+ default: -+ dbg_err("LEB %d index but cat %d", -+ lprops->lnum, cat); -+ return -EINVAL; -+ } -+ } else { -+ switch (cat) { -+ case LPROPS_UNCAT: -+ case LPROPS_DIRTY: -+ case LPROPS_FREE: -+ case LPROPS_EMPTY: -+ case LPROPS_FREEABLE: -+ break; -+ default: -+ dbg_err("LEB %d not index but cat %d", -+ lprops->lnum, cat); -+ return -EINVAL; -+ } -+ } -+ switch (cat) { -+ case LPROPS_UNCAT: -+ list = &c->uncat_list; -+ break; -+ case LPROPS_EMPTY: -+ list = &c->empty_list; -+ break; -+ case LPROPS_FREEABLE: -+ list = &c->freeable_list; -+ break; -+ case LPROPS_FRDI_IDX: -+ list = &c->frdi_idx_list; -+ break; -+ } -+ found = 0; -+ switch (cat) { -+ case LPROPS_DIRTY: -+ case LPROPS_DIRTY_IDX: -+ case LPROPS_FREE: -+ heap = &c->lpt_heap[cat - 1]; -+ if (lprops->hpos < heap->cnt && -+ heap->arr[lprops->hpos] == lprops) -+ found = 1; -+ break; -+ case LPROPS_UNCAT: -+ case LPROPS_EMPTY: -+ case LPROPS_FREEABLE: -+ case LPROPS_FRDI_IDX: -+ list_for_each_entry(lp, list, list) -+ if (lprops == lp) { -+ found = 1; -+ break; -+ } -+ break; -+ } -+ if (!found) { -+ dbg_err("LEB %d cat %d not found in cat heap/list", -+ lprops->lnum, cat); -+ return -EINVAL; -+ } -+ switch (cat) { -+ case LPROPS_EMPTY: -+ if (lprops->free != c->leb_size) { -+ dbg_err("LEB %d cat %d free %d dirty %d", -+ lprops->lnum, cat, lprops->free, -+ lprops->dirty); -+ return -EINVAL; -+ } -+ case LPROPS_FREEABLE: -+ case LPROPS_FRDI_IDX: -+ if (lprops->free + lprops->dirty != c->leb_size) { -+ dbg_err("LEB %d cat %d free %d dirty %d", -+ lprops->lnum, cat, lprops->free, -+ lprops->dirty); -+ return -EINVAL; -+ } -+ } -+ } -+ return 0; -+} -+ -+/** -+ * dbg_check_lpt_nodes - check nnodes and pnodes. -+ * @c: the UBIFS file-system description object -+ * @cnode: next cnode (nnode or pnode) to check -+ * @row: row of cnode (root is zero) -+ * @col: column of cnode (leftmost is zero) -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, -+ int row, int col) -+{ -+ struct ubifs_nnode *nnode, *nn; -+ struct ubifs_cnode *cn; -+ int num, iip = 0, err; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) -+ return 0; -+ -+ while (cnode) { -+ ubifs_assert(row >= 0); -+ nnode = cnode->parent; -+ if (cnode->level) { -+ /* cnode is a nnode */ -+ num = calc_nnode_num(row, col); -+ if (cnode->num != num) { -+ dbg_err("nnode num %d expected %d " -+ "parent num %d iip %d", cnode->num, num, -+ (nnode ? nnode->num : 0), cnode->iip); -+ return -EINVAL; -+ } -+ nn = (struct ubifs_nnode *)cnode; -+ while (iip < UBIFS_LPT_FANOUT) { -+ cn = nn->nbranch[iip].cnode; -+ if (cn) { -+ /* Go down */ -+ row += 1; -+ col <<= UBIFS_LPT_FANOUT_SHIFT; -+ col += iip; -+ iip = 0; -+ cnode = cn; -+ break; -+ } -+ /* Go right */ -+ iip += 1; -+ } -+ if (iip < UBIFS_LPT_FANOUT) -+ continue; -+ } else { -+ struct ubifs_pnode *pnode; -+ -+ /* cnode is a pnode */ -+ pnode = (struct ubifs_pnode *)cnode; -+ err = dbg_chk_pnode(c, pnode, col); -+ if (err) -+ return err; -+ } -+ /* Go up and to the right */ -+ row -= 1; -+ col >>= UBIFS_LPT_FANOUT_SHIFT; -+ iip = cnode->iip + 1; -+ cnode = (struct ubifs_cnode *)nnode; -+ } -+ return 0; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/lpt_commit.c linux-2.6.24.7/fs/ubifs/lpt_commit.c ---- linux-2.6.24.7.old/fs/ubifs/lpt_commit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/lpt_commit.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1639 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements commit-related functionality of the LEB properties -+ * subsystem. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/** -+ * first_dirty_cnode - find first dirty cnode. -+ * @c: UBIFS file-system description object -+ * @nnode: nnode at which to start -+ * -+ * This function returns the first dirty cnode or %NULL if there is not one. -+ */ -+static struct ubifs_cnode *first_dirty_cnode(struct ubifs_nnode *nnode) -+{ -+ ubifs_assert(nnode); -+ while (1) { -+ int i, cont = 0; -+ -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ struct ubifs_cnode *cnode; -+ -+ cnode = nnode->nbranch[i].cnode; -+ if (cnode && -+ test_bit(DIRTY_CNODE, &cnode->flags)) { -+ if (cnode->level == 0) -+ return cnode; -+ nnode = (struct ubifs_nnode *)cnode; -+ cont = 1; -+ break; -+ } -+ } -+ if (!cont) -+ return (struct ubifs_cnode *)nnode; -+ } -+} -+ -+/** -+ * next_dirty_cnode - find next dirty cnode. -+ * @cnode: cnode from which to begin searching -+ * -+ * This function returns the next dirty cnode or %NULL if there is not one. -+ */ -+static struct ubifs_cnode *next_dirty_cnode(struct ubifs_cnode *cnode) -+{ -+ struct ubifs_nnode *nnode; -+ int i; -+ -+ ubifs_assert(cnode); -+ nnode = cnode->parent; -+ if (!nnode) -+ return NULL; -+ for (i = cnode->iip + 1; i < UBIFS_LPT_FANOUT; i++) { -+ cnode = nnode->nbranch[i].cnode; -+ if (cnode && test_bit(DIRTY_CNODE, &cnode->flags)) { -+ if (cnode->level == 0) -+ return cnode; /* cnode is a pnode */ -+ /* cnode is a nnode */ -+ return first_dirty_cnode((struct ubifs_nnode *)cnode); -+ } -+ } -+ return (struct ubifs_cnode *)nnode; -+} -+ -+/** -+ * get_cnodes_to_commit - create list of dirty cnodes to commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns the number of cnodes to commit. -+ */ -+static int get_cnodes_to_commit(struct ubifs_info *c) -+{ -+ struct ubifs_cnode *cnode, *cnext; -+ int cnt = 0; -+ -+ if (!c->nroot) -+ return 0; -+ -+ if (!test_bit(DIRTY_CNODE, &c->nroot->flags)) -+ return 0; -+ -+ c->lpt_cnext = first_dirty_cnode(c->nroot); -+ cnode = c->lpt_cnext; -+ if (!cnode) -+ return 0; -+ cnt += 1; -+ while (1) { -+ ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags)); -+ __set_bit(COW_ZNODE, &cnode->flags); -+ cnext = next_dirty_cnode(cnode); -+ if (!cnext) { -+ cnode->cnext = c->lpt_cnext; -+ break; -+ } -+ cnode->cnext = cnext; -+ cnode = cnext; -+ cnt += 1; -+ } -+ dbg_cmt("committing %d cnodes", cnt); -+ dbg_lp("committing %d cnodes", cnt); -+ ubifs_assert(cnt == c->dirty_nn_cnt + c->dirty_pn_cnt); -+ return cnt; -+} -+ -+/** -+ * upd_ltab - update LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @free: amount of free space -+ * @dirty: amount of dirty space to add -+ */ -+static void upd_ltab(struct ubifs_info *c, int lnum, int free, int dirty) -+{ -+ dbg_lp("LEB %d free %d dirty %d to %d +%d", -+ lnum, c->ltab[lnum - c->lpt_first].free, -+ c->ltab[lnum - c->lpt_first].dirty, free, dirty); -+ ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last); -+ c->ltab[lnum - c->lpt_first].free = free; -+ c->ltab[lnum - c->lpt_first].dirty += dirty; -+} -+ -+/** -+ * alloc_lpt_leb - allocate an LPT LEB that is empty. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number is passed and returned here -+ * -+ * This function finds the next empty LEB in the ltab starting from @lnum. If a -+ * an empty LEB is found it is returned in @lnum and the function returns %0. -+ * Otherwise the function returns -ENOSPC. Note however, that LPT is designed -+ * never to run out of space. -+ */ -+static int alloc_lpt_leb(struct ubifs_info *c, int *lnum) -+{ -+ int i, n; -+ -+ n = *lnum - c->lpt_first + 1; -+ for (i = n; i < c->lpt_lebs; i++) { -+ if (c->ltab[i].tgc || c->ltab[i].cmt) -+ continue; -+ if (c->ltab[i].free == c->leb_size) { -+ c->ltab[i].cmt = 1; -+ *lnum = i + c->lpt_first; -+ return 0; -+ } -+ } -+ -+ for (i = 0; i < n; i++) { -+ if (c->ltab[i].tgc || c->ltab[i].cmt) -+ continue; -+ if (c->ltab[i].free == c->leb_size) { -+ c->ltab[i].cmt = 1; -+ *lnum = i + c->lpt_first; -+ return 0; -+ } -+ } -+ dbg_err("last LEB %d", *lnum); -+ dump_stack(); -+ return -ENOSPC; -+} -+ -+/** -+ * layout_cnodes - layout cnodes for commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int layout_cnodes(struct ubifs_info *c) -+{ -+ int lnum, offs, len, alen, done_lsave, done_ltab, err; -+ struct ubifs_cnode *cnode; -+ -+ cnode = c->lpt_cnext; -+ if (!cnode) -+ return 0; -+ lnum = c->nhead_lnum; -+ offs = c->nhead_offs; -+ /* Try to place lsave and ltab nicely */ -+ done_lsave = !c->big_lpt; -+ done_ltab = 0; -+ if (!done_lsave && offs + c->lsave_sz <= c->leb_size) { -+ done_lsave = 1; -+ c->lsave_lnum = lnum; -+ c->lsave_offs = offs; -+ offs += c->lsave_sz; -+ } -+ -+ if (offs + c->ltab_sz <= c->leb_size) { -+ done_ltab = 1; -+ c->ltab_lnum = lnum; -+ c->ltab_offs = offs; -+ offs += c->ltab_sz; -+ } -+ -+ do { -+ if (cnode->level) { -+ len = c->nnode_sz; -+ c->dirty_nn_cnt -= 1; -+ } else { -+ len = c->pnode_sz; -+ c->dirty_pn_cnt -= 1; -+ } -+ while (offs + len > c->leb_size) { -+ alen = ALIGN(offs, c->min_io_size); -+ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); -+ err = alloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ /* Try to place lsave and ltab nicely */ -+ if (!done_lsave) { -+ done_lsave = 1; -+ c->lsave_lnum = lnum; -+ c->lsave_offs = offs; -+ offs += c->lsave_sz; -+ continue; -+ } -+ if (!done_ltab) { -+ done_ltab = 1; -+ c->ltab_lnum = lnum; -+ c->ltab_offs = offs; -+ offs += c->ltab_sz; -+ continue; -+ } -+ break; -+ } -+ if (cnode->parent) { -+ cnode->parent->nbranch[cnode->iip].lnum = lnum; -+ cnode->parent->nbranch[cnode->iip].offs = offs; -+ } else { -+ c->lpt_lnum = lnum; -+ c->lpt_offs = offs; -+ } -+ offs += len; -+ cnode = cnode->cnext; -+ } while (cnode && cnode != c->lpt_cnext); -+ -+ /* Make sure to place LPT's save table */ -+ if (!done_lsave) { -+ if (offs + c->lsave_sz > c->leb_size) { -+ alen = ALIGN(offs, c->min_io_size); -+ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); -+ err = alloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ } -+ done_lsave = 1; -+ c->lsave_lnum = lnum; -+ c->lsave_offs = offs; -+ offs += c->lsave_sz; -+ } -+ -+ /* Make sure to place LPT's own lprops table */ -+ if (!done_ltab) { -+ if (offs + c->ltab_sz > c->leb_size) { -+ alen = ALIGN(offs, c->min_io_size); -+ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); -+ err = alloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ } -+ done_ltab = 1; -+ c->ltab_lnum = lnum; -+ c->ltab_offs = offs; -+ offs += c->ltab_sz; -+ } -+ -+ alen = ALIGN(offs, c->min_io_size); -+ upd_ltab(c, lnum, c->leb_size - alen, alen - offs); -+ return 0; -+} -+ -+/** -+ * realloc_lpt_leb - allocate an LPT LEB that is empty. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number is passed and returned here -+ * -+ * This function duplicates exactly the results of the function alloc_lpt_leb. -+ * It is used during end commit to reallocate the same LEB numbers that were -+ * allocated by alloc_lpt_leb during start commit. -+ * -+ * This function finds the next LEB that was allocated by the alloc_lpt_leb -+ * function starting from @lnum. If a LEB is found it is returned in @lnum and -+ * the function returns %0. Otherwise the function returns -ENOSPC. -+ * Note however, that LPT is designed never to run out of space. -+ */ -+static int realloc_lpt_leb(struct ubifs_info *c, int *lnum) -+{ -+ int i, n; -+ -+ n = *lnum - c->lpt_first + 1; -+ for (i = n; i < c->lpt_lebs; i++) -+ if (c->ltab[i].cmt) { -+ c->ltab[i].cmt = 0; -+ *lnum = i + c->lpt_first; -+ return 0; -+ } -+ -+ for (i = 0; i < n; i++) -+ if (c->ltab[i].cmt) { -+ c->ltab[i].cmt = 0; -+ *lnum = i + c->lpt_first; -+ return 0; -+ } -+ dbg_err("last LEB %d", *lnum); -+ dump_stack(); -+ return -ENOSPC; -+} -+ -+/** -+ * write_cnodes - write cnodes for commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int write_cnodes(struct ubifs_info *c) -+{ -+ int lnum, offs, len, from, err, wlen, alen, done_ltab, done_lsave; -+ struct ubifs_cnode *cnode; -+ void *buf = c->lpt_buf; -+ -+ cnode = c->lpt_cnext; -+ if (!cnode) -+ return 0; -+ lnum = c->nhead_lnum; -+ offs = c->nhead_offs; -+ from = offs; -+ /* Ensure empty LEB is unmapped */ -+ if (offs == 0) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ /* Try to place lsave and ltab nicely */ -+ done_lsave = !c->big_lpt; -+ done_ltab = 0; -+ if (!done_lsave && offs + c->lsave_sz <= c->leb_size) { -+ done_lsave = 1; -+ ubifs_pack_lsave(c, buf + offs, c->lsave); -+ offs += c->lsave_sz; -+ } -+ -+ if (offs + c->ltab_sz <= c->leb_size) { -+ done_ltab = 1; -+ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); -+ offs += c->ltab_sz; -+ } -+ -+ /* Loop for each cnode */ -+ do { -+ if (cnode->level) -+ len = c->nnode_sz; -+ else -+ len = c->pnode_sz; -+ while (offs + len > c->leb_size) { -+ wlen = offs - from; -+ if (wlen) { -+ alen = ALIGN(wlen, c->min_io_size); -+ memset(buf + offs, 0xff, alen - wlen); -+ err = ubifs_leb_write(c, lnum, buf + from, from, -+ alen, UBI_SHORTTERM); -+ if (err) -+ return err; -+ } -+ err = realloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ from = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ /* Try to place lsave and ltab nicely */ -+ if (!done_lsave) { -+ done_lsave = 1; -+ ubifs_pack_lsave(c, buf + offs, c->lsave); -+ offs += c->lsave_sz; -+ continue; -+ } -+ if (!done_ltab) { -+ done_ltab = 1; -+ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); -+ offs += c->ltab_sz; -+ continue; -+ } -+ break; -+ } -+ if (cnode->level) -+ ubifs_pack_nnode(c, buf + offs, -+ (struct ubifs_nnode *)cnode); -+ else -+ ubifs_pack_pnode(c, buf + offs, -+ (struct ubifs_pnode *)cnode); -+ /* -+ * The reason for the barriers is the same as in case of TNC. -+ * See comment in 'write_index()'. 'dirty_cow_nnode()' and -+ * 'dirty_cow_pnode()' are the functions for which this is -+ * important. -+ */ -+ clear_bit(DIRTY_CNODE, &cnode->flags); -+ smp_mb__before_clear_bit(); -+ clear_bit(COW_ZNODE, &cnode->flags); -+ smp_mb__after_clear_bit(); -+ offs += len; -+ cnode = cnode->cnext; -+ } while (cnode && cnode != c->lpt_cnext); -+ -+ /* Make sure to place LPT's save table */ -+ if (!done_lsave) { -+ if (offs + c->lsave_sz > c->leb_size) { -+ wlen = offs - from; -+ alen = ALIGN(wlen, c->min_io_size); -+ memset(buf + offs, 0xff, alen - wlen); -+ err = ubifs_leb_write(c, lnum, buf + from, from, alen, -+ UBI_SHORTTERM); -+ if (err) -+ return err; -+ err = realloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ done_lsave = 1; -+ ubifs_pack_lsave(c, buf + offs, c->lsave); -+ offs += c->lsave_sz; -+ } -+ -+ /* Make sure to place LPT's own lprops table */ -+ if (!done_ltab) { -+ if (offs + c->ltab_sz > c->leb_size) { -+ wlen = offs - from; -+ alen = ALIGN(wlen, c->min_io_size); -+ memset(buf + offs, 0xff, alen - wlen); -+ err = ubifs_leb_write(c, lnum, buf + from, from, alen, -+ UBI_SHORTTERM); -+ if (err) -+ return err; -+ err = realloc_lpt_leb(c, &lnum); -+ if (err) -+ return err; -+ offs = 0; -+ ubifs_assert(lnum >= c->lpt_first && -+ lnum <= c->lpt_last); -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ done_ltab = 1; -+ ubifs_pack_ltab(c, buf + offs, c->ltab_cmt); -+ offs += c->ltab_sz; -+ } -+ -+ /* Write remaining data in buffer */ -+ wlen = offs - from; -+ alen = ALIGN(wlen, c->min_io_size); -+ memset(buf + offs, 0xff, alen - wlen); -+ err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM); -+ if (err) -+ return err; -+ c->nhead_lnum = lnum; -+ c->nhead_offs = ALIGN(offs, c->min_io_size); -+ -+ dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); -+ dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); -+ dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); -+ if (c->big_lpt) -+ dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); -+ return 0; -+} -+ -+/** -+ * next_pnode - find next pnode. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode -+ * -+ * This function returns the next pnode or %NULL if there are no more pnodes. -+ */ -+static struct ubifs_pnode *next_pnode(struct ubifs_info *c, -+ struct ubifs_pnode *pnode) -+{ -+ struct ubifs_nnode *nnode; -+ int iip; -+ -+ /* Try to go right */ -+ nnode = pnode->parent; -+ iip = pnode->iip + 1; -+ if (iip < UBIFS_LPT_FANOUT) { -+ /* We assume here that LEB zero is never an LPT LEB */ -+ if (nnode->nbranch[iip].lnum) -+ return ubifs_get_pnode(c, nnode, iip); -+ else -+ return NULL; -+ } -+ -+ /* Go up while can't go right */ -+ do { -+ iip = nnode->iip + 1; -+ nnode = nnode->parent; -+ if (!nnode) -+ return NULL; -+ /* We assume here that LEB zero is never an LPT LEB */ -+ } while (iip >= UBIFS_LPT_FANOUT || !nnode->nbranch[iip].lnum); -+ -+ /* Go right */ -+ nnode = ubifs_get_nnode(c, nnode, iip); -+ if (IS_ERR(nnode)) -+ return (void *)nnode; -+ -+ /* Go down to level 1 */ -+ while (nnode->level > 1) { -+ nnode = ubifs_get_nnode(c, nnode, 0); -+ if (IS_ERR(nnode)) -+ return (void *)nnode; -+ } -+ -+ return ubifs_get_pnode(c, nnode, 0); -+} -+ -+/** -+ * pnode_lookup - lookup a pnode in the LPT. -+ * @c: UBIFS file-system description object -+ * @i: pnode number (0 to main_lebs - 1) -+ * -+ * This function returns a pointer to the pnode on success or a negative -+ * error code on failure. -+ */ -+static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i) -+{ -+ int err, h, iip, shft; -+ struct ubifs_nnode *nnode; -+ -+ if (!c->nroot) { -+ err = ubifs_read_nnode(c, NULL, 0); -+ if (err) -+ return ERR_PTR(err); -+ } -+ i <<= UBIFS_LPT_FANOUT_SHIFT; -+ nnode = c->nroot; -+ shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; -+ for (h = 1; h < c->lpt_hght; h++) { -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ shft -= UBIFS_LPT_FANOUT_SHIFT; -+ nnode = ubifs_get_nnode(c, nnode, iip); -+ if (IS_ERR(nnode)) -+ return ERR_PTR(PTR_ERR(nnode)); -+ } -+ iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); -+ return ubifs_get_pnode(c, nnode, iip); -+} -+ -+/** -+ * add_pnode_dirt - add dirty space to LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode for which to add dirt -+ */ -+static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode) -+{ -+ ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum, -+ c->pnode_sz); -+} -+ -+/** -+ * do_make_pnode_dirty - mark a pnode dirty. -+ * @c: UBIFS file-system description object -+ * @pnode: pnode to mark dirty -+ */ -+static void do_make_pnode_dirty(struct ubifs_info *c, struct ubifs_pnode *pnode) -+{ -+ /* Assumes cnext list is empty i.e. not called during commit */ -+ if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) { -+ struct ubifs_nnode *nnode; -+ -+ c->dirty_pn_cnt += 1; -+ add_pnode_dirt(c, pnode); -+ /* Mark parent and ancestors dirty too */ -+ nnode = pnode->parent; -+ while (nnode) { -+ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { -+ c->dirty_nn_cnt += 1; -+ ubifs_add_nnode_dirt(c, nnode); -+ nnode = nnode->parent; -+ } else -+ break; -+ } -+ } -+} -+ -+/** -+ * make_tree_dirty - mark the entire LEB properties tree dirty. -+ * @c: UBIFS file-system description object -+ * -+ * This function is used by the "small" LPT model to cause the entire LEB -+ * properties tree to be written. The "small" LPT model does not use LPT -+ * garbage collection because it is more efficient to write the entire tree -+ * (because it is small). -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_tree_dirty(struct ubifs_info *c) -+{ -+ struct ubifs_pnode *pnode; -+ -+ pnode = pnode_lookup(c, 0); -+ while (pnode) { -+ do_make_pnode_dirty(c, pnode); -+ pnode = next_pnode(c, pnode); -+ if (IS_ERR(pnode)) -+ return PTR_ERR(pnode); -+ } -+ return 0; -+} -+ -+/** -+ * need_write_all - determine if the LPT area is running out of free space. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %1 if the LPT area is running out of free space and %0 -+ * if it is not. -+ */ -+static int need_write_all(struct ubifs_info *c) -+{ -+ long long free = 0; -+ int i; -+ -+ for (i = 0; i < c->lpt_lebs; i++) { -+ if (i + c->lpt_first == c->nhead_lnum) -+ free += c->leb_size - c->nhead_offs; -+ else if (c->ltab[i].free == c->leb_size) -+ free += c->leb_size; -+ else if (c->ltab[i].free + c->ltab[i].dirty == c->leb_size) -+ free += c->leb_size; -+ } -+ /* Less than twice the size left */ -+ if (free <= c->lpt_sz * 2) -+ return 1; -+ return 0; -+} -+ -+/** -+ * lpt_tgc_start - start trivial garbage collection of LPT LEBs. -+ * @c: UBIFS file-system description object -+ * -+ * LPT trivial garbage collection is where a LPT LEB contains only dirty and -+ * free space and so may be reused as soon as the next commit is completed. -+ * This function is called during start commit to mark LPT LEBs for trivial GC. -+ */ -+static void lpt_tgc_start(struct ubifs_info *c) -+{ -+ int i; -+ -+ for (i = 0; i < c->lpt_lebs; i++) { -+ if (i + c->lpt_first == c->nhead_lnum) -+ continue; -+ if (c->ltab[i].dirty > 0 && -+ c->ltab[i].free + c->ltab[i].dirty == c->leb_size) { -+ c->ltab[i].tgc = 1; -+ c->ltab[i].free = c->leb_size; -+ c->ltab[i].dirty = 0; -+ dbg_lp("LEB %d", i + c->lpt_first); -+ } -+ } -+} -+ -+/** -+ * lpt_tgc_end - end trivial garbage collection of LPT LEBs. -+ * @c: UBIFS file-system description object -+ * -+ * LPT trivial garbage collection is where a LPT LEB contains only dirty and -+ * free space and so may be reused as soon as the next commit is completed. -+ * This function is called after the commit is completed (master node has been -+ * written) and unmaps LPT LEBs that were marked for trivial GC. -+ */ -+static int lpt_tgc_end(struct ubifs_info *c) -+{ -+ int i, err; -+ -+ for (i = 0; i < c->lpt_lebs; i++) -+ if (c->ltab[i].tgc) { -+ err = ubifs_leb_unmap(c, i + c->lpt_first); -+ if (err) -+ return err; -+ c->ltab[i].tgc = 0; -+ dbg_lp("LEB %d", i + c->lpt_first); -+ } -+ return 0; -+} -+ -+/** -+ * populate_lsave - fill the lsave array with important LEB numbers. -+ * @c: the UBIFS file-system description object -+ * -+ * This function is only called for the "big" model. It records a small number -+ * of LEB numbers of important LEBs. Important LEBs are ones that are (from -+ * most important to least important): empty, freeable, freeable index, dirty -+ * index, dirty or free. Upon mount, we read this list of LEB numbers and bring -+ * their pnodes into memory. That will stop us from having to scan the LPT -+ * straight away. For the "small" model we assume that scanning the LPT is no -+ * big deal. -+ */ -+static void populate_lsave(struct ubifs_info *c) -+{ -+ struct ubifs_lprops *lprops; -+ struct ubifs_lpt_heap *heap; -+ int i, cnt = 0; -+ -+ ubifs_assert(c->big_lpt); -+ if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) { -+ c->lpt_drty_flgs |= LSAVE_DIRTY; -+ ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz); -+ } -+ list_for_each_entry(lprops, &c->empty_list, list) { -+ c->lsave[cnt++] = lprops->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ list_for_each_entry(lprops, &c->freeable_list, list) { -+ c->lsave[cnt++] = lprops->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ list_for_each_entry(lprops, &c->frdi_idx_list, list) { -+ c->lsave[cnt++] = lprops->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ c->lsave[cnt++] = heap->arr[i]->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ heap = &c->lpt_heap[LPROPS_DIRTY - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ c->lsave[cnt++] = heap->arr[i]->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ heap = &c->lpt_heap[LPROPS_FREE - 1]; -+ for (i = 0; i < heap->cnt; i++) { -+ c->lsave[cnt++] = heap->arr[i]->lnum; -+ if (cnt >= c->lsave_cnt) -+ return; -+ } -+ /* Fill it up completely */ -+ while (cnt < c->lsave_cnt) -+ c->lsave[cnt++] = c->main_first; -+} -+ -+/** -+ * ubifs_lpt_start_commit - UBIFS commit starts. -+ * @c: the UBIFS file-system description object -+ * -+ * This function has to be called when UBIFS starts the commit operation. -+ * This function "freezes" all currently dirty LEB properties and does not -+ * change them anymore. Further changes are saved and tracked separately -+ * because they are not part of this commit. This function returns zero in case -+ * of success and a negative error code in case of failure. -+ */ -+int ubifs_lpt_start_commit(struct ubifs_info *c) -+{ -+ int err, cnt; -+ -+ dbg_lp(""); -+ -+ mutex_lock(&c->lp_mutex); -+ err = dbg_check_ltab(c); -+ if (err) -+ goto out; -+ -+ lpt_tgc_start(c); -+ -+ if (!c->dirty_pn_cnt) { -+ dbg_cmt("no cnodes to commit"); -+ err = 0; -+ goto out; -+ } -+ -+ if (!c->big_lpt && need_write_all(c)) { -+ /* If needed, write everything */ -+ err = make_tree_dirty(c); -+ if (err) -+ goto out; -+ lpt_tgc_start(c); -+ } -+ -+ if (c->big_lpt) -+ populate_lsave(c); -+ -+ cnt = get_cnodes_to_commit(c); -+ ubifs_assert(cnt != 0); -+ -+ err = layout_cnodes(c); -+ if (err) -+ goto out; -+ -+ /* Copy the LPT's own lprops for end commit to write */ -+ memcpy(c->ltab_cmt, c->ltab, -+ sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); -+ c->lpt_drty_flgs &= ~(LTAB_DIRTY | LSAVE_DIRTY); -+ -+out: -+ mutex_unlock(&c->lp_mutex); -+ return err; -+} -+ -+/** -+ * free_obsolete_cnodes - free obsolete cnodes for commit end. -+ * @c: UBIFS file-system description object -+ */ -+static void free_obsolete_cnodes(struct ubifs_info *c) -+{ -+ struct ubifs_cnode *cnode, *cnext; -+ -+ cnext = c->lpt_cnext; -+ if (!cnext) -+ return; -+ do { -+ cnode = cnext; -+ cnext = cnode->cnext; -+ if (test_bit(OBSOLETE_CNODE, &cnode->flags)) -+ kfree(cnode); -+ else -+ cnode->cnext = NULL; -+ } while (cnext != c->lpt_cnext); -+ c->lpt_cnext = NULL; -+} -+ -+/** -+ * ubifs_lpt_end_commit - finish the commit operation. -+ * @c: the UBIFS file-system description object -+ * -+ * This function has to be called when the commit operation finishes. It -+ * flushes the changes which were "frozen" by 'ubifs_lprops_start_commit()' to -+ * the media. Returns zero in case of success and a negative error code in case -+ * of failure. -+ */ -+int ubifs_lpt_end_commit(struct ubifs_info *c) -+{ -+ int err; -+ -+ dbg_lp(""); -+ -+ if (!c->lpt_cnext) -+ return 0; -+ -+ err = write_cnodes(c); -+ if (err) -+ return err; -+ -+ mutex_lock(&c->lp_mutex); -+ free_obsolete_cnodes(c); -+ mutex_unlock(&c->lp_mutex); -+ -+ return 0; -+} -+ -+/** -+ * nnode_lookup - lookup a nnode in the LPT. -+ * @c: UBIFS file-system description object -+ * @i: nnode number -+ * -+ * This function returns a pointer to the nnode on success or a negative -+ * error code on failure. -+ */ -+static struct ubifs_nnode *nnode_lookup(struct ubifs_info *c, int i) -+{ -+ int err, iip; -+ struct ubifs_nnode *nnode; -+ -+ if (!c->nroot) { -+ err = ubifs_read_nnode(c, NULL, 0); -+ if (err) -+ return ERR_PTR(err); -+ } -+ nnode = c->nroot; -+ while (1) { -+ iip = i & (UBIFS_LPT_FANOUT - 1); -+ i >>= UBIFS_LPT_FANOUT_SHIFT; -+ if (!i) -+ break; -+ nnode = ubifs_get_nnode(c, nnode, iip); -+ if (IS_ERR(nnode)) -+ return nnode; -+ } -+ return nnode; -+} -+ -+/** -+ * make_nnode_dirty - find a nnode and, if found, make it dirty. -+ * @c: UBIFS file-system description object -+ * @node_num: nnode number of nnode to make dirty -+ * @lnum: LEB number where nnode was written -+ * @offs: offset where nnode was written -+ * -+ * This function is used by LPT garbage collection. LPT garbage collection is -+ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection -+ * simply involves marking all the nodes in the LEB being garbage-collected as -+ * dirty. The dirty nodes are written next commit, after which the LEB is free -+ * to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_nnode_dirty(struct ubifs_info *c, int node_num, int lnum, -+ int offs) -+{ -+ struct ubifs_nnode *nnode; -+ -+ nnode = nnode_lookup(c, node_num); -+ if (IS_ERR(nnode)) -+ return PTR_ERR(nnode); -+ if (nnode->parent) { -+ struct ubifs_nbranch *branch; -+ -+ branch = &nnode->parent->nbranch[nnode->iip]; -+ if (branch->lnum != lnum || branch->offs != offs) -+ return 0; /* nnode is obsolete */ -+ } else if (c->lpt_lnum != lnum || c->lpt_offs != offs) -+ return 0; /* nnode is obsolete */ -+ /* Assumes cnext list is empty i.e. not called during commit */ -+ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { -+ c->dirty_nn_cnt += 1; -+ ubifs_add_nnode_dirt(c, nnode); -+ /* Mark parent and ancestors dirty too */ -+ nnode = nnode->parent; -+ while (nnode) { -+ if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) { -+ c->dirty_nn_cnt += 1; -+ ubifs_add_nnode_dirt(c, nnode); -+ nnode = nnode->parent; -+ } else -+ break; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * make_pnode_dirty - find a pnode and, if found, make it dirty. -+ * @c: UBIFS file-system description object -+ * @node_num: pnode number of pnode to make dirty -+ * @lnum: LEB number where pnode was written -+ * @offs: offset where pnode was written -+ * -+ * This function is used by LPT garbage collection. LPT garbage collection is -+ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection -+ * simply involves marking all the nodes in the LEB being garbage-collected as -+ * dirty. The dirty nodes are written next commit, after which the LEB is free -+ * to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum, -+ int offs) -+{ -+ struct ubifs_pnode *pnode; -+ struct ubifs_nbranch *branch; -+ -+ pnode = pnode_lookup(c, node_num); -+ if (IS_ERR(pnode)) -+ return PTR_ERR(pnode); -+ branch = &pnode->parent->nbranch[pnode->iip]; -+ if (branch->lnum != lnum || branch->offs != offs) -+ return 0; -+ do_make_pnode_dirty(c, pnode); -+ return 0; -+} -+ -+/** -+ * make_ltab_dirty - make ltab node dirty. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number where ltab was written -+ * @offs: offset where ltab was written -+ * -+ * This function is used by LPT garbage collection. LPT garbage collection is -+ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection -+ * simply involves marking all the nodes in the LEB being garbage-collected as -+ * dirty. The dirty nodes are written next commit, after which the LEB is free -+ * to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_ltab_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ if (lnum != c->ltab_lnum || offs != c->ltab_offs) -+ return 0; /* This ltab node is obsolete */ -+ if (!(c->lpt_drty_flgs & LTAB_DIRTY)) { -+ c->lpt_drty_flgs |= LTAB_DIRTY; -+ ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz); -+ } -+ return 0; -+} -+ -+/** -+ * make_lsave_dirty - make lsave node dirty. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number where lsave was written -+ * @offs: offset where lsave was written -+ * -+ * This function is used by LPT garbage collection. LPT garbage collection is -+ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection -+ * simply involves marking all the nodes in the LEB being garbage-collected as -+ * dirty. The dirty nodes are written next commit, after which the LEB is free -+ * to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_lsave_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ if (lnum != c->lsave_lnum || offs != c->lsave_offs) -+ return 0; /* This lsave node is obsolete */ -+ if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) { -+ c->lpt_drty_flgs |= LSAVE_DIRTY; -+ ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz); -+ } -+ return 0; -+} -+ -+/** -+ * make_node_dirty - make node dirty. -+ * @c: UBIFS file-system description object -+ * @node_type: LPT node type -+ * @node_num: node number -+ * @lnum: LEB number where node was written -+ * @offs: offset where node was written -+ * -+ * This function is used by LPT garbage collection. LPT garbage collection is -+ * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection -+ * simply involves marking all the nodes in the LEB being garbage-collected as -+ * dirty. The dirty nodes are written next commit, after which the LEB is free -+ * to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num, -+ int lnum, int offs) -+{ -+ switch (node_type) { -+ case UBIFS_LPT_NNODE: -+ return make_nnode_dirty(c, node_num, lnum, offs); -+ case UBIFS_LPT_PNODE: -+ return make_pnode_dirty(c, node_num, lnum, offs); -+ case UBIFS_LPT_LTAB: -+ return make_ltab_dirty(c, lnum, offs); -+ case UBIFS_LPT_LSAVE: -+ return make_lsave_dirty(c, lnum, offs); -+ } -+ return -EINVAL; -+} -+ -+/** -+ * get_lpt_node_len - return the length of a node based on its type. -+ * @c: UBIFS file-system description object -+ * @node_type: LPT node type -+ */ -+static int get_lpt_node_len(struct ubifs_info *c, int node_type) -+{ -+ switch (node_type) { -+ case UBIFS_LPT_NNODE: -+ return c->nnode_sz; -+ case UBIFS_LPT_PNODE: -+ return c->pnode_sz; -+ case UBIFS_LPT_LTAB: -+ return c->ltab_sz; -+ case UBIFS_LPT_LSAVE: -+ return c->lsave_sz; -+ } -+ return 0; -+} -+ -+/** -+ * get_pad_len - return the length of padding in a buffer. -+ * @c: UBIFS file-system description object -+ * @buf: buffer -+ * @len: length of buffer -+ */ -+static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len) -+{ -+ int offs, pad_len; -+ -+ if (c->min_io_size == 1) -+ return 0; -+ offs = c->leb_size - len; -+ pad_len = ALIGN(offs, c->min_io_size) - offs; -+ return pad_len; -+} -+ -+/** -+ * get_lpt_node_type - return type (and node number) of a node in a buffer. -+ * @c: UBIFS file-system description object -+ * @buf: buffer -+ * @node_num: node number is returned here -+ */ -+static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int pos = 0, node_type; -+ -+ node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); -+ *node_num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits); -+ return node_type; -+} -+ -+/** -+ * is_a_node - determine if a buffer contains a node. -+ * @c: UBIFS file-system description object -+ * @buf: buffer -+ * @len: length of buffer -+ * -+ * This function returns %1 if the buffer contains a node or %0 if it does not. -+ */ -+static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int pos = 0, node_type, node_len; -+ uint16_t crc, calc_crc; -+ -+ node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS); -+ if (node_type == UBIFS_LPT_NOT_A_NODE) -+ return 0; -+ node_len = get_lpt_node_len(c, node_type); -+ if (!node_len || node_len > len) -+ return 0; -+ pos = 0; -+ addr = buf; -+ crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS); -+ calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ node_len - UBIFS_LPT_CRC_BYTES); -+ if (crc != calc_crc) -+ return 0; -+ return 1; -+} -+ -+ -+/** -+ * lpt_gc_lnum - garbage collect a LPT LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to garbage collect -+ * -+ * LPT garbage collection is used only for the "big" LPT model -+ * (c->big_lpt == 1). Garbage collection simply involves marking all the nodes -+ * in the LEB being garbage-collected as dirty. The dirty nodes are written -+ * next commit, after which the LEB is free to be reused. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int lpt_gc_lnum(struct ubifs_info *c, int lnum) -+{ -+ int err, len = c->leb_size, node_type, node_num, node_len, offs; -+ void *buf = c->lpt_buf; -+ -+ dbg_lp("LEB %d", lnum); -+ err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); -+ if (err) { -+ ubifs_err("cannot read LEB %d, error %d", lnum, err); -+ return err; -+ } -+ while (1) { -+ if (!is_a_node(c, buf, len)) { -+ int pad_len; -+ -+ pad_len = get_pad_len(c, buf, len); -+ if (pad_len) { -+ buf += pad_len; -+ len -= pad_len; -+ continue; -+ } -+ return 0; -+ } -+ node_type = get_lpt_node_type(c, buf, &node_num); -+ node_len = get_lpt_node_len(c, node_type); -+ offs = c->leb_size - len; -+ ubifs_assert(node_len != 0); -+ mutex_lock(&c->lp_mutex); -+ err = make_node_dirty(c, node_type, node_num, lnum, offs); -+ mutex_unlock(&c->lp_mutex); -+ if (err) -+ return err; -+ buf += node_len; -+ len -= node_len; -+ } -+ return 0; -+} -+ -+/** -+ * lpt_gc - LPT garbage collection. -+ * @c: UBIFS file-system description object -+ * -+ * Select a LPT LEB for LPT garbage collection and call 'lpt_gc_lnum()'. -+ * Returns %0 on success and a negative error code on failure. -+ */ -+static int lpt_gc(struct ubifs_info *c) -+{ -+ int i, lnum = -1, dirty = 0; -+ -+ mutex_lock(&c->lp_mutex); -+ for (i = 0; i < c->lpt_lebs; i++) { -+ ubifs_assert(!c->ltab[i].tgc); -+ if (i + c->lpt_first == c->nhead_lnum || -+ c->ltab[i].free + c->ltab[i].dirty == c->leb_size) -+ continue; -+ if (c->ltab[i].dirty > dirty) { -+ dirty = c->ltab[i].dirty; -+ lnum = i + c->lpt_first; -+ } -+ } -+ mutex_unlock(&c->lp_mutex); -+ if (lnum == -1) -+ return -ENOSPC; -+ return lpt_gc_lnum(c, lnum); -+} -+ -+/** -+ * ubifs_lpt_post_commit - post commit LPT trivial GC and LPT GC. -+ * @c: UBIFS file-system description object -+ * -+ * LPT trivial GC is completed after a commit. Also LPT GC is done after a -+ * commit for the "big" LPT model. -+ */ -+int ubifs_lpt_post_commit(struct ubifs_info *c) -+{ -+ int err; -+ -+ mutex_lock(&c->lp_mutex); -+ err = lpt_tgc_end(c); -+ if (err) -+ goto out; -+ if (c->big_lpt) -+ while (need_write_all(c)) { -+ mutex_unlock(&c->lp_mutex); -+ err = lpt_gc(c); -+ if (err) -+ return err; -+ mutex_lock(&c->lp_mutex); -+ } -+out: -+ mutex_unlock(&c->lp_mutex); -+ return err; -+} -+ -+/** -+ * first_nnode - find the first nnode in memory. -+ * @c: UBIFS file-system description object -+ * @hght: height of tree where nnode found is returned here -+ * -+ * This function returns a pointer to the nnode found or %NULL if no nnode is -+ * found. This function is a helper to 'ubifs_lpt_free()'. -+ */ -+static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght) -+{ -+ struct ubifs_nnode *nnode; -+ int h, i, found; -+ -+ nnode = c->nroot; -+ *hght = 0; -+ if (!nnode) -+ return NULL; -+ for (h = 1; h < c->lpt_hght; h++) { -+ found = 0; -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ if (nnode->nbranch[i].nnode) { -+ found = 1; -+ nnode = nnode->nbranch[i].nnode; -+ *hght = h; -+ break; -+ } -+ } -+ if (!found) -+ break; -+ } -+ return nnode; -+} -+ -+/** -+ * next_nnode - find the next nnode in memory. -+ * @c: UBIFS file-system description object -+ * @nnode: nnode from which to start. -+ * @hght: height of tree where nnode is, is passed and returned here -+ * -+ * This function returns a pointer to the nnode found or %NULL if no nnode is -+ * found. This function is a helper to 'ubifs_lpt_free()'. -+ */ -+static struct ubifs_nnode *next_nnode(struct ubifs_info *c, -+ struct ubifs_nnode *nnode, int *hght) -+{ -+ struct ubifs_nnode *parent; -+ int iip, h, i, found; -+ -+ parent = nnode->parent; -+ if (!parent) -+ return NULL; -+ if (nnode->iip == UBIFS_LPT_FANOUT - 1) { -+ *hght -= 1; -+ return parent; -+ } -+ for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) { -+ nnode = parent->nbranch[iip].nnode; -+ if (nnode) -+ break; -+ } -+ if (!nnode) { -+ *hght -= 1; -+ return parent; -+ } -+ for (h = *hght + 1; h < c->lpt_hght; h++) { -+ found = 0; -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ if (nnode->nbranch[i].nnode) { -+ found = 1; -+ nnode = nnode->nbranch[i].nnode; -+ *hght = h; -+ break; -+ } -+ } -+ if (!found) -+ break; -+ } -+ return nnode; -+} -+ -+/** -+ * ubifs_lpt_free - free resources owned by the LPT. -+ * @c: UBIFS file-system description object -+ * @wr_only: free only resources used for writing -+ */ -+void ubifs_lpt_free(struct ubifs_info *c, int wr_only) -+{ -+ struct ubifs_nnode *nnode; -+ int i, hght; -+ -+ /* Free write-only things first */ -+ -+ free_obsolete_cnodes(c); /* Leftover from a failed commit */ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ltab_cmt); -+ kfree(c->lpt_buf); -+#else -+ vfree(c->ltab_cmt); -+ vfree(c->lpt_buf); -+#endif -+ c->ltab_cmt = NULL; -+ c->lpt_buf = NULL; -+ kfree(c->lsave); -+ c->lsave = NULL; -+ -+ if (wr_only) -+ return; -+ -+ /* Now free the rest */ -+ -+ nnode = first_nnode(c, &hght); -+ while (nnode) { -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) -+ kfree(nnode->nbranch[i].nnode); -+ nnode = next_nnode(c, nnode, &hght); -+ } -+ for (i = 0; i < LPROPS_HEAP_CNT; i++) -+ kfree(c->lpt_heap[i].arr); -+ kfree(c->dirty_idx.arr); -+ kfree(c->nroot); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ltab); -+#else -+ vfree(c->ltab); -+#endif -+ kfree(c->lpt_nod_buf); -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * dbg_is_all_ff - determine if a buffer contains only 0xff bytes. -+ * @buf: buffer -+ * @len: buffer length -+ */ -+static int dbg_is_all_ff(uint8_t *buf, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) -+ if (buf[i] != 0xff) -+ return 0; -+ return 1; -+} -+ -+/** -+ * dbg_is_nnode_dirty - determine if a nnode is dirty. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB number where nnode was written -+ * @offs: offset where nnode was written -+ */ -+static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ struct ubifs_nnode *nnode; -+ int hght; -+ -+ /* Entire tree is in memory so first_nnode / next_nnode are ok */ -+ nnode = first_nnode(c, &hght); -+ for (; nnode; nnode = next_nnode(c, nnode, &hght)) { -+ struct ubifs_nbranch *branch; -+ -+ cond_resched(); -+ if (nnode->parent) { -+ branch = &nnode->parent->nbranch[nnode->iip]; -+ if (branch->lnum != lnum || branch->offs != offs) -+ continue; -+ if (test_bit(DIRTY_CNODE, &nnode->flags)) -+ return 1; -+ return 0; -+ } else { -+ if (c->lpt_lnum != lnum || c->lpt_offs != offs) -+ continue; -+ if (test_bit(DIRTY_CNODE, &nnode->flags)) -+ return 1; -+ return 0; -+ } -+ } -+ return 1; -+} -+ -+/** -+ * dbg_is_pnode_dirty - determine if a pnode is dirty. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB number where pnode was written -+ * @offs: offset where pnode was written -+ */ -+static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ int i, cnt; -+ -+ cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); -+ for (i = 0; i < cnt; i++) { -+ struct ubifs_pnode *pnode; -+ struct ubifs_nbranch *branch; -+ -+ cond_resched(); -+ pnode = pnode_lookup(c, i); -+ if (IS_ERR(pnode)) -+ return PTR_ERR(pnode); -+ branch = &pnode->parent->nbranch[pnode->iip]; -+ if (branch->lnum != lnum || branch->offs != offs) -+ continue; -+ if (test_bit(DIRTY_CNODE, &pnode->flags)) -+ return 1; -+ return 0; -+ } -+ return 1; -+} -+ -+/** -+ * dbg_is_ltab_dirty - determine if a ltab node is dirty. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB number where ltab node was written -+ * @offs: offset where ltab node was written -+ */ -+static int dbg_is_ltab_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ if (lnum != c->ltab_lnum || offs != c->ltab_offs) -+ return 1; -+ return (c->lpt_drty_flgs & LTAB_DIRTY) != 0; -+} -+ -+/** -+ * dbg_is_lsave_dirty - determine if a lsave node is dirty. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB number where lsave node was written -+ * @offs: offset where lsave node was written -+ */ -+static int dbg_is_lsave_dirty(struct ubifs_info *c, int lnum, int offs) -+{ -+ if (lnum != c->lsave_lnum || offs != c->lsave_offs) -+ return 1; -+ return (c->lpt_drty_flgs & LSAVE_DIRTY) != 0; -+} -+ -+/** -+ * dbg_is_node_dirty - determine if a node is dirty. -+ * @c: the UBIFS file-system description object -+ * @node_type: node type -+ * @lnum: LEB number where node was written -+ * @offs: offset where node was written -+ */ -+static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum, -+ int offs) -+{ -+ switch (node_type) { -+ case UBIFS_LPT_NNODE: -+ return dbg_is_nnode_dirty(c, lnum, offs); -+ case UBIFS_LPT_PNODE: -+ return dbg_is_pnode_dirty(c, lnum, offs); -+ case UBIFS_LPT_LTAB: -+ return dbg_is_ltab_dirty(c, lnum, offs); -+ case UBIFS_LPT_LSAVE: -+ return dbg_is_lsave_dirty(c, lnum, offs); -+ } -+ return 1; -+} -+ -+/** -+ * dbg_check_ltab_lnum - check the ltab for a LPT LEB number. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB number where node was written -+ * @offs: offset where node was written -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) -+{ -+ int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; -+ int ret; -+ void *buf = c->dbg_buf; -+ -+ dbg_lp("LEB %d", lnum); -+ err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); -+ if (err) { -+ dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err); -+ return err; -+ } -+ while (1) { -+ if (!is_a_node(c, buf, len)) { -+ int i, pad_len; -+ -+ pad_len = get_pad_len(c, buf, len); -+ if (pad_len) { -+ buf += pad_len; -+ len -= pad_len; -+ dirty += pad_len; -+ continue; -+ } -+ if (!dbg_is_all_ff(buf, len)) { -+ dbg_msg("invalid empty space in LEB %d at %d", -+ lnum, c->leb_size - len); -+ err = -EINVAL; -+ } -+ i = lnum - c->lpt_first; -+ if (len != c->ltab[i].free) { -+ dbg_msg("invalid free space in LEB %d " -+ "(free %d, expected %d)", -+ lnum, len, c->ltab[i].free); -+ err = -EINVAL; -+ } -+ if (dirty != c->ltab[i].dirty) { -+ dbg_msg("invalid dirty space in LEB %d " -+ "(dirty %d, expected %d)", -+ lnum, dirty, c->ltab[i].dirty); -+ err = -EINVAL; -+ } -+ return err; -+ } -+ node_type = get_lpt_node_type(c, buf, &node_num); -+ node_len = get_lpt_node_len(c, node_type); -+ ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len); -+ if (ret == 1) -+ dirty += node_len; -+ buf += node_len; -+ len -= node_len; -+ } -+} -+ -+/** -+ * dbg_check_ltab - check the free and dirty space in the ltab. -+ * @c: the UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int dbg_check_ltab(struct ubifs_info *c) -+{ -+ int lnum, err, i, cnt; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) -+ return 0; -+ -+ /* Bring the entire tree into memory */ -+ cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT); -+ for (i = 0; i < cnt; i++) { -+ struct ubifs_pnode *pnode; -+ -+ pnode = pnode_lookup(c, i); -+ if (IS_ERR(pnode)) -+ return PTR_ERR(pnode); -+ cond_resched(); -+ } -+ -+ /* Check nodes */ -+ err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)c->nroot, 0, 0); -+ if (err) -+ return err; -+ -+ /* Check each LEB */ -+ for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) { -+ err = dbg_check_ltab_lnum(c, lnum); -+ if (err) { -+ dbg_err("failed at LEB %d", lnum); -+ return err; -+ } -+ } -+ -+ dbg_lp("succeeded"); -+ return 0; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/master.c linux-2.6.24.7/fs/ubifs/master.c ---- linux-2.6.24.7.old/fs/ubifs/master.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/master.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,387 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* This file implements reading and writing the master node */ -+ -+#include "ubifs.h" -+ -+/** -+ * scan_for_master - search the valid master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function scans the master node LEBs and search for the latest master -+ * node. Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int scan_for_master(struct ubifs_info *c) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ int lnum, offs = 0, nodes_cnt; -+ -+ lnum = UBIFS_MST_LNUM; -+ -+ sleb = ubifs_scan(c, lnum, 0, c->sbuf); -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ nodes_cnt = sleb->nodes_cnt; -+ if (nodes_cnt > 0) { -+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, -+ list); -+ if (snod->type != UBIFS_MST_NODE) -+ goto out; -+ memcpy(c->mst_node, snod->node, snod->len); -+ offs = snod->offs; -+ } -+ ubifs_scan_destroy(sleb); -+ -+ lnum += 1; -+ -+ sleb = ubifs_scan(c, lnum, 0, c->sbuf); -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ if (sleb->nodes_cnt != nodes_cnt) -+ goto out; -+ if (!sleb->nodes_cnt) -+ goto out; -+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list); -+ if (snod->type != UBIFS_MST_NODE) -+ goto out; -+ if (snod->offs != offs) -+ goto out; -+ if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, -+ (void *)snod->node + UBIFS_CH_SZ, -+ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) -+ goto out; -+ c->mst_offs = offs; -+ ubifs_scan_destroy(sleb); -+ return 0; -+ -+out: -+ ubifs_scan_destroy(sleb); -+ return -EINVAL; -+} -+ -+/** -+ * validate_master - validate master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function validates data which was read from master node. Returns zero -+ * if the data is all right and %-EINVAL if not. -+ */ -+static int validate_master(const struct ubifs_info *c) -+{ -+ unsigned long long main_sz; -+ int err; -+ -+ if (c->max_sqnum >= SQNUM_WATERMARK) { -+ err = 1; -+ goto out; -+ } -+ -+ if (c->cmt_no >= c->max_sqnum) { -+ err = 2; -+ goto out; -+ } -+ -+ if (c->highest_inum >= INUM_WATERMARK) { -+ err = 3; -+ goto out; -+ } -+ -+ if (c->lhead_lnum < UBIFS_LOG_LNUM || -+ c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs || -+ c->lhead_offs < 0 || c->lhead_offs >= c->leb_size || -+ c->lhead_offs & (c->min_io_size - 1)) { -+ err = 4; -+ goto out; -+ } -+ -+ if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first || -+ c->zroot.offs >= c->leb_size || c->zroot.offs & 7) { -+ err = 5; -+ goto out; -+ } -+ -+ if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len || -+ c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) { -+ err = 6; -+ goto out; -+ } -+ -+ if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) { -+ err = 7; -+ goto out; -+ } -+ -+ if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first || -+ c->ihead_offs % c->min_io_size || c->ihead_offs < 0 || -+ c->ihead_offs > c->leb_size || c->ihead_offs & 7) { -+ err = 8; -+ goto out; -+ } -+ -+ main_sz = c->main_lebs * (unsigned long long)c->leb_size; -+ if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) { -+ err = 9; -+ goto out; -+ } -+ -+ if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last || -+ c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) { -+ err = 10; -+ goto out; -+ } -+ -+ if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last || -+ c->nhead_offs < 0 || c->nhead_offs % c->min_io_size || -+ c->nhead_offs > c->leb_size) { -+ err = 11; -+ goto out; -+ } -+ -+ if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last || -+ c->ltab_offs < 0 || -+ c->ltab_offs + c->ltab_sz > c->leb_size) { -+ err = 12; -+ goto out; -+ } -+ -+ if (c->big_lpt && (c->lsave_lnum < c->lpt_first || -+ c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 || -+ c->lsave_offs + c->lsave_sz > c->leb_size)) { -+ err = 13; -+ goto out; -+ } -+ -+ if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) { -+ err = 14; -+ goto out; -+ } -+ -+ if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) { -+ err = 15; -+ goto out; -+ } -+ -+ if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) { -+ err = 16; -+ goto out; -+ } -+ -+ if (c->lst.total_free < 0 || c->lst.total_free > main_sz || -+ c->lst.total_free & 7) { -+ err = 17; -+ goto out; -+ } -+ -+ if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) { -+ err = 18; -+ goto out; -+ } -+ -+ if (c->lst.total_used < 0 || (c->lst.total_used & 7)) { -+ err = 19; -+ goto out; -+ } -+ -+ if (c->lst.total_free + c->lst.total_dirty + -+ c->lst.total_used > main_sz) { -+ err = 20; -+ goto out; -+ } -+ -+ if (c->lst.total_dead + c->lst.total_dark + -+ c->lst.total_used + c->old_idx_sz > main_sz) { -+ err = 21; -+ goto out; -+ } -+ -+ if (c->lst.total_dead < 0 || -+ c->lst.total_dead > c->lst.total_free + c->lst.total_dirty || -+ c->lst.total_dead & 7) { -+ err = 22; -+ goto out; -+ } -+ -+ if (c->lst.total_dark < 0 || -+ c->lst.total_dark > c->lst.total_free + c->lst.total_dirty || -+ c->lst.total_dark & 7) { -+ err = 23; -+ goto out; -+ } -+ -+ return 0; -+ -+out: -+ ubifs_err("bad master node at offset %d error %d", c->mst_offs, err); -+ dbg_dump_node(c, c->mst_node); -+ return -EINVAL; -+} -+ -+/** -+ * ubifs_read_master - read master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function finds and reads the master node during file-system mount. If -+ * the flash is empty, it creates default master node as well. Returns zero in -+ * case of success and a negative error code in case of failure. -+ */ -+int ubifs_read_master(struct ubifs_info *c) -+{ -+ int err, old_leb_cnt; -+ -+ c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL); -+ if (!c->mst_node) -+ return -ENOMEM; -+ -+ err = scan_for_master(c); -+ if (err) { -+ err = ubifs_recover_master_node(c); -+ if (err) -+ /* -+ * Note, we do not free 'c->mst_node' here because the -+ * unmount routine will take care of this. -+ */ -+ return err; -+ } -+ -+ /* Make sure that the recovery flag is clear */ -+ c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY); -+ -+ c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum); -+ c->highest_inum = le64_to_cpu(c->mst_node->highest_inum); -+ c->cmt_no = le64_to_cpu(c->mst_node->cmt_no); -+ c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum); -+ c->zroot.offs = le32_to_cpu(c->mst_node->root_offs); -+ c->zroot.len = le32_to_cpu(c->mst_node->root_len); -+ c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum); -+ c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum); -+ c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum); -+ c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs); -+ c->old_idx_sz = le64_to_cpu(c->mst_node->index_size); -+ c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum); -+ c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs); -+ c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum); -+ c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs); -+ c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum); -+ c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs); -+ c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum); -+ c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs); -+ c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum); -+ c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs); -+ c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs); -+ old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt); -+ c->lst.total_free = le64_to_cpu(c->mst_node->total_free); -+ c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty); -+ c->lst.total_used = le64_to_cpu(c->mst_node->total_used); -+ c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); -+ c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); -+ -+ c->calc_idx_sz = c->old_idx_sz; -+ -+ if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) -+ c->no_orphs = 1; -+ -+ if (old_leb_cnt != c->leb_cnt) { -+ /* The file system has been resized */ -+ int growth = c->leb_cnt - old_leb_cnt; -+ -+ if (c->leb_cnt < old_leb_cnt || -+ c->leb_cnt < UBIFS_MIN_LEB_CNT) { -+ ubifs_err("bad leb_cnt on master node"); -+ dbg_dump_node(c, c->mst_node); -+ return -EINVAL; -+ } -+ -+ dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs", -+ old_leb_cnt, c->leb_cnt); -+ c->lst.empty_lebs += growth; -+ c->lst.total_free += growth * (long long)c->leb_size; -+ c->lst.total_dark += growth * (long long)c->dark_wm; -+ -+ /* -+ * Reflect changes back onto the master node. N.B. the master -+ * node gets written immediately whenever mounting (or -+ * remounting) in read-write mode, so we do not need to write it -+ * here. -+ */ -+ c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt); -+ c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs); -+ c->mst_node->total_free = cpu_to_le64(c->lst.total_free); -+ c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark); -+ } -+ -+ err = validate_master(c); -+ if (err) -+ return err; -+ -+ err = dbg_old_index_check_init(c, &c->zroot); -+ -+ return err; -+} -+ -+/** -+ * ubifs_write_master - write master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function writes the master node. The caller has to take the -+ * @c->mst_mutex lock before calling this function. Returns zero in case of -+ * success and a negative error code in case of failure. The master node is -+ * written twice to enable recovery. -+ */ -+int ubifs_write_master(struct ubifs_info *c) -+{ -+ int err, lnum, offs, len; -+ -+ if (c->ro_media) -+ return -EINVAL; -+ -+ lnum = UBIFS_MST_LNUM; -+ offs = c->mst_offs + c->mst_node_alsz; -+ len = UBIFS_MST_NODE_SZ; -+ -+ if (offs + UBIFS_MST_NODE_SZ > c->leb_size) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ offs = 0; -+ } -+ -+ c->mst_offs = offs; -+ c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); -+ -+ err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM); -+ if (err) -+ return err; -+ -+ lnum += 1; -+ -+ if (offs == 0) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM); -+ -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/misc.h linux-2.6.24.7/fs/ubifs/misc.h ---- linux-2.6.24.7.old/fs/ubifs/misc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/misc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,310 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file contains miscellaneous helper functions. -+ */ -+ -+#ifndef __UBIFS_MISC_H__ -+#define __UBIFS_MISC_H__ -+ -+/** -+ * ubifs_zn_dirty - check if znode is dirty. -+ * @znode: znode to check -+ * -+ * This helper function returns %1 if @znode is dirty and %0 otherwise. -+ */ -+static inline int ubifs_zn_dirty(const struct ubifs_znode *znode) -+{ -+ return !!test_bit(DIRTY_ZNODE, &znode->flags); -+} -+ -+/** -+ * ubifs_wake_up_bgt - wake up background thread. -+ * @c: UBIFS file-system description object -+ */ -+static inline void ubifs_wake_up_bgt(struct ubifs_info *c) -+{ -+ if (c->bgt && !c->need_bgt) { -+ c->need_bgt = 1; -+ wake_up_process(c->bgt); -+ } -+} -+ -+/** -+ * ubifs_tnc_find_child - find next child in znode. -+ * @znode: znode to search at -+ * @start: the zbranch index to start at -+ * -+ * This helper function looks for znode child starting at index @start. Returns -+ * the child or %NULL if no children were found. -+ */ -+static inline struct ubifs_znode * -+ubifs_tnc_find_child(struct ubifs_znode *znode, int start) -+{ -+ while (start < znode->child_cnt) { -+ if (znode->zbranch[start].znode) -+ return znode->zbranch[start].znode; -+ start += 1; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * ubifs_inode - get UBIFS inode information by VFS 'struct inode' object. -+ * @inode: the VFS 'struct inode' pointer -+ */ -+static inline struct ubifs_inode *ubifs_inode(const struct inode *inode) -+{ -+ return container_of(inode, struct ubifs_inode, vfs_inode); -+} -+ -+/** -+ * ubifs_ro_mode - switch UBIFS to read read-only mode. -+ * @c: UBIFS file-system description object -+ * @err: error code which is the reason of switching to R/O mode -+ */ -+static inline void ubifs_ro_mode(struct ubifs_info *c, int err) -+{ -+ if (!c->ro_media) { -+ c->ro_media = 1; -+ ubifs_warn("switched to read-only mode, error %d", err); -+ dbg_dump_stack(); -+ } -+} -+ -+/** -+ * ubifs_compr_present - check if compressor was compiled in. -+ * @compr_type: compressor type to check -+ * -+ * This function returns %1 of compressor of type @compr_type is present, and -+ * %0 if not. -+ */ -+static inline int ubifs_compr_present(int compr_type) -+{ -+ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT); -+ return !!ubifs_compressors[compr_type]->capi_name; -+} -+ -+/** -+ * ubifs_compr_name - get compressor name string by its type. -+ * @compr_type: compressor type -+ * -+ * This function returns compressor type string. -+ */ -+static inline const char *ubifs_compr_name(int compr_type) -+{ -+ ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT); -+ return ubifs_compressors[compr_type]->name; -+} -+ -+/** -+ * ubifs_wbuf_sync - synchronize write-buffer. -+ * @wbuf: write-buffer to synchronize -+ * -+ * This is the same as as 'ubifs_wbuf_sync_nolock()' but it does not assume -+ * that the write-buffer is already locked. -+ */ -+static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf) -+{ -+ int err; -+ -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ err = ubifs_wbuf_sync_nolock(wbuf); -+ mutex_unlock(&wbuf->io_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_leb_unmap - unmap an LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to unmap -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum) -+{ -+ int err; -+ -+ err = ubi_leb_unmap(c->ubi, lnum); -+ if (err) { -+ ubifs_err("unmap LEB %d failed, error %d", lnum, err); -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubifs_leb_write - write to a LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number to write -+ * @buf: buffer to write from -+ * @offs: offset within LEB to write to -+ * @len: length to write -+ * @dtype: data type -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum, -+ const void *buf, int offs, int len, int dtype) -+{ -+ int err; -+ -+ err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype); -+ if (err) { -+ ubifs_err("writing %d bytes at %d:%d, error %d", -+ len, lnum, offs, err); -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubifs_encode_dev - encode device node IDs. -+ * @dev: UBIFS device node information -+ * @rdev: device IDs to encode -+ * -+ * This is a helper function which encodes major/minor numbers of a device node -+ * into UBIFS device node description. We use standard Linux "new" and "huge" -+ * encodings. -+ */ -+static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev) -+{ -+ if (new_valid_dev(rdev)) { -+ dev->new = cpu_to_le32(new_encode_dev(rdev)); -+ return sizeof(dev->new); -+ } else { -+ dev->huge = cpu_to_le64(huge_encode_dev(rdev)); -+ return sizeof(dev->huge); -+ } -+} -+ -+/** -+ * ubifs_add_dirt - add dirty space to LEB properties. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB to add dirty space for -+ * @dirty: dirty space to add -+ * -+ * This is a helper function which increased amount of dirty LEB space. Returns -+ * zero in case of success and a negative error code in case of failure. -+ */ -+static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty) -+{ -+ return ubifs_update_one_lp(c, lnum, -1, dirty, 0, 0); -+} -+ -+/** -+ * ubifs_return_leb - return LEB to lprops. -+ * @c: the UBIFS file-system description object -+ * @lnum: LEB to return -+ * -+ * This helper function cleans the "taken" flag of a logical eraseblock in the -+ * lprops. Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static inline int ubifs_return_leb(struct ubifs_info *c, int lnum) -+{ -+ return ubifs_change_one_lp(c, lnum, -1, -1, 0, LPROPS_TAKEN, 0); -+} -+ -+/** -+ * ubifs_idx_node_sz - return index node size. -+ * @c: the UBIFS file-system description object -+ * @child_cnt: number of children of this index node -+ */ -+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) -+{ -+ return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt; -+} -+ -+/** -+ * ubifs_idx_branch - return pointer to an index branch. -+ * @c: the UBIFS file-system description object -+ * @idx: index node -+ * @bnum: branch number -+ */ -+static inline -+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c, -+ const struct ubifs_idx_node *idx, -+ int bnum) -+{ -+ return (struct ubifs_branch *)((void *)idx->branches + -+ (UBIFS_BRANCH_SZ + c->key_len) * bnum); -+} -+ -+/** -+ * ubifs_idx_key - return pointer to an index key. -+ * @c: the UBIFS file-system description object -+ * @idx: index node -+ */ -+static inline void *ubifs_idx_key(const struct ubifs_info *c, -+ const struct ubifs_idx_node *idx) -+{ -+ return (void *)((struct ubifs_branch *)idx->branches)->key; -+} -+ -+/** -+ * ubifs_reported_space - calculate reported free space. -+ * @c: the UBIFS file-system description object -+ * @free: amount of free space -+ * -+ * This function calculates amount of free space which will be reported to -+ * user-space. User-space application tend to expect that if the file-system -+ * (e.g., via the 'statfs()' call) reports that it has N bytes available, they -+ * are able to write a file of size N. UBIFS attaches node headers to each data -+ * node and it has to write indexind nodes as well. This introduces additional -+ * overhead, and UBIFS it has to report sligtly less free space to meet the -+ * above expectetion. -+ * -+ * This function assumes free space is made up of uncompressed data nodes and -+ * full index nodes (one per data node, doubled because we always allow enough -+ * space to write the index twice). -+ * -+ * Note, the calculation is pessimistic, which means that most of the time -+ * UBIFS reports less space than it actually has. -+ */ -+static inline long long ubifs_reported_space(const struct ubifs_info *c, -+ uint64_t free) -+{ -+ int divisor, factor; -+ -+ divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz << 1); -+ factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ; -+ do_div(free, divisor); -+ -+ return free * factor; -+} -+ -+/** -+ * ubifs_current_time - round current time to time granularity. -+ * @inode: inode -+ */ -+static inline struct timespec ubifs_current_time(struct inode *inode) -+{ -+ return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ? -+ current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; -+} -+ -+#endif /* __UBIFS_MISC_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/config linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/config ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/config 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/config 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,11 @@ -+[core] -+ repositoryformatversion = 0 -+ filemode = true -+ bare = false -+ logallrefupdates = true -+[remote "origin"] -+ url = git://git.infradead.org/~dedekind/mkfs.ubifs.git -+ fetch = +refs/heads/*:refs/remotes/origin/* -+[branch "master"] -+ remote = origin -+ merge = refs/heads/master -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/description linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/description ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/description 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/description 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+Unnamed repository; edit this file to name it for gitweb. -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/head linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/head ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/head 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/head 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/heads/master -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/applypatch-msg linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/applypatch-msg ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/applypatch-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/applypatch-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,15 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message taken by -+# applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. The hook is -+# allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/commit-msg" && -+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} -+: -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/commit-msg linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/commit-msg ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,24 @@ -+#!/bin/sh -+# -+# An example hook script to check the commit log message. -+# Called by git-commit with one argument, the name of the file -+# that has the commit message. The hook should exit with non-zero -+# status after issuing an appropriate message if it wants to stop the -+# commit. The hook is allowed to edit the commit message file. -+# -+# To enable this hook, make this file executable. -+ -+# Uncomment the below to add a Signed-off-by line to the message. -+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg -+# hook is more suited to it. -+# -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -+ -+# This example catches duplicate Signed-off-by lines. -+ -+test "" = "$(grep '^Signed-off-by: ' "$1" | -+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { -+ echo >&2 Duplicate Signed-off-by lines. -+ exit 1 -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-commit linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-commit ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script that is called after a successful -+# commit is made. -+# -+# To enable this hook, make this file executable. -+ -+: Nothing -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-receive linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-receive ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-receive 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-receive 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,16 @@ -+#!/bin/sh -+# -+# An example hook script for the post-receive event -+# -+# This script is run after receive-pack has accepted a pack and the -+# repository has been updated. It is passed arguments in through stdin -+# in the form -+# -+# For example: -+# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master -+# -+# see contrib/hooks/ for an sample, or uncomment the next line (on debian) -+# -+ -+ -+#. /usr/share/doc/git-core/contrib/hooks/post-receive-email -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-update linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-update ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/post-update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/post-update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# -+# An example hook script to prepare a packed repository for use over -+# dumb transports. -+# -+# To enable this hook, make this file executable by "chmod +x post-update". -+ -+exec git-update-server-info -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-applypatch linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-applypatch ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-applypatch 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-applypatch 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,14 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed -+# by applypatch from an e-mail message. -+# -+# The hook should exit with non-zero status after issuing an -+# appropriate message if it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+. git-sh-setup -+test -x "$GIT_DIR/hooks/pre-commit" && -+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} -+: -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-commit linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-commit ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-commit 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-commit 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+#!/bin/sh -+# -+# An example hook script to verify what is about to be committed. -+# Called by git-commit with no arguments. The hook should -+# exit with non-zero status after issuing an appropriate message if -+# it wants to stop the commit. -+# -+# To enable this hook, make this file executable. -+ -+# This is slightly modified from Andrew Morton's Perfect Patch. -+# Lines you introduce should not have trailing whitespace. -+# Also check for an indentation that has SP before a TAB. -+ -+if git-rev-parse --verify HEAD 2>/dev/null -+then -+ git-diff-index -p -M --cached HEAD -- -+else -+ # NEEDSWORK: we should produce a diff with an empty tree here -+ # if we want to do the same verification for the initial import. -+ : -+fi | -+perl -e ' -+ my $found_bad = 0; -+ my $filename; -+ my $reported_filename = ""; -+ my $lineno; -+ sub bad_line { -+ my ($why, $line) = @_; -+ if (!$found_bad) { -+ print STDERR "*\n"; -+ print STDERR "* You have some suspicious patch lines:\n"; -+ print STDERR "*\n"; -+ $found_bad = 1; -+ } -+ if ($reported_filename ne $filename) { -+ print STDERR "* In $filename\n"; -+ $reported_filename = $filename; -+ } -+ print STDERR "* $why (line $lineno)\n"; -+ print STDERR "$filename:$lineno:$line\n"; -+ } -+ while (<>) { -+ if (m|^diff --git a/(.*) b/\1$|) { -+ $filename = $1; -+ next; -+ } -+ if (/^@@ -\S+ \+(\d+)/) { -+ $lineno = $1 - 1; -+ next; -+ } -+ if (/^ /) { -+ $lineno++; -+ next; -+ } -+ if (s/^\+//) { -+ $lineno++; -+ chomp; -+ if (/\s$/) { -+ bad_line("trailing whitespace", $_); -+ } -+ if (/^\s* \t/) { -+ bad_line("indent SP followed by a TAB", $_); -+ } -+ if (/^([<>])\1{6} |^={7}$/) { -+ bad_line("unresolved merge conflict", $_); -+ } -+ } -+ } -+ exit($found_bad); -+' -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-rebase linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-rebase ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/pre-rebase 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/pre-rebase 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,150 @@ -+#!/bin/sh -+# -+# Copyright (c) 2006 Junio C Hamano -+# -+ -+publish=next -+basebranch="$1" -+if test "$#" = 2 -+then -+ topic="refs/heads/$2" -+else -+ topic=`git symbolic-ref HEAD` -+fi -+ -+case "$basebranch,$topic" in -+master,refs/heads/??/*) -+ ;; -+*) -+ exit 0 ;# we do not interrupt others. -+ ;; -+esac -+ -+# Now we are dealing with a topic branch being rebased -+# on top of master. Is it OK to rebase it? -+ -+# Is topic fully merged to master? -+not_in_master=`git-rev-list --pretty=oneline ^master "$topic"` -+if test -z "$not_in_master" -+then -+ echo >&2 "$topic is fully merged to master; better remove it." -+ exit 1 ;# we could allow it, but there is no point. -+fi -+ -+# Is topic ever merged to next? If so you should not be rebasing it. -+only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort` -+only_next_2=`git-rev-list ^master ${publish} | sort` -+if test "$only_next_1" = "$only_next_2" -+then -+ not_in_topic=`git-rev-list "^$topic" master` -+ if test -z "$not_in_topic" -+ then -+ echo >&2 "$topic is already up-to-date with master" -+ exit 1 ;# we could allow it, but there is no point. -+ else -+ exit 0 -+ fi -+else -+ not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"` -+ perl -e ' -+ my $topic = $ARGV[0]; -+ my $msg = "* $topic has commits already merged to public branch:\n"; -+ my (%not_in_next) = map { -+ /^([0-9a-f]+) /; -+ ($1 => 1); -+ } split(/\n/, $ARGV[1]); -+ for my $elem (map { -+ /^([0-9a-f]+) (.*)$/; -+ [$1 => $2]; -+ } split(/\n/, $ARGV[2])) { -+ if (!exists $not_in_next{$elem->[0]}) { -+ if ($msg) { -+ print STDERR $msg; -+ undef $msg; -+ } -+ print STDERR " $elem->[1]\n"; -+ } -+ } -+ ' "$topic" "$not_in_next" "$not_in_master" -+ exit 1 -+fi -+ -+exit 0 -+ -+################################################################ -+ -+This sample hook safeguards topic branches that have been -+published from being rewound. -+ -+The workflow assumed here is: -+ -+ * Once a topic branch forks from "master", "master" is never -+ merged into it again (either directly or indirectly). -+ -+ * Once a topic branch is fully cooked and merged into "master", -+ it is deleted. If you need to build on top of it to correct -+ earlier mistakes, a new topic branch is created by forking at -+ the tip of the "master". This is not strictly necessary, but -+ it makes it easier to keep your history simple. -+ -+ * Whenever you need to test or publish your changes to topic -+ branches, merge them into "next" branch. -+ -+The script, being an example, hardcodes the publish branch name -+to be "next", but it is trivial to make it configurable via -+$GIT_DIR/config mechanism. -+ -+With this workflow, you would want to know: -+ -+(1) ... if a topic branch has ever been merged to "next". Young -+ topic branches can have stupid mistakes you would rather -+ clean up before publishing, and things that have not been -+ merged into other branches can be easily rebased without -+ affecting other people. But once it is published, you would -+ not want to rewind it. -+ -+(2) ... if a topic branch has been fully merged to "master". -+ Then you can delete it. More importantly, you should not -+ build on top of it -- other people may already want to -+ change things related to the topic as patches against your -+ "master", so if you need further changes, it is better to -+ fork the topic (perhaps with the same name) afresh from the -+ tip of "master". -+ -+Let's look at this example: -+ -+ o---o---o---o---o---o---o---o---o---o "next" -+ / / / / -+ / a---a---b A / / -+ / / / / -+ / / c---c---c---c B / -+ / / / \ / -+ / / / b---b C \ / -+ / / / / \ / -+ ---o---o---o---o---o---o---o---o---o---o---o "master" -+ -+ -+A, B and C are topic branches. -+ -+ * A has one fix since it was merged up to "next". -+ -+ * B has finished. It has been fully merged up to "master" and "next", -+ and is ready to be deleted. -+ -+ * C has not merged to "next" at all. -+ -+We would want to allow C to be rebased, refuse A, and encourage -+B to be deleted. -+ -+To compute (1): -+ -+ git-rev-list ^master ^topic next -+ git-rev-list ^master next -+ -+ if these match, topic has not merged in next at all. -+ -+To compute (2): -+ -+ git-rev-list master..topic -+ -+ if this is empty, it is fully merged to "master". -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/prepare-commit-msg linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/prepare-commit-msg ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/prepare-commit-msg 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/prepare-commit-msg 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,36 @@ -+#!/bin/sh -+# -+# An example hook script to prepare the commit log message. -+# Called by git-commit with the name of the file that has the -+# commit message, followed by the description of the commit -+# message's source. The hook's purpose is to edit the commit -+# message file. If the hook fails with a non-zero status, -+# the commit is aborted. -+# -+# To enable this hook, make this file executable. -+ -+# This hook includes three examples. The first comments out the -+# "Conflicts:" part of a merge commit. -+# -+# The second includes the output of "git diff --name-status -r" -+# into the message, just before the "git status" output. It is -+# commented because it doesn't cope with --amend or with squashed -+# commits. -+# -+# The third example adds a Signed-off-by line to the message, that can -+# still be edited. This is rarely a good idea. -+ -+case "$2 $3" in -+ merge) -+ sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;; -+ -+# ""|template) -+# perl -i -pe ' -+# print "\n" . `git diff --cached --name-status -r` -+# if /^#/ && $first++ == 0' "$1" ;; -+ -+ *) ;; -+esac -+ -+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') -+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/update linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/update ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/hooks/update 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/hooks/update 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,107 @@ -+#!/bin/sh -+# -+# An example hook script to blocks unannotated tags from entering. -+# Called by git-receive-pack with arguments: refname sha1-old sha1-new -+# -+# To enable this hook, make this file executable by "chmod +x update". -+# -+# Config -+# ------ -+# hooks.allowunannotated -+# This boolean sets whether unannotated tags will be allowed into the -+# repository. By default they won't be. -+# hooks.allowdeletetag -+# This boolean sets whether deleting tags will be allowed in the -+# repository. By default they won't be. -+# hooks.allowdeletebranch -+# This boolean sets whether deleting branches will be allowed in the -+# repository. By default they won't be. -+# -+ -+# --- Command line -+refname="$1" -+oldrev="$2" -+newrev="$3" -+ -+# --- Safety check -+if [ -z "$GIT_DIR" ]; then -+ echo "Don't run this script from the command line." >&2 -+ echo " (if you want, you could supply GIT_DIR then run" >&2 -+ echo " $0 )" >&2 -+ exit 1 -+fi -+ -+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then -+ echo "Usage: $0 " >&2 -+ exit 1 -+fi -+ -+# --- Config -+allowunannotated=$(git config --bool hooks.allowunannotated) -+allowdeletebranch=$(git config --bool hooks.allowdeletebranch) -+allowdeletetag=$(git config --bool hooks.allowdeletetag) -+ -+# check for no description -+projectdesc=$(sed -e '1q' "$GIT_DIR/description") -+if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then -+ echo "*** Project description file hasn't been set" >&2 -+ exit 1 -+fi -+ -+# --- Check types -+# if $newrev is 0000...0000, it's a commit to delete a ref. -+if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then -+ newrev_type=delete -+else -+ newrev_type=$(git-cat-file -t $newrev) -+fi -+ -+case "$refname","$newrev_type" in -+ refs/tags/*,commit) -+ # un-annotated tag -+ short_refname=${refname##refs/tags/} -+ if [ "$allowunannotated" != "true" ]; then -+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 -+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,delete) -+ # delete tag -+ if [ "$allowdeletetag" != "true" ]; then -+ echo "*** Deleting a tag is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/tags/*,tag) -+ # annotated tag -+ ;; -+ refs/heads/*,commit) -+ # branch -+ ;; -+ refs/heads/*,delete) -+ # delete branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ refs/remotes/*,commit) -+ # tracking branch -+ ;; -+ refs/remotes/*,delete) -+ # delete tracking branch -+ if [ "$allowdeletebranch" != "true" ]; then -+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2 -+ exit 1 -+ fi -+ ;; -+ *) -+ # Anything else (is there anything else?) -+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 -+ exit 1 -+ ;; -+esac -+ -+# --- Finished -+exit 0 -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/info/exclude linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/info/exclude ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/info/exclude 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/info/exclude 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,6 @@ -+# git-ls-files --others --exclude-from=.git/info/exclude -+# Lines that start with '#' are comments. -+# For a project mostly in C, the following would be a good set of -+# exclude patterns (uncomment them if you want to use them): -+# *.[oa] -+# *~ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/head linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/head ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/head 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/head 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 549a9c94e7919c86fc260dd534fd908343348228 root 1208919344 -0400 -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/refs/heads/master linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/refs/heads/master ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 549a9c94e7919c86fc260dd534fd908343348228 root 1208919344 -0400 -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/refs/remotes/origin/master linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/refs/remotes/origin/master ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/logs/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/logs/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+0000000000000000000000000000000000000000 549a9c94e7919c86fc260dd534fd908343348228 root 1208919344 -0400 clone: from git://git.infradead.org/~dedekind/mkfs.ubifs.git -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/objects/pack/pack-b57e0a817d6303b8f24187e61200a9f06e6974ce.keep linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/objects/pack/pack-b57e0a817d6303b8f24187e61200a9f06e6974ce.keep ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/objects/pack/pack-b57e0a817d6303b8f24187e61200a9f06e6974ce.keep 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/objects/pack/pack-b57e0a817d6303b8f24187e61200a9f06e6974ce.keep 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+fetch-pack 29608 on localhost.localdomain -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/heads/master linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/heads/master ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/heads/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/heads/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+549a9c94e7919c86fc260dd534fd908343348228 -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/head linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/head ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/head 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/head 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+ref: refs/remotes/origin/master -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/master linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/master ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/master 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.git/refs/remotes/origin/master 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1 @@ -+549a9c94e7919c86fc260dd534fd908343348228 -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.gitignore linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.gitignore ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/.gitignore 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/.gitignore 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,5 @@ -+*.o -+mkfs.ubifs -+patches -+cscope.out -+.pc -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/Makefile linux-2.6.24.7/fs/ubifs/mkfs.ubifs/Makefile ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,24 @@ -+ifeq ($(origin CC),default) -+CC = gcc -+endif -+ -+ALL_SOURCES=*.[ch] hashtable/*.[ch] -+ -+CFLAGS := $(CFLAGS) -Wall -O2 -I./lzo/include -I../../../include -+ -+LDFLAGS := $(LDFLAGS) -lz -llzo2 -lm -L./lzo/lib -+ -+TARGETS = mkfs.ubifs -+ -+all: $(TARGETS) -+ -+mkfs.ubifs: crc16.o crc32.o lpt.o compr.o hashtable/hashtable.o \ -+ hashtable/hashtable_itr.o devtable.o -+ -+clean: -+ rm -f *.o $(TARGETS) cscope.* -+ -+cscope: -+ @echo $(ALL_SOURCES) > cscope.files -+ @cscope -bR -+ @rm cscope.files -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/compr.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/compr.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/compr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/compr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,154 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "compr.h" -+#include "ubifs-media.h" -+ -+static void *lzo_mem; -+static unsigned long long errcnt = 0; -+ -+#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION -+#define DEFLATE_DEF_WINBITS 11 -+#define DEFLATE_DEF_MEMLEVEL 8 -+ -+static int zlib_deflate(void *in_buf, size_t in_len, void *out_buf, -+ size_t *out_len) -+{ -+ z_stream strm; -+ -+ strm.zalloc = NULL; -+ strm.zfree = NULL; -+ -+ /* -+ * Match exactly the zlib parameters used by the linux kernel crypto -+ * API. -+ */ -+ if (deflateInit2(&strm, DEFLATE_DEF_LEVEL, Z_DEFLATED, -+ -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, -+ Z_DEFAULT_STRATEGY)) { -+ errcnt += 1; -+ return -1; -+ } -+ -+ strm.next_in = in_buf; -+ strm.avail_in = in_len; -+ strm.total_in = 0; -+ -+ strm.next_out = out_buf; -+ strm.avail_out = *out_len; -+ strm.total_out = 0; -+ -+ if (deflate(&strm, Z_FINISH) != Z_STREAM_END) { -+ deflateEnd(&strm); -+ errcnt += 1; -+ return -1; -+ } -+ -+ if (deflateEnd(&strm) != Z_OK) { -+ errcnt += 1; -+ return -1; -+ } -+ -+ *out_len = strm.total_out; -+ -+ return 0; -+} -+ -+static int lzo_compress(void *in_buf, size_t in_len, void *out_buf, -+ size_t *out_len) -+{ -+ lzo_uint len; -+ int ret; -+ -+ len = *out_len; -+ ret = lzo1x_999_compress(in_buf, in_len, out_buf, &len, lzo_mem); -+ *out_len = len; -+ -+ if (ret != LZO_E_OK) { -+ errcnt += 1; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int no_compress(void *in_buf, size_t in_len, void *out_buf, -+ size_t *out_len) -+{ -+ memcpy(out_buf, in_buf, in_len); -+ *out_len = in_len; -+ return 0; -+} -+ -+int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, -+ int type) -+{ -+ int ret = 1; -+ -+ if (in_len < UBIFS_MIN_COMPR_LEN) { -+ no_compress(in_buf, in_len, out_buf, out_len); -+ return MKFS_UBIFS_COMPR_NONE; -+ } -+ -+ switch (type) { -+ case MKFS_UBIFS_COMPR_LZO: -+ ret = lzo_compress(in_buf, in_len, out_buf, out_len); -+ break; -+ case MKFS_UBIFS_COMPR_ZLIB: -+ ret = zlib_deflate(in_buf, in_len, out_buf, out_len); -+ break; -+ case MKFS_UBIFS_COMPR_NONE: -+ ret = 1; -+ break; -+ default: -+ errcnt += 1; -+ break; -+ } -+ if (ret || *out_len >= in_len) { -+ no_compress(in_buf, in_len, out_buf, out_len); -+ return MKFS_UBIFS_COMPR_NONE; -+ } -+ return type; -+} -+ -+int init_compression(void) -+{ -+ lzo_mem = malloc(LZO1X_999_MEM_COMPRESS); -+ if (!lzo_mem) -+ return -1; -+ return 0; -+} -+ -+void destroy_compression(void) -+{ -+ free(lzo_mem); -+ if (errcnt) -+ fprintf(stderr, "%llu compression errors occurred\n", errcnt); -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/compr.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/compr.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/compr.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/compr.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,38 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+#ifndef __UBIFS_COMPRESS_H__ -+#define __UBIFS_COMPRESS_H__ -+ -+enum compression_type -+{ -+ MKFS_UBIFS_COMPR_NONE, -+ MKFS_UBIFS_COMPR_LZO, -+ MKFS_UBIFS_COMPR_ZLIB, -+}; -+ -+int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, -+ int type); -+int init_compression(void); -+void destroy_compression(void); -+ -+#endif -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/copying linux-2.6.24.7/fs/ubifs/mkfs.ubifs/copying ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/copying 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/copying 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,340 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. -+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Library General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ -+ Copyright (C) 19yy -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) 19yy name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ , 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Library General -+Public License instead of this License. -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc16.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc16.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc16.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc16.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * This code was taken from the linux kernel. The license is GPL Version 2. -+ */ -+ -+#include "crc16.h" -+ -+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ -+uint16_t const crc16_table[256] = { -+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, -+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, -+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, -+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, -+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, -+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, -+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, -+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, -+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, -+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, -+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, -+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, -+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, -+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, -+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, -+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, -+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, -+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, -+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, -+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, -+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, -+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, -+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, -+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, -+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, -+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, -+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, -+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, -+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, -+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, -+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, -+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 -+}; -+ -+/** -+ * crc16 - compute the CRC-16 for the data buffer -+ * @crc: previous CRC value -+ * @buffer: data pointer -+ * @len: number of bytes in the buffer -+ * -+ * Returns the updated CRC value. -+ */ -+uint16_t crc16(uint16_t crc, uint8_t const *buffer, size_t len) -+{ -+ while (len--) -+ crc = crc16_byte(crc, *buffer++); -+ return crc; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc16.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc16.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc16.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc16.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,27 @@ -+/* -+ * Implements the standard CRC-16: -+ * Width 16 -+ * Poly 0x8005 (x^16 + x^15 + x^2 + 1) -+ * Init 0 -+ * -+ * Copyright (c) 2005 Ben Gardner -+ * -+ * This code was taken from the linux kernel. The license is GPL Version 2. -+ */ -+ -+#ifndef __CRC16_H__ -+#define __CRC16_H__ -+ -+#include -+#include -+ -+extern uint16_t const crc16_table[256]; -+ -+extern uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len); -+ -+static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data) -+{ -+ return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff]; -+} -+ -+#endif /* __CRC16_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc32.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc32.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc32.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,95 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+#include -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc32.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc32.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/crc32.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,22 @@ -+/* -+ * This code was taken from the linux kernel. The license is GPL Version 2. -+ */ -+ -+#ifndef __CRC32_H__ -+#define __CRC32_H__ -+ -+#include -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+static inline uint32_t crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif /* __CRC32_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/defs.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/defs.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/defs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/defs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,105 @@ -+/* -+ * Greate deal of the code was taken from the kernel UBIFS implementation, and -+ * this file contains some "glue" definitions. -+ */ -+ -+#ifndef __UBIFS_DEFS_H__ -+#define __UBIFS_DEFS_H__ -+ -+#define t16(x) ({ \ -+ uint16_t __b = (x); \ -+ (__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_16(__b); \ -+}) -+ -+#define t32(x) ({ \ -+ uint32_t __b = (x); \ -+ (__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_32(__b); \ -+}) -+ -+#define t64(x) ({ \ -+ uint64_t __b = (x); \ -+ (__LITTLE_ENDIAN==__BYTE_ORDER) ? __b : bswap_64(__b); \ -+}) -+ -+#define cpu_to_le16(x) ((__le16){t16(x)}) -+#define cpu_to_le32(x) ((__le32){t32(x)}) -+#define cpu_to_le64(x) ((__le64){t64(x)}) -+ -+#define le16_to_cpu(x) (t16((x))) -+#define le32_to_cpu(x) (t32((x))) -+#define le64_to_cpu(x) (t64((x))) -+ -+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) -+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) -+ -+#define min_t(t,x,y) ({ \ -+ typeof((x)) _x = (x); \ -+ typeof((y)) _y = (y); \ -+ (_x < _y) ? _x : _y; \ -+}) -+ -+#define max_t(t,x,y) ({ \ -+ typeof((x)) _x = (x); \ -+ typeof((y)) _y = (y); \ -+ (_x > _y) ? _x : _y; \ -+}) -+ -+#define unlikely(x) (x) -+ -+struct qstr -+{ -+ char *name; -+ size_t len; -+}; -+ -+/** -+ * fls - find last (most-significant) bit set -+ * @x: the word to search -+ * -+ * This is defined the same way as ffs. -+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. -+ */ -+static inline int fls(int x) -+{ -+ int r = 32; -+ -+ if (!x) -+ return 0; -+ if (!(x & 0xffff0000u)) { -+ x <<= 16; -+ r -= 16; -+ } -+ if (!(x & 0xff000000u)) { -+ x <<= 8; -+ r -= 8; -+ } -+ if (!(x & 0xf0000000u)) { -+ x <<= 4; -+ r -= 4; -+ } -+ if (!(x & 0xc0000000u)) { -+ x <<= 2; -+ r -= 2; -+ } -+ if (!(x & 0x80000000u)) { -+ x <<= 1; -+ r -= 1; -+ } -+ return r; -+} -+ -+#define do_div(n,base) ({ \ -+int __res; \ -+__res = ((unsigned long) n) % (unsigned) base; \ -+n = ((unsigned long) n) / (unsigned) base; \ -+__res; }) -+ -+#if INT_MAX != 0x7fffffff -+#error : sizeof(int) must be 4 for this program -+#endif -+ -+#if (~0ULL) != 0xffffffffffffffffULL -+#error : sizeof(long long) must be 8 for this program -+#endif -+ -+#endif -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/devtable.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/devtable.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/devtable.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/devtable.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,524 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Author: Artem Bityutskiy -+ * -+ * Part of the device table parsing code was taken from the mkfs.jffs2 utility. -+ * The original author of that code is Erik Andersen, hence: -+ * Copyright (C) 2001, 2002 Erik Andersen -+ */ -+ -+/* -+ * This file implemented device table support. Device table entries take the -+ * form of: -+ * -+ * /dev/mem c 640 0 0 1 1 0 0 - -+ * -+ * Type can be one of: -+ * f A regular file -+ * d Directory -+ * c Character special device file -+ * b Block special device file -+ * p Fifo (named pipe) -+ * -+ * Don't bother with symlinks (permissions are irrelevant), hard links (special -+ * cases of regular files), or sockets (why bother). -+ * -+ * Regular files must exist in the target root directory. If a char, block, -+ * fifo, or directory does not exist, it will be created. -+ * -+ * Please, refer the device_table.txt file which can be found at MTD utilities -+ * for more information about what the device table is. -+ */ -+ -+#include "mkfs.ubifs.h" -+#include "hashtable/hashtable.h" -+#include "hashtable/hashtable_itr.h" -+ -+/* -+ * The hash table which contains paths to files/directories/device nodes -+ * referred to in the device table. For example, if the device table refers -+ * "/dev/loop0", the @path_htbl will contain "/dev" element. -+ */ -+static struct hashtable *path_htbl; -+ -+/* Hash function used for hash tables */ -+static unsigned int r5_hash(void *s) -+{ -+ unsigned int a = 0; -+ const signed char *str = s; -+ -+ while (*str) { -+ a += *str << 4; -+ a += *str >> 4; -+ a *= 11; -+ str++; -+ } -+ -+ return a; -+} -+ -+/* -+ * Check whether 2 keys of a hash table are equivalent. The keys are path/file -+ * names, so we simply use 'strcmp()'. -+ */ -+static int is_equivalent(void *k1, void *k2) -+{ -+ return !strcmp(k1, k2); -+} -+ -+/** -+ * separate_last - separate out the last path component -+ * @buf: the path to split -+ * @len: length of the @buf string -+ * @path: the beginning of path is returned here -+ * @name: the last path component is returned here -+ * -+ * This helper function separates out the the last component of the full path -+ * string. For example, "/dev/loop" would be split on "/dev" and "loop". This -+ * function allocates memory for @path and @name and return the result there. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int separate_last(const char *buf, int len, char **path, char **name) -+{ -+ int path_len = len, name_len; -+ const char *p = buf + len, *n; -+ -+ while (*--p != '/') -+ path_len -= 1; -+ -+ /* Drop the final '/' unless this is the root directory */ -+ name_len = len - path_len; -+ n = buf + path_len; -+ if (path_len > 1) -+ path_len -= 1; -+ -+ *path = malloc(path_len + 1); -+ if (!*path) -+ return err_msg("cannot allocate %d bytes of memory", -+ path_len + 1); -+ memcpy(*path, buf, path_len); -+ (*path)[path_len] = '\0'; -+ -+ *name = malloc(name_len + 1); -+ if (!*name) { -+ free(*path); -+ return err_msg("cannot allocate %d bytes of memory", -+ name_len + 1); -+ } -+ memcpy(*name, n, name_len + 1); -+ -+ return 0; -+} -+ -+static int interpret_table_entry(const char *root, const char *line) -+{ -+ char buf[1024], type, *path = NULL, *name = NULL; -+ int len; -+ struct path_htbl_element *ph_elt = NULL; -+ struct name_htbl_element *nh_elt = NULL; -+ unsigned int mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; -+ unsigned int start = 0, increment = 0, count = 0; -+ -+ if (sscanf(line, "%1023s %c %o %u %u %u %u %u %u %u", -+ buf, &type, &mode, &uid, &gid, &major, &minor, -+ &start, &increment, &count) < 0) -+ return sys_err_msg("sscanf failed"); -+ -+ dbg_msg(3, "name %s, type %c, mode %o, uid %u, gid %u, major %u, " -+ "minor %u, start %u, inc %u, cnt %u", -+ buf, type, mode, uid, gid, major, minor, start, -+ increment, count); -+ -+ len = strnlen(buf, 1024); -+ if (len == 1024) -+ return err_msg("too long path"); -+ -+ if (!strcmp(buf, "/")) -+ return err_msg("device table entries require absolute paths"); -+ if (buf[1] == '\0') -+ return err_msg("root directory cannot be created"); -+ if (strstr(buf, "//")) -+ return err_msg("'//' cannot be used in the path"); -+ if (buf[len - 1] == '/') -+ return err_msg("do not put '/' at the end"); -+ -+ if (strstr(buf, "/./") || strstr(buf, "/../") || -+ !strcmp(buf + len - 2, "/.") || !strcmp(buf + len - 3, "/..")) -+ return err_msg("'.' and '..' cannot be used in the path"); -+ -+ switch (type) { -+ case 'd': -+ mode |= S_IFDIR; -+ break; -+ case 'f': -+ mode |= S_IFREG; -+ break; -+ case 'p': -+ mode |= S_IFIFO; -+ break; -+ case 'c': -+ mode |= S_IFCHR; -+ break; -+ case 'b': -+ mode |= S_IFBLK; -+ break; -+ default: -+ return err_msg("unsupported file type '%c'", type); -+ } -+ -+ if (separate_last(buf, len, &path, &name)) -+ return -1; -+ -+ /* -+ * Check if this path already exist in the path hash table and add it -+ * if it is not. -+ */ -+ ph_elt = hashtable_search(path_htbl, path); -+ if (!ph_elt) { -+ dbg_msg(3, "inserting '%s' into path hash table", path); -+ ph_elt = malloc(sizeof(struct path_htbl_element)); -+ if (!ph_elt) { -+ err_msg("cannot allocate %d bytes of memory", -+ sizeof(struct path_htbl_element)); -+ goto out_free; -+ } -+ -+ if (!hashtable_insert(path_htbl, path, ph_elt)) { -+ err_msg("cannot insert into path hash table"); -+ goto out_free; -+ } -+ -+ ph_elt->path = path; -+ path = NULL; -+ ph_elt->name_htbl = create_hashtable(128, &r5_hash, -+ &is_equivalent); -+ if (!ph_elt->name_htbl) { -+ err_msg("cannot create name hash table"); -+ goto out_free; -+ } -+ } -+ -+ if (increment != 0 && count == 0) -+ return err_msg("count cannot be zero if increment is non-zero"); -+ -+ /* -+ * Add the file/directory/device node (last component of the path) to -+ * the name hashtable. The name hashtable resides in the corresponding -+ * path hashtable element. -+ */ -+ -+ if (count == 0) { -+ /* This entry does not require any iterating */ -+ nh_elt = malloc(sizeof(struct name_htbl_element)); -+ if (!nh_elt) { -+ err_msg("cannot allocate %d bytes of memory", -+ sizeof(struct name_htbl_element)); -+ goto out_free; -+ } -+ -+ nh_elt->mode = mode; -+ nh_elt->uid = uid; -+ nh_elt->gid = gid; -+ nh_elt->dev = makedev(major, minor); -+ -+ dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)", -+ name, major(nh_elt->dev), minor(nh_elt->dev)); -+ -+ if (hashtable_search(ph_elt->name_htbl, name)) -+ return err_msg("'%s' is referred twice", buf); -+ -+ nh_elt->name = name; -+ if (!hashtable_insert(ph_elt->name_htbl, name, nh_elt)) { -+ err_msg("cannot insert into name hash table"); -+ goto out_free; -+ } -+ } else { -+ int i, num = start + increment * count, len = strlen(name) + 20; -+ char *nm; -+ -+ for (i = start; i < num; i++) { -+ nh_elt = malloc(sizeof(struct name_htbl_element)); -+ if (!nh_elt) { -+ err_msg("cannot allocate %d bytes of memory", -+ sizeof(struct name_htbl_element)); -+ goto out_free; -+ } -+ -+ nh_elt->mode = mode; -+ nh_elt->uid = uid; -+ nh_elt->gid = gid; -+ nh_elt->dev = makedev(major, minor + i - start); -+ -+ nm = malloc(len); -+ if (!nm) { -+ err_msg("cannot allocate %d bytes of memory", len); -+ goto out_free; -+ } -+ -+ sprintf(nm, "%s%d", name, i); -+ nh_elt->name = nm; -+ -+ dbg_msg(3, "inserting '%s' into name hash table (major %d, minor %d)", -+ nm, major(nh_elt->dev), minor(nh_elt->dev)); -+ -+ if (hashtable_search(ph_elt->name_htbl, nm)) { -+ err_msg("'%s' is referred twice", buf); -+ free (nm); -+ goto out_free; -+ } -+ -+ if (!hashtable_insert(ph_elt->name_htbl, nm, nh_elt)) { -+ err_msg("cannot insert into name hash table"); -+ free (nm); -+ goto out_free; -+ } -+ } -+ free(name); -+ name = NULL; -+ } -+ -+ return 0; -+ -+out_free: -+ free(ph_elt); -+ free(nh_elt); -+ free(path); -+ free(name); -+ return -1; -+} -+ -+/** -+ * parse_devtable - parse the device table. -+ * @tbl_file: device table file name -+ * -+ * This function parses the device table and prepare the hash table which will -+ * later be used by mkfs.ubifs to create the specified files/device nodes. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+int parse_devtable(const char *root, const char *tbl_file) -+{ -+ FILE *f; -+ char *line = NULL; -+ struct stat st; -+ size_t len; -+ -+ dbg_msg(1, "parsing device table file '%s'", tbl_file); -+ -+ path_htbl = create_hashtable(128, &r5_hash, &is_equivalent); -+ if (!path_htbl) -+ return err_msg("cannot create path hash table"); -+ -+ f = fopen(tbl_file, "r"); -+ if (!f) -+ return sys_err_msg("cannot open '%s'", tbl_file); -+ -+ if (fstat(fileno(f), &st) < 0) { -+ sys_err_msg("cannot stat '%s'", tbl_file); -+ goto out_close; -+ } -+ -+ if (st.st_size < 10) { -+ sys_err_msg("'%s' is too short", tbl_file); -+ goto out_close; -+ } -+ -+ /* -+ * The general plan now is to read in one line at a time, check for -+ * leading comment delimiters ('#'), then try and parse the line as a -+ * device table -+ */ -+ while (getline(&line, &len, f) != -1) { -+ /* First trim off any white-space */ -+ len = strlen(line); -+ -+ /* Trim trailing white-space */ -+ while (len > 0 && isspace(line[len - 1])) -+ line[--len] = '\0'; -+ /* Trim leading white-space */ -+ memmove(line, &line[strspn(line, " \n\r\t\v")], len); -+ -+ /* How long are we after trimming? */ -+ len = strlen(line); -+ -+ /* If this is not a comment line, try to interpret it */ -+ if (len && *line != '#') { -+ if (interpret_table_entry(root, line)) { -+ err_msg("cannot parse '%s'", line); -+ goto out_close; -+ } -+ } -+ -+ free(line); -+ line = NULL; -+ } -+ -+ dbg_msg(1, "finished parsing"); -+ fclose(f); -+ return 0; -+ -+out_close: -+ fclose(f); -+ free_devtable_info(); -+ return -1; -+} -+ -+/** -+ * devtbl_find_path - find a path in the path hash table. -+ * @path: UBIFS path to find. -+ * -+ * This looks up the path hash table. Returns the path hash table element -+ * reference if @path was found and %NULL if not. -+ */ -+struct path_htbl_element *devtbl_find_path(const char *path) -+{ -+ if (!path_htbl) -+ return NULL; -+ -+ return hashtable_search(path_htbl, (void *)path); -+} -+ -+/** -+ * devtbl_find_name - find a name in the name hash table. -+ * @ph_etl: path hash table element to find at -+ * @name: name to find -+ * -+ * This looks up the name hash table. Returns the name hash table element -+ * reference if @name found and %NULL if not. -+ */ -+struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt, -+ const char *name) -+{ -+ if (!path_htbl) -+ return NULL; -+ -+ return hashtable_search(ph_elt->name_htbl, (void *)name); -+} -+ -+/** -+ * override_attributes - override inode attributes. -+ * @st: struct stat object to containing the attributes to override -+ * @ph_elt: path hash table element object -+ * @nh_elt: name hash table element object containing the new values -+ * -+ * The device table file may override attributes like UID of files. For -+ * example, the device table may contain a "/dev" entry, and the UBIFS FS on -+ * the host may contain "/dev" directory. In this case the attributes of the -+ * "/dev" directory inode has to be as the device table specifies. -+ * -+ * Note, the hash element is removed by this function as well. -+ */ -+int override_attributes(struct stat *st, struct path_htbl_element *ph_elt, -+ struct name_htbl_element *nh_elt) -+{ -+ if (!path_htbl) -+ return 0; -+ -+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode) || -+ S_ISFIFO(st->st_mode)) -+ return err_msg("%s/%s both exists at UBIFS root at host, " -+ "and is referred from the device table", -+ strcmp(ph_elt->path, "/") ? ph_elt->path : "", -+ nh_elt->name); -+ -+ if ((st->st_mode & S_IFMT) != (nh_elt->mode & S_IFMT)) -+ return err_msg("%s/%s is referred from the device table also exists in " -+ "the UBIFS root directory at host, but the file type is " -+ "different", strcmp(ph_elt->path, "/") ? ph_elt->path : "", -+ nh_elt->name); -+ -+ dbg_msg(3, "set UID %d, GID %d, mode %o for %s/%s as device table says", -+ nh_elt->uid, nh_elt->gid, nh_elt->mode, ph_elt->path, nh_elt->name); -+ -+ st->st_uid = nh_elt->uid; -+ st->st_gid = nh_elt->gid; -+ st->st_mode = nh_elt->mode; -+ -+ hashtable_remove(ph_elt->name_htbl, (void *)nh_elt->name); -+ return 0; -+} -+ -+/** -+ * first_name_htbl_element - return first element of the name hash table. -+ * @ph_elt: the path hash table the name hash table belongs to -+ * @itr: double pointer to a 'struct hashtable_itr' object where the -+ * information about further iterations is stored -+ * -+ * This function implements name hash table iteration together with -+ * 'next_name_htbl_element()'. Returns the first name hash table element or -+ * %NULL if the hash table is empty. -+ */ -+struct name_htbl_element * -+first_name_htbl_element(struct path_htbl_element *ph_elt, -+ struct hashtable_itr **itr) -+{ -+ if (!path_htbl || !ph_elt || hashtable_count(ph_elt->name_htbl) == 0) -+ return NULL; -+ -+ *itr = hashtable_iterator(ph_elt->name_htbl); -+ return hashtable_iterator_value(*itr); -+} -+ -+/** -+ * first_name_htbl_element - return next element of the name hash table. -+ * @ph_elt: the path hash table the name hash table belongs to -+ * @itr: double pointer to a 'struct hashtable_itr' object where the -+ * information about further iterations is stored -+ * -+ * This function implements name hash table iteration together with -+ * 'first_name_htbl_element()'. Returns the next name hash table element or -+ * %NULL if there are no more elements. -+ */ -+struct name_htbl_element * -+next_name_htbl_element(struct path_htbl_element *ph_elt, -+ struct hashtable_itr **itr) -+{ -+ if (!path_htbl || !ph_elt || !hashtable_iterator_advance(*itr)) -+ return NULL; -+ -+ return hashtable_iterator_value(*itr); -+} -+ -+/** -+ * free_devtable_info - free device table information. -+ * -+ * This function frees the path hash table and the name hash tables. -+ */ -+void free_devtable_info(void) -+{ -+ struct hashtable_itr *ph_itr; -+ struct path_htbl_element *ph_elt; -+ -+ if (!path_htbl) -+ return; -+ -+ if (hashtable_count(path_htbl) > 0) { -+ ph_itr = hashtable_iterator(path_htbl); -+ do { -+ ph_elt = hashtable_iterator_value(ph_itr); -+ /* -+ * Note, since we use the same string for the key and -+ * @name in the name hash table elements, we do not -+ * have to iterate name hash table because @name memory -+ * will be freed when freeing the key. -+ */ -+ hashtable_destroy(ph_elt->name_htbl, 1); -+ } while (hashtable_iterator_advance(ph_itr)); -+ } -+ hashtable_destroy(path_htbl, 1); -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,274 @@ -+/* Copyright (C) 2004 Christopher Clark */ -+ -+#include "hashtable.h" -+#include "hashtable_private.h" -+#include -+#include -+#include -+#include -+ -+/* -+Credit for primes table: Aaron Krowne -+ http://br.endernet.org/~akrowne/ -+ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html -+*/ -+static const unsigned int primes[] = { -+53, 97, 193, 389, -+769, 1543, 3079, 6151, -+12289, 24593, 49157, 98317, -+196613, 393241, 786433, 1572869, -+3145739, 6291469, 12582917, 25165843, -+50331653, 100663319, 201326611, 402653189, -+805306457, 1610612741 -+}; -+const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); -+const float max_load_factor = 0.65; -+ -+/*****************************************************************************/ -+struct hashtable * -+create_hashtable(unsigned int minsize, -+ unsigned int (*hashf) (void*), -+ int (*eqf) (void*,void*)) -+{ -+ struct hashtable *h; -+ unsigned int pindex, size = primes[0]; -+ /* Check requested hashtable isn't too large */ -+ if (minsize > (1u << 30)) return NULL; -+ /* Enforce size as prime */ -+ for (pindex=0; pindex < prime_table_length; pindex++) { -+ if (primes[pindex] > minsize) { size = primes[pindex]; break; } -+ } -+ h = (struct hashtable *)malloc(sizeof(struct hashtable)); -+ if (NULL == h) return NULL; /*oom*/ -+ h->table = (struct entry **)malloc(sizeof(struct entry*) * size); -+ if (NULL == h->table) { free(h); return NULL; } /*oom*/ -+ memset(h->table, 0, size * sizeof(struct entry *)); -+ h->tablelength = size; -+ h->primeindex = pindex; -+ h->entrycount = 0; -+ h->hashfn = hashf; -+ h->eqfn = eqf; -+ h->loadlimit = (unsigned int) ceil(size * max_load_factor); -+ return h; -+} -+ -+/*****************************************************************************/ -+unsigned int -+hash(struct hashtable *h, void *k) -+{ -+ /* Aim to protect against poor hash functions by adding logic here -+ * - logic taken from java 1.4 hashtable source */ -+ unsigned int i = h->hashfn(k); -+ i += ~(i << 9); -+ i ^= ((i >> 14) | (i << 18)); /* >>> */ -+ i += (i << 4); -+ i ^= ((i >> 10) | (i << 22)); /* >>> */ -+ return i; -+} -+ -+/*****************************************************************************/ -+static int -+hashtable_expand(struct hashtable *h) -+{ -+ /* Double the size of the table to accomodate more entries */ -+ struct entry **newtable; -+ struct entry *e; -+ struct entry **pE; -+ unsigned int newsize, i, index; -+ /* Check we're not hitting max capacity */ -+ if (h->primeindex == (prime_table_length - 1)) return 0; -+ newsize = primes[++(h->primeindex)]; -+ -+ newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); -+ if (NULL != newtable) -+ { -+ memset(newtable, 0, newsize * sizeof(struct entry *)); -+ /* This algorithm is not 'stable'. ie. it reverses the list -+ * when it transfers entries between the tables */ -+ for (i = 0; i < h->tablelength; i++) { -+ while (NULL != (e = h->table[i])) { -+ h->table[i] = e->next; -+ index = indexFor(newsize,e->h); -+ e->next = newtable[index]; -+ newtable[index] = e; -+ } -+ } -+ free(h->table); -+ h->table = newtable; -+ } -+ /* Plan B: realloc instead */ -+ else -+ { -+ newtable = (struct entry **) -+ realloc(h->table, newsize * sizeof(struct entry *)); -+ if (NULL == newtable) { (h->primeindex)--; return 0; } -+ h->table = newtable; -+ memset(newtable[h->tablelength], 0, newsize - h->tablelength); -+ for (i = 0; i < h->tablelength; i++) { -+ for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { -+ index = indexFor(newsize,e->h); -+ if (index == i) -+ { -+ pE = &(e->next); -+ } -+ else -+ { -+ *pE = e->next; -+ e->next = newtable[index]; -+ newtable[index] = e; -+ } -+ } -+ } -+ } -+ h->tablelength = newsize; -+ h->loadlimit = (unsigned int) ceil(newsize * max_load_factor); -+ return -1; -+} -+ -+/*****************************************************************************/ -+unsigned int -+hashtable_count(struct hashtable *h) -+{ -+ return h->entrycount; -+} -+ -+/*****************************************************************************/ -+int -+hashtable_insert(struct hashtable *h, void *k, void *v) -+{ -+ /* This method allows duplicate keys - but they shouldn't be used */ -+ unsigned int index; -+ struct entry *e; -+ if (++(h->entrycount) > h->loadlimit) -+ { -+ /* Ignore the return value. If expand fails, we should -+ * still try cramming just this value into the existing table -+ * -- we may not have memory for a larger table, but one more -+ * element may be ok. Next time we insert, we'll try expanding again.*/ -+ hashtable_expand(h); -+ } -+ e = (struct entry *)malloc(sizeof(struct entry)); -+ if (NULL == e) { --(h->entrycount); return 0; } /*oom*/ -+ e->h = hash(h,k); -+ index = indexFor(h->tablelength,e->h); -+ e->k = k; -+ e->v = v; -+ e->next = h->table[index]; -+ h->table[index] = e; -+ return -1; -+} -+ -+/*****************************************************************************/ -+void * /* returns value associated with key */ -+hashtable_search(struct hashtable *h, void *k) -+{ -+ struct entry *e; -+ unsigned int hashvalue, index; -+ hashvalue = hash(h,k); -+ index = indexFor(h->tablelength,hashvalue); -+ e = h->table[index]; -+ while (NULL != e) -+ { -+ /* Check hash value to short circuit heavier comparison */ -+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; -+ e = e->next; -+ } -+ return NULL; -+} -+ -+/*****************************************************************************/ -+void * /* returns value associated with key */ -+hashtable_remove(struct hashtable *h, void *k) -+{ -+ /* TODO: consider compacting the table when the load factor drops enough, -+ * or provide a 'compact' method. */ -+ -+ struct entry *e; -+ struct entry **pE; -+ void *v; -+ unsigned int hashvalue, index; -+ -+ hashvalue = hash(h,k); -+ index = indexFor(h->tablelength,hash(h,k)); -+ pE = &(h->table[index]); -+ e = *pE; -+ while (NULL != e) -+ { -+ /* Check hash value to short circuit heavier comparison */ -+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) -+ { -+ *pE = e->next; -+ h->entrycount--; -+ v = e->v; -+ freekey(e->k); -+ free(e); -+ return v; -+ } -+ pE = &(e->next); -+ e = e->next; -+ } -+ return NULL; -+} -+ -+/*****************************************************************************/ -+/* destroy */ -+void -+hashtable_destroy(struct hashtable *h, int free_values) -+{ -+ unsigned int i; -+ struct entry *e, *f; -+ struct entry **table = h->table; -+ if (free_values) -+ { -+ for (i = 0; i < h->tablelength; i++) -+ { -+ e = table[i]; -+ while (NULL != e) -+ { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } -+ } -+ } -+ else -+ { -+ for (i = 0; i < h->tablelength; i++) -+ { -+ e = table[i]; -+ while (NULL != e) -+ { f = e; e = e->next; freekey(f->k); free(f); } -+ } -+ } -+ free(h->table); -+ free(h); -+} -+ -+/* -+ * Copyright (c) 2002, Christopher Clark -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * * Neither the name of the original author; nor the names of any contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,199 @@ -+/* Copyright (C) 2002 Christopher Clark */ -+ -+#ifndef __HASHTABLE_CWC22_H__ -+#define __HASHTABLE_CWC22_H__ -+ -+struct hashtable; -+ -+/* Example of use: -+ * -+ * struct hashtable *h; -+ * struct some_key *k; -+ * struct some_value *v; -+ * -+ * static unsigned int hash_from_key_fn( void *k ); -+ * static int keys_equal_fn ( void *key1, void *key2 ); -+ * -+ * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); -+ * k = (struct some_key *) malloc(sizeof(struct some_key)); -+ * v = (struct some_value *) malloc(sizeof(struct some_value)); -+ * -+ * (initialise k and v to suitable values) -+ * -+ * if (! hashtable_insert(h,k,v) ) -+ * { exit(-1); } -+ * -+ * if (NULL == (found = hashtable_search(h,k) )) -+ * { printf("not found!"); } -+ * -+ * if (NULL == (found = hashtable_remove(h,k) )) -+ * { printf("Not found\n"); } -+ * -+ */ -+ -+/* Macros may be used to define type-safe(r) hashtable access functions, with -+ * methods specialized to take known key and value types as parameters. -+ * -+ * Example: -+ * -+ * Insert this at the start of your file: -+ * -+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); -+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); -+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); -+ * -+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'. -+ * These operate just like hashtable_insert etc., with the same parameters, -+ * but their function signatures have 'struct some_key *' rather than -+ * 'void *', and hence can generate compile time errors if your program is -+ * supplying incorrect data as a key (and similarly for value). -+ * -+ * Note that the hash and key equality functions passed to create_hashtable -+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be -+ * a difficult issue as they're only defined and passed once, and the other -+ * functions will ensure that only valid keys are supplied to them. -+ * -+ * The cost for this checking is increased code size and runtime overhead -+ * - if performance is important, it may be worth switching back to the -+ * unsafe methods once your program has been debugged with the safe methods. -+ * This just requires switching to some simple alternative defines - eg: -+ * #define insert_some hashtable_insert -+ * -+ */ -+ -+/***************************************************************************** -+ * create_hashtable -+ -+ * @name create_hashtable -+ * @param minsize minimum initial size of hashtable -+ * @param hashfunction function for hashing keys -+ * @param key_eq_fn function for determining key equality -+ * @return newly created hashtable or NULL on failure -+ */ -+ -+struct hashtable * -+create_hashtable(unsigned int minsize, -+ unsigned int (*hashfunction) (void*), -+ int (*key_eq_fn) (void*,void*)); -+ -+/***************************************************************************** -+ * hashtable_insert -+ -+ * @name hashtable_insert -+ * @param h the hashtable to insert into -+ * @param k the key - hashtable claims ownership and will free on removal -+ * @param v the value - does not claim ownership -+ * @return non-zero for successful insertion -+ * -+ * This function will cause the table to expand if the insertion would take -+ * the ratio of entries to table size over the maximum load factor. -+ * -+ * This function does not check for repeated insertions with a duplicate key. -+ * The value returned when using a duplicate key is undefined -- when -+ * the hashtable changes size, the order of retrieval of duplicate key -+ * entries is reversed. -+ * If in doubt, remove before insert. -+ */ -+ -+int -+hashtable_insert(struct hashtable *h, void *k, void *v); -+ -+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ -+int fnname (struct hashtable *h, keytype *k, valuetype *v) \ -+{ \ -+ return hashtable_insert(h,k,v); \ -+} -+ -+/***************************************************************************** -+ * hashtable_search -+ -+ * @name hashtable_search -+ * @param h the hashtable to search -+ * @param k the key to search for - does not claim ownership -+ * @return the value associated with the key, or NULL if none found -+ */ -+ -+void * -+hashtable_search(struct hashtable *h, void *k); -+ -+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ -+valuetype * fnname (struct hashtable *h, keytype *k) \ -+{ \ -+ return (valuetype *) (hashtable_search(h,k)); \ -+} -+ -+/***************************************************************************** -+ * hashtable_remove -+ -+ * @name hashtable_remove -+ * @param h the hashtable to remove the item from -+ * @param k the key to search for - does not claim ownership -+ * @return the value associated with the key, or NULL if none found -+ */ -+ -+void * /* returns value */ -+hashtable_remove(struct hashtable *h, void *k); -+ -+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ -+valuetype * fnname (struct hashtable *h, keytype *k) \ -+{ \ -+ return (valuetype *) (hashtable_remove(h,k)); \ -+} -+ -+ -+/***************************************************************************** -+ * hashtable_count -+ -+ * @name hashtable_count -+ * @param h the hashtable -+ * @return the number of items stored in the hashtable -+ */ -+unsigned int -+hashtable_count(struct hashtable *h); -+ -+ -+/***************************************************************************** -+ * hashtable_destroy -+ -+ * @name hashtable_destroy -+ * @param h the hashtable -+ * @param free_values whether to call 'free' on the remaining values -+ */ -+ -+void -+hashtable_destroy(struct hashtable *h, int free_values); -+ -+#endif /* __HASHTABLE_CWC22_H__ */ -+ -+/* -+ * Copyright (c) 2002, Christopher Clark -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * * Neither the name of the original author; nor the names of any contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,188 @@ -+/* Copyright (C) 2002, 2004 Christopher Clark */ -+ -+#include "hashtable.h" -+#include "hashtable_private.h" -+#include "hashtable_itr.h" -+#include /* defines NULL */ -+ -+/*****************************************************************************/ -+/* hashtable_iterator - iterator constructor */ -+ -+struct hashtable_itr * -+hashtable_iterator(struct hashtable *h) -+{ -+ unsigned int i, tablelength; -+ struct hashtable_itr *itr = (struct hashtable_itr *) -+ malloc(sizeof(struct hashtable_itr)); -+ if (NULL == itr) return NULL; -+ itr->h = h; -+ itr->e = NULL; -+ itr->parent = NULL; -+ tablelength = h->tablelength; -+ itr->index = tablelength; -+ if (0 == h->entrycount) return itr; -+ -+ for (i = 0; i < tablelength; i++) -+ { -+ if (NULL != h->table[i]) -+ { -+ itr->e = h->table[i]; -+ itr->index = i; -+ break; -+ } -+ } -+ return itr; -+} -+ -+/*****************************************************************************/ -+/* key - return the key of the (key,value) pair at the current position */ -+/* value - return the value of the (key,value) pair at the current position */ -+ -+void * -+hashtable_iterator_key(struct hashtable_itr *i) -+{ return i->e->k; } -+ -+void * -+hashtable_iterator_value(struct hashtable_itr *i) -+{ return i->e->v; } -+ -+/*****************************************************************************/ -+/* advance - advance the iterator to the next element -+ * returns zero if advanced to end of table */ -+ -+int -+hashtable_iterator_advance(struct hashtable_itr *itr) -+{ -+ unsigned int j,tablelength; -+ struct entry **table; -+ struct entry *next; -+ if (NULL == itr->e) return 0; /* stupidity check */ -+ -+ next = itr->e->next; -+ if (NULL != next) -+ { -+ itr->parent = itr->e; -+ itr->e = next; -+ return -1; -+ } -+ tablelength = itr->h->tablelength; -+ itr->parent = NULL; -+ if (tablelength <= (j = ++(itr->index))) -+ { -+ itr->e = NULL; -+ return 0; -+ } -+ table = itr->h->table; -+ while (NULL == (next = table[j])) -+ { -+ if (++j >= tablelength) -+ { -+ itr->index = tablelength; -+ itr->e = NULL; -+ return 0; -+ } -+ } -+ itr->index = j; -+ itr->e = next; -+ return -1; -+} -+ -+/*****************************************************************************/ -+/* remove - remove the entry at the current iterator position -+ * and advance the iterator, if there is a successive -+ * element. -+ * If you want the value, read it before you remove: -+ * beware memory leaks if you don't. -+ * Returns zero if end of iteration. */ -+ -+int -+hashtable_iterator_remove(struct hashtable_itr *itr) -+{ -+ struct entry *remember_e, *remember_parent; -+ int ret; -+ -+ /* Do the removal */ -+ if (NULL == (itr->parent)) -+ { -+ /* element is head of a chain */ -+ itr->h->table[itr->index] = itr->e->next; -+ } else { -+ /* element is mid-chain */ -+ itr->parent->next = itr->e->next; -+ } -+ /* itr->e is now outside the hashtable */ -+ remember_e = itr->e; -+ itr->h->entrycount--; -+ freekey(remember_e->k); -+ -+ /* Advance the iterator, correcting the parent */ -+ remember_parent = itr->parent; -+ ret = hashtable_iterator_advance(itr); -+ if (itr->parent == remember_e) { itr->parent = remember_parent; } -+ free(remember_e); -+ return ret; -+} -+ -+/*****************************************************************************/ -+int /* returns zero if not found */ -+hashtable_iterator_search(struct hashtable_itr *itr, -+ struct hashtable *h, void *k) -+{ -+ struct entry *e, *parent; -+ unsigned int hashvalue, index; -+ -+ hashvalue = hash(h,k); -+ index = indexFor(h->tablelength,hashvalue); -+ -+ e = h->table[index]; -+ parent = NULL; -+ while (NULL != e) -+ { -+ /* Check hash value to short circuit heavier comparison */ -+ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) -+ { -+ itr->index = index; -+ itr->e = e; -+ itr->parent = parent; -+ itr->h = h; -+ return -1; -+ } -+ parent = e; -+ e = e->next; -+ } -+ return 0; -+} -+ -+ -+/* -+ * Copyright (c) 2002, 2004, Christopher Clark -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * * Neither the name of the original author; nor the names of any contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_itr.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,112 @@ -+/* Copyright (C) 2002, 2004 Christopher Clark */ -+ -+#ifndef __HASHTABLE_ITR_CWC22__ -+#define __HASHTABLE_ITR_CWC22__ -+#include "hashtable.h" -+#include "hashtable_private.h" /* needed to enable inlining */ -+ -+/*****************************************************************************/ -+/* This struct is only concrete here to allow the inlining of two of the -+ * accessor functions. */ -+struct hashtable_itr -+{ -+ struct hashtable *h; -+ struct entry *e; -+ struct entry *parent; -+ unsigned int index; -+}; -+ -+ -+/*****************************************************************************/ -+/* hashtable_iterator -+ */ -+ -+struct hashtable_itr * -+hashtable_iterator(struct hashtable *h); -+ -+/*****************************************************************************/ -+/* hashtable_iterator_key -+ * - return the value of the (key,value) pair at the current position */ -+ -+extern inline void * -+hashtable_iterator_key(struct hashtable_itr *i) -+{ -+ return i->e->k; -+} -+ -+/*****************************************************************************/ -+/* value - return the value of the (key,value) pair at the current position */ -+ -+extern inline void * -+hashtable_iterator_value(struct hashtable_itr *i) -+{ -+ return i->e->v; -+} -+ -+/*****************************************************************************/ -+/* advance - advance the iterator to the next element -+ * returns zero if advanced to end of table */ -+ -+int -+hashtable_iterator_advance(struct hashtable_itr *itr); -+ -+/*****************************************************************************/ -+/* remove - remove current element and advance the iterator to the next element -+ * NB: if you need the value to free it, read it before -+ * removing. ie: beware memory leaks! -+ * returns zero if advanced to end of table */ -+ -+int -+hashtable_iterator_remove(struct hashtable_itr *itr); -+ -+/*****************************************************************************/ -+/* search - overwrite the supplied iterator, to point to the entry -+ * matching the supplied key. -+ h points to the hashtable to be searched. -+ * returns zero if not found. */ -+int -+hashtable_iterator_search(struct hashtable_itr *itr, -+ struct hashtable *h, void *k); -+ -+#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ -+int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \ -+{ \ -+ return (hashtable_iterator_search(i,h,k)); \ -+} -+ -+ -+ -+#endif /* __HASHTABLE_ITR_CWC22__*/ -+ -+/* -+ * Copyright (c) 2002, 2004, Christopher Clark -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * * Neither the name of the original author; nor the names of any contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_private.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_private.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/hashtable/hashtable_private.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/hashtable/hashtable_private.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,85 @@ -+/* Copyright (C) 2002, 2004 Christopher Clark */ -+ -+#ifndef __HASHTABLE_PRIVATE_CWC22_H__ -+#define __HASHTABLE_PRIVATE_CWC22_H__ -+ -+#include "hashtable.h" -+ -+/*****************************************************************************/ -+struct entry -+{ -+ void *k, *v; -+ unsigned int h; -+ struct entry *next; -+}; -+ -+struct hashtable { -+ unsigned int tablelength; -+ struct entry **table; -+ unsigned int entrycount; -+ unsigned int loadlimit; -+ unsigned int primeindex; -+ unsigned int (*hashfn) (void *k); -+ int (*eqfn) (void *k1, void *k2); -+}; -+ -+/*****************************************************************************/ -+unsigned int -+hash(struct hashtable *h, void *k); -+ -+/*****************************************************************************/ -+/* indexFor */ -+static inline unsigned int -+indexFor(unsigned int tablelength, unsigned int hashvalue) { -+ return (hashvalue % tablelength); -+}; -+ -+/* Only works if tablelength == 2^N */ -+/*static inline unsigned int -+indexFor(unsigned int tablelength, unsigned int hashvalue) -+{ -+ return (hashvalue & (tablelength - 1u)); -+} -+*/ -+ -+/*****************************************************************************/ -+#define freekey(X) free(X) -+/*define freekey(X) ; */ -+ -+ -+/*****************************************************************************/ -+ -+#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/ -+ -+/* -+ * Copyright (c) 2002, Christopher Clark -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * * Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * * Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * * Neither the name of the original author; nor the names of any contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+*/ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/key.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/key.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/key.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/key.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,511 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This header contains various key-related definitions and helper function. -+ * UBIFS allows several key schemes, so we access key fields only via these -+ * helpers. At the moment only one key scheme is supported. -+ * -+ * Simple key scheme -+ * ~~~~~~~~~~~~~~~~~ -+ * -+ * Keys are 64-bits long. First 32-bits are inode number (parent inode number -+ * in case of direntry key). Next 3 bits are node type. The last 29 bits are -+ * 4KiB offset in case of inode node, and direntry hash in case of a direntry -+ * node. We use "r5" hash borrowed from reiserfs. -+ */ -+ -+#ifndef __UBIFS_KEY_H__ -+#define __UBIFS_KEY_H__ -+ -+/** -+ * key_r5_hash - R5 hash function (borrowed from reiserfs). -+ * @s: direntry name -+ * @len: name length -+ */ -+static inline uint32_t key_r5_hash(const char *s, int len) -+{ -+ uint32_t a = 0; -+ const signed char *str = (const signed char *)s; -+ -+ while (*str) { -+ a += *str << 4; -+ a += *str >> 4; -+ a *= 11; -+ str++; -+ } -+ -+ a &= UBIFS_S_KEY_HASH_MASK; -+ -+ /* -+ * We use hash values as offset in directories, so values %0 and %1 are -+ * reserved for "." and "..". %2 is reserved for possible future use. -+ */ -+ if (unlikely(a >= 0 && a <= 2)) -+ a += 3; -+ return a; -+} -+ -+/** -+ * key_test_hash - testing hash function. -+ * @str: direntry name -+ * @len: name length -+ */ -+static inline uint32_t key_test_hash(const char *str, int len) -+{ -+ uint32_t a = 0; -+ -+ len = min_t(uint32_t, len, 4); -+ memcpy(&a, str, len); -+ a &= UBIFS_S_KEY_HASH_MASK; -+ if (unlikely(a >= 0 && a <= 2)) -+ a += 3; -+ return a; -+} -+ -+/** -+ * ino_key_init - initialize inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void ino_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * ino_key_init_flash - initialize on-flash inode key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ */ -+static inline void ino_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum) -+{ -+ union ubifs_key *key = k; -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(UBIFS_INO_KEY << UBIFS_S_KEY_BLOCK_BITS); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_ino_key - get the lowest possible inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void lowest_ino_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = 0; -+} -+ -+/** -+ * highest_ino_key - get the highest possible inode key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void highest_ino_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = 0xffffffff; -+} -+ -+/** -+ * dent_key_init - initialize directory entry key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: parent inode number -+ * @nm: direntry name and length -+ */ -+static inline void dent_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ const struct qstr *nm) -+{ -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * dent_key_init_hash - initialize directory entry key without re-calculating -+ * hash function. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: parent inode number -+ * @hash: direntry name hash -+ */ -+static inline void dent_key_init_hash(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ uint32_t hash) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * dent_key_init_flash - initialize on-flash directory entry key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: parent inode number -+ * @nm: direntry name and length -+ */ -+static inline void dent_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, const struct qstr *nm) -+{ -+ union ubifs_key *key = k; -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(hash | -+ (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_dent_key - get the lowest possible directory entry key. -+ * @c: UBIFS file-system description object -+ * @key: where to store the lowest key -+ * @inum: parent inode number -+ */ -+static inline void lowest_dent_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS; -+} -+ -+/** -+ * xent_key_init - initialize extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: host inode number -+ * @nm: extended attribute entry name and length -+ */ -+static inline void xent_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ const struct qstr *nm) -+{ -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * xent_key_init_hash - initialize extended attribute entry key without -+ * re-calculating hash function. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: host inode number -+ * @hash: extended attribute entry name hash -+ */ -+static inline void xent_key_init_hash(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ uint32_t hash) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); -+} -+ -+/** -+ * xent_key_init_flash - initialize on-flash extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: host inode number -+ * @nm: extended attribute entry name and length -+ */ -+static inline void xent_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, const struct qstr *nm) -+{ -+ union ubifs_key *key = k; -+ uint32_t hash = c->key_hash(nm->name, nm->len); -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(hash | -+ (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * lowest_xent_key - get the lowest possible extended attribute entry key. -+ * @c: UBIFS file-system description object -+ * @key: where to store the lowest key -+ * @inum: host inode number -+ */ -+static inline void lowest_xent_key(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS; -+} -+ -+/** -+ * data_key_init - initialize data key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ * @block: block number -+ */ -+static inline void data_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum, -+ unsigned int block) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS); -+} -+ -+/** -+ * data_key_init_flash - initialize on-flash data key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ * @block: block number -+ */ -+static inline void data_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum, unsigned int block) -+{ -+ union ubifs_key *key = k; -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(block | -+ (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS)); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * trun_key_init - initialize truncation node key. -+ * @c: UBIFS file-system description object -+ * @key: key to initialize -+ * @inum: inode number -+ */ -+static inline void trun_key_init(const struct ubifs_info *c, -+ union ubifs_key *key, ino_t inum) -+{ -+ key->u32[0] = inum; -+ key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * trun_key_init_flash - initialize on-flash truncation node key. -+ * @c: UBIFS file-system description object -+ * @k: key to initialize -+ * @inum: inode number -+ */ -+static inline void trun_key_init_flash(const struct ubifs_info *c, void *k, -+ ino_t inum) -+{ -+ union ubifs_key *key = k; -+ -+ key->j32[0] = cpu_to_le32(inum); -+ key->j32[1] = cpu_to_le32(UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS); -+ memset(k + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * key_type - get key type. -+ * @c: UBIFS file-system description object -+ * @key: key to get type of -+ */ -+static inline int key_type(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * key_type_flash - get type of a on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: key to get type of -+ */ -+static inline int key_type_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->u32[1]) >> UBIFS_S_KEY_BLOCK_BITS; -+} -+ -+/** -+ * key_ino - fetch inode number from key. -+ * @c: UBIFS file-system description object -+ * @k: key to fetch inode number from -+ */ -+static inline ino_t key_ino(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return key->u32[0]; -+} -+ -+/** -+ * key_ino_flash - fetch inode number from an on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: key to fetch inode number from -+ */ -+static inline ino_t key_ino_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->j32[0]); -+} -+ -+/** -+ * key_hash - get directory entry hash. -+ * @c: UBIFS file-system description object -+ * @key: the key to get hash from -+ */ -+static inline int key_hash(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] & UBIFS_S_KEY_HASH_MASK; -+} -+ -+/** -+ * key_hash_flash - get directory entry hash from an on-flash formatted key. -+ * @c: UBIFS file-system description object -+ * @k: the key to get hash from -+ */ -+static inline int key_hash_flash(const struct ubifs_info *c, const void *k) -+{ -+ const union ubifs_key *key = k; -+ -+ return le32_to_cpu(key->j32[1]) & UBIFS_S_KEY_HASH_MASK; -+} -+ -+/** -+ * key_block - get data block number. -+ * @c: UBIFS file-system description object -+ * @key: the key to get the block number from -+ */ -+static inline unsigned int key_block(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK; -+} -+ -+/** -+ * key_read - transform a key to in-memory format. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_read(const struct ubifs_info *c, const void *from, -+ union ubifs_key *to) -+{ -+ const union ubifs_key *f = from; -+ -+ to->u32[0] = le32_to_cpu(f->j32[0]); -+ to->u32[1] = le32_to_cpu(f->j32[1]); -+} -+ -+/** -+ * key_write - transform a key from in-memory format. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_write(const struct ubifs_info *c, -+ const union ubifs_key *from, void *to) -+{ -+ union ubifs_key *t = to; -+ -+ t->j32[0] = cpu_to_le32(from->u32[0]); -+ t->j32[1] = cpu_to_le32(from->u32[1]); -+ memset(to + 8, 0, UBIFS_MAX_KEY_LEN - 8); -+} -+ -+/** -+ * key_write_idx - transform a key from in-memory format for the index. -+ * @c: UBIFS file-system description object -+ * @from: the key to transform -+ * @to: the key to store the result -+ */ -+static inline void key_write_idx(const struct ubifs_info *c, -+ const union ubifs_key *from, void *to) -+{ -+ union ubifs_key *t = to; -+ -+ t->j32[0] = cpu_to_le32(from->u32[0]); -+ t->j32[1] = cpu_to_le32(from->u32[1]); -+} -+ -+/** -+ * key_copy - copy a key. -+ * @c: UBIFS file-system description object -+ * @from: the key to copy from -+ * @to: the key to copy to -+ */ -+static inline void key_copy(const struct ubifs_info *c, -+ const union ubifs_key *from, union ubifs_key *to) -+{ -+ to->u64[0] = from->u64[0]; -+} -+ -+/** -+ * keys_cmp - compare keys. -+ * @c: UBIFS file-system description object -+ * @key1: the first key to compare -+ * @key2: the second key to compare -+ * -+ * This function compares 2 keys and returns %-1 if @key1 is less than -+ * @key2, 0 if the keys are equivalent and %1 if @key1 is greater than @key2. -+ */ -+static inline int keys_cmp(const struct ubifs_info *c, -+ const union ubifs_key *key1, -+ const union ubifs_key *key2) -+{ -+ if (key1->u32[0] < key2->u32[0]) -+ return -1; -+ if (key1->u32[0] > key2->u32[0]) -+ return 1; -+ if (key1->u32[1] < key2->u32[1]) -+ return -1; -+ if (key1->u32[1] > key2->u32[1]) -+ return 1; -+ -+ return 0; -+} -+ -+/** -+ * is_hash_key - is a key vulnerable to hash collisions. -+ * @c: UBIFS file-system description object -+ * @key: key -+ * -+ * This function returns %1 if @key is a hashed key or %0 otherwise. -+ */ -+static inline int is_hash_key(const struct ubifs_info *c, -+ const union ubifs_key *key) -+{ -+ int type = key_type(c, key); -+ -+ return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY; -+} -+ -+#endif /* !__UBIFS_KEY_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lpt.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lpt.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lpt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lpt.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,577 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006, 2007 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy -+ */ -+ -+#include "mkfs.ubifs.h" -+ -+/** -+ * do_calc_lpt_geom - calculate sizes for the LPT area. -+ * @c: the UBIFS file-system description object -+ * -+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the -+ * properties of the flash and whether LPT is "big" (c->big_lpt). -+ */ -+static void do_calc_lpt_geom(struct ubifs_info *c) -+{ -+ int n, bits, per_leb_wastage; -+ long long sz, tot_wastage; -+ -+ c->pnode_cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT; -+ -+ n = (c->pnode_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT; -+ c->nnode_cnt = n; -+ while (n > 1) { -+ n = (n + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT; -+ c->nnode_cnt += n; -+ } -+ -+ c->lpt_hght = 1; -+ n = UBIFS_LPT_FANOUT; -+ while (n < c->pnode_cnt) { -+ c->lpt_hght += 1; -+ n <<= UBIFS_LPT_FANOUT_SHIFT; -+ } -+ -+ c->space_bits = fls(c->leb_size) - 3; -+ c->lpt_lnum_bits = fls(c->lpt_lebs); -+ c->lpt_offs_bits = fls(c->leb_size - 1); -+ c->lpt_spc_bits = fls(c->leb_size); -+ -+ n = (c->max_leb_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT; -+ c->pcnt_bits = fls(n - 1); -+ -+ c->lnum_bits = fls(c->max_leb_cnt - 1); -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ (c->big_lpt ? c->pcnt_bits : 0) + -+ (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT; -+ c->pnode_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ (c->big_lpt ? c->pcnt_bits : 0) + -+ (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT; -+ c->nnode_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ c->lpt_lebs * c->lpt_spc_bits * 2; -+ c->ltab_sz = (bits + 7) / 8; -+ -+ bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS + -+ c->lnum_bits * c->lsave_cnt; -+ c->lsave_sz = (bits + 7) / 8; -+ -+ /* Calculate the minimum LPT size */ -+ c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; -+ c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz; -+ c->lpt_sz += c->ltab_sz; -+ c->lpt_sz += c->lsave_sz; -+ -+ /* Add wastage */ -+ sz = c->lpt_sz; -+ per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz); -+ sz += per_leb_wastage; -+ tot_wastage = per_leb_wastage; -+ while (sz > c->leb_size) { -+ sz += per_leb_wastage; -+ sz -= c->leb_size; -+ tot_wastage += per_leb_wastage; -+ } -+ tot_wastage += ALIGN(sz, c->min_io_size) - sz; -+ c->lpt_sz += tot_wastage; -+} -+ -+/** -+ * calc_dflt_lpt_geom - calculate default LPT geometry. -+ * @c: the UBIFS file-system description object -+ * @main_lebs: number of main area LEBs is passed and returned here -+ * @big_lpt: whether the LPT area is "big" is returned here -+ * -+ * The size of the LPT area depends on parameters that themselves are dependent -+ * on the size of the LPT area. This function, successively recalculates the LPT -+ * area geometry until the parameters and resultant geometry are consistent. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt) -+{ -+ int i, lebs_needed; -+ long long sz; -+ -+ /* Start by assuming the minimum number of LPT LEBs */ -+ c->lpt_lebs = UBIFS_MIN_LPT_LEBS; -+ c->main_lebs = *main_lebs - c->lpt_lebs; -+ if (c->main_lebs <= 0) -+ return -EINVAL; -+ -+ /* And assume we will use the small LPT model */ -+ c->big_lpt = 0; -+ -+ /* -+ * Calculate the geometry based on assumptions above and then see if it -+ * makes sense -+ */ -+ do_calc_lpt_geom(c); -+ -+ /* Small LPT model must have lpt_sz < leb_size */ -+ if (c->lpt_sz > c->leb_size) { -+ /* Nope, so try again using big LPT model */ -+ c->big_lpt = 1; -+ do_calc_lpt_geom(c); -+ } -+ -+ /* Now check there are enough LPT LEBs */ -+ for (i = 0; i < 64 ; i++) { -+ sz = c->lpt_sz * 4; /* Allow 4 times the size */ -+ sz += c->leb_size - 1; -+ do_div(sz, c->leb_size); -+ lebs_needed = sz; -+ if (lebs_needed > c->lpt_lebs) { -+ /* Not enough LPT LEBs so try again with more */ -+ c->lpt_lebs = lebs_needed; -+ c->main_lebs = *main_lebs - c->lpt_lebs; -+ if (c->main_lebs <= 0) -+ return -EINVAL; -+ do_calc_lpt_geom(c); -+ continue; -+ } -+ if (c->ltab_sz > c->leb_size) { -+ err_msg("LPT ltab too big"); -+ return -EINVAL; -+ } -+ *main_lebs = c->main_lebs; -+ *big_lpt = c->big_lpt; -+ return 0; -+ } -+ return -EINVAL; -+} -+ -+/** -+ * pack_bits - pack bit fields end-to-end. -+ * @addr: address at which to pack (passed and next address returned) -+ * @pos: bit position at which to pack (passed and next position returned) -+ * @val: value to pack -+ * @nrbits: number of bits of value to pack (1-32) -+ */ -+static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits) -+{ -+ uint8_t *p = *addr; -+ int b = *pos; -+ -+ if (b) { -+ *p |= ((uint8_t)val) << b; -+ nrbits += b; -+ if (nrbits > 8) { -+ *++p = (uint8_t)(val >>= (8 - b)); -+ if (nrbits > 16) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 24) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 32) -+ *++p = (uint8_t)(val >>= 8); -+ } -+ } -+ } -+ } else { -+ *p = (uint8_t)val; -+ if (nrbits > 8) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 16) { -+ *++p = (uint8_t)(val >>= 8); -+ if (nrbits > 24) -+ *++p = (uint8_t)(val >>= 8); -+ } -+ } -+ } -+ b = nrbits & 7; -+ if (b == 0) -+ p++; -+ *addr = p; -+ *pos = b; -+} -+ -+/** -+ * pack_pnode - pack all the bit fields of a pnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @pnode: pnode to pack -+ */ -+static void pack_pnode(struct ubifs_info *c, void *buf, -+ struct ubifs_pnode *pnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS); -+ if (c->big_lpt) -+ pack_bits(&addr, &pos, pnode->num, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ pack_bits(&addr, &pos, pnode->lprops[i].free >> 3, -+ c->space_bits); -+ pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3, -+ c->space_bits); -+ if (pnode->lprops[i].flags & LPROPS_INDEX) -+ pack_bits(&addr, &pos, 1, 1); -+ else -+ pack_bits(&addr, &pos, 0, 1); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->pnode_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * pack_nnode - pack all the bit fields of a nnode. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @nnode: nnode to pack -+ */ -+static void pack_nnode(struct ubifs_info *c, void *buf, -+ struct ubifs_nnode *nnode) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS); -+ if (c->big_lpt) -+ pack_bits(&addr, &pos, nnode->num, c->pcnt_bits); -+ for (i = 0; i < UBIFS_LPT_FANOUT; i++) { -+ int lnum = nnode->nbranch[i].lnum; -+ -+ if (lnum == 0) -+ lnum = c->lpt_last + 1; -+ pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits); -+ pack_bits(&addr, &pos, nnode->nbranch[i].offs, -+ c->lpt_offs_bits); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->nnode_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * pack_ltab - pack the LPT's own lprops table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @ltab: LPT's own lprops table to pack -+ */ -+static void pack_ltab(struct ubifs_info *c, void *buf, -+ struct ubifs_lpt_lprops *ltab) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS); -+ for (i = 0; i < c->lpt_lebs; i++) { -+ pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits); -+ pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits); -+ } -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->ltab_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * pack_lsave - pack the LPT's save table. -+ * @c: UBIFS file-system description object -+ * @buf: buffer into which to pack -+ * @lsave: LPT's save table to pack -+ */ -+static void pack_lsave(struct ubifs_info *c, void *buf, int *lsave) -+{ -+ uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; -+ int i, pos = 0; -+ uint16_t crc; -+ -+ pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS); -+ for (i = 0; i < c->lsave_cnt; i++) -+ pack_bits(&addr, &pos, lsave[i], c->lnum_bits); -+ crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES, -+ c->lsave_sz - UBIFS_LPT_CRC_BYTES); -+ addr = buf; -+ pos = 0; -+ pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS); -+} -+ -+/** -+ * set_ltab - set LPT LEB properties. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @free: amount of free space -+ * @dirty: amount of dirty space -+ */ -+static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty) -+{ -+ dbg_msg(3, "LEB %d free %d dirty %d to %d %d", -+ lnum, c->ltab[lnum - c->lpt_first].free, -+ c->ltab[lnum - c->lpt_first].dirty, free, dirty); -+ c->ltab[lnum - c->lpt_first].free = free; -+ c->ltab[lnum - c->lpt_first].dirty = dirty; -+} -+ -+/** -+ * calc_nnode_num - calculate nnode number. -+ * @row: the row in the tree (root is zero) -+ * @col: the column in the row (leftmost is zero) -+ * -+ * The nnode number is a number that uniquely identifies a nnode and can be used -+ * easily to traverse the tree from the root to that nnode. -+ * -+ * This function calculates and returns the nnode number for the nnode at @row -+ * and @col. -+ */ -+static int calc_nnode_num(int row, int col) -+{ -+ int num, bits; -+ -+ num = 1; -+ while (row--) { -+ bits = (col & (UBIFS_LPT_FANOUT - 1)); -+ col >>= UBIFS_LPT_FANOUT_SHIFT; -+ num <<= UBIFS_LPT_FANOUT_SHIFT; -+ num |= bits; -+ } -+ return num; -+} -+ -+/** -+ * create_lpt - create LPT. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int create_lpt(struct ubifs_info *c) -+{ -+ int lnum, err = 0, i, j, cnt, len, alen, row; -+ int blnum, boffs, bsz, bcnt; -+ struct ubifs_pnode *pnode = NULL; -+ struct ubifs_nnode *nnode = NULL; -+ void *buf = NULL, *p; -+ int *lsave = NULL; -+ -+ pnode = malloc(sizeof(struct ubifs_pnode)); -+ nnode = malloc(sizeof(struct ubifs_nnode)); -+ buf = malloc(c->leb_size); -+ lsave = malloc(sizeof(int) * c->lsave_cnt); -+ if (!pnode || !nnode || !buf || !lsave) { -+ err = -ENOMEM; -+ goto out; -+ } -+ memset(pnode, 0 , sizeof(struct ubifs_pnode)); -+ memset(nnode, 0 , sizeof(struct ubifs_pnode)); -+ -+ c->lscan_lnum = c->main_first; -+ -+ lnum = c->lpt_first; -+ p = buf; -+ len = 0; -+ /* Number of leaf nodes (pnodes) */ -+ cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) >> UBIFS_LPT_FANOUT_SHIFT; -+ //printf("pnode_cnt=%d\n",cnt); -+ -+ /* -+ * To calculate the internal node branches, we keep information about -+ * the level below. -+ */ -+ blnum = lnum; /* LEB number of level below */ -+ boffs = 0; /* Offset of level below */ -+ bcnt = cnt; /* Number of nodes in level below */ -+ bsz = c->pnode_sz; /* Size of nodes in level below */ -+ -+ /* Add pnodes */ -+ for (i = 0; i < cnt; i++) { -+ if (len + c->pnode_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = write_leb(lnum++, alen, buf); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ /* Fill in the pnode */ -+ for (j = 0; j < UBIFS_LPT_FANOUT; j++) { -+ int k = (i << UBIFS_LPT_FANOUT_SHIFT) + j; -+ -+ if (k < c->main_lebs) -+ pnode->lprops[j] = c->lpt[k]; -+ else { -+ pnode->lprops[j].free = c->leb_size; -+ pnode->lprops[j].dirty = 0; -+ pnode->lprops[j].flags = 0; -+ } -+ } -+ pack_pnode(c, p, pnode); -+ p += c->pnode_sz; -+ len += c->pnode_sz; -+ /* -+ * pnodes are simply numbered left to right starting at zero, -+ * which means the pnode number can be used easily to traverse -+ * down the tree to the corresponding pnode. -+ */ -+ pnode->num += 1; -+ } -+ -+ row = c->lpt_hght - 1; -+ /* Add all nnodes, one level at a time */ -+ while (1) { -+ /* Number of internal nodes (nnodes) at next level */ -+ cnt = (cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT; -+ if (cnt == 0) -+ cnt = 1; -+ for (i = 0; i < cnt; i++) { -+ if (len + c->nnode_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, -+ alen - len); -+ memset(p, 0xff, alen - len); -+ err = write_leb(lnum++, alen, buf); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ /* The root is on row zero */ -+ if (row == 0) { -+ c->lpt_lnum = lnum; -+ c->lpt_offs = len; -+ } -+ /* Set branches to the level below */ -+ for (j = 0; j < UBIFS_LPT_FANOUT; j++) { -+ if (bcnt) { -+ if (boffs + bsz > c->leb_size) { -+ blnum += 1; -+ boffs = 0; -+ } -+ nnode->nbranch[j].lnum = blnum; -+ nnode->nbranch[j].offs = boffs; -+ boffs += bsz; -+ bcnt--; -+ } else { -+ nnode->nbranch[j].lnum = 0; -+ nnode->nbranch[j].offs = 0; -+ } -+ } -+ nnode->num = calc_nnode_num(row, i); -+ pack_nnode(c, p, nnode); -+ p += c->nnode_sz; -+ len += c->nnode_sz; -+ } -+ /* Row zero is the top row */ -+ if (row == 0) -+ break; -+ /* Update the information about the level below */ -+ bcnt = cnt; -+ bsz = c->nnode_sz; -+ row -= 1; -+ } -+ -+ if (c->big_lpt) { -+ /* Need to add LPT's save table */ -+ if (len + c->lsave_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = write_leb(lnum++, alen, buf); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ -+ c->lsave_lnum = lnum; -+ c->lsave_offs = len; -+ -+ for (i = 0; i < c->lsave_cnt; i++) -+ lsave[i] = c->main_first + i; -+ -+ pack_lsave(c, p, lsave); -+ p += c->lsave_sz; -+ len += c->lsave_sz; -+ } -+ -+ /* Need to add LPT's own LEB properties table */ -+ if (len + c->ltab_sz > c->leb_size) { -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ memset(p, 0xff, alen - len); -+ err = write_leb(lnum++, alen, buf); -+ if (err) -+ goto out; -+ p = buf; -+ len = 0; -+ } -+ -+ c->ltab_lnum = lnum; -+ c->ltab_offs = len; -+ -+ /* Update ltab before packing it */ -+ len += c->ltab_sz; -+ alen = ALIGN(len, c->min_io_size); -+ set_ltab(c, lnum, c->leb_size - alen, alen - len); -+ -+ pack_ltab(c, p, c->ltab); -+ p += c->ltab_sz; -+ -+ /* Write remaining buffer */ -+ memset(p, 0xff, alen - len); -+ err = write_leb(lnum, alen, buf); -+ if (err) -+ goto out; -+ -+ c->nhead_lnum = lnum; -+ c->nhead_offs = ALIGN(len, c->min_io_size); -+ -+ dbg_msg(1, "space_bits: %d", c->space_bits); -+ dbg_msg(1, "lpt_lnum_bits: %d", c->lpt_lnum_bits); -+ dbg_msg(1, "lpt_offs_bits: %d", c->lpt_offs_bits); -+ dbg_msg(1, "lpt_spc_bits: %d", c->lpt_spc_bits); -+ dbg_msg(1, "pcnt_bits: %d", c->pcnt_bits); -+ dbg_msg(1, "lnum_bits: %d", c->lnum_bits); -+ dbg_msg(1, "pnode_sz: %d", c->pnode_sz); -+ dbg_msg(1, "nnode_sz: %d", c->nnode_sz); -+ dbg_msg(1, "ltab_sz: %d", c->ltab_sz); -+ dbg_msg(1, "lsave_sz: %d", c->lsave_sz); -+ dbg_msg(1, "lsave_cnt: %d", c->lsave_cnt); -+ dbg_msg(1, "lpt_hght: %d", c->lpt_hght); -+ dbg_msg(1, "big_lpt: %d", c->big_lpt); -+ dbg_msg(1, "LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs); -+ dbg_msg(1, "LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs); -+ dbg_msg(1, "LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs); -+ if (c->big_lpt) -+ dbg_msg(1, "LPT lsave is at %d:%d", -+ c->lsave_lnum, c->lsave_offs); -+out: -+ free(lsave); -+ free(buf); -+ free(nnode); -+ free(pnode); -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lpt.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lpt.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lpt.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lpt.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ */ -+ -+#ifndef __UBIFS_LPT_H__ -+#define __UBIFS_LPT_H__ -+ -+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt); -+int create_lpt(struct ubifs_info *c); -+ -+#endif -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,92 @@ -+/* lzo1.h -- public interface of the LZO1 compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1_H_INCLUDED -+#define __LZO1_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1_MEM_COMPRESS ((lzo_uint32) (8192L * lzo_sizeof_dict_t)) -+#define LZO1_MEM_DECOMPRESS (0) -+ -+ -+LZO_EXTERN(int) -+lzo1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+LZO_EXTERN(int) -+lzo1_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1_99_MEM_COMPRESS ((lzo_uint32) (65536L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1_99_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1a.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1a.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1a.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1a.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,92 @@ -+/* lzo1a.h -- public interface of the LZO1A compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1A_H_INCLUDED -+#define __LZO1A_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1A_MEM_COMPRESS ((lzo_uint32) (8192L * lzo_sizeof_dict_t)) -+#define LZO1A_MEM_DECOMPRESS (0) -+ -+ -+LZO_EXTERN(int) -+lzo1a_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+LZO_EXTERN(int) -+lzo1a_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1A_99_MEM_COMPRESS ((lzo_uint32) (65536L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1a_99_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1b.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1b.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1b.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1b.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* lzo1b.h -- public interface of the LZO1B compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1B_H_INCLUDED -+#define __LZO1B_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1B_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+#define LZO1B_MEM_DECOMPRESS (0) -+ -+ -+/* compression levels */ -+#define LZO1B_BEST_SPEED 1 -+#define LZO1B_BEST_COMPRESSION 9 -+#define LZO1B_DEFAULT_COMPRESSION (-1) /* fastest by default */ -+ -+ -+LZO_EXTERN(int) -+lzo1b_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem, -+ int compression_level ); -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1b_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1b_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1b_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_2_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_3_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_4_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_5_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_6_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_7_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_8_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1b_9_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1B_99_MEM_COMPRESS ((lzo_uint32) (65536L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1b_99_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+#define LZO1B_999_MEM_COMPRESS ((lzo_uint32) (3 * 65536L * sizeof(lzo_xint))) -+ -+LZO_EXTERN(int) -+lzo1b_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1c.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1c.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1c.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1c.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,156 @@ -+/* lzo1c.h -- public interface of the LZO1C compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1C_H_INCLUDED -+#define __LZO1C_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1C_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+#define LZO1C_MEM_DECOMPRESS (0) -+ -+ -+/* compression levels */ -+#define LZO1C_BEST_SPEED 1 -+#define LZO1C_BEST_COMPRESSION 9 -+#define LZO1C_DEFAULT_COMPRESSION (-1) /* fastest by default */ -+ -+ -+LZO_EXTERN(int) -+lzo1c_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem, -+ int compression_level ); -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1c_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1c_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1c_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_2_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_3_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_4_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_5_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_6_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_7_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_8_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+LZO_EXTERN(int) -+lzo1c_9_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1C_99_MEM_COMPRESS ((lzo_uint32) (65536L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1c_99_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+#define LZO1C_999_MEM_COMPRESS ((lzo_uint32) (5 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo1c_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1f.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1f.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1f.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1f.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,104 @@ -+/* lzo1f.h -- public interface of the LZO1F compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1F_H_INCLUDED -+#define __LZO1F_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1F_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+#define LZO1F_MEM_DECOMPRESS (0) -+ -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1f_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1f_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1f_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1F_999_MEM_COMPRESS ((lzo_uint32) (5 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo1f_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1x.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1x.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1x.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1x.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,173 @@ -+/* lzo1x.h -- public interface of the LZO1X compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1X_H_INCLUDED -+#define __LZO1X_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS -+#define LZO1X_MEM_DECOMPRESS (0) -+#define LZO1X_MEM_OPTIMIZE (0) -+ -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// special compressor versions -+************************************************************************/ -+ -+/* this version needs only 8 kB work memory */ -+#define LZO1X_1_11_MEM_COMPRESS ((lzo_uint32) (2048L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1x_1_11_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/* this version needs 16 kB work memory */ -+#define LZO1X_1_12_MEM_COMPRESS ((lzo_uint32) (4096L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1x_1_12_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/* use this version if you need a little more compression speed */ -+#define LZO1X_1_15_MEM_COMPRESS ((lzo_uint32) (32768L * lzo_sizeof_dict_t)) -+ -+LZO_EXTERN(int) -+lzo1x_1_15_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1X_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo1x_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1x_999_compress_dict ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+LZO_EXTERN(int) -+lzo1x_999_compress_level ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len, -+ lzo_callback_p cb, -+ int compression_level ); -+ -+LZO_EXTERN(int) -+lzo1x_decompress_dict_safe ( const lzo_bytep in, lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+ -+/*********************************************************************** -+// optimize a compressed data block -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1x_optimize ( lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1y.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1y.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1y.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1y.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,141 @@ -+/* lzo1y.h -- public interface of the LZO1Y compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1Y_H_INCLUDED -+#define __LZO1Y_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1Y_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+#define LZO1Y_MEM_DECOMPRESS (0) -+#define LZO1Y_MEM_OPTIMIZE (0) -+ -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1y_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1y_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1y_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1Y_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo1y_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1y_999_compress_dict ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+LZO_EXTERN(int) -+lzo1y_999_compress_level ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len, -+ lzo_callback_p cb, -+ int compression_level ); -+ -+LZO_EXTERN(int) -+lzo1y_decompress_dict_safe ( const lzo_bytep in, lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+ -+/*********************************************************************** -+// optimize a compressed data block -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1y_optimize ( lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1z.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1z.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1z.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo1z.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,146 @@ -+/* lzo1z.h -- public interface of the LZO1Z compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO1Z_H_INCLUDED -+#define __LZO1Z_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+/* Memory required for the wrkmem parameter. -+ * When the required size is 0, you can also pass a NULL pointer. -+ */ -+ -+#define LZO1Z_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) -+#define LZO1Z_MEM_DECOMPRESS (0) -+#define LZO1Z_MEM_OPTIMIZE (0) -+ -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo1z_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo1z_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+#if 0 -+/* not yet implemented */ -+LZO_EXTERN(int) -+lzo1z_1_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+#endif -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO1Z_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo1z_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+LZO_EXTERN(int) -+lzo1z_999_compress_dict ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+LZO_EXTERN(int) -+lzo1z_999_compress_level ( const lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len, -+ lzo_callback_p cb, -+ int compression_level ); -+ -+LZO_EXTERN(int) -+lzo1z_decompress_dict_safe ( const lzo_bytep in, lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+ -+/*********************************************************************** -+// optimize a compressed data block -+************************************************************************/ -+ -+#if 0 -+/* not yet implemented */ -+LZO_EXTERN(int) -+lzo1z_optimize ( lzo_bytep in , lzo_uint in_len, -+ lzo_bytep out, lzo_uintp out_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+#endif -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo2a.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo2a.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo2a.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo2a.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,88 @@ -+/* lzo2a.h -- public interface of the LZO2A compression algorithm -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO2A_H_INCLUDED -+#define __LZO2A_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// -+************************************************************************/ -+ -+#define LZO2A_MEM_DECOMPRESS (0) -+ -+/* decompression */ -+LZO_EXTERN(int) -+lzo2a_decompress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+/* safe decompression with overrun testing */ -+LZO_EXTERN(int) -+lzo2a_decompress_safe ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem /* NOT USED */ ); -+ -+ -+/*********************************************************************** -+// better compression ratio at the cost of more memory and time -+************************************************************************/ -+ -+#define LZO2A_999_MEM_COMPRESS ((lzo_uint32) (8 * 16384L * sizeof(short))) -+ -+LZO_EXTERN(int) -+lzo2a_999_compress ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo_asm.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo_asm.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo_asm.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzo_asm.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,135 @@ -+/* lzo_asm.h -- assembler prototypes for the LZO data compression library -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZO_ASM_H_INCLUDED -+#define __LZO_ASM_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// assembly decompressors -+************************************************************************/ -+ -+LZO_EXTERN(int) lzo1c_decompress_asm -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1c_decompress_asm_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+ -+LZO_EXTERN(int) lzo1f_decompress_asm_fast -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1f_decompress_asm_fast_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+ -+LZO_EXTERN(int) lzo1x_decompress_asm -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1x_decompress_asm_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1x_decompress_asm_fast -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1x_decompress_asm_fast_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+ -+LZO_EXTERN(int) lzo1y_decompress_asm -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1y_decompress_asm_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1y_decompress_asm_fast -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+LZO_EXTERN(int) lzo1y_decompress_asm_fast_safe -+ (const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem); -+ -+ -+/*********************************************************************** -+// checksum and misc functions -+************************************************************************/ -+ -+#if 0 -+ -+LZO_EXTERN(lzo_uint32) -+lzo_crc32_asm(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len, -+ const lzo_uint32p _crc_table); -+ -+LZO_EXTERN(lzo_uint32) -+lzo_crc32_asm_small(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len); -+ -+LZO_EXTERN(int) -+lzo_cpuid_asm(lzo_uint32p /* lzo_uint32 info[16] */ ); -+ -+LZO_EXTERN(lzo_uint32) -+lzo_rdtsc_asm(lzo_uint32p /* lzo_uint32 ticks[2] */ ); -+ -+#endif -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoconf.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoconf.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoconf.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoconf.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,413 @@ -+/* lzoconf.h -- configuration for the LZO real-time data compression library -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZOCONF_H_INCLUDED -+#define __LZOCONF_H_INCLUDED -+ -+#define LZO_VERSION 0x2020 -+#define LZO_VERSION_STRING "2.02" -+#define LZO_VERSION_DATE "Oct 17 2005" -+ -+/* internal Autoconf configuration file - only used when building LZO */ -+#if defined(LZO_HAVE_CONFIG_H) -+# include -+#endif -+#include -+#include -+ -+ -+/*********************************************************************** -+// LZO requires a conforming -+************************************************************************/ -+ -+#if !defined(CHAR_BIT) || (CHAR_BIT != 8) -+# error "invalid CHAR_BIT" -+#endif -+#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) -+# error "check your compiler installation" -+#endif -+#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) -+# error "your limits.h macros are broken" -+#endif -+ -+/* get OS and architecture defines */ -+#ifndef __LZODEFS_H_INCLUDED -+#include "lzodefs.h" -+#endif -+ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// some core defines -+************************************************************************/ -+ -+#if !defined(LZO_UINT32_C) -+# if (UINT_MAX < LZO_0xffffffffL) -+# define LZO_UINT32_C(c) c ## UL -+# else -+# define LZO_UINT32_C(c) ((c) + 0U) -+# endif -+#endif -+ -+/* memory checkers */ -+#if !defined(__LZO_CHECKER) -+# if defined(__BOUNDS_CHECKING_ON) -+# define __LZO_CHECKER 1 -+# elif defined(__CHECKER__) -+# define __LZO_CHECKER 1 -+# elif defined(__INSURE__) -+# define __LZO_CHECKER 1 -+# elif defined(__PURIFY__) -+# define __LZO_CHECKER 1 -+# endif -+#endif -+ -+ -+/*********************************************************************** -+// integral and pointer types -+************************************************************************/ -+ -+/* lzo_uint should match size_t */ -+#if !defined(LZO_UINT_MAX) -+# if defined(LZO_ABI_LLP64) /* WIN64 */ -+# if defined(LZO_OS_WIN64) -+ typedef unsigned __int64 lzo_uint; -+ typedef __int64 lzo_int; -+# else -+ typedef unsigned long long lzo_uint; -+ typedef long long lzo_int; -+# endif -+# define LZO_UINT_MAX 0xffffffffffffffffull -+# define LZO_INT_MAX 9223372036854775807LL -+# define LZO_INT_MIN (-1LL - LZO_INT_MAX) -+# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */ -+ typedef unsigned int lzo_uint; -+ typedef int lzo_int; -+# define LZO_UINT_MAX UINT_MAX -+# define LZO_INT_MAX INT_MAX -+# define LZO_INT_MIN INT_MIN -+# elif (ULONG_MAX >= LZO_0xffffffffL) -+ typedef unsigned long lzo_uint; -+ typedef long lzo_int; -+# define LZO_UINT_MAX ULONG_MAX -+# define LZO_INT_MAX LONG_MAX -+# define LZO_INT_MIN LONG_MIN -+# else -+# error "lzo_uint" -+# endif -+#endif -+ -+/* Integral types with 32 bits or more. */ -+#if !defined(LZO_UINT32_MAX) -+# if (UINT_MAX >= LZO_0xffffffffL) -+ typedef unsigned int lzo_uint32; -+ typedef int lzo_int32; -+# define LZO_UINT32_MAX UINT_MAX -+# define LZO_INT32_MAX INT_MAX -+# define LZO_INT32_MIN INT_MIN -+# elif (ULONG_MAX >= LZO_0xffffffffL) -+ typedef unsigned long lzo_uint32; -+ typedef long lzo_int32; -+# define LZO_UINT32_MAX ULONG_MAX -+# define LZO_INT32_MAX LONG_MAX -+# define LZO_INT32_MIN LONG_MIN -+# else -+# error "lzo_uint32" -+# endif -+#endif -+ -+/* The larger type of lzo_uint and lzo_uint32. */ -+#if (LZO_UINT_MAX >= LZO_UINT32_MAX) -+# define lzo_xint lzo_uint -+#else -+# define lzo_xint lzo_uint32 -+#endif -+ -+/* Memory model that allows to access memory at offsets of lzo_uint. */ -+#if !defined(__LZO_MMODEL) -+# if (LZO_UINT_MAX <= UINT_MAX) -+# define __LZO_MMODEL -+# elif defined(LZO_HAVE_MM_HUGE_PTR) -+# define __LZO_MMODEL_HUGE 1 -+# define __LZO_MMODEL __huge -+# else -+# define __LZO_MMODEL -+# endif -+#endif -+ -+/* no typedef here because of const-pointer issues */ -+#define lzo_bytep unsigned char __LZO_MMODEL * -+#define lzo_charp char __LZO_MMODEL * -+#define lzo_voidp void __LZO_MMODEL * -+#define lzo_shortp short __LZO_MMODEL * -+#define lzo_ushortp unsigned short __LZO_MMODEL * -+#define lzo_uint32p lzo_uint32 __LZO_MMODEL * -+#define lzo_int32p lzo_int32 __LZO_MMODEL * -+#define lzo_uintp lzo_uint __LZO_MMODEL * -+#define lzo_intp lzo_int __LZO_MMODEL * -+#define lzo_xintp lzo_xint __LZO_MMODEL * -+#define lzo_voidpp lzo_voidp __LZO_MMODEL * -+#define lzo_bytepp lzo_bytep __LZO_MMODEL * -+/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */ -+#define lzo_byte unsigned char __LZO_MMODEL -+ -+typedef int lzo_bool; -+ -+ -+/*********************************************************************** -+// function types -+************************************************************************/ -+ -+/* name mangling */ -+#if !defined(__LZO_EXTERN_C) -+# ifdef __cplusplus -+# define __LZO_EXTERN_C extern "C" -+# else -+# define __LZO_EXTERN_C extern -+# endif -+#endif -+ -+/* calling convention */ -+#if !defined(__LZO_CDECL) -+# define __LZO_CDECL __lzo_cdecl -+#endif -+ -+/* DLL export information */ -+#if !defined(__LZO_EXPORT1) -+# define __LZO_EXPORT1 -+#endif -+#if !defined(__LZO_EXPORT2) -+# define __LZO_EXPORT2 -+#endif -+ -+/* __cdecl calling convention for public C and assembly functions */ -+#if !defined(LZO_PUBLIC) -+# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL -+#endif -+#if !defined(LZO_EXTERN) -+# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) -+#endif -+#if !defined(LZO_PRIVATE) -+# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL -+#endif -+ -+/* function types */ -+typedef int -+(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+typedef int -+(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+typedef int -+(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem ); -+ -+typedef int -+(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+typedef int -+(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len, -+ lzo_bytep dst, lzo_uintp dst_len, -+ lzo_voidp wrkmem, -+ const lzo_bytep dict, lzo_uint dict_len ); -+ -+ -+/* Callback interface. Currently only the progress indicator ("nprogress") -+ * is used, but this may change in a future release. */ -+ -+struct lzo_callback_t; -+typedef struct lzo_callback_t lzo_callback_t; -+#define lzo_callback_p lzo_callback_t __LZO_MMODEL * -+ -+/* malloc & free function types */ -+typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t) -+ (lzo_callback_p self, lzo_uint items, lzo_uint size); -+typedef void (__LZO_CDECL *lzo_free_func_t) -+ (lzo_callback_p self, lzo_voidp ptr); -+ -+/* a progress indicator callback function */ -+typedef void (__LZO_CDECL *lzo_progress_func_t) -+ (lzo_callback_p, lzo_uint, lzo_uint, int); -+ -+struct lzo_callback_t -+{ -+ /* custom allocators (set to 0 to disable) */ -+ lzo_alloc_func_t nalloc; /* [not used right now] */ -+ lzo_free_func_t nfree; /* [not used right now] */ -+ -+ /* a progress indicator callback function (set to 0 to disable) */ -+ lzo_progress_func_t nprogress; -+ -+ /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress -+ * callbacks points back to this struct, so you are free to store -+ * some extra info in the following variables. */ -+ lzo_voidp user1; -+ lzo_xint user2; -+ lzo_xint user3; -+}; -+ -+ -+/*********************************************************************** -+// error codes and prototypes -+************************************************************************/ -+ -+/* Error codes for the compression/decompression functions. Negative -+ * values are errors, positive values will be used for special but -+ * normal events. -+ */ -+#define LZO_E_OK 0 -+#define LZO_E_ERROR (-1) -+#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ -+#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ -+#define LZO_E_INPUT_OVERRUN (-4) -+#define LZO_E_OUTPUT_OVERRUN (-5) -+#define LZO_E_LOOKBEHIND_OVERRUN (-6) -+#define LZO_E_EOF_NOT_FOUND (-7) -+#define LZO_E_INPUT_NOT_CONSUMED (-8) -+#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ -+ -+ -+#ifndef lzo_sizeof_dict_t -+# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep)) -+#endif -+ -+/* lzo_init() should be the first function you call. -+ * Check the return code ! -+ * -+ * lzo_init() is a macro to allow checking that the library and the -+ * compiler's view of various types are consistent. -+ */ -+#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ -+ (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ -+ (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ -+ (int)sizeof(lzo_callback_t)) -+LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int); -+ -+/* version functions (useful for shared libraries) */ -+LZO_EXTERN(unsigned) lzo_version(void); -+LZO_EXTERN(const char *) lzo_version_string(void); -+LZO_EXTERN(const char *) lzo_version_date(void); -+LZO_EXTERN(const lzo_charp) _lzo_version_string(void); -+LZO_EXTERN(const lzo_charp) _lzo_version_date(void); -+ -+/* string functions */ -+LZO_EXTERN(int) -+lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len); -+LZO_EXTERN(lzo_voidp) -+lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); -+LZO_EXTERN(lzo_voidp) -+lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); -+LZO_EXTERN(lzo_voidp) -+lzo_memset(lzo_voidp _s, int _c, lzo_uint _len); -+ -+/* checksum functions */ -+LZO_EXTERN(lzo_uint32) -+lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len); -+LZO_EXTERN(lzo_uint32) -+lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len); -+LZO_EXTERN(const lzo_uint32p) -+lzo_get_crc32_table(void); -+ -+/* misc. */ -+LZO_EXTERN(int) _lzo_config_check(void); -+typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; -+typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; -+typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t; -+ -+/* align a char pointer on a boundary that is a multiple of `size' */ -+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); -+#define LZO_PTR_ALIGN_UP(_ptr,_size) \ -+ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size))) -+ -+ -+/*********************************************************************** -+// deprecated macros - only for backward compatibility with LZO v1.xx -+************************************************************************/ -+ -+#if defined(LZO_CFG_COMPAT) -+ -+#define __LZOCONF_H 1 -+ -+#if defined(LZO_ARCH_I086) -+# define __LZO_i386 1 -+#elif defined(LZO_ARCH_I386) -+# define __LZO_i386 1 -+#endif -+ -+#if defined(LZO_OS_DOS16) -+# define __LZO_DOS 1 -+# define __LZO_DOS16 1 -+#elif defined(LZO_OS_DOS32) -+# define __LZO_DOS 1 -+#elif defined(LZO_OS_WIN16) -+# define __LZO_WIN 1 -+# define __LZO_WIN16 1 -+#elif defined(LZO_OS_WIN32) -+# define __LZO_WIN 1 -+#endif -+ -+#define __LZO_CMODEL -+#define __LZO_DMODEL -+#define __LZO_ENTRY __LZO_CDECL -+#define LZO_EXTERN_CDECL LZO_EXTERN -+#define LZO_ALIGN LZO_PTR_ALIGN_UP -+ -+#define lzo_compress_asm_t lzo_compress_t -+#define lzo_decompress_asm_t lzo_decompress_t -+ -+#endif /* LZO_CFG_COMPAT */ -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzodefs.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzodefs.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzodefs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzodefs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1545 @@ -+/* lzodefs.h -- architecture, OS and compiler specific defines -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZODEFS_H_INCLUDED -+#define __LZODEFS_H_INCLUDED 1 -+ -+#if defined(__CYGWIN32__) && !defined(__CYGWIN__) -+# define __CYGWIN__ __CYGWIN32__ -+#endif -+#if defined(__IBMCPP__) && !defined(__IBMC__) -+# define __IBMC__ __IBMCPP__ -+#endif -+#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) -+# define __INTEL_COMPILER __ICL -+#endif -+#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) -+# define _ALL_SOURCE 1 -+#endif -+#if defined(__mips__) && defined(__R5900__) -+# if !defined(__LONG_MAX__) -+# define __LONG_MAX__ 9223372036854775807L -+# endif -+#endif -+#if defined(__INTEL_COMPILER) && defined(__linux__) -+# pragma warning(disable: 193) -+#endif -+#if defined(__KEIL__) && defined(__C166__) -+# pragma warning disable = 322 -+#elif 0 && defined(__C251__) -+# pragma warning disable = 322 -+#endif -+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) -+# if (_MSC_VER >= 1300) -+# pragma warning(disable: 4668) -+# endif -+#endif -+#if 0 && defined(__WATCOMC__) -+# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) -+# pragma warning 203 9 -+# endif -+#endif -+#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) -+# pragma option -h -+#endif -+#if 0 -+#define LZO_0xffffL 0xfffful -+#define LZO_0xffffffffL 0xfffffffful -+#else -+#define LZO_0xffffL 65535ul -+#define LZO_0xffffffffL 4294967295ul -+#endif -+#if (LZO_0xffffL == LZO_0xffffffffL) -+# error "your preprocessor is broken 1" -+#endif -+#if (16ul * 16384ul != 262144ul) -+# error "your preprocessor is broken 2" -+#endif -+#if 0 -+#if (32767 >= 4294967295ul) -+# error "your preprocessor is broken 3" -+#endif -+#if (65535u >= 4294967295ul) -+# error "your preprocessor is broken 4" -+#endif -+#endif -+#if (UINT_MAX == LZO_0xffffL) -+#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) -+# if !defined(MSDOS) -+# define MSDOS 1 -+# endif -+# if !defined(_MSDOS) -+# define _MSDOS 1 -+# endif -+#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) -+# if (__VERSION == 520) && (MB_LEN_MAX == 1) -+# if !defined(__AZTEC_C__) -+# define __AZTEC_C__ __VERSION -+# endif -+# if !defined(__DOS__) -+# define __DOS__ 1 -+# endif -+# endif -+#endif -+#endif -+#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL) -+# define ptrdiff_t long -+# define _PTRDIFF_T_DEFINED -+#endif -+#if (UINT_MAX == LZO_0xffffL) -+# undef __LZO_RENAME_A -+# undef __LZO_RENAME_B -+# if defined(__AZTEC_C__) && defined(__DOS__) -+# define __LZO_RENAME_A 1 -+# elif defined(_MSC_VER) && defined(MSDOS) -+# if (_MSC_VER < 600) -+# define __LZO_RENAME_A 1 -+# elif (_MSC_VER < 700) -+# define __LZO_RENAME_B 1 -+# endif -+# elif defined(__TSC__) && defined(__OS2__) -+# define __LZO_RENAME_A 1 -+# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) -+# define __LZO_RENAME_A 1 -+# elif defined(__PACIFIC__) && defined(DOS) -+# if !defined(__far) -+# define __far far -+# endif -+# if !defined(__near) -+# define __near near -+# endif -+# endif -+# if defined(__LZO_RENAME_A) -+# if !defined(__cdecl) -+# define __cdecl cdecl -+# endif -+# if !defined(__far) -+# define __far far -+# endif -+# if !defined(__huge) -+# define __huge huge -+# endif -+# if !defined(__near) -+# define __near near -+# endif -+# if !defined(__pascal) -+# define __pascal pascal -+# endif -+# if !defined(__huge) -+# define __huge huge -+# endif -+# elif defined(__LZO_RENAME_B) -+# if !defined(__cdecl) -+# define __cdecl _cdecl -+# endif -+# if !defined(__far) -+# define __far _far -+# endif -+# if !defined(__huge) -+# define __huge _huge -+# endif -+# if !defined(__near) -+# define __near _near -+# endif -+# if !defined(__pascal) -+# define __pascal _pascal -+# endif -+# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -+# if !defined(__cdecl) -+# define __cdecl cdecl -+# endif -+# if !defined(__pascal) -+# define __pascal pascal -+# endif -+# endif -+# undef __LZO_RENAME_A -+# undef __LZO_RENAME_B -+#endif -+#if (UINT_MAX == LZO_0xffffL) -+#if defined(__AZTEC_C__) && defined(__DOS__) -+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -+#elif defined(_MSC_VER) && defined(MSDOS) -+# if (_MSC_VER < 600) -+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -+# endif -+# if (_MSC_VER < 700) -+# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -+# define LZO_BROKEN_SIZEOF 1 -+# endif -+#elif defined(__PACIFIC__) && defined(DOS) -+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -+#elif defined(__TURBOC__) && defined(__MSDOS__) -+# if (__TURBOC__ < 0x0150) -+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -+# define LZO_BROKEN_INTEGRAL_PROMOTION 1 -+# endif -+# if (__TURBOC__ < 0x0200) -+# define LZO_BROKEN_SIZEOF 1 -+# endif -+# if (__TURBOC__ < 0x0400) && defined(__cplusplus) -+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -+# endif -+#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) -+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1 -+# define LZO_BROKEN_SIZEOF 1 -+#endif -+#endif -+#if defined(__WATCOMC__) && (__WATCOMC__ < 900) -+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1 -+#endif -+#define LZO_CPP_STRINGIZE(x) #x -+#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x) -+#define LZO_CPP_CONCAT2(a,b) a ## b -+#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c -+#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d -+#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e -+#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b) -+#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c) -+#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d) -+#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e) -+#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) -+#if 1 && defined(__cplusplus) -+# if !defined(__STDC_CONSTANT_MACROS) -+# define __STDC_CONSTANT_MACROS 1 -+# endif -+# if !defined(__STDC_LIMIT_MACROS) -+# define __STDC_LIMIT_MACROS 1 -+# endif -+#endif -+#if defined(__cplusplus) -+# define LZO_EXTERN_C extern "C" -+#else -+# define LZO_EXTERN_C extern -+#endif -+#if !defined(__LZO_OS_OVERRIDE) -+#if defined(LZO_OS_FREESTANDING) -+# define LZO_INFO_OS "freestanding" -+#elif defined(LZO_OS_EMBEDDED) -+# define LZO_INFO_OS "embedded" -+#elif defined(__CYGWIN__) && defined(__GNUC__) -+# define LZO_OS_CYGWIN 1 -+# define LZO_INFO_OS "cygwin" -+#elif defined(__EMX__) && defined(__GNUC__) -+# define LZO_OS_EMX 1 -+# define LZO_INFO_OS "emx" -+#elif defined(__BEOS__) -+# define LZO_OS_BEOS 1 -+# define LZO_INFO_OS "beos" -+#elif defined(__Lynx__) -+# define LZO_OS_LYNXOS 1 -+# define LZO_INFO_OS "lynxos" -+#elif defined(__OS400__) -+# define LZO_OS_OS400 1 -+# define LZO_INFO_OS "os400" -+#elif defined(__QNX__) -+# define LZO_OS_QNX 1 -+# define LZO_INFO_OS "qnx" -+#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) -+# define LZO_OS_DOS32 1 -+# define LZO_INFO_OS "dos32" -+#elif defined(__BORLANDC__) && defined(__DPMI16__) -+# define LZO_OS_DOS16 1 -+# define LZO_INFO_OS "dos16" -+#elif defined(__ZTC__) && defined(DOS386) -+# define LZO_OS_DOS32 1 -+# define LZO_INFO_OS "dos32" -+#elif defined(__OS2__) || defined(__OS2V2__) -+# if (UINT_MAX == LZO_0xffffL) -+# define LZO_OS_OS216 1 -+# define LZO_INFO_OS "os216" -+# elif (UINT_MAX == LZO_0xffffffffL) -+# define LZO_OS_OS2 1 -+# define LZO_INFO_OS "os2" -+# else -+# error "check your limits.h header" -+# endif -+#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) -+# define LZO_OS_WIN64 1 -+# define LZO_INFO_OS "win64" -+#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) -+# define LZO_OS_WIN32 1 -+# define LZO_INFO_OS "win32" -+#elif defined(__MWERKS__) && defined(__INTEL__) -+# define LZO_OS_WIN32 1 -+# define LZO_INFO_OS "win32" -+#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) -+# if (UINT_MAX == LZO_0xffffL) -+# define LZO_OS_WIN16 1 -+# define LZO_INFO_OS "win16" -+# elif (UINT_MAX == LZO_0xffffffffL) -+# define LZO_OS_WIN32 1 -+# define LZO_INFO_OS "win32" -+# else -+# error "check your limits.h header" -+# endif -+#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) -+# if (UINT_MAX == LZO_0xffffL) -+# define LZO_OS_DOS16 1 -+# define LZO_INFO_OS "dos16" -+# elif (UINT_MAX == LZO_0xffffffffL) -+# define LZO_OS_DOS32 1 -+# define LZO_INFO_OS "dos32" -+# else -+# error "check your limits.h header" -+# endif -+#elif defined(__WATCOMC__) -+# if defined(__NT__) && (UINT_MAX == LZO_0xffffL) -+# define LZO_OS_DOS16 1 -+# define LZO_INFO_OS "dos16" -+# elif defined(__NT__) && (__WATCOMC__ < 1100) -+# define LZO_OS_WIN32 1 -+# define LZO_INFO_OS "win32" -+# else -+# error "please specify a target using the -bt compiler option" -+# endif -+#elif defined(__palmos__) -+# define LZO_OS_PALMOS 1 -+# define LZO_INFO_OS "palmos" -+#elif defined(__TOS__) || defined(__atarist__) -+# define LZO_OS_TOS 1 -+# define LZO_INFO_OS "tos" -+#elif defined(macintosh) && !defined(__ppc__) -+# define LZO_OS_MACCLASSIC 1 -+# define LZO_INFO_OS "macclassic" -+#elif defined(__VMS) -+# define LZO_OS_VMS 1 -+# define LZO_INFO_OS "vms" -+#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -+# define LZO_OS_CONSOLE 1 -+# define LZO_OS_CONSOLE_PS2 1 -+# define LZO_INFO_OS "console" -+# define LZO_INFO_OS_CONSOLE "ps2" -+#elif (defined(__mips__) && defined(__psp__)) -+# define LZO_OS_CONSOLE 1 -+# define LZO_OS_CONSOLE_PSP 1 -+# define LZO_INFO_OS "console" -+# define LZO_INFO_OS_CONSOLE "psp" -+#else -+# define LZO_OS_POSIX 1 -+# define LZO_INFO_OS "posix" -+#endif -+#if (LZO_OS_POSIX) -+# if defined(_AIX) || defined(__AIX__) || defined(__aix__) -+# define LZO_OS_POSIX_AIX 1 -+# define LZO_INFO_OS_POSIX "aix" -+# elif defined(__FreeBSD__) -+# define LZO_OS_POSIX_FREEBSD 1 -+# define LZO_INFO_OS_POSIX "freebsd" -+# elif defined(__hpux__) || defined(__hpux) -+# define LZO_OS_POSIX_HPUX 1 -+# define LZO_INFO_OS_POSIX "hpux" -+# elif defined(__INTERIX) -+# define LZO_OS_POSIX_INTERIX 1 -+# define LZO_INFO_OS_POSIX "interix" -+# elif defined(__IRIX__) || defined(__irix__) -+# define LZO_OS_POSIX_IRIX 1 -+# define LZO_INFO_OS_POSIX "irix" -+# elif defined(__linux__) || defined(__linux) -+# define LZO_OS_POSIX_LINUX 1 -+# define LZO_INFO_OS_POSIX "linux" -+# elif defined(__APPLE__) || defined(__MACOS__) -+# define LZO_OS_POSIX_MACOSX 1 -+# define LZO_INFO_OS_POSIX "macosx" -+# elif defined(__NetBSD__) -+# define LZO_OS_POSIX_NETBSD 1 -+# define LZO_INFO_OS_POSIX "netbsd" -+# elif defined(__OpenBSD__) -+# define LZO_OS_POSIX_OPENBSD 1 -+# define LZO_INFO_OS_POSIX "openbsd" -+# elif defined(__osf__) -+# define LZO_OS_POSIX_OSF 1 -+# define LZO_INFO_OS_POSIX "osf" -+# elif defined(__solaris__) || defined(__sun) -+# if defined(__SVR4) || defined(__svr4__) -+# define LZO_OS_POSIX_SOLARIS 1 -+# define LZO_INFO_OS_POSIX "solaris" -+# else -+# define LZO_OS_POSIX_SUNOS 1 -+# define LZO_INFO_OS_POSIX "sunos" -+# endif -+# elif defined(__ultrix__) || defined(__ultrix) -+# define LZO_OS_POSIX_ULTRIX 1 -+# define LZO_INFO_OS_POSIX "ultrix" -+# else -+# define LZO_OS_POSIX_UNKNOWN 1 -+# define LZO_INFO_OS_POSIX "unknown" -+# endif -+#endif -+#endif -+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -+# if (UINT_MAX != LZO_0xffffL) -+# error "this should not happen" -+# endif -+# if (ULONG_MAX != LZO_0xffffffffL) -+# error "this should not happen" -+# endif -+#endif -+#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64) -+# if (UINT_MAX != LZO_0xffffffffL) -+# error "this should not happen" -+# endif -+# if (ULONG_MAX != LZO_0xffffffffL) -+# error "this should not happen" -+# endif -+#endif -+#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) -+# define LZO_CC_CILLY 1 -+# define LZO_INFO_CC "Cilly" -+# if defined(__CILLY__) -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__CILLY__) -+# else -+# define LZO_INFO_CCVER "unknown" -+# endif -+#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) -+# define LZO_CC_SDCC 1 -+# define LZO_INFO_CC "sdcc" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(SDCC) -+#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) -+# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) -+# define LZO_INFO_CC "Pathscale C" -+# define LZO_INFO_CCVER __PATHSCALE__ -+#elif defined(__INTEL_COMPILER) -+# define LZO_CC_INTELC 1 -+# define LZO_INFO_CC "Intel C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__INTEL_COMPILER) -+#elif defined(__POCC__) && defined(_WIN32) -+# define LZO_CC_PELLESC 1 -+# define LZO_INFO_CC "Pelles C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__POCC__) -+#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) -+# define LZO_CC_LLVM 1 -+# define LZO_INFO_CC "llvm-gcc" -+# define LZO_INFO_CCVER __VERSION__ -+#elif defined(__GNUC__) && defined(__VERSION__) -+# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) -+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) -+# elif defined(__GNUC_MINOR__) -+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) -+# else -+# define LZO_CC_GNUC (__GNUC__ * 0x10000L) -+# endif -+# define LZO_INFO_CC "gcc" -+# define LZO_INFO_CCVER __VERSION__ -+#elif defined(__AZTEC_C__) -+# define LZO_CC_AZTECC 1 -+# define LZO_INFO_CC "Aztec C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__AZTEC_C__) -+#elif defined(__BORLANDC__) -+# define LZO_CC_BORLANDC 1 -+# define LZO_INFO_CC "Borland C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__BORLANDC__) -+#elif defined(__DMC__) && defined(__SC__) -+# define LZO_CC_DMC 1 -+# define LZO_INFO_CC "Digital Mars C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__DMC__) -+#elif defined(__DECC) -+# define LZO_CC_DECC 1 -+# define LZO_INFO_CC "DEC C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__DECC) -+#elif defined(__HIGHC__) -+# define LZO_CC_HIGHC 1 -+# define LZO_INFO_CC "MetaWare High C" -+# define LZO_INFO_CCVER "unknown" -+#elif defined(__IBMC__) -+# define LZO_CC_IBMC 1 -+# define LZO_INFO_CC "IBM C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__IBMC__) -+#elif defined(__KEIL__) && defined(__C166__) -+# define LZO_CC_KEILC 1 -+# define LZO_INFO_CC "Keil C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__C166__) -+#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) -+# define LZO_CC_LCCWIN32 1 -+# define LZO_INFO_CC "lcc-win32" -+# define LZO_INFO_CCVER "unknown" -+#elif defined(__LCC__) -+# define LZO_CC_LCC 1 -+# define LZO_INFO_CC "lcc" -+# if defined(__LCC_VERSION__) -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__LCC_VERSION__) -+# else -+# define LZO_INFO_CCVER "unknown" -+# endif -+#elif defined(_MSC_VER) -+# define LZO_CC_MSC 1 -+# define LZO_INFO_CC "Microsoft C" -+# if defined(_MSC_FULL_VER) -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(_MSC_VER) "." LZO_CPP_MACRO_EXPAND(_MSC_FULL_VER) -+# else -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(_MSC_VER) -+# endif -+#elif defined(__MWERKS__) -+# define LZO_CC_MWERKS 1 -+# define LZO_INFO_CC "Metrowerks C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__MWERKS__) -+#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) -+# define LZO_CC_NDPC 1 -+# define LZO_INFO_CC "Microway NDP C" -+# define LZO_INFO_CCVER "unknown" -+#elif defined(__PACIFIC__) -+# define LZO_CC_PACIFICC 1 -+# define LZO_INFO_CC "Pacific C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__PACIFIC__) -+#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) -+# define LZO_CC_PGI 1 -+# define LZO_INFO_CC "Portland Group PGI C" -+# define LZO_INFO_CCVER "unknown" -+#elif defined(__PUREC__) && defined(__TOS__) -+# define LZO_CC_PUREC 1 -+# define LZO_INFO_CC "Pure C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__PUREC__) -+#elif defined(__SC__) && defined(__ZTC__) -+# define LZO_CC_SYMANTECC 1 -+# define LZO_INFO_CC "Symantec C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__SC__) -+#elif defined(__SUNPRO_C) -+# define LZO_CC_SUNPROC 1 -+# define LZO_INFO_CC "Sun C" -+# define LZO_INFO_CCVER "unknown" -+#elif defined(__TINYC__) -+# define LZO_CC_TINYC 1 -+# define LZO_INFO_CC "Tiny C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__TINYC__) -+#elif defined(__TSC__) -+# define LZO_CC_TOPSPEEDC 1 -+# define LZO_INFO_CC "TopSpeed C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__TSC__) -+#elif defined(__WATCOMC__) -+# define LZO_CC_WATCOMC 1 -+# define LZO_INFO_CC "Watcom C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__WATCOMC__) -+#elif defined(__TURBOC__) -+# define LZO_CC_TURBOC 1 -+# define LZO_INFO_CC "Turbo C" -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__TURBOC__) -+#elif defined(__ZTC__) -+# define LZO_CC_ZORTECHC 1 -+# define LZO_INFO_CC "Zortech C" -+# if (__ZTC__ == 0x310) -+# define LZO_INFO_CCVER "0x310" -+# else -+# define LZO_INFO_CCVER LZO_CPP_MACRO_EXPAND(__ZTC__) -+# endif -+#else -+# define LZO_CC_UNKNOWN 1 -+# define LZO_INFO_CC "unknown" -+# define LZO_INFO_CCVER "unknown" -+#endif -+#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) -+# error "LZO_CC_MSC: _MSC_FULL_VER is not defined" -+#endif -+#if !defined(__LZO_ARCH_OVERRIDE) -+#if defined(LZO_ARCH_GENERIC) -+# define LZO_INFO_ARCH "generic" -+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -+# define LZO_ARCH_I086 1 -+# define LZO_ARCH_IA16 1 -+# define LZO_INFO_ARCH "i086" -+#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) -+# define LZO_ARCH_ALPHA 1 -+# define LZO_INFO_ARCH "alpha" -+#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) -+# define LZO_ARCH_AMD64 1 -+# define LZO_INFO_ARCH "amd64" -+#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) -+# define LZO_ARCH_ARM 1 -+# define LZO_ARCH_ARM_THUMB 1 -+# define LZO_INFO_ARCH "arm_thumb" -+#elif defined(__arm__) || defined(_M_ARM) -+# define LZO_ARCH_ARM 1 -+# define LZO_INFO_ARCH "arm" -+#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__) -+# define LZO_ARCH_AVR 1 -+# define LZO_INFO_ARCH "avr" -+#elif defined(__bfin__) -+# define LZO_ARCH_BLACKFIN 1 -+# define LZO_INFO_ARCH "blackfin" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__) -+# define LZO_ARCH_C166 1 -+# define LZO_INFO_ARCH "c166" -+#elif defined(__cris__) -+# define LZO_ARCH_CRIS 1 -+# define LZO_INFO_ARCH "cris" -+#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -+# define LZO_ARCH_H8300 1 -+# define LZO_INFO_ARCH "h8300" -+#elif defined(__hppa__) || defined(__hppa) -+# define LZO_ARCH_HPPA 1 -+# define LZO_INFO_ARCH "hppa" -+#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) -+# define LZO_ARCH_I386 1 -+# define LZO_ARCH_IA32 1 -+# define LZO_INFO_ARCH "i386" -+#elif (LZO_CC_ZORTECHC && defined(__I86__)) -+# define LZO_ARCH_I386 1 -+# define LZO_ARCH_IA32 1 -+# define LZO_INFO_ARCH "i386" -+#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386) -+# define LZO_ARCH_I386 1 -+# define LZO_ARCH_IA32 1 -+# define LZO_INFO_ARCH "i386" -+#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) -+# define LZO_ARCH_IA64 1 -+# define LZO_INFO_ARCH "ia64" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__) -+# define LZO_ARCH_M16C 1 -+# define LZO_INFO_ARCH "m16c" -+#elif defined(__m32r__) -+# define LZO_ARCH_M32R 1 -+# define LZO_INFO_ARCH "m32r" -+#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(_M_M68K) -+# define LZO_ARCH_M68K 1 -+# define LZO_INFO_ARCH "m68k" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__) -+# define LZO_ARCH_MCS251 1 -+# define LZO_INFO_ARCH "mcs251" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__) -+# define LZO_ARCH_MCS51 1 -+# define LZO_INFO_ARCH "mcs51" -+#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) -+# define LZO_ARCH_MIPS 1 -+# define LZO_INFO_ARCH "mips" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__) -+# define LZO_ARCH_MSP430 1 -+# define LZO_INFO_ARCH "msp430" -+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) -+# define LZO_ARCH_POWERPC 1 -+# define LZO_INFO_ARCH "powerpc" -+#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) -+# define LZO_ARCH_S390 1 -+# define LZO_INFO_ARCH "s390" -+#elif defined(__sh__) || defined(_M_SH) -+# define LZO_ARCH_SH 1 -+# define LZO_INFO_ARCH "sh" -+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) -+# define LZO_ARCH_SPARC 1 -+# define LZO_INFO_ARCH "sparc" -+#elif (UINT_MAX == LZO_0xffffL) && defined(__z80) -+# define LZO_ARCH_Z80 1 -+# define LZO_INFO_ARCH "z80" -+#else -+# define LZO_ARCH_UNKNOWN 1 -+# define LZO_INFO_ARCH "unknown" -+#endif -+#endif -+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2) -+# error "FIXME - missing define for CPU architecture" -+#endif -+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32) -+# error "FIXME - missing WIN32 define for CPU architecture" -+#endif -+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64) -+# error "FIXME - missing WIN64 define for CPU architecture" -+#endif -+#if (LZO_OS_OS216 || LZO_OS_WIN16) -+# define LZO_ARCH_I086PM 1 -+# define LZO_ARCH_IA16PM 1 -+#elif 1 && (LZO_OS_DOS16 && defined(BLX286)) -+# define LZO_ARCH_I086PM 1 -+# define LZO_ARCH_IA16PM 1 -+#elif 1 && (LZO_OS_DOS16 && defined(DOSX286)) -+# define LZO_ARCH_I086PM 1 -+# define LZO_ARCH_IA16PM 1 -+#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__)) -+# define LZO_ARCH_I086PM 1 -+# define LZO_ARCH_IA16PM 1 -+#endif -+#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM) -+# error "this should not happen" -+#endif -+#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086) -+# error "this should not happen" -+#endif -+#if (LZO_ARCH_I086) -+# if (UINT_MAX != LZO_0xffffL) -+# error "this should not happen" -+# endif -+# if (ULONG_MAX != LZO_0xffffffffL) -+# error "this should not happen" -+# endif -+#endif -+#if (LZO_ARCH_I386) -+# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__) -+# error "this should not happen" -+# endif -+# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__) -+# error "this should not happen" -+# endif -+# if (ULONG_MAX != LZO_0xffffffffL) -+# error "this should not happen" -+# endif -+#endif -+#if !defined(__LZO_MM_OVERRIDE) -+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16) -+#if (UINT_MAX != LZO_0xffffL) -+# error "this should not happen" -+#endif -+#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) -+# define LZO_MM_TINY 1 -+#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) -+# define LZO_MM_HUGE 1 -+#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) -+# define LZO_MM_SMALL 1 -+#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) -+# define LZO_MM_MEDIUM 1 -+#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) -+# define LZO_MM_COMPACT 1 -+#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) -+# define LZO_MM_LARGE 1 -+#elif (LZO_CC_AZTECC) -+# if defined(_LARGE_CODE) && defined(_LARGE_DATA) -+# define LZO_MM_LARGE 1 -+# elif defined(_LARGE_CODE) -+# define LZO_MM_MEDIUM 1 -+# elif defined(_LARGE_DATA) -+# define LZO_MM_COMPACT 1 -+# else -+# define LZO_MM_SMALL 1 -+# endif -+#elif (LZO_CC_ZORTECHC && defined(__VCM__)) -+# define LZO_MM_LARGE 1 -+#else -+# error "unknown memory model" -+#endif -+#define LZO_HAVE_MM_HUGE_PTR 1 -+#define LZO_HAVE_MM_HUGE_ARRAY 1 -+#if (LZO_MM_TINY) -+# undef LZO_HAVE_MM_HUGE_ARRAY -+#endif -+#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC) -+# undef LZO_HAVE_MM_HUGE_PTR -+# undef LZO_HAVE_MM_HUGE_ARRAY -+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -+# undef LZO_HAVE_MM_HUGE_ARRAY -+#elif (LZO_CC_MSC && defined(_QC)) -+# undef LZO_HAVE_MM_HUGE_ARRAY -+# if (_MSC_VER < 600) -+# undef LZO_HAVE_MM_HUGE_PTR -+# endif -+#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295)) -+# undef LZO_HAVE_MM_HUGE_ARRAY -+#endif -+#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR) -+# if (LZO_OS_DOS16) -+# error "this should not happen" -+# elif (LZO_CC_ZORTECHC) -+# else -+# error "this should not happen" -+# endif -+#endif -+#ifdef __cplusplus -+extern "C" { -+#endif -+#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) -+ extern void __near __cdecl _AHSHIFT(void); -+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -+ extern void __near __cdecl _AHSHIFT(void); -+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -+#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC) -+ extern void __near __cdecl _AHSHIFT(void); -+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -+#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295)) -+ extern void __near __cdecl _AHSHIFT(void); -+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT) -+#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16) -+# define LZO_MM_AHSHIFT 12 -+#elif (LZO_CC_WATCOMC) -+ extern unsigned char _HShift; -+# define LZO_MM_AHSHIFT ((unsigned) _HShift) -+#else -+# error "FIXME - implement LZO_MM_AHSHIFT" -+#endif -+#ifdef __cplusplus -+} -+#endif -+#elif (LZO_ARCH_C166) -+#if !defined(__MODEL__) -+# error "FIXME - C166 __MODEL__" -+#elif ((__MODEL__) == 0) -+# define LZO_MM_SMALL 1 -+#elif ((__MODEL__) == 1) -+# define LZO_MM_SMALL 1 -+#elif ((__MODEL__) == 2) -+# define LZO_MM_LARGE 1 -+#elif ((__MODEL__) == 3) -+# define LZO_MM_TINY 1 -+#elif ((__MODEL__) == 4) -+# define LZO_MM_XTINY 1 -+#elif ((__MODEL__) == 5) -+# define LZO_MM_XSMALL 1 -+#else -+# error "FIXME - C166 __MODEL__" -+#endif -+#elif (LZO_ARCH_MCS251) -+#if !defined(__MODEL__) -+# error "FIXME - MCS251 __MODEL__" -+#elif ((__MODEL__) == 0) -+# define LZO_MM_SMALL 1 -+#elif ((__MODEL__) == 2) -+# define LZO_MM_LARGE 1 -+#elif ((__MODEL__) == 3) -+# define LZO_MM_TINY 1 -+#elif ((__MODEL__) == 4) -+# define LZO_MM_XTINY 1 -+#elif ((__MODEL__) == 5) -+# define LZO_MM_XSMALL 1 -+#else -+# error "FIXME - MCS251 __MODEL__" -+#endif -+#elif (LZO_ARCH_MCS51) -+#if !defined(__MODEL__) -+# error "FIXME - MCS51 __MODEL__" -+#elif ((__MODEL__) == 1) -+# define LZO_MM_SMALL 1 -+#elif ((__MODEL__) == 2) -+# define LZO_MM_LARGE 1 -+#elif ((__MODEL__) == 3) -+# define LZO_MM_TINY 1 -+#elif ((__MODEL__) == 4) -+# define LZO_MM_XTINY 1 -+#elif ((__MODEL__) == 5) -+# define LZO_MM_XSMALL 1 -+#else -+# error "FIXME - MCS51 __MODEL__" -+#endif -+#else -+# define LZO_MM_FLAT 1 -+#endif -+#if (LZO_MM_FLAT) -+# define LZO_INFO_MM "flat" -+#elif (LZO_MM_TINY) -+# define LZO_INFO_MM "tiny" -+#elif (LZO_MM_SMALL) -+# define LZO_INFO_MM "small" -+#elif (LZO_MM_MEDIUM) -+# define LZO_INFO_MM "medium" -+#elif (LZO_MM_COMPACT) -+# define LZO_INFO_MM "compact" -+#elif (LZO_MM_LARGE) -+# define LZO_INFO_MM "large" -+#elif (LZO_MM_HUGE) -+# define LZO_INFO_MM "huge" -+#else -+# error "unknown memory model" -+#endif -+#endif -+#if defined(SIZEOF_SHORT) -+# define LZO_SIZEOF_SHORT (SIZEOF_SHORT) -+#endif -+#if defined(SIZEOF_INT) -+# define LZO_SIZEOF_INT (SIZEOF_INT) -+#endif -+#if defined(SIZEOF_LONG) -+# define LZO_SIZEOF_LONG (SIZEOF_LONG) -+#endif -+#if defined(SIZEOF_LONG_LONG) -+# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) -+#endif -+#if defined(SIZEOF___INT16) -+# define LZO_SIZEOF___INT16 (SIZEOF___INT16) -+#endif -+#if defined(SIZEOF___INT32) -+# define LZO_SIZEOF___INT32 (SIZEOF___INT32) -+#endif -+#if defined(SIZEOF___INT64) -+# define LZO_SIZEOF___INT64 (SIZEOF___INT64) -+#endif -+#if defined(SIZEOF_VOID_P) -+# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P) -+#endif -+#if defined(SIZEOF_SIZE_T) -+# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T) -+#endif -+#if defined(SIZEOF_PTRDIFF_T) -+# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) -+#endif -+#define __LZO_LSR(x,b) (((x)+0ul) >> (b)) -+#if !defined(LZO_SIZEOF_SHORT) -+# if (USHRT_MAX == LZO_0xffffL) -+# define LZO_SIZEOF_SHORT 2 -+# elif (__LZO_LSR(USHRT_MAX,7) == 1) -+# define LZO_SIZEOF_SHORT 1 -+# elif (__LZO_LSR(USHRT_MAX,15) == 1) -+# define LZO_SIZEOF_SHORT 2 -+# elif (__LZO_LSR(USHRT_MAX,31) == 1) -+# define LZO_SIZEOF_SHORT 4 -+# elif (__LZO_LSR(USHRT_MAX,63) == 1) -+# define LZO_SIZEOF_SHORT 8 -+# elif (__LZO_LSR(USHRT_MAX,127) == 1) -+# define LZO_SIZEOF_SHORT 16 -+# else -+# error "LZO_SIZEOF_SHORT" -+# endif -+#endif -+#if !defined(LZO_SIZEOF_INT) -+# if (UINT_MAX == LZO_0xffffL) -+# define LZO_SIZEOF_INT 2 -+# elif (UINT_MAX == LZO_0xffffffffL) -+# define LZO_SIZEOF_INT 4 -+# elif (__LZO_LSR(UINT_MAX,7) == 1) -+# define LZO_SIZEOF_INT 1 -+# elif (__LZO_LSR(UINT_MAX,15) == 1) -+# define LZO_SIZEOF_INT 2 -+# elif (__LZO_LSR(UINT_MAX,31) == 1) -+# define LZO_SIZEOF_INT 4 -+# elif (__LZO_LSR(UINT_MAX,63) == 1) -+# define LZO_SIZEOF_INT 8 -+# elif (__LZO_LSR(UINT_MAX,127) == 1) -+# define LZO_SIZEOF_INT 16 -+# else -+# error "LZO_SIZEOF_INT" -+# endif -+#endif -+#if !defined(LZO_SIZEOF_LONG) -+# if (ULONG_MAX == LZO_0xffffffffL) -+# define LZO_SIZEOF_LONG 4 -+# elif (__LZO_LSR(ULONG_MAX,7) == 1) -+# define LZO_SIZEOF_LONG 1 -+# elif (__LZO_LSR(ULONG_MAX,15) == 1) -+# define LZO_SIZEOF_LONG 2 -+# elif (__LZO_LSR(ULONG_MAX,31) == 1) -+# define LZO_SIZEOF_LONG 4 -+# elif (__LZO_LSR(ULONG_MAX,63) == 1) -+# define LZO_SIZEOF_LONG 8 -+# elif (__LZO_LSR(ULONG_MAX,127) == 1) -+# define LZO_SIZEOF_LONG 16 -+# else -+# error "LZO_SIZEOF_LONG" -+# endif -+#endif -+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -+# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) -+# if (LZO_CC_GNUC >= 0x030300ul) -+# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) -+# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG -+# endif -+# endif -+# endif -+#endif -+#endif -+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64) -+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8) -+#if (LZO_ARCH_I086 && LZO_CC_DMC) -+#elif (LZO_CC_CILLY) && defined(__GNUC__) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif ((LZO_OS_WIN32 || LZO_OS_WIN64) && LZO_CC_MSC && (_MSC_VER >= 1400)) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_OS_WIN64) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_DMC)) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700))) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__))) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI)) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC)) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_OS_WIN32 && (LZO_CC_MSC)) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100))) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) -+# define LZO_SIZEOF___INT64 8 -+#elif (LZO_OS_OS400) && defined(__LLP64_IFC__) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -+# define LZO_SIZEOF_LONG_LONG 8 -+#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2) -+#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -+# define LZO_SIZEOF_LONG_LONG 8 -+#endif -+#endif -+#endif -+#if defined(__cplusplus) && defined(LZO_CC_GNUC) -+# if (LZO_CC_GNUC < 0x020800ul) -+# undef LZO_SIZEOF_LONG_LONG -+# endif -+#endif -+#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) -+# undef LZO_SIZEOF_LONG_LONG -+#endif -+#if !defined(LZO_SIZEOF_VOID_P) -+#if (LZO_ARCH_I086) -+# define __LZO_WORDSIZE 2 -+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM) -+# define LZO_SIZEOF_VOID_P 2 -+# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE) -+# define LZO_SIZEOF_VOID_P 4 -+# else -+# error "LZO_MM" -+# endif -+#elif (LZO_ARCH_AVR || LZO_ARCH_Z80) -+# define __LZO_WORDSIZE 1 -+# define LZO_SIZEOF_VOID_P 2 -+#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430) -+# define LZO_SIZEOF_VOID_P 2 -+#elif (LZO_ARCH_H8300) -+# if defined(__NORMAL_MODE__) -+# define __LZO_WORDSIZE 4 -+# define LZO_SIZEOF_VOID_P 2 -+# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) -+# define __LZO_WORDSIZE 4 -+# define LZO_SIZEOF_VOID_P 4 -+# else -+# define __LZO_WORDSIZE 2 -+# define LZO_SIZEOF_VOID_P 2 -+# endif -+# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4) -+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT -+# endif -+#elif (LZO_ARCH_M16C) -+# define __LZO_WORDSIZE 2 -+# if defined(__m32c_cpu__) || defined(__m32cm_cpu__) -+# define LZO_SIZEOF_VOID_P 4 -+# else -+# define LZO_SIZEOF_VOID_P 2 -+# endif -+#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) -+# define __LZO_WORDSIZE 8 -+# define LZO_SIZEOF_VOID_P 4 -+#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) -+# define __LZO_WORDSIZE 8 -+# define LZO_SIZEOF_VOID_P 8 -+#elif (LZO_OS_OS400) && defined(__LLP64_IFC__) -+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -+#elif (LZO_OS_OS400) -+# define __LZO_WORDSIZE LZO_SIZEOF_LONG -+# define LZO_SIZEOF_VOID_P 16 -+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) -+# define LZO_SIZEOF_VOID_P 8 -+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG -+#else -+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG -+#endif -+#endif -+#if !defined(LZO_WORDSIZE) -+# if defined(__LZO_WORDSIZE) -+# define LZO_WORDSIZE __LZO_WORDSIZE -+# else -+# define LZO_WORDSIZE LZO_SIZEOF_VOID_P -+# endif -+#endif -+#if !defined(LZO_SIZEOF_SIZE_T) -+#if (LZO_ARCH_I086 || LZO_ARCH_M16C) -+# define LZO_SIZEOF_SIZE_T 2 -+#else -+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P -+#endif -+#endif -+#if !defined(LZO_SIZEOF_PTRDIFF_T) -+#if (LZO_ARCH_I086) -+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE) -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P -+# elif (LZO_MM_COMPACT || LZO_MM_LARGE) -+# if (LZO_CC_BORLANDC || LZO_CC_TURBOC) -+# define LZO_SIZEOF_PTRDIFF_T 4 -+# else -+# define LZO_SIZEOF_PTRDIFF_T 2 -+# endif -+# else -+# error "LZO_MM" -+# endif -+#else -+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T -+#endif -+#endif -+#if !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN) && !defined(LZO_ABI_NEUTRAL_ENDIAN) -+#if (LZO_ARCH_AMD64 || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430) -+# define LZO_ABI_LITTLE_ENDIAN 1 -+#elif (LZO_ARCH_M68K || LZO_ARCH_S390) -+# define LZO_ABI_BIG_ENDIAN 1 -+#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) -+# define LZO_ABI_BIG_ENDIAN 1 -+#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) -+# define LZO_ABI_LITTLE_ENDIAN 1 -+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) -+# define LZO_ABI_BIG_ENDIAN 1 -+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) -+# define LZO_ABI_LITTLE_ENDIAN 1 -+#endif -+#endif -+#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN) -+# error "this should not happen" -+#endif -+#if defined(LZO_ABI_BIG_ENDIAN) -+# define LZO_INFO_ABI_ENDIAN "be" -+#elif defined(LZO_ABI_LITTLE_ENDIAN) -+# define LZO_INFO_ABI_ENDIAN "le" -+#elif defined(LZO_ABI_NEUTRAL_ENDIAN) -+# define LZO_INFO_ABI_ENDIAN "neutral" -+#endif -+#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -+# define LZO_ABI_I8LP16 1 -+# define LZO_INFO_ABI_PM "i8lp16" -+#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2) -+# define LZO_ABI_ILP16 1 -+# define LZO_INFO_ABI_PM "ilp16" -+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4) -+# define LZO_ABI_ILP32 1 -+# define LZO_INFO_ABI_PM "ilp32" -+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8) -+# define LZO_ABI_LLP64 1 -+# define LZO_INFO_ABI_PM "llp64" -+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -+# define LZO_ABI_LP64 1 -+# define LZO_INFO_ABI_PM "lp64" -+#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8) -+# define LZO_ABI_ILP64 1 -+# define LZO_INFO_ABI_PM "ilp64" -+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4) -+# define LZO_ABI_IP32L64 1 -+# define LZO_INFO_ABI_PM "ip32l64" -+#endif -+#if !defined(__LZO_LIBC_OVERRIDE) -+#if defined(LZO_LIBC_NAKED) -+# define LZO_INFO_LIBC "naked" -+#elif defined(LZO_LIBC_FREESTANDING) -+# define LZO_INFO_LIBC "freestanding" -+#elif defined(LZO_LIBC_MOSTLY_FREESTANDING) -+# define LZO_INFO_LIBC "mfreestanding" -+#elif defined(LZO_LIBC_ISOC90) -+# define LZO_INFO_LIBC "isoc90" -+#elif defined(LZO_LIBC_ISOC99) -+# define LZO_INFO_LIBC "isoc99" -+#elif defined(__dietlibc__) -+# define LZO_LIBC_DIETLIBC 1 -+# define LZO_INFO_LIBC "dietlibc" -+#elif defined(_NEWLIB_VERSION) -+# define LZO_LIBC_NEWLIB 1 -+# define LZO_INFO_LIBC "newlib" -+#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) -+# if defined(__UCLIBC_SUBLEVEL__) -+# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) -+# else -+# define LZO_LIBC_UCLIBC 0x00090bL -+# endif -+# define LZO_INFO_LIBC "uclibc" -+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) -+# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) -+# define LZO_INFO_LIBC "glibc" -+#elif (LZO_CC_MWERKS) && defined(__MSL__) -+# define LZO_LIBC_MSL __MSL__ -+# define LZO_INFO_LIBC "msl" -+#else -+# define LZO_LIBC_DEFAULT 1 -+# define LZO_INFO_LIBC "default" -+#endif -+#endif -+#if (LZO_CC_GNUC >= 0x020800ul) -+# define __lzo_gnuc_extension__ __extension__ -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_gnuc_extension__ __extension__ -+#else -+# define __lzo_gnuc_extension__ -+#endif -+#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -+# define lzo_alignof(e) __alignof__(e) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700)) -+# define lzo_alignof(e) __alignof__(e) -+#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -+# define lzo_alignof(e) __alignof(e) -+#endif -+#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295)) -+#elif defined(__cplusplus) -+# define __lzo_inline inline -+#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) -+# define __lzo_inline __inline -+#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI) -+# define __lzo_inline __inline__ -+#elif (LZO_CC_DMC) -+# define __lzo_inline __inline -+#elif (LZO_CC_INTELC) -+# define __lzo_inline __inline -+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405)) -+# define __lzo_inline __inline -+#elif (LZO_CC_MSC && (_MSC_VER >= 900)) -+# define __lzo_inline __inline -+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) -+# define __lzo_inline inline -+#endif -+#if (LZO_CC_GNUC >= 0x030200ul) -+# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -+# define __lzo_forceinline __forceinline -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) -+# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_forceinline __inline__ __attribute__((__always_inline__)) -+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -+# define __lzo_forceinline __forceinline -+#endif -+#if (LZO_CC_GNUC >= 0x030200ul) -+# define __lzo_noinline __attribute__((__noinline__)) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -+# define __lzo_noinline __declspec(noinline) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) -+# define __lzo_noinline __attribute__((__noinline__)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_noinline __attribute__((__noinline__)) -+#elif (LZO_CC_MSC && (_MSC_VER >= 1300)) -+# define __lzo_noinline __declspec(noinline) -+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -+# if defined(__cplusplus) -+# else -+# define __lzo_noinline __declspec(noinline) -+# endif -+#endif -+#if (defined(__lzo_forceinline) || defined(__lzo_noinline)) && !defined(__lzo_inline) -+# error "this should not happen" -+#endif -+#if (LZO_CC_GNUC >= 0x020700ul) -+# define __lzo_noreturn __attribute__((__noreturn__)) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && (LZO_OS_WIN32 || LZO_OS_WIN64)) -+# define __lzo_noreturn __declspec(noreturn) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && (LZO_OS_POSIX)) -+# define __lzo_noreturn __attribute__((__noreturn__)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_noreturn __attribute__((__noreturn__)) -+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) -+# define __lzo_noreturn __declspec(noreturn) -+#endif -+#if (LZO_CC_GNUC >= 0x030400ul) -+# define __lzo_constructor __attribute__((__constructor__,__used__)) -+#elif (LZO_CC_GNUC >= 0x020700ul) -+# define __lzo_constructor __attribute__((__constructor__)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_constructor __attribute__((__constructor__)) -+#endif -+#if (LZO_CC_GNUC >= 0x030400ul) -+# define __lzo_destructor __attribute__((__destructor__,__used__)) -+#elif (LZO_CC_GNUC >= 0x020700ul) -+# define __lzo_destructor __attribute__((__destructor__)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_destructor __attribute__((__destructor__)) -+#endif -+#if defined(__lzo_destructor) && !defined(__lzo_constructor) -+# error "this should not happen" -+#endif -+#if (LZO_CC_GNUC >= 0x030200ul) -+# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800)) -+# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define __lzo_likely(e) (__builtin_expect(!!(e),1)) -+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0)) -+#else -+# define __lzo_likely(e) (e) -+# define __lzo_unlikely(e) (e) -+#endif -+#if !defined(LZO_UNUSED) -+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -+# define LZO_UNUSED(var) ((void) &var) -+# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC) -+# define LZO_UNUSED(var) if (&var) ; else -+# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE) -+# define LZO_UNUSED(var) ((void) var) -+# elif (LZO_CC_MSC && (_MSC_VER < 900)) -+# define LZO_UNUSED(var) if (&var) ; else -+# elif (LZO_CC_KEILC) -+# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];} -+# elif (LZO_CC_PACIFICC) -+# define LZO_UNUSED(var) ((void) sizeof(var)) -+# elif (LZO_CC_WATCOMC) && defined(__cplusplus) -+# define LZO_UNUSED(var) ((void) var) -+# else -+# define LZO_UNUSED(var) ((void) &var) -+# endif -+#endif -+#if !defined(LZO_UNUSED_FUNC) -+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) -+# define LZO_UNUSED_FUNC(func) ((void) func) -+# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC) -+# define LZO_UNUSED_FUNC(func) if (func) ; else -+# elif (LZO_CC_LLVM) -+# define LZO_UNUSED_FUNC(func) ((void) &func) -+# elif (LZO_CC_MSC && (_MSC_VER < 900)) -+# define LZO_UNUSED_FUNC(func) if (func) ; else -+# elif (LZO_CC_MSC) -+# define LZO_UNUSED_FUNC(func) ((void) &func) -+# elif (LZO_CC_KEILC || LZO_CC_PELLESC) -+# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];} -+# else -+# define LZO_UNUSED_FUNC(func) ((void) func) -+# endif -+#endif -+#if !defined(LZO_UNUSED_LABEL) -+# if (LZO_CC_WATCOMC) && defined(__cplusplus) -+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -+# elif (LZO_CC_INTELC || LZO_CC_WATCOMC) -+# define LZO_UNUSED_LABEL(l) if (0) goto l -+# else -+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l -+# endif -+#endif -+#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER) -+# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC) -+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC) -+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)]; -+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)]; -+# else -+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)]; -+# endif -+#endif -+#if !defined(LZO_COMPILE_TIME_ASSERT) -+# if (LZO_CC_AZTECC) -+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];} -+# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -+# elif (LZO_CC_MSC && (_MSC_VER < 900)) -+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295)) -+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; -+# else -+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];} -+# endif -+#endif -+#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64) -+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC) -+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC) -+# define __lzo_cdecl __cdecl -+# define __lzo_cdecl_atexit -+# define __lzo_cdecl_main __cdecl -+# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -+# define __lzo_cdecl_qsort __pascal -+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -+# define __lzo_cdecl_qsort _stdcall -+# else -+# define __lzo_cdecl_qsort __cdecl -+# endif -+# elif (LZO_CC_WATCOMC) -+# define __lzo_cdecl __cdecl -+# else -+# define __lzo_cdecl __cdecl -+# define __lzo_cdecl_atexit __cdecl -+# define __lzo_cdecl_main __cdecl -+# define __lzo_cdecl_qsort __cdecl -+# endif -+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC) -+# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC)) -+# define __lzo_cdecl_sighandler __pascal -+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC)) -+# define __lzo_cdecl_sighandler _stdcall -+# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) -+# define __lzo_cdecl_sighandler __clrcall -+# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) -+# if defined(_DLL) -+# define __lzo_cdecl_sighandler _far _cdecl _loadds -+# elif defined(_MT) -+# define __lzo_cdecl_sighandler _far _cdecl -+# else -+# define __lzo_cdecl_sighandler _cdecl -+# endif -+# else -+# define __lzo_cdecl_sighandler __cdecl -+# endif -+#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC)) -+# define __lzo_cdecl cdecl -+#endif -+#if !defined(__lzo_cdecl) -+# define __lzo_cdecl -+#endif -+#if !defined(__lzo_cdecl_atexit) -+# define __lzo_cdecl_atexit -+#endif -+#if !defined(__lzo_cdecl_main) -+# define __lzo_cdecl_main -+#endif -+#if !defined(__lzo_cdecl_qsort) -+# define __lzo_cdecl_qsort -+#endif -+#if !defined(__lzo_cdecl_sighandler) -+# define __lzo_cdecl_sighandler -+#endif -+#if !defined(__lzo_cdecl_va) -+# define __lzo_cdecl_va __lzo_cdecl -+#endif -+#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64) -+# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000)) -+# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__) -+# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul))) -+# else -+# define LZO_HAVE_WINDOWS_H 1 -+# endif -+#endif -+#if (LZO_ARCH_ALPHA) -+# define LZO_OPT_AVOID_UINT_INDEX 1 -+# define LZO_OPT_AVOID_SHORT 1 -+# define LZO_OPT_AVOID_USHORT 1 -+#elif (LZO_ARCH_AMD64) -+# define LZO_OPT_AVOID_INT_INDEX 1 -+# define LZO_OPT_AVOID_UINT_INDEX 1 -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+# define LZO_OPT_UNALIGNED64 1 -+#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB) -+#elif (LZO_ARCH_ARM) -+# define LZO_OPT_AVOID_SHORT 1 -+# define LZO_OPT_AVOID_USHORT 1 -+#elif (LZO_ARCH_CRIS) -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+#elif (LZO_ARCH_I386) -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+#elif (LZO_ARCH_IA64) -+# define LZO_OPT_AVOID_INT_INDEX 1 -+# define LZO_OPT_AVOID_UINT_INDEX 1 -+# define LZO_OPT_PREFER_POSTINC 1 -+#elif (LZO_ARCH_M68K) -+# define LZO_OPT_PREFER_POSTINC 1 -+# define LZO_OPT_PREFER_PREDEC 1 -+# if defined(__mc68020__) && !defined(__mcoldfire__) -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+# endif -+#elif (LZO_ARCH_MIPS) -+# define LZO_OPT_AVOID_UINT_INDEX 1 -+#elif (LZO_ARCH_POWERPC) -+# define LZO_OPT_PREFER_PREINC 1 -+# define LZO_OPT_PREFER_PREDEC 1 -+# if defined(LZO_ABI_BIG_ENDIAN) -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+# endif -+#elif (LZO_ARCH_S390) -+# define LZO_OPT_UNALIGNED16 1 -+# define LZO_OPT_UNALIGNED32 1 -+# if (LZO_SIZEOF_SIZE_T == 8) -+# define LZO_OPT_UNALIGNED64 1 -+# endif -+#elif (LZO_ARCH_SH) -+# define LZO_OPT_PREFER_POSTINC 1 -+# define LZO_OPT_PREFER_PREDEC 1 -+#endif -+#if !defined(LZO_CFG_NO_INLINE_ASM) -+#if defined(LZO_CC_LLVM) -+# define LZO_CFG_NO_INLINE_ASM 1 -+#endif -+#endif -+#if !defined(LZO_CFG_NO_UNALIGNED) -+#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC) -+# define LZO_CFG_NO_UNALIGNED 1 -+#endif -+#endif -+#if defined(LZO_CFG_NO_UNALIGNED) -+# undef LZO_OPT_UNALIGNED16 -+# undef LZO_OPT_UNALIGNED32 -+# undef LZO_OPT_UNALIGNED64 -+#endif -+#if defined(LZO_CFG_NO_INLINE_ASM) -+#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -+# define LZO_ASM_SYNTAX_MSC 1 -+#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC)) -+#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -+# define LZO_ASM_SYNTAX_GNUC 1 -+#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE)) -+# define LZO_ASM_SYNTAX_GNUC 1 -+#endif -+#if (LZO_ASM_SYNTAX_GNUC) -+#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul)) -+# define __LZO_ASM_CLOBBER "ax" -+#elif (LZO_CC_INTELC) -+# define __LZO_ASM_CLOBBER "memory" -+#else -+# define __LZO_ASM_CLOBBER "cc", "memory" -+#endif -+#endif -+#if defined(__LZO_INFOSTR_MM) -+#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM)) -+# define __LZO_INFOSTR_MM "" -+#elif defined(LZO_INFO_MM) -+# define __LZO_INFOSTR_MM "." LZO_INFO_MM -+#else -+# define __LZO_INFOSTR_MM "" -+#endif -+#if defined(__LZO_INFOSTR_PM) -+#elif defined(LZO_INFO_ABI_PM) -+# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM -+#else -+# define __LZO_INFOSTR_PM "" -+#endif -+#if defined(__LZO_INFOSTR_ENDIAN) -+#elif defined(LZO_INFO_ABI_ENDIAN) -+# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN -+#else -+# define __LZO_INFOSTR_ENDIAN "" -+#endif -+#if defined(__LZO_INFOSTR_OSNAME) -+#elif defined(LZO_INFO_OS_CONSOLE) -+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE -+#elif defined(LZO_INFO_OS_POSIX) -+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX -+#else -+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS -+#endif -+#if defined(__LZO_INFOSTR_LIBC) -+#elif defined(LZO_INFO_LIBC) -+# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC -+#else -+# define __LZO_INFOSTR_LIBC "" -+#endif -+#if defined(__LZO_INFOSTR_CCVER) -+#elif defined(LZO_INFO_CCVER) -+# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER -+#else -+# define __LZO_INFOSTR_CCVER "" -+#endif -+#define LZO_INFO_STRING \ -+ LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \ -+ " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER -+ -+#endif /* already included */ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoutil.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoutil.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoutil.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/include/lzo/lzoutil.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,69 @@ -+/* lzoutil.h -- utilitiy functions for use by applications [DEPRECATED] -+ -+ This file is part of the LZO real-time data compression library. -+ -+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer -+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer -+ All Rights Reserved. -+ -+ The LZO library 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. -+ -+ The LZO library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with the LZO library; see the file COPYING. -+ If not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ -+ Markus F.X.J. Oberhumer -+ -+ http://www.oberhumer.com/opensource/lzo/ -+ */ -+ -+ -+#ifndef __LZOUTIL_H_INCLUDED -+#define __LZOUTIL_H_INCLUDED -+ -+#ifndef __LZOCONF_H_INCLUDED -+#include "lzoconf.h" -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/*********************************************************************** -+// LZO-v1 deprecated macros (which were used in the old example programs) -+// DO NOT USE -+************************************************************************/ -+ -+#define lzo_alloc(a,b) (malloc((a)*(b))) -+#define lzo_malloc(a) (malloc(a)) -+#define lzo_free(a) (free(a)) -+ -+#define lzo_fread(f,b,s) (fread(b,1,s,f)) -+#define lzo_fwrite(f,b,s) (fwrite(b,1,s,f)) -+ -+ -+#ifdef __cplusplus -+} /* extern "C" */ -+#endif -+ -+#endif /* already included */ -+ -+ -+/* vim:set ts=4 et: */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/lib/liblzo2.la linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/lib/liblzo2.la ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/lzo/lib/liblzo2.la 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/lzo/lib/liblzo2.la 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,35 @@ -+# liblzo2.la - a libtool library file -+# Generated by ltmain.sh - GNU libtool 1.5.6 (1.1220.2.95 2004/04/11 05:50:42) Debian: 220 $ -+# -+# Please DO NOT delete this file! -+# It is necessary for linking the library. -+ -+# The name that we can dlopen(3). -+dlname='liblzo2.so.2' -+ -+# Names of this library. -+library_names='liblzo2.so.2.0.0 liblzo2.so.2 liblzo2.so' -+ -+# The name of the static archive. -+old_library='liblzo2.a' -+ -+# Libraries that this one depends upon. -+dependency_libs='' -+ -+# Version information for liblzo2. -+current=2 -+age=0 -+revision=0 -+ -+# Is this an already installed library? -+installed=yes -+ -+# Should we warn about portability when linking against -modules? -+shouldnotlink=no -+ -+# Files to dlopen/dlpreopen -+dlopen='' -+dlpreopen='' -+ -+# Directory that this library needs to be installed in: -+libdir='/home/yrtan/lzo/lib' -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/mkfs.ubifs.c linux-2.6.24.7/fs/ubifs/mkfs.ubifs/mkfs.ubifs.c ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/mkfs.ubifs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/mkfs.ubifs.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2163 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy -+ * Zoltan Sogor -+ */ -+ -+#include "mkfs.ubifs.h" -+ -+#define PROGRAM_VERSION "0.6" -+ -+/* Size (prime number) of hash table for link counting */ -+#define HASH_TABLE_SIZE 10099 -+ -+/* The node buffer must allow for worst case compression */ -+#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * 4) -+ -+/* Default time granularity in nanoseconds */ -+#define DEFAULT_TIME_GRAN 1000000000 -+ -+/* UBI EC and VID header sizes - used when calculating LEB size from PRB size */ -+#define UBI_EC_HDR_SIZE 64 -+#define UBI_VID_HDR_SIZE 64 -+ -+/** -+ * struct idx_entry - index entry. -+ * @next: next index entry (NULL at end of list) -+ * @prev: previous index entry (NULL at beginning of list) -+ * @key: key -+ * @name: directory entry name used for sorting colliding keys by name -+ * @lnum: LEB number -+ * @offs: offset -+ * @len: length -+ * -+ * The index is recorded as a linked list which is sorted and used to create -+ * the bottom level of the on-flash index tree. The remaining levels of the -+ * index tree are each built from the level below. -+ */ -+struct idx_entry { -+ struct idx_entry *next; -+ struct idx_entry *prev; -+ union ubifs_key key; -+ char *name; -+ int lnum; -+ int offs; -+ int len; -+}; -+ -+/** -+ * struct inum_mapping - inode number mapping for link counting. -+ * @next: next inum_mapping (NULL at end of list) -+ * @prev: previous inum_mapping (NULL at beginning of list) -+ * @dev: source device on which the source inode number resides -+ * @inum: source inode number of the file -+ * @use_inum: target inode number of the file -+ * @use_nlink: number of links -+ * @path_name: a path name of the file -+ * @st: struct stat object containing inode attributes which have to be used -+ * when the inode is being created (actually only UID, GID, access -+ * mode, major and minor device numbers) -+ * -+ * If a file has more than one hard link, then the number of hard links that -+ * exist in the source directory hierarchy must be counted to exclude the -+ * possibility that the file is linked from outside the source directory -+ * hierarchy. -+ * -+ * The inum_mappings are stored in a hash_table of linked lists. -+ */ -+struct inum_mapping { -+ struct inum_mapping *next; -+ struct inum_mapping *prev; -+ dev_t dev; -+ ino_t inum; -+ ino_t use_inum; -+ unsigned int use_nlink; -+ char *path_name; -+ struct stat st; -+}; -+ -+/* -+ * Because we copy functions from the kernel, we use a subset of the UBIFS -+ * file-system description object struct ubifs_info. -+ */ -+static struct ubifs_info info_, *c = &info_; -+ -+/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */ -+int debug_level; -+int verbose; -+ -+static char *root; -+static int root_len; -+static struct stat root_st; -+static char *output; -+static int out_fd; -+static int squash_owner; -+ -+/* The 'head' (position) which nodes are written */ -+static int head_lnum; -+static int head_offs; -+static int head_flags; -+ -+/* The index list */ -+static struct idx_entry *idx_list_first; -+static struct idx_entry *idx_list_last; -+static size_t idx_cnt; -+ -+/* Global buffers */ -+static void *leb_buf; -+static void *node_buf; -+static void *block_buf; -+ -+/* Hash table for inode link counting */ -+static struct inum_mapping **hash_table; -+ -+/* Inode creation sequence number */ -+static unsigned long long creat_sqnum; -+ -+static const char *optstring = "d:r:m:o:D:h?vVe:c:g:f:P:k:x:j:l:j:U"; -+ -+static const struct option longopts[] = { -+ {"root", 1, NULL, 'r'}, -+ {"min-io-size", 1, NULL, 'm'}, -+ {"leb-size", 1, NULL, 'e'}, -+ {"max-leb-cnt", 1, NULL, 'c'}, -+ {"output", 1, NULL, 'o'}, -+ {"devtable", 1, NULL, 'D'}, -+ {"help", 0, NULL, 'h'}, -+ {"verbose", 0, NULL, 'v'}, -+ {"version", 0, NULL, 'V'}, -+ {"debug-level", 1, NULL, 'g'}, -+ {"jrn-size", 1, NULL, 'j'}, -+ {"compr", 1, NULL, 'x'}, -+ {"fanout", 1, NULL, 'f'}, -+ {"keyhash", 1, NULL, 'k'}, -+ {"log-lebs", 1, NULL, 'l'}, -+ {"orph-lebs", 1, NULL, 'p'}, -+ {"squash-uids" , 0, NULL, 'U'}, -+ {NULL, 0, NULL, 0} -+}; -+ -+static const char *helptext = -+"Usage: mkfs.ubifs [OPTIONS]\n" -+"Make a UBIFS file system image from an existing directory tree\n\n" -+"Options:\n" -+"-r, -d, --root=DIR build file system from directory DIR\n" -+"-m, --min-io-size=SIZE minimum I/O unit size\n" -+"-e, --leb-size=SIZE logical erase block size\n" -+"-c, --max-leb-cnt=COUNT maximum logical erase block count\n" -+"-o, --output=FILE output to FILE\n" -+"-j, --jrn-size=SIZE journal size\n" -+"-x, --compr=TYPE compression type - \"lzo\", \"zlib\" or \"none\"\n" -+" (default: \"lzo\")\n" -+"-f, --fanout=NUM fanout NUM (default: 8)\n" -+"-k, --keyhash=TYPE key hash type - \"r5\" or \"test\" (default: \"r5\")\n" -+"-l, --log-lebs=COUNT count of erase blocks for the log\n" -+"-p, --orph-lebs=COUNT count of erase blocks for orphans (default: 1)\n" -+"-D, --devtable=FILE use device table FILE\n" -+"-U, --squash-uids squash owners making all files owned by root\n" -+"-v, --verbose verbose operation\n" -+"-V, --version display version information\n" -+"-g, --debug=LEVEL display debug information (0 - none, 1 - statistics,\n" -+" 2 - files, 3 - more details)\n" -+"-h, --help display this help text\n\n" -+"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n" -+"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n"; -+ -+/** -+ * make_path - make a path name from a directory and a name. -+ * @dir: directory path name -+ * @name: name -+ */ -+static char *make_path(const char *dir, const char *name) -+{ -+ char *s; -+ -+ s = malloc(strlen(dir) + strlen(name) + 2); -+ if (!s) -+ return NULL; -+ strcpy(s, dir); -+ if (dir[strlen(dir) - 1] != '/') -+ strcat(s, "/"); -+ strcat(s, name); -+ return s; -+} -+ -+/** -+ * same_dir - determine if two file descriptors refer to the same directory. -+ * @fd1: file descriptor 1 -+ * @fd2: file descriptor 2 -+ */ -+static int same_dir(int fd1, int fd2) -+{ -+ struct stat stat1, stat2; -+ -+ if (fstat(fd1, &stat1) == -1) -+ return -1; -+ if (fstat(fd2, &stat2) == -1) -+ return -1; -+ return stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino; -+} -+ -+/** -+ * do_openat - open a file in a directory. -+ * @fd: file descriptor of open directory -+ * @path: path relative to directory -+ * @flags: open flags -+ * -+ * This function is provided because the library function openat is sometimes -+ * not available. -+ */ -+static int do_openat(int fd, const char *path, int flags) -+{ -+ int ret; -+ char *cwd; -+ -+ cwd = getcwd(NULL, 0); -+ if (!cwd) -+ return -1; -+ ret = fchdir(fd); -+ if (ret != -1) -+ ret = open(path, flags); -+ chdir(cwd); -+ free(cwd); -+ return ret; -+} -+ -+/** -+ * in_path - determine if a file is beneath a directory. -+ * @dir_name: directory path name -+ * @file_name: file path name -+ */ -+static int in_path(const char *dir_name, const char *file_name) -+{ -+ char *fn = strdup(file_name); -+ char *dn; -+ int fd1, fd2, fd3, ret = -1, top_fd; -+ -+ if (!fn) -+ return -1; -+ top_fd = open("/", O_RDONLY); -+ if (top_fd != -1) { -+ dn = dirname(fn); -+ fd1 = open(dir_name, O_RDONLY); -+ if (fd1 != -1) { -+ fd2 = open(dn, O_RDONLY); -+ if (fd2 != -1) { -+ while (1) { -+ int same; -+ -+ same = same_dir(fd1, fd2); -+ if (same) { -+ ret = same; -+ break; -+ } -+ if (same_dir(fd2, top_fd)) { -+ ret = 0; -+ break; -+ } -+ fd3 = do_openat(fd2, "..", O_RDONLY); -+ if (fd3 == -1) -+ break; -+ close(fd2); -+ fd2 = fd3; -+ } -+ close(fd2); -+ } -+ close(fd1); -+ } -+ close(top_fd); -+ } -+ free(fn); -+ return ret; -+} -+ -+/** -+ * calc_min_log_lebs - calculate the minimum number of log LEBs needed. -+ * @max_bud_bytes: journal size (buds only) -+ */ -+static int calc_min_log_lebs(unsigned long long max_bud_bytes) -+{ -+ int buds, log_lebs; -+ unsigned long long log_size; -+ -+ buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size; -+ log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); -+ log_size *= buds; -+ log_size += ALIGN(UBIFS_CS_NODE_SZ + -+ UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2), -+ c->min_io_size); -+ log_lebs = (log_size + c->leb_size - 1) / c->leb_size; -+ log_lebs += 1; -+ return log_lebs; -+} -+ -+static inline int is_power_of_2(unsigned long long n) -+{ -+ return (n != 0 && ((n & (n - 1)) == 0)); -+} -+ -+static int validate_options(void) -+{ -+ int tmp; -+ -+ if (!root) -+ return err_msg("root directory was not specified"); -+ if (!output) -+ return err_msg("no output file specified"); -+ if (in_path(root, output)) -+ return err_msg("output file cannot be in the UBIFS root " -+ "directory"); -+ if (!is_power_of_2(c->min_io_size)) -+ return err_msg("min. I/O unit size should be power of 2"); -+ if (c->leb_size < c->min_io_size) -+ return err_msg("min. I/O unit cannot be larger than LEB size"); -+ if (c->leb_size < UBIFS_MIN_LEB_SZ) -+ return err_msg("too smal LEB size %d, minimum is %d", -+ c->min_io_size, UBIFS_MIN_LEB_SZ); -+ if (c->leb_size % c->min_io_size) -+ return err_msg("LEB should be multiple of min. I/O units"); -+ if (c->leb_size % 8) -+ return err_msg("LEB size has to be multiple of 8"); -+ if (c->leb_size > 1024*1024) -+ return err_msg("too large LEB size %d", c->leb_size); -+ if (c->max_leb_cnt < UBIFS_MIN_LEB_CNT) -+ return err_msg("too low max. count of LEBs, minimum is %d", -+ UBIFS_MIN_LEB_CNT); -+ if (c->fanout < UBIFS_MIN_FANOUT) -+ return err_msg("too low fanout, minimum is %d", -+ UBIFS_MIN_FANOUT); -+ tmp = c->leb_size - UBIFS_IDX_NODE_SZ; -+ tmp /= UBIFS_BRANCH_SZ + UBIFS_MAX_KEY_LEN; -+ if (c->fanout > tmp) -+ return err_msg("too high fanout, maximum is %d", tmp); -+ if (c->log_lebs < UBIFS_MIN_LOG_LEBS) -+ return err_msg("too few log LEBs, minimum is %d", -+ UBIFS_MIN_LOG_LEBS); -+ if (c->log_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT) -+ return err_msg("too many log LEBs, maximum is %d", -+ c->max_leb_cnt - UBIFS_MIN_LEB_CNT); -+ if (c->orph_lebs < UBIFS_MIN_ORPH_LEBS) -+ return err_msg("too few orphan LEBs, minimum is %d", -+ UBIFS_MIN_ORPH_LEBS); -+ if (c->orph_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT) -+ return err_msg("too many orphan LEBs, maximum is %d", -+ c->max_leb_cnt - UBIFS_MIN_LEB_CNT); -+ tmp = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs; -+ tmp += c->orph_lebs + 4; -+ if (tmp > c->max_leb_cnt) -+ return err_msg("too low max. count of LEBs, expected at " -+ "least %d", tmp); -+ tmp = calc_min_log_lebs(c->max_bud_bytes); -+ if (c->log_lebs < calc_min_log_lebs(c->max_bud_bytes)) -+ return err_msg("too few log LEBs, expected at least %d", -+ tmp); -+ return 0; -+} -+ -+/** -+ * get_multiplier - convert size specifier to an integer multiplier. -+ * @str: the size specifier string -+ * -+ * This function parses the @str size specifier, which may be one of -+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive -+ * size multiplier in case of success and %-1 in case of failure. -+ */ -+static int get_multiplier(const char *str) -+{ -+ if (!str) -+ return 1; -+ -+ /* Remove spaces before the specifier */ -+ while (*str == ' ' || *str == '\t') -+ str += 1; -+ -+ if (!strcmp(str, "KiB")) -+ return 1024; -+ if (!strcmp(str, "MiB")) -+ return 1024 * 1024; -+ if (!strcmp(str, "GiB")) -+ return 1024 * 1024 * 1024; -+ -+ return -1; -+} -+ -+/** -+ * get_bytes - convert a string containing amount of bytes into an -+ * integer. -+ * @str: string to convert -+ * -+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size -+ * specifiers. Returns positive amount of bytes in case of success and %-1 in -+ * case of failure. -+ */ -+static long long get_bytes(const char *str) -+{ -+ char *endp; -+ long long bytes = strtoull(str, &endp, 0); -+ -+ if (endp == str || bytes < 0) -+ return err_msg("incorrect amount of bytes: \"%s\"", str); -+ -+ if (*endp != '\0') { -+ int mult = get_multiplier(endp); -+ -+ if (mult == -1) -+ return err_msg("bad size specifier: \"%s\" - " -+ "should be 'KiB', 'MiB' or 'GiB'", endp); -+ bytes *= mult; -+ } -+ -+ return bytes; -+} -+ -+static int get_options(int argc, char**argv) -+{ -+ int opt, i; -+ const char *tbl_file = NULL; -+ struct stat st; -+ char *endp; -+ -+ c->fanout = 8; -+ c->orph_lebs = 1; -+ c->key_hash = key_r5_hash; -+ c->key_len = UBIFS_SK_LEN; -+ c->default_compr = UBIFS_COMPR_LZO; -+ c->lsave_cnt = 256; -+ c->leb_size = -1; -+ c->min_io_size = -1; -+ c->max_bud_bytes = -1; -+ c->log_lebs = -1; -+ -+ while (1) { -+ opt = getopt_long(argc, argv, optstring, longopts, &i); -+ if (opt == -1) -+ break; -+ switch (opt) { -+ case 'r': -+ case 'd': -+ root_len = strlen(optarg); -+ root = malloc(root_len + 2); -+ if (!root) -+ return err_msg("cannot allocate memory"); -+ -+ /* -+ * The further code expects '/' at the end of the root -+ * UBIFS directory on the host. -+ */ -+ memcpy(root, optarg, root_len); -+ if (root[root_len - 1] != '/') -+ root[root_len++] = '/'; -+ root[root_len] = 0; -+ -+ /* Make sure the root directory exists */ -+ if (stat(root, &st)) -+ return sys_err_msg("bad root directory '%s'", -+ root); -+ break; -+ case 'm': -+ c->min_io_size = get_bytes(optarg); -+ if (c->min_io_size <= 0) -+ return err_msg("bad min. I/O size"); -+ break; -+ case 'e': -+ c->leb_size = get_bytes(optarg); -+ if (c->leb_size <= 0) -+ return err_msg("bad LEB size"); -+ break; -+ case 'c': -+ c->max_leb_cnt = get_bytes(optarg); -+ if (c->max_leb_cnt <= 0) -+ return err_msg("bad maximum LEB count"); -+ break; -+ case 'o': -+ output = strdup(optarg); -+ break; -+ case 'D': -+ tbl_file = optarg; -+ if (stat(tbl_file, &st) < 0) -+ return sys_err_msg("bad device table file '%s'", -+ tbl_file); -+ break; -+ case 'h': -+ case '?': -+ printf(helptext); -+ exit(0); -+ case 'v': -+ verbose = 1; -+ break; -+ case 'V': -+ printf("Version " PROGRAM_VERSION "\n"); -+ exit(0); -+ case 'g': -+ debug_level = strtol(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || -+ debug_level < 0 || debug_level > 3) -+ return err_msg("bad debugging level '%s'", -+ optarg); -+ break; -+ case 'f': -+ c->fanout = strtol(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || c->fanout <= 0) -+ return err_msg("bad fanout %s", optarg); -+ break; -+ case 'l': -+ c->log_lebs = strtol(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || c->log_lebs <= 0) -+ return err_msg("bad count of log LEBs '%s'", -+ optarg); -+ break; -+ case 'p': -+ c->orph_lebs = strtol(optarg, &endp, 0); -+ if (*endp != '\0' || endp == optarg || -+ c->orph_lebs <= 0) -+ return err_msg("bad orphan LEB count '%s'", -+ optarg); -+ break; -+ case 'k': -+ if (strcmp(optarg, "r5") == 0) { -+ c->key_hash = key_r5_hash; -+ c->key_hash_type = UBIFS_KEY_HASH_R5; -+ } else if (strcmp(optarg, "test") == 0) { -+ c->key_hash = key_test_hash; -+ c->key_hash_type = UBIFS_KEY_HASH_TEST; -+ } else -+ return err_msg("bad key hash"); -+ break; -+ case 'x': -+ if (strcmp(optarg, "lzo") == 0) -+ c->default_compr = UBIFS_COMPR_LZO; -+ else if (strcmp(optarg, "zlib") == 0) -+ c->default_compr = UBIFS_COMPR_ZLIB; -+ else if (strcmp(optarg, "none") == 0) -+ c->default_compr = UBIFS_COMPR_NONE; -+ else -+ return err_msg("bad compressor name"); -+ break; -+ case 'j': -+ c->max_bud_bytes = get_bytes(optarg); -+ if (c->max_bud_bytes <= 0) -+ return err_msg("bad maximum amount of buds"); -+ break; -+ case 'U': -+ squash_owner = 1; -+ break; -+ } -+ } -+ -+ if (c->min_io_size == -1) -+ return err_msg("min. I/O unit was not specified " -+ "(use -h for help)"); -+ -+ if (c->leb_size == -1) -+ return err_msg("LEB size was not specified (use -h for help)"); -+ -+ if (c->max_bud_bytes == -1) { -+ int lebs; -+ -+ lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; -+ lebs -= c->orph_lebs; -+ if (c->log_lebs) -+ lebs -= c->log_lebs; -+ else -+ lebs -= UBIFS_MIN_LOG_LEBS; -+ if (c->lpt_lebs) -+ lebs -= c->lpt_lebs; -+ else -+ lebs -= UBIFS_MIN_LPT_LEBS; -+ /* Make the journal about 12.5% of main area lebs */ -+ c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size; -+ /* Make the max journal size 8MiB */ -+ if (c->max_bud_bytes > 8 * 1024 * 1024) -+ c->max_bud_bytes = 8 * 1024 * 1024; -+ if (c->max_bud_bytes < 4 * c->leb_size) -+ c->max_bud_bytes = 4 * c->leb_size; -+ } -+ -+ if (c->log_lebs == -1) { -+ c->log_lebs = calc_min_log_lebs(c->max_bud_bytes); -+ c->log_lebs += 2; -+ } -+ -+ if (verbose) { -+ printf("mkfs.ubifs\n"); -+ printf("\troot: %s\n", root); -+ printf("\tmin_io_size: %d\n", c->min_io_size); -+ printf("\tleb_size: %d\n", c->leb_size); -+ printf("\tmax_leb_cnt: %d\n", c->max_leb_cnt); -+ printf("\toutput: %s\n", output); -+ printf("\tjrn_size: %llu\n", c->max_bud_bytes); -+ switch (c->default_compr) { -+ case UBIFS_COMPR_LZO: -+ printf("\tcompr: lzo\n"); -+ break; -+ case UBIFS_COMPR_ZLIB: -+ printf("\tcompr: zlib\n"); -+ break; -+ case UBIFS_COMPR_NONE: -+ printf("\tcompr: none\n"); -+ break; -+ } -+ printf("\tkeyhash: %s\n", (c->key_hash == key_r5_hash) ? -+ "r5" : "test"); -+ printf("\tfanout: %d\n", c->fanout); -+ printf("\torph_lebs: %d\n", c->orph_lebs); -+ } -+ -+ if (c->min_io_size < 8) -+ c->min_io_size = 8; -+ -+ if (validate_options()) -+ return -1; -+ -+ if (tbl_file && parse_devtable(root, tbl_file)) -+ return err_msg("cannot parse device table file '%s'", tbl_file); -+ -+ return 0; -+} -+ -+/** -+ * prepare_node - fill in the common header. -+ * @node: node -+ * @len: node length -+ */ -+static void prepare_node(void *node, int len) -+{ -+ uint32_t crc; -+ struct ubifs_ch *ch = node; -+ -+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); -+ ch->len = cpu_to_le32(len); -+ ch->group_type = UBIFS_NO_NODE_GROUP; -+ ch->sqnum = cpu_to_le64(++c->max_sqnum); -+ ch->padding[0] = ch->padding[1] = 0; -+ crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); -+ ch->crc = cpu_to_le32(crc); -+} -+ -+/** -+ * write_leb - copy the image of a LEB to the output file. -+ * @lnum: LEB number -+ * @len: length of data in the buffer -+ * @buf: buffer (must be at least c->leb_size bytes) -+ */ -+int write_leb(int lnum, int len, void *buf) -+{ -+ off64_t pos = (off64_t)lnum * c->leb_size; -+ -+ dbg_msg(3, "LEB %d len %d", lnum, len); -+ if (lseek64(out_fd, pos, SEEK_SET) != pos) -+ return sys_err_msg("lseek64 failed seeking %lld", pos); -+ -+ memset(buf + len, 0xff, c->leb_size - len); -+ -+ if (write(out_fd, buf, c->leb_size) != c->leb_size) -+ return sys_err_msg("write failed writing %d bytes at pos %lld", -+ c->leb_size, pos); -+ -+ return 0; -+} -+ -+/** -+ * write_empty_leb - copy the image of an empty LEB to the output file. -+ * @lnum: LEB number -+ */ -+static int write_empty_leb(int lnum) -+{ -+ return write_leb(lnum, 0, leb_buf); -+} -+ -+/** -+ * do_pad - pad a buffer to the minimum I/O size. -+ * @buf: buffer -+ * @len: buffer length -+ */ -+static int do_pad(void *buf, int len) -+{ -+ int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size); -+ uint32_t crc; -+ -+ memset(buf + len, 0xff, alen - len); -+ pad_len = wlen - alen; -+ dbg_msg(3, "len %d pad_len %d", len, pad_len); -+ buf += alen; -+ if (pad_len >= UBIFS_PAD_NODE_SZ) { -+ struct ubifs_ch *ch = buf; -+ struct ubifs_pad_node *pad_node = buf; -+ -+ ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); -+ ch->node_type = UBIFS_PAD_NODE; -+ ch->group_type = UBIFS_NO_NODE_GROUP; -+ ch->padding[0] = ch->padding[1] = 0; -+ ch->sqnum = cpu_to_le64(0); -+ ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ); -+ -+ pad_len -= UBIFS_PAD_NODE_SZ; -+ pad_node->pad_len = cpu_to_le32(pad_len); -+ -+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, UBIFS_PAD_NODE_SZ - 8); -+ ch->crc = cpu_to_le32(crc); -+ -+ memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len); -+ } else if (pad_len > 0) -+ memset(buf, UBIFS_PADDING_BYTE, pad_len); -+ -+ return wlen; -+} -+ -+/** -+ * write_node - write a node to a LEB. -+ * @node: node -+ * @len: node length -+ * @lnum: LEB number -+ */ -+static int write_node(void *node, int len, int lnum) -+{ -+ prepare_node(node, len); -+ -+ memcpy(leb_buf, node, len); -+ -+ len = do_pad(leb_buf, len); -+ -+ return write_leb(lnum, len, leb_buf); -+} -+ -+/** -+ * calc_dark - calculate LEB dark space size. -+ * @c: the UBIFS file-system description object -+ * @spc: amount of free and dirty space in the LEB -+ * -+ * This function calculates amount of dark space in an LEB which has @spc bytes -+ * of free and dirty space. Returns the calculations result. -+ * -+ * Dark space is the space which is not always usable - it depends on which -+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes, -+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot -+ * count on this LEB and treat these 512 bytes as usable because it is not true -+ * if, for example, only big chunks of uncompressible data will be written to -+ * the FS. -+ */ -+static int calc_dark(struct ubifs_info *c, int spc) -+{ -+ if (spc < c->dark_wm) -+ return spc; -+ -+ /* -+ * If we have slightly more space then the dark space watermark, we can -+ * anyway safely assume it we'll be able to write a node of the -+ * smallest size there. -+ */ -+ if (spc - c->dark_wm < MIN_WRITE_SZ) -+ return spc - MIN_WRITE_SZ; -+ -+ return c->dark_wm; -+} -+ -+/** -+ * set_lprops - set the LEB property values for a LEB. -+ * @lnum: LEB number -+ * @offs: end offset of data in the LEB -+ * @flags: LEB property flags -+ */ -+static void set_lprops(int lnum, int offs, int flags) -+{ -+ int i = lnum - c->main_first, free, dirty; -+ int a = max_t(int, c->min_io_size, 8); -+ -+ free = c->leb_size - ALIGN(offs, a); -+ dirty = c->leb_size - free - ALIGN(offs, 8); -+ dbg_msg(3, "LEB %d free %d dirty %d flags %d", lnum, free, dirty, -+ flags); -+ c->lpt[i].free = free; -+ c->lpt[i].dirty = dirty; -+ c->lpt[i].flags = flags; -+ c->lst.total_free += free; -+ c->lst.total_dirty += dirty; -+ if (flags & LPROPS_INDEX) -+ c->lst.idx_lebs += 1; -+ else { -+ int spc; -+ -+ spc = free + dirty; -+ if (spc < c->dead_wm) -+ c->lst.total_dead += spc; -+ else -+ c->lst.total_dark += calc_dark(c, spc); -+ c->lst.total_used += c->leb_size - spc; -+ } -+} -+ -+/** -+ * add_to_index - add a node key and position to the index. -+ * @key: node key -+ * @lnum: node LEB number -+ * @offs: node offset -+ * @len: node length -+ */ -+static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs, -+ int len) -+{ -+ struct idx_entry *e; -+ -+ dbg_msg(3, "LEB %d offs %d len %d", lnum, offs, len); -+ e = malloc(sizeof(struct idx_entry)); -+ if (!e) -+ return err_msg("out of memory"); -+ e->next = NULL; -+ e->prev = idx_list_last; -+ e->key = *key; -+ e->name = name; -+ e->lnum = lnum; -+ e->offs = offs; -+ e->len = len; -+ if (!idx_list_first) -+ idx_list_first = e; -+ if (idx_list_last) -+ idx_list_last->next = e; -+ idx_list_last = e; -+ idx_cnt += 1; -+ return 0; -+} -+ -+/** -+ * flush_nodes - write the current head and move the head to the next LEB. -+ */ -+static int flush_nodes(void) -+{ -+ int len, err; -+ -+ if (!head_offs) -+ return 0; -+ len = do_pad(leb_buf, head_offs); -+ err = write_leb(head_lnum, len, leb_buf); -+ if (err) -+ return err; -+ set_lprops(head_lnum, head_offs, head_flags); -+ head_lnum += 1; -+ head_offs = 0; -+ return 0; -+} -+ -+/** -+ * reserve_space - reserve space for a node on the head. -+ * @len: node length -+ * @lnum: LEB number is returned here -+ * @offs: offset is returned here -+ */ -+static int reserve_space(int len, int *lnum, int *offs) -+{ -+ int err; -+ -+ if (len > c->leb_size - head_offs) { -+ err = flush_nodes(); -+ if (err) -+ return err; -+ } -+ *lnum = head_lnum; -+ *offs = head_offs; -+ head_offs += ALIGN(len, 8); -+ return 0; -+} -+ -+/** -+ * add_node - write a node to the head. -+ * @key: node key -+ * @node: node -+ * @len: node length -+ */ -+static int add_node(union ubifs_key *key, char *name, void *node, int len) -+{ -+ int err, lnum, offs; -+ -+ prepare_node(node, len); -+ -+ err = reserve_space(len, &lnum, &offs); -+ if (err) -+ return err; -+ -+ memcpy(leb_buf + offs, node, len); -+ memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len); -+ -+ add_to_index(key, name, lnum, offs, len); -+ -+ return 0; -+} -+ -+/** -+ * add_inode_with_data - write an inode. -+ * @st: stat information of source inode -+ * @inum: target inode number -+ * @data: inode data (for special inodes e.g. symlink path etc) -+ * @data_len: inode data length -+ * @flags: source inode flags -+ */ -+static int add_inode_with_data(struct stat *st, ino_t inum, void *data, -+ unsigned int data_len, int flags) -+{ -+ struct ubifs_ino_node *ino = node_buf; -+ union ubifs_key key; -+ int len, use_flags = 0; -+ -+ if (c->default_compr != UBIFS_COMPR_NONE) -+ use_flags |= UBIFS_COMPR_FL; -+ if (flags & FS_COMPR_FL) -+ use_flags |= UBIFS_COMPR_FL; -+ if (flags & FS_SYNC_FL) -+ use_flags |= UBIFS_SYNC_FL; -+ if (flags & FS_IMMUTABLE_FL) -+ use_flags |= UBIFS_IMMUTABLE_FL; -+ if (flags & FS_APPEND_FL) -+ use_flags |= UBIFS_APPEND_FL; -+ if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode)) -+ use_flags |= UBIFS_DIRSYNC_FL; -+ -+ memset(ino, 0, UBIFS_INO_NODE_SZ); -+ -+ ino_key_init(c, &key, inum); -+ ino->ch.node_type = UBIFS_INO_NODE; -+ key_write(c, &key, &ino->key); -+ ino->creat_sqnum = cpu_to_le64(creat_sqnum); -+ ino->size = cpu_to_le64(st->st_size); -+ ino->nlink = cpu_to_le32(st->st_nlink); -+ /* -+ * The time fields are updated assuming the default time granularity -+ * of 1 second. To support finer granularities, utime() would be needed. -+ */ -+ ino->atime_sec = cpu_to_le64(st->st_atime); -+ ino->ctime_sec = cpu_to_le64(st->st_ctime); -+ ino->mtime_sec = cpu_to_le64(st->st_mtime); -+ ino->atime_nsec = 0; -+ ino->ctime_nsec = 0; -+ ino->mtime_nsec = 0; -+ ino->uid = cpu_to_le32(st->st_uid); -+ ino->gid = cpu_to_le32(st->st_gid); -+ ino->uid = cpu_to_le32(st->st_uid); -+ ino->gid = cpu_to_le32(st->st_gid); -+ ino->mode = cpu_to_le32(st->st_mode); -+ ino->flags = cpu_to_le32(use_flags); -+ ino->data_len = cpu_to_le32(data_len); -+ ino->compr_type = cpu_to_le16(c->default_compr); -+ if (data_len) -+ memcpy(&ino->data, data, data_len); -+ -+ len = UBIFS_INO_NODE_SZ + data_len; -+ -+ return add_node(&key, NULL, ino, len); -+} -+ -+/** -+ * add_inode - write an inode. -+ * @st: stat information of source inode -+ * @inum: target inode number -+ * @flags: source inode flags -+ */ -+static int add_inode(struct stat *st, ino_t inum, int flags) -+{ -+ return add_inode_with_data(st, inum, NULL, 0, flags); -+} -+ -+/** -+ * add_dir_inode - write an inode for a directory. -+ * @dir: source directory -+ * @inum: target inode number -+ * @size: target directory size -+ * @nlink: target directory link count -+ * @st: struct stat object describing attributes (except size and nlink) of the -+ * target inode to create -+ * -+ * Note, this function may be called with %NULL @dir, when the directory which -+ * is being created does not exist at the host file system, but is defined by -+ * the device table. -+ */ -+static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink, -+ struct stat *st) -+{ -+ int fd, flags = 0; -+ -+ st->st_size = size; -+ st->st_nlink = nlink; -+ -+ if (dir) { -+ fd = dirfd(dir); -+ if (fd == -1) -+ return sys_err_msg("dirfd failed"); -+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) -+ flags = 0; -+ } -+ -+ return add_inode(st, inum, flags); -+} -+ -+/** -+ * add_dev_inode - write an inode for a character or block device. -+ * @st: stat information of source inode -+ * @inum: target inode number -+ * @flags: source inode flags -+ */ -+static int add_dev_inode(struct stat *st, ino_t inum, int flags) -+{ -+ union ubifs_dev_desc dev; -+ -+ dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev))); -+ return add_inode_with_data(st, inum, &dev, 8, flags); -+} -+ -+/** -+ * add_symlink_inode - write an inode for a symbolic link. -+ * @path_name: path name of symbolic link inode itself (not the link target) -+ * @st: stat information of source inode -+ * @inum: target inode number -+ * @flags: source inode flags -+ */ -+static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum, -+ int flags) -+{ -+ char buf[UBIFS_MAX_INO_DATA + 2]; -+ ssize_t len; -+ -+ /* Take the symlink as is */ -+ len = readlink(path_name, buf, UBIFS_MAX_INO_DATA + 1); -+ if (len <= 0) -+ return sys_err_msg("readlink failed for %s", path_name); -+ if (len > UBIFS_MAX_INO_DATA) -+ return err_msg("symlink too long for %s", path_name); -+ -+ return add_inode_with_data(st, inum, buf, len, flags); -+} -+ -+/** -+ * add_dent_node - write a directory entry node. -+ * @dir_inum: target inode number of directory -+ * @name: directory entry name -+ * @inum: target inode number of the directory entry -+ * @type: type of the target inode -+ */ -+static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum, -+ unsigned char type) -+{ -+ struct ubifs_dent_node *dent = node_buf; -+ union ubifs_key key; -+ struct qstr dname; -+ char *kname; -+ int len; -+ -+ dbg_msg(3, "%s ino %lu type %u dir ino %lu", name, inum, -+ (unsigned)type, dir_inum); -+ memset(dent, 0, UBIFS_DENT_NODE_SZ); -+ -+ dname.name = (void *)name; -+ dname.len = strlen(name); -+ -+ dent->ch.node_type = UBIFS_DENT_NODE; -+ -+ dent_key_init(c, &key, dir_inum, &dname); -+ key_write(c, &key, dent->key); -+ dent->inum = cpu_to_le64(inum); -+ dent->padding1 = 0; -+ dent->type = type; -+ dent->nlen = cpu_to_le16(dname.len); -+ memcpy(dent->name, dname.name, dname.len); -+ dent->name[dname.len] = '\0'; -+ -+ len = UBIFS_DENT_NODE_SZ + dname.len + 1; -+ -+ kname = strdup(name); -+ if (!kname) -+ return err_msg("cannot allocate memory"); -+ -+ return add_node(&key, kname, dent, len); -+} -+ -+/** -+ * lookup_inum_mapping - add an inode mapping for link counting. -+ * @dev: source device on which source inode number resides -+ * @inum: source inode number -+ */ -+static struct inum_mapping *lookup_inum_mapping(dev_t dev, ino_t inum) -+{ -+ struct inum_mapping *im; -+ unsigned int k; -+ -+ k = inum % HASH_TABLE_SIZE; -+ im = hash_table[k]; -+ while (im) { -+ if (im->dev == dev && im->inum == inum) -+ return im; -+ im = im->next; -+ } -+ im = malloc(sizeof(struct inum_mapping)); -+ if (!im) -+ return NULL; -+ im->next = hash_table[k]; -+ im->prev = NULL; -+ im->dev = dev; -+ im->inum = inum; -+ im->use_inum = 0; -+ im->use_nlink = 0; -+ if (hash_table[k]) -+ hash_table[k]->prev = im; -+ hash_table[k] = im; -+ return im; -+} -+ -+/** -+ * all_zero - does a buffer contain only zero bytes. -+ * @buf: buffer -+ * @len: buffer length -+ */ -+static int all_zero(void *buf, int len) -+{ -+ unsigned char *p = buf; -+ -+ while (len--) -+ if (*p++ != 0) -+ return 0; -+ return 1; -+} -+ -+/** -+ * add_file - write the data of a file and its inode to the output file. -+ * @path_name: source path name -+ * @st: source inode stat information -+ * @inum: target inode number -+ * @flags: source inode flags -+ */ -+static int add_file(const char *path_name, struct stat *st, ino_t inum, -+ int flags) -+{ -+ struct ubifs_data_node *dn = node_buf; -+ void *buf = block_buf; -+ loff_t file_size = 0; -+ ssize_t ret, bytes_read; -+ union ubifs_key key; -+ int fd, dn_len, err, compr_type, use_compr; -+ unsigned int block_no = 0; -+ size_t out_len; -+ -+ fd = open(path_name, O_RDONLY | O_LARGEFILE); -+ if (fd == -1) -+ return sys_err_msg("failed to open file '%s'", path_name); -+ do { -+ /* Read next block */ -+ bytes_read = 0; -+ do { -+ ret = read(fd, buf + bytes_read, -+ UBIFS_BLOCK_SIZE - bytes_read); -+ if (ret == -1) { -+ sys_err_msg("failed to read file '%s'", -+ path_name); -+ close(fd); -+ return 1; -+ } -+ bytes_read += ret; -+ } while (ret != 0 && bytes_read != UBIFS_BLOCK_SIZE); -+ if (bytes_read == 0) -+ break; -+ file_size += bytes_read; -+ /* Skip holes */ -+ if (all_zero(buf, bytes_read)) { -+ block_no += 1; -+ continue; -+ } -+ /* Make data node */ -+ memset(dn, 0, UBIFS_DATA_NODE_SZ); -+ data_key_init(c, &key, inum, block_no++); -+ dn->ch.node_type = UBIFS_DATA_NODE; -+ key_write(c, &key, &dn->key); -+ dn->size = cpu_to_le32(bytes_read); -+ out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ; -+ if (c->default_compr == UBIFS_COMPR_NONE && -+ (flags & FS_COMPR_FL)) -+ use_compr = UBIFS_COMPR_LZO; -+ else -+ use_compr = c->default_compr; -+ compr_type = compress_data(buf, bytes_read, &dn->data, -+ &out_len, use_compr); -+ dn->compr_type = cpu_to_le16(compr_type); -+ dn_len = UBIFS_DATA_NODE_SZ + out_len; -+ /* Add data node to file system */ -+ err = add_node(&key, NULL, dn, dn_len); -+ if (err) { -+ close(fd); -+ return err; -+ } -+ } while (ret != 0); -+ if (close(fd) == -1) -+ return sys_err_msg("failed to close file '%s'", path_name); -+ if (file_size != st->st_size) -+ return err_msg("file size changed during writing file '%s'", -+ path_name); -+ return add_inode(st, inum, flags); -+} -+ -+/** -+ * add_non_dir - write a non-directory to the output file. -+ * @path_name: source path name -+ * @inum: target inode number is passed and returned here (due to link counting) -+ * @nlink: number of links if known otherwise zero -+ * @type: UBIFS inode type is returned here -+ * @st: struct stat object containing inode attributes which should be use when -+ * creating the UBIFS inode -+ */ -+static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink, -+ unsigned char *type, struct stat *st) -+{ -+ int fd, flags = 0; -+ -+ dbg_msg(2, "%s", path_name); -+ -+ if (S_ISREG(st->st_mode)) { -+ fd = open(path_name, O_RDONLY); -+ if (fd == -1) -+ return sys_err_msg("failed to open file '%s'", -+ path_name); -+ if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) -+ flags = 0; -+ if (close(fd) == -1) -+ return sys_err_msg("failed to close file '%s'", -+ path_name); -+ *type = UBIFS_ITYPE_REG; -+ } else if (S_ISCHR(st->st_mode)) -+ *type = UBIFS_ITYPE_CHR; -+ else if (S_ISBLK(st->st_mode)) -+ *type = UBIFS_ITYPE_BLK; -+ else if (S_ISLNK(st->st_mode)) -+ *type = UBIFS_ITYPE_LNK; -+ else if (S_ISSOCK(st->st_mode)) -+ *type = UBIFS_ITYPE_SOCK; -+ else if (S_ISFIFO(st->st_mode)) -+ *type = UBIFS_ITYPE_FIFO; -+ else -+ return err_msg("file '%s' has unknown inode type", path_name); -+ -+ if (nlink) -+ st->st_nlink = nlink; -+ else if (st->st_nlink > 1) { -+ /* -+ * If the number of links is greater than 1, then add this file -+ * later when we know the number of links that we actually have. -+ * For now, we just put the inode mapping in the hash table. -+ */ -+ struct inum_mapping *im; -+ -+ im = lookup_inum_mapping(st->st_dev, st->st_ino); -+ if (!im) -+ return err_msg("out of memory"); -+ if (im->use_nlink == 0) { -+ /* New entry */ -+ im->use_inum = *inum; -+ im->use_nlink = 1; -+ im->path_name = malloc(strlen(path_name) + 1); -+ if (!im->path_name) -+ return err_msg("out of memory"); -+ strcpy(im->path_name, path_name); -+ } else { -+ /* Existing entry */ -+ *inum = im->use_inum; -+ im->use_nlink += 1; -+ /* Return unused inode number */ -+ c->highest_inum -= 1; -+ } -+ -+ memcpy(&im->st, st, sizeof(struct stat)); -+ return 0; -+ } else -+ st->st_nlink = 1; -+ -+ creat_sqnum = ++c->max_sqnum; -+ -+ if (S_ISREG(st->st_mode)) -+ return add_file(path_name, st, *inum, flags); -+ if (S_ISCHR(st->st_mode)) -+ return add_dev_inode(st, *inum, flags); -+ if (S_ISBLK(st->st_mode)) -+ return add_dev_inode(st, *inum, flags); -+ if (S_ISLNK(st->st_mode)) -+ return add_symlink_inode(path_name, st, *inum, flags); -+ if (S_ISSOCK(st->st_mode)) -+ return add_inode(st, *inum, flags); -+ if (S_ISFIFO(st->st_mode)) -+ return add_inode(st, *inum, flags); -+ -+ return err_msg("file '%s' has unknown inode type", path_name); -+} -+ -+/** -+ * add_directory - write a directory tree to the output file. -+ * @dir_name: directory path name -+ * @dir_inum: UBIFS inode number of directory -+ * @st: directory inode statistics -+ * @non_existing: non-zero if this function is called for a directory which -+ * does not exist on the host file-system and it is being -+ * created because it is defined in the device table file. -+ */ -+static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st, -+ int non_existing) -+{ -+ struct dirent *entry; -+ DIR *dir = NULL; -+ int err = 0; -+ loff_t size = UBIFS_INO_NODE_SZ; -+ char *name = NULL; -+ unsigned int nlink = 2; -+ struct path_htbl_element *ph_elt; -+ struct name_htbl_element *nh_elt = NULL; -+ struct hashtable_itr *itr; -+ ino_t inum; -+ unsigned char type; -+ unsigned long long dir_creat_sqnum = ++c->max_sqnum; -+ -+ dbg_msg(2, "%s", dir_name); -+ if (!non_existing) { -+ dir = opendir(dir_name); -+ if (dir == NULL) -+ return sys_err_msg("cannot open directory '%s'", -+ dir_name); -+ } -+ -+ /* -+ * Check whether this directory contains files which should be -+ * added/changed because they were specified in the device table. -+ * @ph_elt will be non-zero if yes. -+ */ -+ ph_elt = devtbl_find_path(dir_name + root_len - 1); -+ -+ /* -+ * Before adding the directory itself, we have to iterate over all the -+ * entries the device table adds to this directory and create them. -+ */ -+ for (; !non_existing;) { -+ struct stat dent_st; -+ -+ errno = 0; -+ entry = readdir(dir); -+ if (!entry) { -+ if (errno == 0) -+ break; -+ sys_err_msg("error reading directory '%s'", dir_name); -+ err = -1; -+ break; -+ } -+ -+ if (strcmp(".", entry->d_name) == 0) -+ continue; -+ if (strcmp("..", entry->d_name) == 0) -+ continue; -+ -+ if (ph_elt) -+ /* -+ * This directory was referred to at the device table -+ * file. Check if this directory entry is referred at -+ * too. -+ */ -+ nh_elt = devtbl_find_name(ph_elt, entry->d_name); -+ -+ /* -+ * We are going to create the file corresponding to this -+ * directory entry (@entry->d_name). We use 'struct stat' -+ * object to pass information about file attributes (actually -+ * only about UID, GID, mode, major, and minor). Get attributes -+ * for this file from the UBIFS rootfs on the host. -+ */ -+ free(name); -+ name = make_path(dir_name, entry->d_name); -+ if (lstat(name, &dent_st) == -1) { -+ sys_err_msg("lstat failed for file '%s'", name); -+ goto out_free; -+ } -+ -+ if (squash_owner) -+ /* -+ * Squash UID/GID. But the device table may override -+ * this. -+ */ -+ dent_st.st_uid = dent_st.st_gid = 0; -+ -+ /* -+ * And if the device table describes the same file, override -+ * the attributes. However, this is not allowed for device node -+ * files. -+ */ -+ if (nh_elt && override_attributes(&dent_st, ph_elt, nh_elt)) -+ goto out_free; -+ -+ inum = ++c->highest_inum; -+ -+ if (S_ISDIR(dent_st.st_mode)) { -+ err = add_directory(name, inum, &dent_st, 0); -+ if (err) -+ goto out_free; -+ nlink += 1; -+ type = UBIFS_ITYPE_DIR; -+ } else { -+ err = add_non_dir(name, &inum, 0, &type, &dent_st); -+ if (err) -+ goto out_free; -+ } -+ -+ err = add_dent_node(dir_inum, entry->d_name, inum, type); -+ if (err) -+ goto out_free; -+ size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(entry->d_name) + 1, -+ 8); -+ } -+ -+ /* -+ * OK, we have created all files in this directory (recursively), let's -+ * also create all files described in the device table. All t -+ */ -+ nh_elt = first_name_htbl_element(ph_elt, &itr); -+ while (nh_elt) { -+ struct stat fake_st; -+ -+ /* -+ * We prohibit creating regular files using the device table, -+ * the device table may only re-define attributes of regular -+ * files. -+ */ -+ if (S_ISREG(nh_elt->mode)) { -+ err_msg("Bad device table entry %s/%s - it is " -+ "prohibited to create regular files " -+ "via device table", -+ strcmp(ph_elt->path, "/") ? ph_elt->path : "", -+ nh_elt->name); -+ goto out_free; -+ } -+ -+ memcpy(&fake_st, &root_st, sizeof(struct stat)); -+ fake_st.st_uid = nh_elt->uid; -+ fake_st.st_uid = nh_elt->uid; -+ fake_st.st_mode = nh_elt->mode; -+ fake_st.st_rdev = nh_elt->dev; -+ fake_st.st_nlink = 1; -+ -+ free(name); -+ name = make_path(dir_name, nh_elt->name); -+ inum = ++c->highest_inum; -+ -+ if (S_ISDIR(nh_elt->mode)) { -+ err = add_directory(name, inum, &fake_st, 1); -+ if (err) -+ goto out_free; -+ nlink += 1; -+ type = UBIFS_ITYPE_DIR; -+ } else { -+ err = add_non_dir(name, &inum, 0, &type, &fake_st); -+ if (err) -+ goto out_free; -+ } -+ -+ err = add_dent_node(dir_inum, nh_elt->name, inum, type); -+ if (err) -+ goto out_free; -+ size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(nh_elt->name) + 1, 8); -+ -+ nh_elt = next_name_htbl_element(ph_elt, &itr); -+ } -+ -+ creat_sqnum = dir_creat_sqnum; -+ -+ err = add_dir_inode(dir, dir_inum, size, nlink, st); -+ if (err) -+ goto out_free; -+ -+ free(name); -+ if (!non_existing && closedir(dir) == -1) -+ return sys_err_msg("error closing directory '%s'", dir_name); -+ -+ return 0; -+ -+out_free: -+ free(name); -+ if (!non_existing) -+ closedir(dir); -+ return -1; -+} -+ -+/** -+ * add_multi_linked_files - write all the files for which we counted links. -+ */ -+static int add_multi_linked_files(void) -+{ -+ int i, err; -+ -+ for (i = 0; i < HASH_TABLE_SIZE; i++) { -+ struct inum_mapping *im; -+ unsigned char type = 0; -+ -+ for (im = hash_table[i]; im; im = im->next) { -+ dbg_msg(2, "%s", im->path_name); -+ err = add_non_dir(im->path_name, &im->use_inum, -+ im->use_nlink, &type, &im->st); -+ if (err) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * write_data - write the files and directories. -+ */ -+static int write_data(void) -+{ -+ int err; -+ -+ err = stat(root, &root_st); -+ if (err) -+ return sys_err_msg("bad root file-system directory '%s'", root); -+ root_st.st_uid = root_st.st_gid = 0; -+ root_st.st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; -+ -+ head_flags = 0; -+ err = add_directory(root, UBIFS_ROOT_INO, &root_st, 0); -+ if (err) -+ return err; -+ err = add_multi_linked_files(); -+ if (err) -+ return err; -+ return flush_nodes(); -+} -+ -+static int namecmp(const char *name1, const char *name2) -+{ -+ size_t len1 = strlen(name1), len2 = strlen(name2); -+ size_t clen = (len1 < len2) ? len1 : len2; -+ int cmp; -+ -+ cmp = memcmp(name1, name2, clen); -+ if (cmp) -+ return cmp; -+ return (len1 < len2) ? -1 : 1; -+} -+ -+static int cmp_idx(const void *a, const void *b) -+{ -+ const struct idx_entry *e1 = *(const struct idx_entry **)a; -+ const struct idx_entry *e2 = *(const struct idx_entry **)b; -+ int cmp; -+ -+ cmp = keys_cmp(c, &e1->key, &e2->key); -+ if (cmp) -+ return cmp; -+ return namecmp(e1->name, e2->name); -+} -+ -+/** -+ * add_idx_node - write an index node to the head. -+ * @node: index node -+ * @child_cnt: number of children of this index node -+ */ -+static int add_idx_node(void *node, int child_cnt) -+{ -+ int err, lnum, offs, len; -+ -+ len = ubifs_idx_node_sz(c, child_cnt); -+ -+ prepare_node(node, len); -+ -+ err = reserve_space(len, &lnum, &offs); -+ if (err) -+ return err; -+ -+ memcpy(leb_buf + offs, node, len); -+ memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len); -+ -+ c->old_idx_sz += ALIGN(len, 8); -+ -+ dbg_msg(3, "at %d:%d len %d index size %llu", lnum, offs, len, -+ c->old_idx_sz); -+ -+ /* The last index node written will be the root */ -+ c->zroot.lnum = lnum; -+ c->zroot.offs = offs; -+ c->zroot.len = len; -+ -+ return 0; -+} -+ -+/** -+ * write_index - write out the index. -+ */ -+static int write_index(void) -+{ -+ size_t sz, i, cnt, idx_sz, pstep, bcnt; -+ struct idx_entry **idx_ptr, **p; -+ struct ubifs_idx_node *idx; -+ struct ubifs_branch *br; -+ int child_cnt, j, level, blnum, boffs, blen, blast_len, err; -+ -+ dbg_msg(1, "leaf node count: %d", idx_cnt); -+ -+ /* Reset the head for the index */ -+ head_flags = LPROPS_INDEX; -+ /* Allocate index node */ -+ idx_sz = ubifs_idx_node_sz(c, c->fanout); -+ idx = malloc(idx_sz); -+ if (!idx) -+ return err_msg("out of memory"); -+ /* Make an array of pointers to sort the index list */ -+ sz = idx_cnt * sizeof(struct idx_entry *); -+ if (sz / sizeof(struct idx_entry *) != idx_cnt) { -+ free(idx); -+ return err_msg("index is too big (%zu entries)", idx_cnt); -+ } -+ idx_ptr = malloc(sz); -+ if (!idx_ptr) { -+ free(idx); -+ return err_msg("out of memory - needed %zu bytes for index", -+ sz); -+ } -+ idx_ptr[0] = idx_list_first; -+ for (i = 1; i < idx_cnt; i++) -+ idx_ptr[i] = idx_ptr[i - 1]->next; -+ qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx); -+ /* Write level 0 index nodes */ -+ cnt = idx_cnt / c->fanout; -+ if (idx_cnt % c->fanout) -+ cnt += 1; -+ p = idx_ptr; -+ blnum = head_lnum; -+ boffs = head_offs; -+ for (i = 0; i < cnt; i++) { -+ /* -+ * Calculate the child count. All index nodes are created full -+ * except for the last index node on each row. -+ */ -+ if (i == cnt - 1) { -+ child_cnt = idx_cnt % c->fanout; -+ if (child_cnt == 0) -+ child_cnt = c->fanout; -+ } else -+ child_cnt = c->fanout; -+ memset(idx, 0, idx_sz); -+ idx->ch.node_type = UBIFS_IDX_NODE; -+ idx->child_cnt = cpu_to_le16(child_cnt); -+ idx->level = cpu_to_le16(0); -+ for (j = 0; j < child_cnt; j++, p++) { -+ br = ubifs_idx_branch(c, idx, j); -+ key_write_idx(c, &(*p)->key, &br->key); -+ br->lnum = cpu_to_le32((*p)->lnum); -+ br->offs = cpu_to_le32((*p)->offs); -+ br->len = cpu_to_le32((*p)->len); -+ } -+ add_idx_node(idx, child_cnt); -+ } -+ /* Write level 1 index nodes and above */ -+ level = 0; -+ pstep = 1; -+ while (cnt > 1) { -+ /* -+ * 'blast_len' is the length of the last index node in the level -+ * below. -+ */ -+ blast_len = ubifs_idx_node_sz(c, child_cnt); -+ /* 'bcnt' is the number of index nodes in the level below */ -+ bcnt = cnt; -+ /* 'cnt' is the number of index nodes in this level */ -+ cnt = (cnt + c->fanout - 1) / c->fanout; -+ if (cnt == 0) -+ cnt = 1; -+ level += 1; -+ /* -+ * The key of an index node is the same as the key of its first -+ * child. Thus we can get the key by stepping along the bottom -+ * level 'p' with an increasing large step 'pstep'. -+ */ -+ p = idx_ptr; -+ pstep *= c->fanout; -+ for (i = 0; i < cnt; i++) { -+ /* -+ * Calculate the child count. All index nodes are -+ * created full except for the last index node on each -+ * row. -+ */ -+ if (i == cnt - 1) { -+ child_cnt = bcnt % c->fanout; -+ if (child_cnt == 0) -+ child_cnt = c->fanout; -+ } else -+ child_cnt = c->fanout; -+ memset(idx, 0, idx_sz); -+ idx->ch.node_type = UBIFS_IDX_NODE; -+ idx->child_cnt = cpu_to_le16(child_cnt); -+ idx->level = cpu_to_le16(level); -+ for (j = 0; j < child_cnt; j++) { -+ size_t bn = i * c->fanout + j; -+ -+ /* -+ * The length of the index node in the level -+ * below is 'idx_sz' except when it is the last -+ * node on the row. i.e. all the others on the -+ * row are full. -+ */ -+ if (bn == bcnt - 1) -+ blen = blast_len; -+ else -+ blen = idx_sz; -+ /* -+ * 'blnum' and 'boffs' hold the position of the -+ * index node on the level below. -+ */ -+ if (boffs + blen > c->leb_size) { -+ blnum += 1; -+ boffs = 0; -+ } -+ /* -+ * Fill in the branch with the key and position -+ * of the index node from the level below. -+ */ -+ br = ubifs_idx_branch(c, idx, j); -+ key_write_idx(c, &(*p)->key, &br->key); -+ br->lnum = cpu_to_le32(blnum); -+ br->offs = cpu_to_le32(boffs); -+ br->len = cpu_to_le32(blen); -+ /* -+ * Step to the next index node on the level -+ * below. -+ */ -+ boffs += ALIGN(blen, 8); -+ p += pstep; -+ } -+ add_idx_node(idx, child_cnt); -+ } -+ } -+ -+ /* Free stuff */ -+ for (i = 0; i < idx_cnt; i++) -+ free(idx_ptr[i]); -+ free(idx_ptr); -+ free(idx); -+ -+ dbg_msg(1, "zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs, -+ c->zroot.len); -+ -+ /* Set the index head */ -+ c->ihead_lnum = head_lnum; -+ c->ihead_offs = ALIGN(head_offs, c->min_io_size); -+ dbg_msg(1, "ihead is at %d:%d", c->ihead_lnum, c->ihead_offs); -+ -+ /* Flush the last index LEB */ -+ err = flush_nodes(); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/** -+ * set_gc_lnum - set the LEB number reserved for the garbage collector. -+ */ -+static int set_gc_lnum(void) -+{ -+ int err; -+ -+ c->gc_lnum = head_lnum++; -+ err = write_empty_leb(c->gc_lnum); -+ if (err) -+ return err; -+ set_lprops(c->gc_lnum, 0, 0); -+ c->lst.empty_lebs += 1; -+ return 0; -+} -+ -+/** -+ * finalize_leb_cnt - now that we know how many LEBs we used. -+ */ -+static int finalize_leb_cnt(void) -+{ -+ c->leb_cnt = head_lnum; -+ if (c->leb_cnt > c->max_leb_cnt) -+ /* TODO: in this case it segfaults because buffer overruns - we -+ * somewhere allocate smaller buffers - fix */ -+ return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt); -+ c->main_lebs = c->leb_cnt - c->main_first; -+ if (verbose) { -+ printf("\tsuper lebs: %d\n", UBIFS_SB_LEBS); -+ printf("\tmaster lebs: %d\n", UBIFS_MST_LEBS); -+ printf("\tlog_lebs: %d\n", c->log_lebs); -+ printf("\tlpt_lebs: %d\n", c->lpt_lebs); -+ printf("\torph_lebs: %d\n", c->orph_lebs); -+ printf("\tmain_lebs: %d\n", c->main_lebs); -+ printf("\tgc lebs: %d\n", 1); -+ printf("\tindex lebs: %d\n", c->lst.idx_lebs); -+ printf("\tleb_cnt: %d\n", c->leb_cnt); -+ } -+ dbg_msg(1, "total_free: %llu", c->lst.total_free); -+ dbg_msg(1, "total_dirty: %llu", c->lst.total_dirty); -+ dbg_msg(1, "total_used: %llu", c->lst.total_used); -+ dbg_msg(1, "total_dead: %llu", c->lst.total_dead); -+ dbg_msg(1, "total_dark: %llu", c->lst.total_dark); -+ dbg_msg(1, "index size: %llu", c->old_idx_sz); -+ dbg_msg(1, "empty_lebs: %d", c->lst.empty_lebs); -+ return 0; -+} -+ -+/** -+ * write_super - write the super block. -+ */ -+static int write_super(void) -+{ -+ struct ubifs_sb_node sup; -+ -+ memset(&sup, 0, UBIFS_SB_NODE_SZ); -+ -+ sup.ch.node_type = UBIFS_SB_NODE; -+ sup.key_hash = c->key_hash_type; -+ sup.min_io_size = cpu_to_le32(c->min_io_size); -+ sup.leb_size = cpu_to_le32(c->leb_size); -+ sup.leb_cnt = cpu_to_le32(c->leb_cnt); -+ sup.max_leb_cnt = cpu_to_le32(c->max_leb_cnt); -+ sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes); -+ sup.log_lebs = cpu_to_le32(c->log_lebs); -+ sup.lpt_lebs = cpu_to_le32(c->lpt_lebs); -+ sup.orph_lebs = cpu_to_le32(c->orph_lebs); -+ sup.jhead_cnt = cpu_to_le32(c->jhead_cnt); -+ sup.fanout = cpu_to_le32(c->fanout); -+ sup.lsave_cnt = cpu_to_le32(c->lsave_cnt); -+ sup.fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); -+ sup.default_compr = cpu_to_le16(c->default_compr); -+ sup.time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); -+ if (c->big_lpt) -+ sup.flags |= UBIFS_FLG_BIGLPT; -+ -+ return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM); -+} -+ -+/** -+ * write_master - write the master node. -+ */ -+static int write_master(void) -+{ -+ struct ubifs_mst_node mst; -+ int err; -+ -+ memset(&mst, 0, UBIFS_MST_NODE_SZ); -+ -+ mst.ch.node_type = UBIFS_MST_NODE; -+ mst.log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); -+ mst.highest_inum = cpu_to_le64(c->highest_inum); -+ mst.cmt_no = cpu_to_le64(0); -+ mst.flags = cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ mst.root_lnum = cpu_to_le32(c->zroot.lnum); -+ mst.root_offs = cpu_to_le32(c->zroot.offs); -+ mst.root_len = cpu_to_le32(c->zroot.len); -+ mst.gc_lnum = cpu_to_le32(c->gc_lnum); -+ mst.ihead_lnum = cpu_to_le32(c->ihead_lnum); -+ mst.ihead_offs = cpu_to_le32(c->ihead_offs); -+ mst.index_size = cpu_to_le64(c->old_idx_sz); -+ mst.lpt_lnum = cpu_to_le32(c->lpt_lnum); -+ mst.lpt_offs = cpu_to_le32(c->lpt_offs); -+ mst.nhead_lnum = cpu_to_le32(c->nhead_lnum); -+ mst.nhead_offs = cpu_to_le32(c->nhead_offs); -+ mst.ltab_lnum = cpu_to_le32(c->ltab_lnum); -+ mst.ltab_offs = cpu_to_le32(c->ltab_offs); -+ mst.lsave_lnum = cpu_to_le32(c->lsave_lnum); -+ mst.lsave_offs = cpu_to_le32(c->lsave_offs); -+ mst.lscan_lnum = cpu_to_le32(c->lscan_lnum); -+ mst.empty_lebs = cpu_to_le32(c->lst.empty_lebs); -+ mst.idx_lebs = cpu_to_le32(c->lst.idx_lebs); -+ mst.total_free = cpu_to_le64(c->lst.total_free); -+ mst.total_dirty = cpu_to_le64(c->lst.total_dirty); -+ mst.total_used = cpu_to_le64(c->lst.total_used); -+ mst.total_dead = cpu_to_le64(c->lst.total_dead); -+ mst.total_dark = cpu_to_le64(c->lst.total_dark); -+ mst.leb_cnt = cpu_to_le32(c->leb_cnt); -+ -+ err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM); -+ if (err) -+ return err; -+ -+ err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/** -+ * write_log - write an empty log. -+ */ -+static int write_log(void) -+{ -+ struct ubifs_cs_node cs; -+ int err, i, lnum; -+ -+ lnum = UBIFS_LOG_LNUM; -+ -+ cs.ch.node_type = UBIFS_CS_NODE; -+ cs.cmt_no = cpu_to_le64(0); -+ -+ err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum); -+ if (err) -+ return err; -+ -+ lnum += 1; -+ -+ for (i = 1; i < c->log_lebs; i++, lnum++) { -+ err = write_empty_leb(lnum); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * write_lpt - write the LEB properties tree. -+ */ -+static int write_lpt(void) -+{ -+ int err, lnum; -+ -+ err = create_lpt(c); -+ if (err) -+ return err; -+ -+ lnum = c->nhead_lnum + 1; -+ while (lnum <= c->lpt_last) { -+ err = write_empty_leb(lnum++); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * write_orphan_area - write an empty orphan area. -+ */ -+static int write_orphan_area(void) -+{ -+ int err, i, lnum; -+ -+ lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs; -+ for (i = 0; i < c->orph_lebs; i++, lnum++) { -+ err = write_empty_leb(lnum); -+ if (err) -+ return err; -+ } -+ return 0; -+} -+ -+/** -+ * open_target - open the output file. -+ */ -+static int open_target(void) -+{ -+ out_fd = open(output, O_CREAT | O_RDWR | O_TRUNC, -+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); -+ if (out_fd == -1) -+ return sys_err_msg("cannot create output file '%s'", output); -+ return 0; -+} -+ -+/** -+ * close_target - close the output file. -+ */ -+static int close_target(void) -+{ -+ if (close(out_fd) == -1) -+ return sys_err_msg("cannot close output file '%s'", output); -+ return 0; -+} -+ -+/** -+ * init - initialize things. -+ */ -+static int init(void) -+{ -+ int err, i, main_lebs, big_lpt = 0, sz; -+ -+ c->highest_inum = UBIFS_FIRST_INO; -+ -+ c->jhead_cnt = 1; -+ -+ main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; -+ main_lebs -= c->log_lebs + c->orph_lebs; -+ -+ err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt); -+ if (err) -+ return err; -+ -+ c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs + -+ c->orph_lebs; -+ head_lnum = c->main_first; -+ head_offs = 0; -+ -+ c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs; -+ c->lpt_last = c->lpt_first + c->lpt_lebs - 1; -+ -+ c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops)); -+ if (!c->lpt) -+ return err_msg("unable to allocate LPT"); -+ -+ c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops)); -+ if (!c->ltab) -+ return err_msg("unable to allocate LPT ltab"); -+ -+ /* Initialize LPT's own lprops */ -+ for (i = 0; i < c->lpt_lebs; i++) { -+ c->ltab[i].free = c->leb_size; -+ c->ltab[i].dirty = 0; -+ } -+ -+ c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); -+ c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); -+ dbg_msg(1, "dead_wm %d dark_wm %d", c->dead_wm, c->dark_wm); -+ -+ leb_buf = malloc(c->leb_size); -+ if (!leb_buf) -+ return err_msg("out of memory"); -+ -+ node_buf = malloc(NODE_BUFFER_SIZE); -+ if (!node_buf) -+ return err_msg("out of memory"); -+ -+ block_buf = malloc(UBIFS_BLOCK_SIZE); -+ if (!block_buf) -+ return err_msg("out of memory"); -+ -+ sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE; -+ hash_table = malloc(sz); -+ if (!hash_table) -+ return err_msg("out of memory"); -+ memset(hash_table, 0, sz); -+ -+ err = init_compression(); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static void destroy_hash_table(void) -+{ -+ int i; -+ -+ for (i = 0; i < HASH_TABLE_SIZE; i++) { -+ struct inum_mapping *im, *q; -+ -+ for (im = hash_table[i]; im; ) { -+ q = im; -+ im = im->next; -+ free(q->path_name); -+ free(q); -+ } -+ } -+} -+ -+/** -+ * deinit - deinitialize things. -+ */ -+static void deinit(void) -+{ -+ free(c->lpt); -+ free(c->ltab); -+ free(leb_buf); -+ free(node_buf); -+ free(block_buf); -+ destroy_hash_table(); -+ free(hash_table); -+ destroy_compression(); -+ free_devtable_info(); -+} -+ -+/** -+ * mkfs - make the file system. -+ * -+ * Each on-flash area has a corresponding function to create it. The order of -+ * the functions reflects what information must be known to complete each stage. -+ * As a consequence the output file is not written sequentially. No effort has -+ * been made to make efficient use of memory or to allow for the possibility of -+ * incremental updates to the output file. -+ */ -+static int mkfs(void) -+{ -+ int err = 0; -+ -+ err = init(); -+ if (err) -+ goto out; -+ -+ err = write_data(); -+ if (err) -+ goto out; -+ -+ err = set_gc_lnum(); -+ if (err) -+ goto out; -+ -+ err = write_index(); -+ if (err) -+ goto out; -+ -+ err = finalize_leb_cnt(); -+ if (err) -+ goto out; -+ -+ err = write_lpt(); -+ if (err) -+ goto out; -+ -+ err = write_super(); -+ if (err) -+ goto out; -+ -+ err = write_master(); -+ if (err) -+ goto out; -+ -+ err = write_log(); -+ if (err) -+ goto out; -+ -+ err = write_orphan_area(); -+ -+out: -+ deinit(); -+ return err; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int err; -+ -+ err = get_options(argc, argv); -+ if (err) -+ return err; -+ -+ err = open_target(); -+ if (err) -+ return err; -+ -+ err = mkfs(); -+ if (err) { -+ close_target(); -+ return err; -+ } -+ -+ err = close_target(); -+ if (err) -+ return err; -+ -+ if (verbose) -+ printf("Success!\n"); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/mkfs.ubifs.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/mkfs.ubifs.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/mkfs.ubifs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/mkfs.ubifs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,143 @@ -+/* -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+#ifndef __MKFS_UBIFS_H__ -+#define __MKFS_UBIFS_H__ -+ -+#define _GNU_SOURCE -+#define _LARGEFILE64_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "crc32.h" -+#include "defs.h" -+#include "crc16.h" -+#include "ubifs-media.h" -+#include "ubifs.h" -+#include "key.h" -+#include "lpt.h" -+#include "compr.h" -+ -+/* -+ * Compression flags are duplicated so that compr.c can compile without ubifs.h. -+ * Here we make sure they are the same. -+ */ -+#if MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE -+#error MKFS_UBIFS_COMPR_NONE != UBIFS_COMPR_NONE -+#endif -+#if MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO -+#error MKFS_UBIFS_COMPR_LZO != UBIFS_COMPR_LZO -+#endif -+#if MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB -+#error MKFS_UBIFS_COMPR_ZLIB != UBIFS_COMPR_ZLIB -+#endif -+ -+extern int verbose; -+extern int debug_level; -+ -+#define dbg_msg(lvl, fmt, ...) do {if (debug_level >= lvl) \ -+ printf("mkfs.ubifs: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__); \ -+} while(0) -+ -+#define err_msg(fmt, ...) ({ \ -+ fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \ -+ -1; \ -+}) -+ -+#define sys_err_msg(fmt, ...) ({ \ -+ int err_ = errno; \ -+ fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \ -+ fprintf(stderr, " %s (error %d)\n", strerror(err_), err_); \ -+ -1; \ -+}) -+ -+/** -+ * struct path_htbl_element - an element of the path hash table. -+ * @path: the UBIFS path the element describes (the key of the element) -+ * @name_htbl: one more (nested) hash table containing names of all -+ * files/directories/device nodes which should be created at this -+ * path -+ * -+ * See device table handling for more information. -+ */ -+struct path_htbl_element { -+ const char *path; -+ struct hashtable *name_htbl; -+}; -+ -+/** -+ * struct name_htbl_element - an element in the name hash table -+ * @name: name of the file/directory/device node (the key of the element) -+ * @mode: accsess rights and file type -+ * @uid: user ID -+ * @gid: group ID -+ * @major: device node major number -+ * @minor: device node minor number -+ * -+ * This is an element of the name hash table. Name hash table sits in the path -+ * hash table elements and describes file names which should be created/changed -+ * at this path. -+ */ -+struct name_htbl_element { -+ const char *name; -+ unsigned int mode; -+ unsigned int uid; -+ unsigned int gid; -+ dev_t dev; -+}; -+ -+struct hashtable_itr; -+ -+int write_leb(int lnum, int len, void *buf); -+int parse_devtable(const char *root, const char *tbl_file); -+struct path_htbl_element *devtbl_find_path(const char *path); -+struct name_htbl_element *devtbl_find_name(struct path_htbl_element *ph_elt, -+ const char *name); -+int override_attributes(struct stat *st, struct path_htbl_element *ph_elt, -+ struct name_htbl_element *nh_elt); -+struct name_htbl_element * -+first_name_htbl_element(struct path_htbl_element *ph_elt, -+ struct hashtable_itr **itr); -+struct name_htbl_element * -+next_name_htbl_element(struct path_htbl_element *ph_elt, -+ struct hashtable_itr **itr); -+void free_devtable_info(void); -+ -+#endif -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/readme linux-2.6.24.7/fs/ubifs/mkfs.ubifs/readme ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/readme 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/readme 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+UBIFS File System - Make File System program -+ -+* crc16.h and crc16.c were copied from the linux kernel. -+* crc32.h and crc32.c were copied from mtd-utils and amended. -+* ubifs-media.h is fs/ubifs/ubifs-media.h from the linux kernel -+* ubifs.h is a selection of definitions from fs/ubifs/ubifs.h from the linux kernel. -+* key.h is copied from fs/ubifs/key.h from the linux kernel. -+* defs.h is a bunch of definitions to smooth things over. -+* lpt.c is a selection of functions copied from fs/ubifs/lpt.c from the linux kernel, and amended. -+* hashtable/* was downloaded from http://www.cl.cam.ac.uk/~cwc22/hashtable/ -+ -+*************************************************************************** -+ -+To build the mkfs.ubifs: -+ -+$ cd fs/ubifs/mkfs.ubifs -+$ make -+ -+To run mkfs.ubifs: -+ -+$ export LD_LIBRARY_PATH=`pwd`/lzo/lib:$LD_LIBRARY_PATH -+$ ./mkfs.ubifs -h -+ -+To build an ubifs image: -+ -+$ ./mkfs.ubifs -r /nfsroot/root26 -m 2048 -e 258048 -c 813 -o ubifs.img -+ -+*************************************************************************** -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/ubifs-media.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/ubifs-media.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/ubifs-media.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/ubifs-media.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,725 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file describes UBIFS on-flash format and contains definitions of all the -+ * relevant data structures and constants. -+ * -+ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start -+ * with the UBIFS node magic number and have the same common header. Nodes -+ * always sit at 8-byte aligned positions on the media and node header sizes are -+ * also 8-byte aligned (except for the indexing node and the padding node). -+ */ -+ -+#ifndef __UBIFS_MEDIA_H__ -+#define __UBIFS_MEDIA_H__ -+ -+/* UBIFS node magic number (must not have the padding byte first or last) */ -+#define UBIFS_NODE_MAGIC 0x06101831 -+ -+/* UBIFS on-flash format version */ -+#define UBIFS_FORMAT_VERSION 3 -+ -+/* Minimum logical eraseblock size in bytes */ -+#define UBIFS_MIN_LEB_SZ (15*1024) -+ -+/* Initial CRC32 value used when calculating CRC checksums */ -+#define UBIFS_CRC32_INIT 0xFFFFFFFFU -+ -+/* -+ * UBIFS does not try to compress data if its length is less than the below -+ * constant. -+ */ -+#define UBIFS_MIN_COMPR_LEN 128 -+ -+/* Root inode number */ -+#define UBIFS_ROOT_INO 1 -+ -+/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */ -+#define UBIFS_FIRST_INO 64 -+ -+/* -+ * Maximum file name and extended attribute length (must be a multiple of 8, -+ * minus 1). -+ */ -+#define UBIFS_MAX_NLEN 255 -+ -+/* Maximum number of data journal heads */ -+#define UBIFS_MAX_JHEADS 1 -+ -+/* -+ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system, -+ * which means that it does not treat the underlying media as consisting of -+ * blocks like in case of hard drives. Do not be confused. UBIFS block is just -+ * the maximum amount of data which one data node can have or which can be -+ * attached to an inode node. -+ */ -+#define UBIFS_BLOCK_SIZE 4096 -+#define UBIFS_BLOCK_SHIFT 12 -+#define UBIFS_BLOCK_MASK 0x00000FFF -+ -+/* UBIFS padding byte pattern (must not be first or last byte of node magic) */ -+#define UBIFS_PADDING_BYTE 0xCE -+ -+/* Maximum possible key length */ -+#define UBIFS_MAX_KEY_LEN 16 -+ -+/* Key length ("simple" format) */ -+#define UBIFS_SK_LEN 8 -+ -+/* Minimum index tree fanout */ -+#define UBIFS_MIN_FANOUT 2 -+ -+/* Maximum number of levels in UBIFS indexing B-tree */ -+#define UBIFS_MAX_LEVELS 512 -+ -+/* Maximum amount of data attached to an inode in bytes */ -+#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE -+ -+/* LEB Properties Tree fanout (must be power of 2) and fanout shift */ -+#define UBIFS_LPT_FANOUT 4 -+#define UBIFS_LPT_FANOUT_SHIFT 2 -+ -+/* LEB Properties Tree bit field sizes */ -+#define UBIFS_LPT_CRC_BITS 16 -+#define UBIFS_LPT_CRC_BYTES 2 -+#define UBIFS_LPT_TYPE_BITS 4 -+ -+/* The key is always at the same position in all keyed nodes */ -+#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key) -+ -+/* -+ * LEB Properties Tree node types. -+ * -+ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties) -+ * UBIFS_LPT_NNODE: LPT internal node -+ * UBIFS_LPT_LTAB: LPT's own lprops table -+ * UBIFS_LPT_LSAVE: LPT's save table (big model only) -+ * UBIFS_LPT_NODE_CNT: count of LPT node types -+ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type -+ */ -+enum { -+ UBIFS_LPT_PNODE, -+ UBIFS_LPT_NNODE, -+ UBIFS_LPT_LTAB, -+ UBIFS_LPT_LSAVE, -+ UBIFS_LPT_NODE_CNT, -+ UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1, -+}; -+ -+/* -+ * UBIFS inode types. -+ * -+ * UBIFS_ITYPE_REG: regular file -+ * UBIFS_ITYPE_DIR: directory -+ * UBIFS_ITYPE_LNK: soft link -+ * UBIFS_ITYPE_BLK: block device node -+ * UBIFS_ITYPE_CHR: character device node -+ * UBIFS_ITYPE_FIFO: fifo -+ * UBIFS_ITYPE_SOCK: socket -+ * UBIFS_ITYPES_CNT: count of supported file types -+ */ -+enum { -+ UBIFS_ITYPE_REG, -+ UBIFS_ITYPE_DIR, -+ UBIFS_ITYPE_LNK, -+ UBIFS_ITYPE_BLK, -+ UBIFS_ITYPE_CHR, -+ UBIFS_ITYPE_FIFO, -+ UBIFS_ITYPE_SOCK, -+ UBIFS_ITYPES_CNT, -+}; -+ -+/* -+ * Supported key hash functions. -+ * -+ * UBIFS_KEY_HASH_R5: R5 hash -+ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name -+ */ -+enum { -+ UBIFS_KEY_HASH_R5, -+ UBIFS_KEY_HASH_TEST, -+}; -+ -+/* -+ * Supported key formats. -+ * -+ * UBIFS_SIMPLE_KEY_FMT: simple key format -+ */ -+enum { -+ UBIFS_SIMPLE_KEY_FMT, -+}; -+ -+/* -+ * The simple key format uses 29 bits for storing UBIFS block number and hash -+ * value. -+ */ -+#define UBIFS_S_KEY_BLOCK_BITS 29 -+#define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF -+#define UBIFS_S_KEY_HASH_BITS UBIFS_S_KEY_BLOCK_BITS -+#define UBIFS_S_KEY_HASH_MASK UBIFS_S_KEY_BLOCK_MASK -+ -+/* -+ * Key types. -+ * -+ * UBIFS_INO_KEY: inode node key -+ * UBIFS_DATA_KEY: data node key -+ * UBIFS_DENT_KEY: directory entry node key -+ * UBIFS_XENT_KEY: extended attribute entry key -+ * UBIFS_TRUN_KEY: truncation node key -+ * UBIFS_KEY_TYPES_CNT: number of supported key types -+ */ -+enum { -+ UBIFS_INO_KEY, -+ UBIFS_DATA_KEY, -+ UBIFS_DENT_KEY, -+ UBIFS_XENT_KEY, -+ UBIFS_TRUN_KEY, -+ UBIFS_KEY_TYPES_CNT, -+}; -+ -+/* Count of LEBs reserved for the superblock area */ -+#define UBIFS_SB_LEBS 1 -+/* Count of LEBs reserved for the master area */ -+#define UBIFS_MST_LEBS 2 -+ -+/* First LEB of the superblock area */ -+#define UBIFS_SB_LNUM 0 -+/* First LEB of the master area */ -+#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS) -+/* First LEB of the log area */ -+#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS) -+ -+/* Minimum number of logical eraseblocks in the log */ -+#define UBIFS_MIN_LOG_LEBS 2 -+/* Minimum number of bud logical eraseblocks */ -+#define UBIFS_MIN_BUD_LEBS 2 -+/* Minimum number of journal logical eraseblocks */ -+#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS) -+/* Minimum number of LPT area logical eraseblocks */ -+#define UBIFS_MIN_LPT_LEBS 2 -+/* Minimum number of orphan area logical eraseblocks */ -+#define UBIFS_MIN_ORPH_LEBS 1 -+/* Minimum number of main area logical eraseblocks */ -+#define UBIFS_MIN_MAIN_LEBS 8 -+ -+/* Minimum number of logical eraseblocks */ -+#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ -+ UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS + \ -+ UBIFS_MIN_LPT_LEBS + UBIFS_MIN_ORPH_LEBS + \ -+ UBIFS_MIN_MAIN_LEBS) -+ -+/* Node sizes (N.B. these are guaranteed to be multiples of 8) */ -+#define UBIFS_CH_SZ sizeof(struct ubifs_ch) -+#define UBIFS_INO_NODE_SZ sizeof(struct ubifs_ino_node) -+#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node) -+#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node) -+#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node) -+#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node) -+#define UBIFS_SB_NODE_SZ sizeof(struct ubifs_sb_node) -+#define UBIFS_MST_NODE_SZ sizeof(struct ubifs_mst_node) -+#define UBIFS_REF_NODE_SZ sizeof(struct ubifs_ref_node) -+#define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node) -+#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node) -+#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node) -+/* Extended attribute entry nodes are identical to directory entry nodes */ -+#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ -+/* Only this does not have to be multiple of 8 bytes */ -+#define UBIFS_BRANCH_SZ sizeof(struct ubifs_branch) -+ -+/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */ -+#define UBIFS_MAX_DATA_NODE_SZ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE) -+#define UBIFS_MAX_INO_NODE_SZ (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA) -+#define UBIFS_MAX_DENT_NODE_SZ (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1) -+#define UBIFS_MAX_XENT_NODE_SZ UBIFS_MAX_DENT_NODE_SZ -+ -+/* The largest UBIFS node */ -+#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ -+ -+/* -+ * On-flash inode flags. -+ * -+ * UBIFS_COMPR_FL: use compression for this inode -+ * UBIFS_SYNC_FL: I/O on this inode has to be synchronous -+ * UBIFS_IMMUTABLE_FL: inode is immutable -+ * UBIFS_APPEND_FL: writes to the inode may only append data -+ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous -+ * -+ * Note, these are on-flash flags which correspond to ioctl flags -+ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not -+ * have to be the same. -+ */ -+enum { -+ UBIFS_COMPR_FL = 0x01, -+ UBIFS_SYNC_FL = 0x02, -+ UBIFS_IMMUTABLE_FL = 0x04, -+ UBIFS_APPEND_FL = 0x08, -+ UBIFS_DIRSYNC_FL = 0x10, -+}; -+ -+/* Inode flag bits used by UBIFS */ -+#define UBIFS_FL_MASK 0x0000001F -+ -+/* -+ * UBIFS compression algorithms. -+ * -+ * UBIFS_COMPR_NONE: no compression -+ * UBIFS_COMPR_LZO: LZO compression -+ * UBIFS_COMPR_ZLIB: ZLIB compression -+ * UBIFS_COMPR_TYPES_CNT: count of supported compression types -+ */ -+enum { -+ UBIFS_COMPR_NONE, -+ UBIFS_COMPR_LZO, -+ UBIFS_COMPR_ZLIB, -+ UBIFS_COMPR_TYPES_CNT, -+}; -+ -+/* -+ * UBIFS node types. -+ * -+ * UBIFS_INO_NODE: inode node -+ * UBIFS_DATA_NODE: data node -+ * UBIFS_DENT_NODE: directory entry node -+ * UBIFS_XENT_NODE: extended attribute node -+ * UBIFS_TRUN_NODE: truncation node -+ * UBIFS_PAD_NODE: padding node -+ * UBIFS_SB_NODE: superblock node -+ * UBIFS_MST_NODE: master node -+ * UBIFS_REF_NODE: LEB reference node -+ * UBIFS_IDX_NODE: index node -+ * UBIFS_CS_NODE: commit start node -+ * UBIFS_ORPH_NODE: orphan node -+ * UBIFS_NODE_TYPES_CNT: count of supported node types -+ * -+ * Note, we index arrays by these numbers, so keep them low and contiguous. -+ * Node type constants for inodes, direntries and so on have to be the same as -+ * corresponding key type constants. -+ */ -+enum { -+ UBIFS_INO_NODE, -+ UBIFS_DATA_NODE, -+ UBIFS_DENT_NODE, -+ UBIFS_XENT_NODE, -+ UBIFS_TRUN_NODE, -+ UBIFS_PAD_NODE, -+ UBIFS_SB_NODE, -+ UBIFS_MST_NODE, -+ UBIFS_REF_NODE, -+ UBIFS_IDX_NODE, -+ UBIFS_CS_NODE, -+ UBIFS_ORPH_NODE, -+ UBIFS_NODE_TYPES_CNT, -+}; -+ -+/* -+ * Master node flags. -+ * -+ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty -+ * UBIFS_MST_NO_ORPHS: no orphan inodes present -+ * UBIFS_MST_RCVRY: written by recovery -+ */ -+enum { -+ UBIFS_MST_DIRTY = 1, -+ UBIFS_MST_NO_ORPHS = 2, -+ UBIFS_MST_RCVRY = 4, -+}; -+ -+/* -+ * Node group type (used by recovery to recover whole group or none). -+ * -+ * UBIFS_NO_NODE_GROUP: this node is not part of a group -+ * UBIFS_IN_NODE_GROUP: this node is a part of a group -+ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group -+ */ -+enum { -+ UBIFS_NO_NODE_GROUP = 0, -+ UBIFS_IN_NODE_GROUP, -+ UBIFS_LAST_OF_NODE_GROUP, -+}; -+ -+/* -+ * Superblock flags. -+ * -+ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set -+ */ -+enum { -+ UBIFS_FLG_BIGLPT = 0x02, -+}; -+ -+/** -+ * struct ubifs_ch - common header node. -+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) -+ * @crc: CRC-32 checksum of the node header -+ * @sqnum: sequence number -+ * @len: full node length -+ * @node_type: node type -+ * @group_type: node group type -+ * @padding: reserved for future, zeroes -+ * -+ * Every UBIFS node starts with this common part. If the node has a key, the -+ * key always goes next. -+ */ -+struct ubifs_ch { -+ __le32 magic; -+ __le32 crc; -+ __le64 sqnum; -+ __le32 len; -+ __u8 node_type; -+ __u8 group_type; -+ __u8 padding[2]; -+} __attribute__ ((packed)); -+ -+/** -+ * union ubifs_dev_desc - device node descriptor. -+ * @new: new type device descriptor -+ * @huge: huge type device descriptor -+ * -+ * This data structure describes major/minor numbers of a device node. In an -+ * inode is a device node then its data contains an object of this type. UBIFS -+ * uses standard Linux "new" and "huge" device node encodings. -+ */ -+union ubifs_dev_desc { -+ __le32 new; -+ __le64 huge; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_ino_node - inode node. -+ * @ch: common header -+ * @key: node key -+ * @creat_sqnum: sequence number at time of creation -+ * @size: inode size in bytes (amount of uncompressed data) -+ * @atime_sec: access time seconds -+ * @ctime_sec: creation time seconds -+ * @mtime_sec: modification time seconds -+ * @atime_nsec: access time nanoseconds -+ * @ctime_nsec: creation time nanoseconds -+ * @mtime_nsec: modification time nanoseconds -+ * @nlink: number of hard links -+ * @uid: owner ID -+ * @gid: group ID -+ * @mode: access flags -+ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc) -+ * @data_len: inode data length -+ * @xattr_cnt: count of extended attributes this inode has -+ * @xattr_size: summarized size of all extended attributes in bytes -+ * @xattr_names: sum of lengths of all extended attribute names belonging to -+ * this inode -+ * @compr_type: compression type used for this inode -+ * @padding: reserved for future, zeroes -+ * @data: data attached to the inode -+ * -+ * Note, even though inode compression type is defined by @compr_type, some -+ * nodes of this inode may be compressed with different compressor - this -+ * happens if compression type is changed while the inode already has data -+ * nodes. But @compr_type will be use for further writes to the inode. -+ * -+ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing -+ * the padding fields. -+ */ -+struct ubifs_ino_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 creat_sqnum; -+ __le64 size; -+ __le64 atime_sec; -+ __le64 ctime_sec; -+ __le64 mtime_sec; -+ __le32 atime_nsec; -+ __le32 ctime_nsec; -+ __le32 mtime_nsec; -+ __le32 nlink; -+ __le32 uid; -+ __le32 gid; -+ __le32 mode; -+ __le32 flags; -+ __le32 data_len; -+ __le32 xattr_cnt; -+ __le64 xattr_size; -+ __le32 xattr_names; -+ __le16 compr_type; -+ __u8 padding[26]; /* Watch 'zero_ino_node_unused()' if changing! */ -+ __u8 data[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_dent_node - directory entry node. -+ * @ch: common header -+ * @key: node key -+ * @inum: target inode number -+ * @padding1: reserved for future, zeroes -+ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc) -+ * @nlen: name length -+ * @padding2: reserved for future, zeroes -+ * @name: zero-terminated name -+ * -+ * Note, do not forget to amend 'zero_dent_node_unused()' function when -+ * changing the padding fields. -+ */ -+struct ubifs_dent_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 inum; -+ __u8 padding1; -+ __u8 type; -+ __le16 nlen; -+ __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */ -+ __u8 name[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_data_node - data node. -+ * @ch: common header -+ * @key: node key -+ * @size: uncompressed data size in bytes -+ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc) -+ * @padding: reserved for future, zeroes -+ * @data: data -+ * -+ * Note, do not forget to amend 'zero_data_node_unused()' function when -+ * changing the padding fields. -+ */ -+struct ubifs_data_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le32 size; -+ __le16 compr_type; -+ __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */ -+ __u8 data[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_trun_node - truncation node. -+ * @ch: common header -+ * @key: truncation node key -+ * @old_size: size before truncation -+ * @new_size: size after truncation -+ * -+ * This node exists only in the journal and never goes to the main area. -+ */ -+struct ubifs_trun_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 old_size; -+ __le64 new_size; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_pad_node - padding node. -+ * @ch: common header -+ * @pad_len: how many bytes after this node are unused (because padded) -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_pad_node { -+ struct ubifs_ch ch; -+ __le32 pad_len; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_sb_node - superblock node. -+ * @ch: common header -+ * @padding: reserved for future, zeroes -+ * @key_hash: type of hash function used in keys -+ * @key_fmt: format of the key -+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) -+ * @min_io_size: minimal input/output unit size -+ * @leb_size: logical eraseblock size in bytes -+ * @leb_cnt: count of LEBs used by filesystem -+ * @max_leb_cnt: maximum count of LEBs used by filesystem -+ * @max_bud_bytes: maximum amount of data stored in buds -+ * @log_lebs: log size in logical eraseblocks -+ * @lpt_lebs: number of LEBs used for lprops table -+ * @orph_lebs: number of LEBs used for recording orphans -+ * @jhead_cnt: count of journal heads -+ * @fanout: tree fanout (max. number of links per indexing node) -+ * @lsave_cnt: number of LEB numbers in LPT's save table -+ * @fmt_version: UBIFS on-flash format version -+ * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) -+ * @padding1: reserved for future, zeroes -+ * @rp_uid: reserve pool UID -+ * @rp_gid: reserve pool GID -+ * @rp_size: size of the reserved pool in bytes -+ * @padding2: reserved for future, zeroes -+ * @time_gran: time granularity in nanoseconds -+ */ -+struct ubifs_sb_node { -+ struct ubifs_ch ch; -+ __u8 padding[2]; -+ __u8 key_hash; -+ __u8 key_fmt; -+ __le32 flags; -+ __le32 min_io_size; -+ __le32 leb_size; -+ __le32 leb_cnt; -+ __le32 max_leb_cnt; -+ __le64 max_bud_bytes; -+ __le32 log_lebs; -+ __le32 lpt_lebs; -+ __le32 orph_lebs; -+ __le32 jhead_cnt; -+ __le32 fanout; -+ __le32 lsave_cnt; -+ __le32 fmt_version; -+ __le16 default_compr; -+ __u8 padding1[2]; -+ __le32 rp_uid; -+ __le32 rp_gid; -+ __le64 rp_size; -+ __le32 time_gran; -+ __u8 padding2[3988]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_mst_node - master node. -+ * @ch: common header -+ * @highest_inum: highest inode number in the committed index -+ * @cmt_no: commit number -+ * @flags: various flags (%UBIFS_MST_DIRTY, etc) -+ * @log_lnum: start of the log -+ * @root_lnum: LEB number of the root indexing node -+ * @root_offs: offset within @root_lnum -+ * @root_len: root indexing node length -+ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was -+ * not reserved and should be reserved on mount) -+ * @ihead_lnum: LEB number of index head -+ * @ihead_offs: offset of index head -+ * @index_size: size of index on flash -+ * @total_free: total free space in bytes -+ * @total_dirty: total dirty space in bytes -+ * @total_used: total used space in bytes (includes only data LEBs) -+ * @total_dead: total dead space in bytes (includes only data LEBs) -+ * @total_dark: total dark space in bytes (includes only data LEBs) -+ * @lpt_lnum: LEB number of LPT root nnode -+ * @lpt_offs: offset of LPT root nnode -+ * @nhead_lnum: LEB number of LPT head -+ * @nhead_offs: offset of LPT head -+ * @ltab_lnum: LEB number of LPT's own lprops table -+ * @ltab_offs: offset of LPT's own lprops table -+ * @lsave_lnum: LEB number of LPT's save table (big model only) -+ * @lsave_offs: offset of LPT's save table (big model only) -+ * @lscan_lnum: LEB number of last LPT scan -+ * @empty_lebs: number of empty logical eraseblocks -+ * @idx_lebs: number of indexing logical eraseblocks -+ * @leb_cnt: count of LEBs used by filesystem -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_mst_node { -+ struct ubifs_ch ch; -+ __le64 highest_inum; -+ __le64 cmt_no; -+ __le32 flags; -+ __le32 log_lnum; -+ __le32 root_lnum; -+ __le32 root_offs; -+ __le32 root_len; -+ __le32 gc_lnum; -+ __le32 ihead_lnum; -+ __le32 ihead_offs; -+ __le64 index_size; -+ __le64 total_free; -+ __le64 total_dirty; -+ __le64 total_used; -+ __le64 total_dead; -+ __le64 total_dark; -+ __le32 lpt_lnum; -+ __le32 lpt_offs; -+ __le32 nhead_lnum; -+ __le32 nhead_offs; -+ __le32 ltab_lnum; -+ __le32 ltab_offs; -+ __le32 lsave_lnum; -+ __le32 lsave_offs; -+ __le32 lscan_lnum; -+ __le32 empty_lebs; -+ __le32 idx_lebs; -+ __le32 leb_cnt; -+ __u8 padding[344]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_ref_node - logical eraseblock reference node. -+ * @ch: common header -+ * @lnum: the referred logical eraseblock number -+ * @offs: start offset in the referred LEB -+ * @jhead: journal head number -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_ref_node { -+ struct ubifs_ch ch; -+ __le32 lnum; -+ __le32 offs; -+ __le32 jhead; -+ __u8 padding[28]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_branch - key/reference/length branch -+ * @lnum: LEB number of the target node -+ * @offs: offset within @lnum -+ * @len: target node length -+ * @key: key -+ */ -+struct ubifs_branch { -+ __le32 lnum; -+ __le32 offs; -+ __le32 len; -+ __u8 key[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_idx_node - indexing node. -+ * @ch: common header -+ * @child_cnt: number of child index nodes -+ * @level: tree level -+ * @branches: LEB number / offset / length / key branches -+ */ -+struct ubifs_idx_node { -+ struct ubifs_ch ch; -+ __le16 child_cnt; -+ __le16 level; -+ __u8 branches[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_cs_node - commit start node. -+ * @ch: common header -+ * @cmt_no: commit number -+ */ -+struct ubifs_cs_node { -+ struct ubifs_ch ch; -+ __le64 cmt_no; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_orph_node - orphan node. -+ * @ch: common header -+ * @cmt_no: commit number (also top bit is set on the last node of the commit) -+ * @inos: inode numbers of orphans -+ */ -+struct ubifs_orph_node { -+ struct ubifs_ch ch; -+ __le64 cmt_no; -+ __le64 inos[]; -+} __attribute__ ((packed)); -+ -+#endif /* __UBIFS_MEDIA_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/ubifs.h linux-2.6.24.7/fs/ubifs/mkfs.ubifs/ubifs.h ---- linux-2.6.24.7.old/fs/ubifs/mkfs.ubifs/ubifs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/mkfs.ubifs/ubifs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,424 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2008 Nokia Corporation. -+ * Copyright (C) 2008 University of Szeged, Hungary -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy -+ * Adrian Hunter -+ * Zoltan Sogor -+ */ -+ -+#ifndef __UBIFS_H__ -+#define __UBIFS_H__ -+ -+/* Minimum amount of data UBIFS writes to the flash */ -+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8) -+ -+/* Largest key size supported in this implementation */ -+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN -+ -+/* The below union makes it easier to deal with keys */ -+union ubifs_key -+{ -+ uint8_t u8[CUR_MAX_KEY_LEN]; -+ uint32_t u32[CUR_MAX_KEY_LEN/4]; -+ uint64_t u64[CUR_MAX_KEY_LEN/8]; -+ __le32 j32[CUR_MAX_KEY_LEN/4]; -+}; -+ -+/* -+ * LEB properties flags. -+ * -+ * LPROPS_UNCAT: not categorized -+ * LPROPS_DIRTY: dirty > 0, not index -+ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index -+ * LPROPS_FREE: free > 0, not empty, not index -+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs -+ * LPROPS_EMPTY: LEB is empty, not taken -+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken -+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken -+ * LPROPS_CAT_MASK: mask for the LEB categories above -+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media) -+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash) -+ */ -+enum { -+ LPROPS_UNCAT = 0, -+ LPROPS_DIRTY = 1, -+ LPROPS_DIRTY_IDX = 2, -+ LPROPS_FREE = 3, -+ LPROPS_HEAP_CNT = 3, -+ LPROPS_EMPTY = 4, -+ LPROPS_FREEABLE = 5, -+ LPROPS_FRDI_IDX = 6, -+ LPROPS_CAT_MASK = 15, -+ LPROPS_TAKEN = 16, -+ LPROPS_INDEX = 32, -+}; -+ -+/** -+ * struct ubifs_lprops - logical eraseblock properties. -+ * @free: amount of free space in bytes -+ * @dirty: amount of dirty space in bytes -+ * @flags: LEB properties flags (see above) -+ */ -+struct ubifs_lprops -+{ -+ int free; -+ int dirty; -+ int flags; -+}; -+ -+/** -+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties. -+ * @free: amount of free space in bytes -+ * @dirty: amount of dirty space in bytes -+ */ -+struct ubifs_lpt_lprops -+{ -+ int free; -+ int dirty; -+}; -+ -+struct ubifs_nnode; -+ -+/** -+ * struct ubifs_cnode - LEB Properties Tree common node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes) -+ * @num: node number -+ */ -+struct ubifs_cnode -+{ -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+}; -+ -+/** -+ * struct ubifs_pnode - LEB Properties Tree leaf node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (always zero for pnodes) -+ * @num: node number -+ * @lprops: LEB properties array -+ */ -+struct ubifs_pnode -+{ -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+ struct ubifs_lprops lprops[UBIFS_LPT_FANOUT]; -+}; -+ -+/** -+ * struct ubifs_nbranch - LEB Properties Tree internal node branch. -+ * @lnum: LEB number of child -+ * @offs: offset of child -+ * @nnode: nnode child -+ * @pnode: pnode child -+ * @cnode: cnode child -+ */ -+struct ubifs_nbranch -+{ -+ int lnum; -+ int offs; -+ union -+ { -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ struct ubifs_cnode *cnode; -+ }; -+}; -+ -+/** -+ * struct ubifs_nnode - LEB Properties Tree internal node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (always greater than zero for nnodes) -+ * @num: node number -+ * @nbranch: branches to child nodes -+ */ -+struct ubifs_nnode -+{ -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+ struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT]; -+}; -+ -+/** -+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area. -+ * @empty_lebs: number of empty LEBs -+ * @taken_empty_lebs: number of taken LEBs -+ * @idx_lebs: number of indexing LEBs -+ * @total_free: total free space in bytes -+ * @total_dirty: total dirty space in bytes -+ * @total_used: total used space in bytes (includes only data LEBs) -+ * @total_dead: total dead space in bytes (includes only data LEBs) -+ * @total_dark: total dark space in bytes (includes only data LEBs) -+ */ -+struct ubifs_lp_stats { -+ int empty_lebs; -+ int taken_empty_lebs; -+ int idx_lebs; -+ long long total_free; -+ long long total_dirty; -+ long long total_used; -+ long long total_dead; -+ long long total_dark; -+}; -+ -+/** -+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes. -+ * @key: key -+ * @znode: znode address in memory -+ * @lnum: LEB number of the indexing node -+ * @offs: offset of the indexing node within @lnum -+ * @len: target node length -+ */ -+struct ubifs_zbranch -+{ -+ union ubifs_key key; -+ struct ubifs_znode *znode; -+ int lnum; -+ int offs; -+ int len; -+}; -+ -+/** -+ * struct ubifs_znode - in-memory representation of an indexing node. -+ * @parent: parent znode or NULL if it is the root -+ * @cnext: next znode to commit -+ * @flags: flags -+ * @time: last access time (seconds) -+ * @level: level of the entry in the TNC tree -+ * @child_cnt: count of child znodes -+ * @iip: index in parent's zbranch array -+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0 -+ * @zbranch: array of znode branches (@c->fanout elements) -+ */ -+struct ubifs_znode -+{ -+ struct ubifs_znode *parent; -+ struct ubifs_znode *cnext; -+ unsigned long flags; -+ unsigned long time; -+ int level; -+ int child_cnt; -+ int iip; -+ int alt; -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ int lnum, offs, len; -+#endif -+ struct ubifs_zbranch zbranch[]; -+}; -+ -+/** -+ * struct ubifs_info - UBIFS file-system description data structure -+ * (per-superblock). -+ * -+ * @highest_inum: highest used inode number -+ * @max_sqnum: current global sequence number -+ * -+ * @jhead_cnt: count of journal heads -+ * @max_bud_bytes: maximum number of bytes allowed in buds -+ * -+ * @zroot: zbranch which points to the root index node and znode -+ * @ihead_lnum: LEB number of index head -+ * @ihead_offs: offset of index head -+ * -+ * @log_lebs: number of logical eraseblocks in the log -+ * @lpt_lebs: number of LEBs used for lprops table -+ * @lpt_first: first LEB of the lprops table area -+ * @lpt_last: last LEB of the lprops table area -+ * @main_lebs: count of LEBs in the main area -+ * @main_first: first LEB of the main area -+ * @default_compr: default compression type -+ * -+ * @key_hash_type: type of the key hash -+ * @key_hash: direntry key hash function -+ * @key_len: key length -+ * @fanout: fanout of the index tree (number of links per indexing node) -+ * -+ * @min_io_size: minimal input/output unit size -+ * @leb_size: logical eraseblock size in bytes -+ * @leb_cnt: count of logical eraseblocks -+ * @max_leb_cnt: maximum count of logical eraseblocks -+ * -+ * @old_idx_sz: size of index on flash -+ * @lst: lprops statistics -+ * -+ * @dead_wm: LEB dead space watermark -+ * @dark_wm: LEB dark space watermark -+ * -+ * @gc_lnum: LEB number used for garbage collection -+ * @space_bits: number of bits needed to record free or dirty space -+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT -+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT -+ * @lpt_spc_bits: number of bits needed to space in the LPT -+ * @pcnt_bits: number of bits needed to record pnode or nnode number -+ * @lnum_bits: number of bits needed to record LEB number -+ * @nnode_sz: size of on-flash nnode -+ * @pnode_sz: size of on-flash pnode -+ * @ltab_sz: size of on-flash LPT lprops table -+ * @lsave_sz: size of on-flash LPT save table -+ * @pnode_cnt: number of pnodes -+ * @nnode_cnt: number of nnodes -+ * @lpt_hght: height of the LPT -+ * -+ * @lpt_lnum: LEB number of the root nnode of the LPT -+ * @lpt_offs: offset of the root nnode of the LPT -+ * @nhead_lnum: LEB number of LPT head -+ * @nhead_offs: offset of LPT head -+ * @big_lpt: flag that LPT is too big to write whole during commit -+ * @lpt_sz: LPT size -+ * -+ * @ltab_lnum: LEB number of LPT's own lprops table -+ * @ltab_offs: offset of LPT's own lprops table -+ * @lpt: lprops table -+ * @ltab: LPT's own lprops table -+ * @lsave_cnt: number of LEB numbers in LPT's save table -+ * @lsave_lnum: LEB number of LPT's save table -+ * @lsave_offs: offset of LPT's save table -+ * @lsave: LPT's save table -+ * @lscan_lnum: LEB number of last LPT scan -+ */ -+struct ubifs_info -+{ -+ ino_t highest_inum; -+ unsigned long long max_sqnum; -+ -+ int jhead_cnt; -+ long long max_bud_bytes; -+ -+ struct ubifs_zbranch zroot; -+ int ihead_lnum; -+ int ihead_offs; -+ -+ int log_lebs; -+ int lpt_lebs; -+ int lpt_first; -+ int lpt_last; -+ int orph_lebs; -+ int main_lebs; -+ int main_first; -+ int default_compr; -+ -+ uint8_t key_hash_type; -+ uint32_t (*key_hash)(const char *str, int len); -+ int key_len; -+ int fanout; -+ -+ int min_io_size; -+ int leb_size; -+ int leb_cnt; -+ int max_leb_cnt; -+ -+ unsigned long long old_idx_sz; -+ struct ubifs_lp_stats lst; -+ -+ int dead_wm; -+ int dark_wm; -+ -+ int gc_lnum; -+ -+ int space_bits; -+ int lpt_lnum_bits; -+ int lpt_offs_bits; -+ int lpt_spc_bits; -+ int pcnt_bits; -+ int lnum_bits; -+ int nnode_sz; -+ int pnode_sz; -+ int ltab_sz; -+ int lsave_sz; -+ int pnode_cnt; -+ int nnode_cnt; -+ int lpt_hght; -+ -+ int lpt_lnum; -+ int lpt_offs; -+ int nhead_lnum; -+ int nhead_offs; -+ int big_lpt; -+ long long lpt_sz; -+ -+ int ltab_lnum; -+ int ltab_offs; -+ struct ubifs_lprops *lpt; -+ struct ubifs_lpt_lprops *ltab; -+ int lsave_cnt; -+ int lsave_lnum; -+ int lsave_offs; -+ int *lsave; -+ int lscan_lnum; -+ -+}; -+ -+/** -+ * ubifs_idx_node_sz - return index node size. -+ * @c: the UBIFS file-system description object -+ * @child_cnt: number of children of this index node -+ */ -+static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) -+{ -+ return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt; -+} -+ -+/** -+ * ubifs_idx_branch - return pointer to an index branch. -+ * @c: the UBIFS file-system description object -+ * @idx: index node -+ * @bnum: branch number -+ */ -+static inline -+struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c, -+ const struct ubifs_idx_node *idx, -+ int bnum) -+{ -+ return (struct ubifs_branch *)((void *)idx->branches + -+ (UBIFS_BRANCH_SZ + c->key_len) * bnum); -+} -+ -+/** -+ * ubifs_idx_key - return pointer to an index key. -+ * @c: the UBIFS file-system description object -+ * @idx: index node -+ */ -+static inline void *ubifs_idx_key(const struct ubifs_info *c, -+ const struct ubifs_idx_node *idx) -+{ -+ return (void *)((struct ubifs_branch *)idx->branches)->key; -+} -+ -+#endif /* __UBIFS_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/orphan.c linux-2.6.24.7/fs/ubifs/orphan.c ---- linux-2.6.24.7.old/fs/ubifs/orphan.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/orphan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,959 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Author: Adrian Hunter -+ */ -+ -+#include "ubifs.h" -+ -+/* -+ * An orphan is an inode number whose inode node has been committed to the index -+ * with a link count of zero. That happens when an open file is deleted -+ * (unlinked) and then a commit is run. In the normal course of events the inode -+ * would be deleted when the file is closed. However in the case of an unclean -+ * unmount, orphans need to be accounted for. After an unclean unmount, the -+ * orphans' inodes must be deleted which means either scanning the entire index -+ * looking for them, or keeping a list on flash somewhere. This unit implements -+ * the latter approach. -+ * -+ * The orphan area is a fixed number of LEBs situated between the LPT area and -+ * the main area. The number of orphan area LEBs is specified when the file -+ * system is created. The minimum number is 1. The size of the orphan area -+ * should be so that it can hold the maximum number of orphans that are expected -+ * to ever exist at one time. -+ * -+ * The number of orphans that can fit in a LEB is: -+ * -+ * (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64) -+ * -+ * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough. -+ * -+ * Orphans are accumulated in a rb-tree. When an inode's link count drops to -+ * zero, the inode number is added to the rb-tree. It is removed from the tree -+ * when the inode is deleted. Any new orphans that are in the orphan tree when -+ * the commit is run, are written to the orphan area in 1 or more orph nodes. -+ * If the orphan area is full, it is consolidated to make space. There is -+ * always enough space because validation prevents the user from creating more -+ * than the maximum number of orphans allowed. -+ */ -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+static int dbg_check_orphans(struct ubifs_info *c); -+#else -+#define dbg_check_orphans(c) 0 -+#endif -+ -+/** -+ * ubifs_add_orphan - add an orphan. -+ * @c: UBIFS file-system description object -+ * @inum: orphan inode number -+ * -+ * Add an orphan. This function is called when an inodes link count drops to -+ * zero. -+ */ -+int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) -+{ -+ struct ubifs_orphan *orphan, *o; -+ struct rb_node **p, *parent = NULL; -+ -+ orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS); -+ if (!orphan) -+ return -ENOMEM; -+ orphan->inum = inum; -+ orphan->new = 1; -+ -+ spin_lock(&c->orphan_lock); -+ if (c->tot_orphans >= c->max_orphans) { -+ spin_unlock(&c->orphan_lock); -+ kfree(orphan); -+ return -ENFILE; -+ } -+ p = &c->orph_tree.rb_node; -+ while (*p) { -+ parent = *p; -+ o = rb_entry(parent, struct ubifs_orphan, rb); -+ if (inum < o->inum) -+ p = &(*p)->rb_left; -+ else if (inum > o->inum) -+ p = &(*p)->rb_right; -+ else { -+ dbg_err("orphaned twice"); -+ spin_unlock(&c->orphan_lock); -+ kfree(orphan); -+ return 0; -+ } -+ } -+ c->tot_orphans += 1; -+ c->new_orphans += 1; -+ rb_link_node(&orphan->rb, parent, p); -+ rb_insert_color(&orphan->rb, &c->orph_tree); -+ list_add_tail(&orphan->list, &c->orph_list); -+ list_add_tail(&orphan->new_list, &c->orph_new); -+ spin_unlock(&c->orphan_lock); -+ dbg_gen("ino %lu", inum); -+ return 0; -+} -+ -+/** -+ * ubifs_delete_orphan - delete an orphan. -+ * @c: UBIFS file-system description object -+ * @inum: orphan inode number -+ * -+ * Delete an orphan. This function is called when an inode is deleted. -+ */ -+void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) -+{ -+ struct ubifs_orphan *o; -+ struct rb_node *p; -+ -+ spin_lock(&c->orphan_lock); -+ p = c->orph_tree.rb_node; -+ while (p) { -+ o = rb_entry(p, struct ubifs_orphan, rb); -+ if (inum < o->inum) -+ p = p->rb_left; -+ else if (inum > o->inum) -+ p = p->rb_right; -+ else { -+ if (o->dnext) { -+ spin_unlock(&c->orphan_lock); -+ dbg_gen("deleted twice ino %lu", inum); -+ return; -+ } -+ if (o->cnext) { -+ o->dnext = c->orph_dnext; -+ c->orph_dnext = o; -+ spin_unlock(&c->orphan_lock); -+ dbg_gen("delete later ino %lu", inum); -+ return; -+ } -+ rb_erase(p, &c->orph_tree); -+ list_del(&o->list); -+ c->tot_orphans -= 1; -+ if (o->new) { -+ list_del(&o->new_list); -+ c->new_orphans -= 1; -+ } -+ spin_unlock(&c->orphan_lock); -+ kfree(o); -+ dbg_gen("inum %lu", inum); -+ return; -+ } -+ } -+ spin_unlock(&c->orphan_lock); -+ dbg_err("missing orphan ino %lu", inum); -+ dbg_dump_stack(); -+} -+ -+/** -+ * ubifs_orphan_start_commit - start commit of orphans. -+ * @c: UBIFS file-system description object -+ * -+ * Start commit of orphans. -+ */ -+int ubifs_orphan_start_commit(struct ubifs_info *c) -+{ -+ struct ubifs_orphan *orphan, **last; -+ -+ spin_lock(&c->orphan_lock); -+ last = &c->orph_cnext; -+ list_for_each_entry(orphan, &c->orph_new, new_list) { -+ ubifs_assert(orphan->new); -+ orphan->new = 0; -+ *last = orphan; -+ last = &orphan->cnext; -+ } -+ *last = orphan->cnext; -+ c->cmt_orphans = c->new_orphans; -+ c->new_orphans = 0; -+ dbg_cmt("%d orphans to commit", c->cmt_orphans); -+ INIT_LIST_HEAD(&c->orph_new); -+ if (c->tot_orphans == 0) -+ c->no_orphs = 1; -+ else -+ c->no_orphs = 0; -+ spin_unlock(&c->orphan_lock); -+ return 0; -+} -+ -+/** -+ * avail_orphs - calculate available space. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns the number of orphans that can be written in the -+ * available space. -+ */ -+static int avail_orphs(struct ubifs_info *c) -+{ -+ int avail_lebs, avail, gap; -+ -+ avail_lebs = c->orph_lebs - (c->ohead_lnum - c->orph_first) - 1; -+ avail = avail_lebs * -+ ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)); -+ gap = c->leb_size - c->ohead_offs; -+ if (gap >= UBIFS_ORPH_NODE_SZ + sizeof(__le64)) -+ avail += (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64); -+ return avail; -+} -+ -+/** -+ * tot_avail_orphs - calculate total space. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns the number of orphans that can be written in half -+ * the total space. That leaves half the space for adding new orphans. -+ */ -+static int tot_avail_orphs(struct ubifs_info *c) -+{ -+ int avail_lebs, avail; -+ -+ avail_lebs = c->orph_lebs; -+ avail = avail_lebs * -+ ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)); -+ return avail / 2; -+} -+ -+/** -+ * do_write_orph_node - write a node -+ * @c: UBIFS file-system description object -+ * @len: length of node -+ * @atomic: write atomically -+ * -+ * This function writes a node to the orphan head from the orphan buffer. If -+ * %atomic is not zero, then the write is done atomically. On success, %0 is -+ * returned, otherwise a negative error code is returned. -+ */ -+static int do_write_orph_node(struct ubifs_info *c, int len, int atomic) -+{ -+ int err = 0; -+ -+ if (atomic) { -+ ubifs_assert(c->ohead_offs == 0); -+ ubifs_prepare_node(c, c->orph_buf, len, 1); -+ len = ALIGN(len, c->min_io_size); -+ err = ubi_leb_change(c->ubi, c->ohead_lnum, c->orph_buf, len, -+ UBI_SHORTTERM); -+ } else { -+ if (c->ohead_offs == 0) { -+ /* Ensure LEB has been unmapped */ -+ err = ubifs_leb_unmap(c, c->ohead_lnum); -+ if (err) -+ return err; -+ } -+ err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum, -+ c->ohead_offs, UBI_SHORTTERM); -+ } -+ return err; -+} -+ -+/** -+ * write_orph_node - write an orph node -+ * @c: UBIFS file-system description object -+ * @atomic: write atomically -+ * -+ * This function builds an orph node from the cnext list and writes it to the -+ * orphan head. On success, %0 is returned, otherwise a negative error code -+ * is returned. -+ */ -+static int write_orph_node(struct ubifs_info *c, int atomic) -+{ -+ struct ubifs_orphan *orphan, *cnext; -+ struct ubifs_orph_node *orph; -+ int gap, err, len, cnt, i; -+ -+ ubifs_assert(c->cmt_orphans > 0); -+ gap = c->leb_size - c->ohead_offs; -+ if (gap < UBIFS_ORPH_NODE_SZ + sizeof(__le64)) { -+ c->ohead_lnum += 1; -+ c->ohead_offs = 0; -+ gap = c->leb_size; -+ if (c->ohead_lnum > c->orph_last) { -+ /* -+ * We limit the number of orphans so that this should -+ * never happen. -+ */ -+ ubifs_err("out of space in orphan area"); -+ return -EINVAL; -+ } -+ } -+ cnt = (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64); -+ if (cnt > c->cmt_orphans) -+ cnt = c->cmt_orphans; -+ len = UBIFS_ORPH_NODE_SZ + cnt * sizeof(__le64); -+ ubifs_assert(c->orph_buf); -+ orph = c->orph_buf; -+ orph->ch.node_type = UBIFS_ORPH_NODE; -+ spin_lock(&c->orphan_lock); -+ cnext = c->orph_cnext; -+ for (i = 0; i < cnt; i++) { -+ orphan = cnext; -+ orph->inos[i] = cpu_to_le64(orphan->inum); -+ cnext = orphan->cnext; -+ orphan->cnext = NULL; -+ } -+ c->orph_cnext = cnext; -+ c->cmt_orphans -= cnt; -+ spin_unlock(&c->orphan_lock); -+ if (c->cmt_orphans) -+ orph->cmt_no = cpu_to_le64(c->cmt_no + 1); -+ else -+ /* Mark the last node of the commit */ -+ orph->cmt_no = cpu_to_le64((c->cmt_no + 1) | (1ULL << 63)); -+ ubifs_assert(c->ohead_offs + len <= c->leb_size); -+ ubifs_assert(c->ohead_lnum >= c->orph_first); -+ ubifs_assert(c->ohead_lnum <= c->orph_last); -+ err = do_write_orph_node(c, len, atomic); -+ c->ohead_offs += ALIGN(len, c->min_io_size); -+ c->ohead_offs = ALIGN(c->ohead_offs, 8); -+ return err; -+} -+ -+/** -+ * write_orph_nodes - write orph nodes until there are no more to commit -+ * @c: UBIFS file-system description object -+ * @atomic: write atomically -+ * -+ * This function writes orph nodes for all the orphans to commit. On success, -+ * %0 is returned, otherwise a negative error code is returned. -+ */ -+static int write_orph_nodes(struct ubifs_info *c, int atomic) -+{ -+ int err; -+ -+ while (c->cmt_orphans > 0) { -+ err = write_orph_node(c, atomic); -+ if (err) -+ return err; -+ } -+ if (atomic) { -+ int lnum; -+ -+ /* Unmap any unused LEBs after consolidation */ -+ lnum = c->ohead_lnum + 1; -+ for (lnum = c->ohead_lnum + 1; lnum <= c->orph_last; lnum++) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * consolidate - consolidate the orphan area. -+ * @c: UBIFS file-system description object -+ * -+ * This function enables consolidation by putting all the orphans into the list -+ * to commit. The list is in the order that the orphans were added, and the -+ * LEBs are written atomically in order, so at no time can orphans be lost by -+ * an unclean unmount. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int consolidate(struct ubifs_info *c) -+{ -+ int tot_avail = tot_avail_orphs(c), err = 0; -+ -+ spin_lock(&c->orphan_lock); -+ dbg_cmt("there is space for %d orphans and there are %d", -+ tot_avail, c->tot_orphans); -+ if (c->tot_orphans - c->new_orphans <= tot_avail) { -+ struct ubifs_orphan *orphan, **last; -+ int cnt = 0; -+ -+ /* Change the cnext list to include all non-new orphans */ -+ last = &c->orph_cnext; -+ list_for_each_entry(orphan, &c->orph_list, list) { -+ if (orphan->new) -+ continue; -+ *last = orphan; -+ last = &orphan->cnext; -+ cnt += 1; -+ } -+ *last = orphan->cnext; -+ ubifs_assert(cnt == c->tot_orphans - c->new_orphans); -+ c->cmt_orphans = cnt; -+ c->ohead_lnum = c->orph_first; -+ c->ohead_offs = 0; -+ } else { -+ /* -+ * We limit the number of orphans so that this should -+ * never happen. -+ */ -+ ubifs_err("out of space in orphan area"); -+ err = -EINVAL; -+ } -+ spin_unlock(&c->orphan_lock); -+ return err; -+} -+ -+/** -+ * commit_orphans - commit orphans. -+ * @c: UBIFS file-system description object -+ * -+ * This function commits orphans to flash. On success, %0 is returned, -+ * otherwise a negative error code is returned. -+ */ -+static int commit_orphans(struct ubifs_info *c) -+{ -+ int avail, atomic = 0, err; -+ -+ ubifs_assert(c->cmt_orphans > 0); -+ avail = avail_orphs(c); -+ if (avail < c->cmt_orphans) { -+ /* Not enough space to write new orphans, so consolidate */ -+ err = consolidate(c); -+ if (err) -+ return err; -+ atomic = 1; -+ } -+ err = write_orph_nodes(c, atomic); -+ return err; -+} -+ -+/** -+ * erase_deleted - erase the orphans marked for deletion. -+ * @c: UBIFS file-system description object -+ * -+ * During commit, the orphans being committed cannot be deleted, so they are -+ * marked for deletion and deleted by this function. Also, the recovery -+ * adds killed orphans to the deletion list, and therefore they are deleted -+ * here too. -+ */ -+static void erase_deleted(struct ubifs_info *c) -+{ -+ struct ubifs_orphan *orphan, *dnext; -+ -+ spin_lock(&c->orphan_lock); -+ dnext = c->orph_dnext; -+ while (dnext) { -+ orphan = dnext; -+ dnext = orphan->dnext; -+ ubifs_assert(!orphan->new); -+ rb_erase(&orphan->rb, &c->orph_tree); -+ list_del(&orphan->list); -+ c->tot_orphans -= 1; -+ dbg_gen("deleting orphan ino %lu", orphan->inum); -+ kfree(orphan); -+ } -+ c->orph_dnext = NULL; -+ spin_unlock(&c->orphan_lock); -+} -+ -+/** -+ * ubifs_orphan_end_commit - end commit of orphans. -+ * @c: UBIFS file-system description object -+ * -+ * End commit of orphans. -+ */ -+int ubifs_orphan_end_commit(struct ubifs_info *c) -+{ -+ int err; -+ -+ if (c->cmt_orphans != 0) { -+ err = commit_orphans(c); -+ if (err) -+ return err; -+ } -+ erase_deleted(c); -+ err = dbg_check_orphans(c); -+ return err; -+} -+ -+/** -+ * clear_orphans - erase all LEBs used for orphans. -+ * @c: UBIFS file-system description object -+ * -+ * If recovery is not required, then the orphans from the previous session -+ * are not needed. This function locates the LEBs used to record -+ * orphans, and un-maps them. -+ */ -+static int clear_orphans(struct ubifs_info *c) -+{ -+ int lnum, err; -+ -+ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } -+ c->ohead_lnum = c->orph_first; -+ c->ohead_offs = 0; -+ return 0; -+} -+ -+/** -+ * insert_dead_orphan - insert an orphan. -+ * @c: UBIFS file-system description object -+ * @inum: orphan inode number -+ * -+ * This function is a helper to the 'do_kill_orphans()' function. The orphan -+ * must be kept until the next commit, so it is added to the rb-tree and the -+ * deletion list. -+ */ -+static int insert_dead_orphan(struct ubifs_info *c, ino_t inum) -+{ -+ struct ubifs_orphan *orphan, *o; -+ struct rb_node **p, *parent = NULL; -+ -+ orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL); -+ if (!orphan) -+ return -ENOMEM; -+ orphan->inum = inum; -+ -+ p = &c->orph_tree.rb_node; -+ while (*p) { -+ parent = *p; -+ o = rb_entry(parent, struct ubifs_orphan, rb); -+ if (inum < o->inum) -+ p = &(*p)->rb_left; -+ else if (inum > o->inum) -+ p = &(*p)->rb_right; -+ else { -+ /* Already added - no problem */ -+ kfree(orphan); -+ return 0; -+ } -+ } -+ c->tot_orphans += 1; -+ rb_link_node(&orphan->rb, parent, p); -+ rb_insert_color(&orphan->rb, &c->orph_tree); -+ list_add_tail(&orphan->list, &c->orph_list); -+ orphan->dnext = c->orph_dnext; -+ c->orph_dnext = orphan; -+ dbg_mnt("ino %lu, new %d, tot %d", -+ inum, c->new_orphans, c->tot_orphans); -+ return 0; -+} -+ -+/** -+ * do_kill_orphans - remove orphan inodes from the index. -+ * @c: UBIFS file-system description object -+ * @sleb: scanned LEB -+ * @last_cmt_no: cmt_no of last orph node read is passed and returned here -+ * @outofdate: whether the LEB is out of date is returned here -+ * @last_flagged: whether the end orph node is encountered -+ * -+ * This function is a helper to the 'kill_orphans()' function. It goes through -+ * every orphan node in a LEB and for every inode number recorded, removes -+ * all keys for that inode from the TNC. -+ */ -+static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ unsigned long long *last_cmt_no, int *outofdate, -+ int *last_flagged) -+{ -+ struct ubifs_scan_node *snod; -+ struct ubifs_orph_node *orph; -+ unsigned long long cmt_no; -+ ino_t inum; -+ int i, n, err, first = 1; -+ -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ if (snod->type != UBIFS_ORPH_NODE) { -+ ubifs_err("invalid node type %d in orphan area at " -+ "%d:%d", snod->type, sleb->lnum, snod->offs); -+ dbg_dump_node(c, snod->node); -+ return -EINVAL; -+ } -+ -+ orph = snod->node; -+ -+ /* Check commit number */ -+ cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX; -+ /* -+ * The commit number on the master node may be less, because -+ * of a failed commit. If there are several failed commits in a -+ * row, the commit number written on orph nodes will continue to -+ * increase (because the commit number is adjusted here) even -+ * though the commit number on the master node stays the same -+ * because the master node has not been re-written. -+ */ -+ if (cmt_no > c->cmt_no) -+ c->cmt_no = cmt_no; -+ if (cmt_no < *last_cmt_no && *last_flagged) { -+ /* -+ * The last orph node had a higher commit number and was -+ * flagged as the last written for that commit number. -+ * That makes this orph node, out of date. -+ */ -+ if (!first) { -+ ubifs_err("out of order commit number %llu in " -+ "orphan node at %d:%d", -+ cmt_no, sleb->lnum, snod->offs); -+ dbg_dump_node(c, snod->node); -+ return -EINVAL; -+ } -+ dbg_rcvry("out of date LEB %d", sleb->lnum); -+ *outofdate = 1; -+ return 0; -+ } -+ -+ if (first) -+ first = 0; -+ -+ n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; -+ for (i = 0; i < n; i++) { -+ inum = le64_to_cpu(orph->inos[i]); -+ dbg_rcvry("deleting orphaned inode %lu", inum); -+ err = ubifs_tnc_remove_ino(c, inum); -+ if (err) -+ return err; -+ err = insert_dead_orphan(c, inum); -+ if (err) -+ return err; -+ } -+ -+ *last_cmt_no = cmt_no; -+ if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) { -+ dbg_rcvry("last orph node for commit %llu at %d:%d", -+ cmt_no, sleb->lnum, snod->offs); -+ *last_flagged = 1; -+ } else -+ *last_flagged = 0; -+ } -+ -+ return 0; -+} -+ -+/** -+ * kill_orphans - remove all orphan inodes from the index. -+ * @c: UBIFS file-system description object -+ * -+ * If recovery is required, then orphan inodes recorded during the previous -+ * session (which ended with an unclean unmount) must be deleted from the index. -+ * This is done by updating the TNC, but since the index is not updated until -+ * the next commit, the LEBs where the orphan information is recorded are not -+ * erased until the next commit. -+ */ -+static int kill_orphans(struct ubifs_info *c) -+{ -+ unsigned long long last_cmt_no = 0; -+ int lnum, err = 0, outofdate = 0, last_flagged = 0; -+ -+ c->ohead_lnum = c->orph_first; -+ c->ohead_offs = 0; -+ /* Check no-orphans flag and skip this if no orphans */ -+ if (c->no_orphs) { -+ dbg_rcvry("no orphans"); -+ return 0; -+ } -+ /* -+ * Orph nodes always start at c->orph_first and are written to each -+ * successive LEB in turn. Generally unused LEBs will have been unmapped -+ * but may contain out of date orph nodes if the unmap didn't go -+ * through. In addition, the last orph node written for each commit is -+ * marked (top bit of orph->cmt_no is set to 1). It is possible that -+ * there are orph nodes from the next commit (i.e. the commit did not -+ * complete successfully). In that case, no orphans will have been lost -+ * due to the way that orphans are written, and any orphans added will -+ * be valid orphans anyway and so can be deleted. -+ */ -+ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { -+ struct ubifs_scan_leb *sleb; -+ -+ dbg_rcvry("LEB %d", lnum); -+ sleb = ubifs_scan(c, lnum, 0, c->sbuf); -+ if (IS_ERR(sleb)) { -+ sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0); -+ if (IS_ERR(sleb)) { -+ err = PTR_ERR(sleb); -+ break; -+ } -+ } -+ err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate, -+ &last_flagged); -+ if (err || outofdate) { -+ ubifs_scan_destroy(sleb); -+ break; -+ } -+ if (sleb->endpt) { -+ c->ohead_lnum = lnum; -+ c->ohead_offs = sleb->endpt; -+ } -+ ubifs_scan_destroy(sleb); -+ } -+ return err; -+} -+ -+/** -+ * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them. -+ * @c: UBIFS file-system description object -+ * @unclean: %1 => recover from unclean unmount -+ * -+ * This function is called when mounting to erase orphans from the previous -+ * session. If UBIFS was not unmounted cleanly, then the inodes recorded as -+ * orphans are deleted. -+ */ -+int ubifs_mount_orphans(struct ubifs_info *c, int unclean) -+{ -+ int err = 0; -+ -+ c->max_orphans = tot_avail_orphs(c); -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->orph_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->orph_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->orph_buf) -+ return -ENOMEM; -+ -+ if (unclean) -+ err = kill_orphans(c); -+ else -+ err = clear_orphans(c); -+ -+ return err; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+struct check_orphan { -+ struct rb_node rb; -+ ino_t inum; -+}; -+ -+struct check_info { -+ unsigned long last_ino; -+ unsigned long tot_inos; -+ unsigned long missing; -+ unsigned long long leaf_cnt; -+ struct ubifs_ino_node *node; -+ struct rb_root root; -+}; -+ -+static int dbg_find_orphan(struct ubifs_info *c, ino_t inum) -+{ -+ struct ubifs_orphan *o; -+ struct rb_node *p; -+ -+ spin_lock(&c->orphan_lock); -+ p = c->orph_tree.rb_node; -+ while (p) { -+ o = rb_entry(p, struct ubifs_orphan, rb); -+ if (inum < o->inum) -+ p = p->rb_left; -+ else if (inum > o->inum) -+ p = p->rb_right; -+ else { -+ spin_unlock(&c->orphan_lock); -+ return 1; -+ } -+ } -+ spin_unlock(&c->orphan_lock); -+ return 0; -+} -+ -+static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum) -+{ -+ struct check_orphan *orphan, *o; -+ struct rb_node **p, *parent = NULL; -+ -+ orphan = kzalloc(sizeof(struct check_orphan), GFP_NOFS); -+ if (!orphan) -+ return -ENOMEM; -+ orphan->inum = inum; -+ -+ p = &root->rb_node; -+ while (*p) { -+ parent = *p; -+ o = rb_entry(parent, struct check_orphan, rb); -+ if (inum < o->inum) -+ p = &(*p)->rb_left; -+ else if (inum > o->inum) -+ p = &(*p)->rb_right; -+ else { -+ kfree(orphan); -+ return 0; -+ } -+ } -+ rb_link_node(&orphan->rb, parent, p); -+ rb_insert_color(&orphan->rb, root); -+ return 0; -+} -+ -+static int dbg_find_check_orphan(struct rb_root *root, ino_t inum) -+{ -+ struct check_orphan *o; -+ struct rb_node *p; -+ -+ p = root->rb_node; -+ while (p) { -+ o = rb_entry(p, struct check_orphan, rb); -+ if (inum < o->inum) -+ p = p->rb_left; -+ else if (inum > o->inum) -+ p = p->rb_right; -+ else -+ return 1; -+ } -+ return 0; -+} -+ -+static void dbg_free_check_tree(struct rb_root *root) -+{ -+ struct rb_node *this = root->rb_node; -+ struct check_orphan *o; -+ -+ while (this) { -+ if (this->rb_left) { -+ this = this->rb_left; -+ continue; -+ } else if (this->rb_right) { -+ this = this->rb_right; -+ continue; -+ } -+ o = rb_entry(this, struct check_orphan, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &o->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(o); -+ } -+} -+ -+static int dbg_orphan_check(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *priv) -+{ -+ struct check_info *ci = priv; -+ ino_t inum; -+ int err; -+ -+ inum = key_ino(c, &zbr->key); -+ if (inum != ci->last_ino) { -+ /* Lowest node type is the inode node, so it comes first */ -+ if (key_type(c, &zbr->key) != UBIFS_INO_KEY) -+ ubifs_err("found orphan node ino %lu, type %d", inum, -+ key_type(c, &zbr->key)); -+ ci->last_ino = inum; -+ ci->tot_inos += 1; -+ err = dbg_read_leaf_nolock(c, zbr, ci->node); -+ if (err) { -+ ubifs_err("node read failed, error %d", err); -+ return err; -+ } -+ if (ci->node->nlink == 0) -+ /* Must be recorded as an orphan */ -+ if (!dbg_find_check_orphan(&ci->root, inum) && -+ !dbg_find_orphan(c, inum)) { -+ ubifs_err("missing orphan, ino %lu", inum); -+ ci->missing += 1; -+ } -+ } -+ ci->leaf_cnt += 1; -+ return 0; -+} -+ -+static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb) -+{ -+ struct ubifs_scan_node *snod; -+ struct ubifs_orph_node *orph; -+ ino_t inum; -+ int i, n, err; -+ -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ cond_resched(); -+ if (snod->type != UBIFS_ORPH_NODE) -+ continue; -+ orph = snod->node; -+ n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; -+ for (i = 0; i < n; i++) { -+ inum = le64_to_cpu(orph->inos[i]); -+ err = dbg_ins_check_orphan(&ci->root, inum); -+ if (err) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci) -+{ -+ int lnum, err = 0; -+ -+ /* Check no-orphans flag and skip this if no orphans */ -+ if (c->no_orphs) -+ return 0; -+ -+ for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) { -+ struct ubifs_scan_leb *sleb; -+ -+ sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); -+ if (IS_ERR(sleb)) { -+ err = PTR_ERR(sleb); -+ break; -+ } -+ -+ err = dbg_read_orphans(ci, sleb); -+ ubifs_scan_destroy(sleb); -+ if (err) -+ break; -+ } -+ -+ return err; -+} -+ -+static int dbg_check_orphans(struct ubifs_info *c) -+{ -+ struct check_info ci; -+ int err; -+ -+ if (!(ubifs_chk_flags & UBIFS_CHK_ORPH)) -+ return 0; -+ -+ ci.last_ino = 0; -+ ci.tot_inos = 0; -+ ci.missing = 0; -+ ci.leaf_cnt = 0; -+ ci.root = RB_ROOT; -+ ci.node = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); -+ if (!ci.node) { -+ ubifs_err("out of memory"); -+ return -ENOMEM; -+ } -+ -+ err = dbg_scan_orphans(c, &ci); -+ if (err) -+ goto out; -+ -+ err = dbg_walk_index(c, &dbg_orphan_check, NULL, &ci); -+ if (err) { -+ ubifs_err("cannot scan TNC, error %d", err); -+ goto out; -+ } -+ -+ if (ci.missing) { -+ ubifs_err("%lu missing orphan(s)", ci.missing); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ dbg_cmt("last inode number is %lu", ci.last_ino); -+ dbg_cmt("total number of inodes is %lu", ci.tot_inos); -+ dbg_cmt("total number of leaf nodes is %llu", ci.leaf_cnt); -+ -+out: -+ dbg_free_check_tree(&ci.root); -+ kfree(ci.node); -+ return err; -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/recovery.c linux-2.6.24.7/fs/ubifs/recovery.c ---- linux-2.6.24.7.old/fs/ubifs/recovery.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/recovery.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1524 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements functions needed to recover from unclean un-mounts. -+ * When UBIFS is mounted, it checks a flag on the master node to determine if -+ * an un-mount was completed sucessfully. If not, the process of mounting -+ * incorparates additional checking and fixing of on-flash data structures. -+ * UBIFS always cleans away all remnants of an unclean un-mount, so that -+ * errors do not accumulate. However UBIFS defers recovery if it is mounted -+ * read-only, and the flash is not modified in that case. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/** -+ * is_empty - determine whether a buffer is empty (contains all 0xff). -+ * @buf: buffer to clean -+ * @len: length of buffer -+ * -+ * This function returns %1 if the buffer is empty (contains all 0xff) otherwise -+ * %0 is returned. -+ */ -+static int is_empty(void *buf, int len) -+{ -+ uint8_t *p = buf; -+ int i; -+ -+ for (i = 0; i < len; i++) -+ if (*p++ != 0xff) -+ return 0; -+ return 1; -+} -+ -+/** -+ * get_master_node - get the last valid master node allowing for corruption. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @pbuf: buffer containing the LEB read, is returned here -+ * @mst: master node, if found, is returned here -+ * @cor: corruption, if found, is returned here -+ * -+ * This function allocates a buffer, reads the LEB into it, and finds and -+ * returns the last valid master node allowing for one area of corruption. -+ * The corrupt area, if there is one, must be consistent with the assumption -+ * that it is the result of an unclean unmount while the master node was being -+ * written. Under those circumstances, it is valid to use the previously written -+ * master node. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, -+ struct ubifs_mst_node **mst, void **cor) -+{ -+ const int sz = c->mst_node_alsz; -+ int err, offs, len; -+ void *sbuf, *buf; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ sbuf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ sbuf = vmalloc(c->leb_size); -+#endif -+ if (!sbuf) -+ return -ENOMEM; -+ -+ err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size); -+ if (err && err != -EBADMSG) -+ goto out_free; -+ -+ /* Find the first position that is definitely not a node */ -+ offs = 0; -+ buf = sbuf; -+ len = c->leb_size; -+ while (offs + UBIFS_MST_NODE_SZ <= c->leb_size) { -+ struct ubifs_ch *ch = buf; -+ -+ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) -+ break; -+ offs += sz; -+ buf += sz; -+ len -= sz; -+ } -+ /* See if there was a valid master node before that */ -+ if (offs) { -+ int ret; -+ -+ offs -= sz; -+ buf -= sz; -+ len += sz; -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); -+ if (ret != SCANNED_A_NODE && offs) { -+ /* Could have been corruption so check one place back */ -+ offs -= sz; -+ buf -= sz; -+ len += sz; -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); -+ if (ret != SCANNED_A_NODE) -+ /* -+ * We accept only one area of corruption because -+ * we are assuming that it was caused while -+ * trying to write a master node. -+ */ -+ goto out_err; -+ } -+ if (ret == SCANNED_A_NODE) { -+ struct ubifs_ch *ch = buf; -+ -+ if (ch->node_type != UBIFS_MST_NODE) -+ goto out_err; -+ dbg_rcvry("found a master node at %d:%d", lnum, offs); -+ *mst = buf; -+ offs += sz; -+ buf += sz; -+ len -= sz; -+ } -+ } -+ /* Check for corruption */ -+ if (offs < c->leb_size) { -+ if (!is_empty(buf, min_t(int, len, sz))) { -+ *cor = buf; -+ dbg_rcvry("found corruption at %d:%d", lnum, offs); -+ } -+ offs += sz; -+ buf += sz; -+ len -= sz; -+ } -+ /* Check remaining empty space */ -+ if (offs < c->leb_size) -+ if (!is_empty(buf, len)) -+ goto out_err; -+ *pbuf = sbuf; -+ return 0; -+ -+out_err: -+ err = -EINVAL; -+out_free: -+ vfree(sbuf); -+ *mst = NULL; -+ *cor = NULL; -+ return err; -+} -+ -+/** -+ * write_rcvrd_mst_node - write recovered master node. -+ * @c: UBIFS file-system description object -+ * @mst: master node -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int write_rcvrd_mst_node(struct ubifs_info *c, -+ struct ubifs_mst_node *mst) -+{ -+ int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz; -+ uint32_t save_flags; -+ -+ dbg_rcvry("recovery"); -+ -+ save_flags = mst->flags; -+ mst->flags = cpu_to_le32(le32_to_cpu(mst->flags) | UBIFS_MST_RCVRY); -+ -+ ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); -+ err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM); -+ if (err) -+ goto out; -+ err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM); -+ if (err) -+ goto out; -+out: -+ mst->flags = save_flags; -+ return err; -+} -+ -+/** -+ * ubifs_recover_master_node - recover the master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function recovers the master node from corruption that may occur due to -+ * an unclean unmount. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_recover_master_node(struct ubifs_info *c) -+{ -+ void *buf1 = NULL, *buf2 = NULL, *cor1 = NULL, *cor2 = NULL; -+ struct ubifs_mst_node *mst1 = NULL, *mst2 = NULL, *mst; -+ const int sz = c->mst_node_alsz; -+ int err, offs1, offs2; -+ -+ dbg_rcvry("recovery"); -+ -+ err = get_master_node(c, UBIFS_MST_LNUM, &buf1, &mst1, &cor1); -+ if (err) -+ goto out_free; -+ -+ err = get_master_node(c, UBIFS_MST_LNUM + 1, &buf2, &mst2, &cor2); -+ if (err) -+ goto out_free; -+ -+ if (mst1) { -+ offs1 = (void *)mst1 - buf1; -+ if ((le32_to_cpu(mst1->flags) & UBIFS_MST_RCVRY) && -+ (offs1 == 0 && !cor1)) { -+ /* -+ * mst1 was written by recovery at offset 0 with no -+ * corruption. -+ */ -+ dbg_rcvry("recovery recovery"); -+ mst = mst1; -+ } else if (mst2) { -+ offs2 = (void *)mst2 - buf2; -+ if (offs1 == offs2) { -+ /* Same offset, so must be the same */ -+ if (memcmp((void *)mst1 + UBIFS_CH_SZ, -+ (void *)mst2 + UBIFS_CH_SZ, -+ UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) -+ goto out_err; -+ mst = mst1; -+ } else if (offs2 + sz == offs1) { -+ /* 1st LEB was written, 2nd was not */ -+ if (cor1) -+ goto out_err; -+ mst = mst1; -+ } else if (offs1 == 0 && offs2 + sz >= c->leb_size) { -+ /* 1st LEB was unmapped and written, 2nd not */ -+ if (cor1) -+ goto out_err; -+ mst = mst1; -+ } else -+ goto out_err; -+ } else { -+ /* -+ * 2nd LEB was unmapped and about to be written, so -+ * there must be only one master node in the first LEB -+ * and no corruption. -+ */ -+ if (offs1 != 0 || cor1) -+ goto out_err; -+ mst = mst1; -+ } -+ } else { -+ if (!mst2) -+ goto out_err; -+ /* -+ * 1st LEB was unmapped and about to be written, so there must -+ * be no room left in 2nd LEB. -+ */ -+ offs2 = (void *)mst2 - buf2; -+ if (offs2 + sz + sz <= c->leb_size) -+ goto out_err; -+ mst = mst2; -+ } -+ -+ dbg_rcvry("recovered master node from LEB %d", -+ (mst == mst1 ? UBIFS_MST_LNUM : UBIFS_MST_LNUM + 1)); -+ -+ memcpy(c->mst_node, mst, UBIFS_MST_NODE_SZ); -+ -+ if ((c->vfs_sb->s_flags & MS_RDONLY)) { -+ /* Read-only mode. Keep a copy for switching to rw mode */ -+ c->rcvrd_mst_node = kmalloc(sz, GFP_KERNEL); -+ if (!c->rcvrd_mst_node) { -+ err = -ENOMEM; -+ goto out_free; -+ } -+ memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ); -+ } else { -+ /* Write the recovered master node */ -+ c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1; -+ err = write_rcvrd_mst_node(c, c->mst_node); -+ if (err) -+ goto out_free; -+ } -+ -+ vfree(buf2); -+ vfree(buf1); -+ -+ return 0; -+ -+out_err: -+ err = -EINVAL; -+out_free: -+ ubifs_err("failed to recover master node"); -+ if (mst1) { -+ dbg_err("dumping first master node"); -+ dbg_dump_node(c, mst1); -+ } -+ if (mst2) { -+ dbg_err("dumping second master node"); -+ dbg_dump_node(c, mst2); -+ } -+ vfree(buf2); -+ vfree(buf1); -+ return err; -+} -+ -+/** -+ * ubifs_write_rcvrd_mst_node - write the recovered master node. -+ * @c: UBIFS file-system description object -+ * -+ * This function writes the master node that was recovered during mounting in -+ * read-only mode and must now be written because we are remounting rw. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c) -+{ -+ int err; -+ -+ if (!c->rcvrd_mst_node) -+ return 0; -+ c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ err = write_rcvrd_mst_node(c, c->rcvrd_mst_node); -+ if (err) -+ return err; -+ kfree(c->rcvrd_mst_node); -+ c->rcvrd_mst_node = NULL; -+ return 0; -+} -+ -+/** -+ * is_last_write - determine if an offset was in the last write to a LEB. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to check -+ * @offs: offset to check -+ * -+ * This function returns %1 if @offs was in the last write to the LEB whose data -+ * is in @buf, otherwise %0 is returned. The determination is made by checking -+ * for subsequent empty space starting from the next min_io_size boundary (or a -+ * bit less than the common header size if min_io_size is one). -+ */ -+static int is_last_write(const struct ubifs_info *c, void *buf, int offs) -+{ -+ int empty_offs; -+ int check_len; -+ uint8_t *p; -+ -+ if (c->min_io_size == 1) { -+ check_len = c->leb_size - offs; -+ p = buf + check_len; -+ for (; check_len > 0; check_len--) -+ if (*--p != 0xff) -+ break; -+ /* -+ * 'check_len' is the size of the corruption which cannot be -+ * more than the size of 1 node if it was caused by an unclean -+ * unmount. -+ */ -+ if (check_len > UBIFS_MAX_NODE_SZ) -+ return 0; -+ return 1; -+ } -+ -+ /* -+ * Round up to the next c->min_io_size boundary i.e. 'offs' is in the -+ * last wbuf written. After that should be empty space. -+ */ -+ empty_offs = ALIGN(offs + 1, c->min_io_size); -+ check_len = c->leb_size - empty_offs; -+ p = buf + empty_offs - offs; -+ -+ for (; check_len > 0; check_len--) -+ if (*p++ != 0xff) -+ return 0; -+ return 1; -+} -+ -+/** -+ * clean_buf - clean the data from an LEB sitting in a buffer. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to clean -+ * @lnum: LEB number to clean -+ * @offs: offset from which to clean -+ * @len: length of buffer -+ * -+ * This function pads up to the next min_io_size boundary (if there is one) and -+ * sets empty space to all 0xff. @buf, @offs and @len are updated to the next -+ * min_io_size boundary (if there is one). -+ */ -+static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, -+ int *offs, int *len) -+{ -+ int empty_offs, pad_len; -+ -+ lnum = lnum; -+ dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs); -+ -+ if (c->min_io_size == 1) { -+ memset(*buf, 0xff, c->leb_size - *offs); -+ return; -+ } -+ -+ ubifs_assert(!(*offs & 7)); -+ empty_offs = ALIGN(*offs, c->min_io_size); -+ pad_len = empty_offs - *offs; -+ ubifs_pad(c, *buf, pad_len); -+ *offs += pad_len; -+ *buf += pad_len; -+ *len -= pad_len; -+ memset(*buf, 0xff, c->leb_size - empty_offs); -+} -+ -+/** -+ * no_more_nodes - determine if there are no more nodes in a buffer. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to check -+ * @len: length of buffer -+ * @lnum: LEB number of the LEB from which @buf was read -+ * @offs: offset from which @buf was read -+ * -+ * This function scans @buf for more nodes and returns %0 is a node is found and -+ * %1 if no more nodes are found. -+ */ -+static int no_more_nodes(const struct ubifs_info *c, void *buf, int len, -+ int lnum, int offs) -+{ -+ int skip, next_offs = 0; -+ -+ if (len > UBIFS_DATA_NODE_SZ) { -+ struct ubifs_ch *ch = buf; -+ int dlen = le32_to_cpu(ch->len); -+ -+ if (ch->node_type == UBIFS_DATA_NODE && dlen >= UBIFS_CH_SZ && -+ dlen <= UBIFS_MAX_DATA_NODE_SZ) -+ /* The corrupt node looks like a data node */ -+ next_offs = ALIGN(offs + dlen, 8); -+ } -+ -+ if (c->min_io_size == 1) -+ skip = 8; -+ else -+ skip = ALIGN(offs + 1, c->min_io_size) - offs; -+ -+ offs += skip; -+ buf += skip; -+ len -= skip; -+ while (len > 8) { -+ struct ubifs_ch *ch = buf; -+ uint32_t magic = le32_to_cpu(ch->magic); -+ int ret; -+ -+ if (magic == UBIFS_NODE_MAGIC) { -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1); -+ if (ret == SCANNED_A_NODE || ret > 0) { -+ /* -+ * There is a small chance this is just data in -+ * a data node, so check that possibility. e.g. -+ * this is part of a file that itself contains -+ * a UBIFS image. -+ */ -+ if (next_offs && offs + le32_to_cpu(ch->len) <= -+ next_offs) -+ continue; -+ dbg_rcvry("unexpected node at %d:%d", lnum, -+ offs); -+ return 0; -+ } -+ } -+ offs += 8; -+ buf += 8; -+ len -= 8; -+ } -+ return 1; -+} -+ -+/** -+ * fix_unclean_leb - fix an unclean LEB. -+ * @c: UBIFS file-system description object -+ * @sleb: scanned LEB information -+ * @start: offset where scan started -+ */ -+static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ int start) -+{ -+ int lnum = sleb->lnum, endpt = start; -+ -+ /* Get the end offset of the last node we are keeping */ -+ if (!list_empty(&sleb->nodes)) { -+ struct ubifs_scan_node *snod; -+ -+ snod = list_entry(sleb->nodes.prev, -+ struct ubifs_scan_node, list); -+ endpt = snod->offs + snod->len; -+ } -+ -+ if ((c->vfs_sb->s_flags & MS_RDONLY) && !c->remounting_rw) { -+ /* Add to recovery list */ -+ struct ubifs_unclean_leb *ucleb; -+ -+ dbg_rcvry("need to fix LEB %d start %d endpt %d", -+ lnum, start, sleb->endpt); -+ ucleb = kzalloc(sizeof(struct ubifs_unclean_leb), GFP_NOFS); -+ if (!ucleb) -+ return -ENOMEM; -+ ucleb->lnum = lnum; -+ ucleb->endpt = endpt; -+ list_add_tail(&ucleb->list, &c->unclean_leb_list); -+ } else { -+ /* Write the fixed LEB back to flash */ -+ int err; -+ -+ dbg_rcvry("fixing LEB %d start %d endpt %d", -+ lnum, start, sleb->endpt); -+ if (endpt == 0) { -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ } else { -+ int len = ALIGN(endpt, c->min_io_size); -+ -+ if (start) { -+ err = ubi_read(c->ubi, lnum, sleb->buf, 0, -+ start); -+ if (err) -+ return err; -+ } -+ /* Pad to min_io_size */ -+ if (len > endpt) { -+ int pad_len = len - ALIGN(endpt, 8); -+ -+ if (pad_len > 0) { -+ void *buf = sleb->buf + len - pad_len; -+ -+ ubifs_pad(c, buf, pad_len); -+ } -+ } -+ err = ubi_leb_change(c->ubi, lnum, sleb->buf, len, -+ UBI_UNKNOWN); -+ if (err) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+/** -+ * drop_incomplete_group - drop nodes from an incomplete group. -+ * @sleb: scanned LEB information -+ * @offs: offset of dropped nodes is returned here -+ * -+ * This function returns %1 if nodes are dropped and %0 otherwise. -+ */ -+static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs) -+{ -+ int dropped = 0; -+ -+ while (!list_empty(&sleb->nodes)) { -+ struct ubifs_scan_node *snod; -+ struct ubifs_ch *ch; -+ -+ snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, -+ list); -+ ch = snod->node; -+ if (ch->group_type != UBIFS_IN_NODE_GROUP) -+ return dropped; -+ dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs); -+ *offs = snod->offs; -+ list_del(&snod->list); -+ kfree(snod); -+ sleb->nodes_cnt -= 1; -+ dropped = 1; -+ } -+ return dropped; -+} -+ -+/** -+ * ubifs_recover_leb - scan and recover a LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @offs: offset -+ * @sbuf: LEB-sized buffer to use -+ * @grouped: nodes may be grouped for recovery -+ * -+ * This function does a scan of a LEB, but caters for errors that might have -+ * been caused by the unclean unmount from which we are attempting to recover. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, -+ int offs, void *sbuf, int grouped) -+{ -+ int err, len = c->leb_size - offs, need_clean = 0, quiet = 1; -+ int empty_chkd = 0, start = offs; -+ struct ubifs_scan_leb *sleb; -+ void *buf = sbuf + offs; -+ -+ dbg_rcvry("%d:%d", lnum, offs); -+ -+ sleb = ubifs_start_scan(c, lnum, offs, sbuf); -+ if (IS_ERR(sleb)) -+ return sleb; -+ -+ if (sleb->ecc) -+ need_clean = 1; -+ -+ while (len >= 8) { -+ int ret; -+ -+ dbg_scan("look at LEB %d:%d (%d bytes left)", -+ lnum, offs, len); -+ -+ cond_resched(); -+ -+ /* -+ * Scan quietly until there is an error from which we cannot -+ * recover -+ */ -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet); -+ -+ if (ret == SCANNED_A_NODE) { -+ /* A valid node, and not a padding node */ -+ struct ubifs_ch *ch = buf; -+ int node_len; -+ -+ err = ubifs_add_snod(c, sleb, buf, offs); -+ if (err) -+ goto error; -+ node_len = ALIGN(le32_to_cpu(ch->len), 8); -+ offs += node_len; -+ buf += node_len; -+ len -= node_len; -+ continue; -+ } -+ -+ if (ret > 0) { -+ /* Padding bytes or a valid padding node */ -+ offs += ret; -+ buf += ret; -+ len -= ret; -+ continue; -+ } -+ -+ if (ret == SCANNED_EMPTY_SPACE) { -+ if (!is_empty(buf, len)) { -+ if (!is_last_write(c, buf, offs)) -+ break; -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ } -+ empty_chkd = 1; -+ break; -+ } -+ -+ if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) -+ if (is_last_write(c, buf, offs)) { -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ empty_chkd = 1; -+ break; -+ } -+ -+ if (ret == SCANNED_A_CORRUPT_NODE) -+ if (no_more_nodes(c, buf, len, lnum, offs)) { -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ empty_chkd = 1; -+ break; -+ } -+ -+ if (quiet) { -+ /* Redo the last scan but noisily */ -+ quiet = 0; -+ continue; -+ } -+ -+ switch (ret) { -+ case SCANNED_GARBAGE: -+ dbg_err("garbage"); -+ goto corrupted; -+ case SCANNED_A_CORRUPT_NODE: -+ case SCANNED_A_BAD_PAD_NODE: -+ dbg_err("bad node"); -+ goto corrupted; -+ default: -+ dbg_err("unknown"); -+ goto corrupted; -+ } -+ } -+ -+ if (!empty_chkd && !is_empty(buf, len)) { -+ if (is_last_write(c, buf, offs)) { -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ } else { -+ ubifs_err("corrupt empty space at LEB %d:%d", -+ lnum, offs); -+ goto corrupted; -+ } -+ } -+ -+ /* Drop nodes from incomplete group */ -+ if (grouped && drop_incomplete_group(sleb, &offs)) { -+ buf = sbuf + offs; -+ len = c->leb_size - offs; -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ } -+ -+ if (offs % c->min_io_size) { -+ clean_buf(c, &buf, lnum, &offs, &len); -+ need_clean = 1; -+ } -+ -+ ubifs_end_scan(c, sleb, lnum, offs); -+ -+ if (need_clean) { -+ err = fix_unclean_leb(c, sleb, start); -+ if (err) -+ goto error; -+ } -+ -+ return sleb; -+ -+corrupted: -+ ubifs_scanned_corruption(c, lnum, offs, buf); -+ err = -EUCLEAN; -+error: -+ ubifs_err("LEB %d scanning failed", lnum); -+ ubifs_scan_destroy(sleb); -+ return ERR_PTR(err); -+} -+ -+/** -+ * get_cs_sqnum - get commit start sequence number. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of commit start node -+ * @offs: offset of commit start node -+ * @cs_sqnum: commit start sequence number is returned here -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs, -+ unsigned long long *cs_sqnum) -+{ -+ struct ubifs_cs_node *cs_node = NULL; -+ int err, ret; -+ -+ dbg_rcvry("at %d:%d", lnum, offs); -+ cs_node = kmalloc(UBIFS_CS_NODE_SZ, GFP_KERNEL); -+ if (!cs_node) -+ return -ENOMEM; -+ if (c->leb_size - offs < UBIFS_CS_NODE_SZ) -+ goto out_err; -+ err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ); -+ if (err && err != -EBADMSG) -+ goto out_free; -+ ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0); -+ if (ret != SCANNED_A_NODE) { -+ dbg_err("Not a valid node"); -+ goto out_err; -+ } -+ if (cs_node->ch.node_type != UBIFS_CS_NODE) { -+ dbg_err("Node a CS node, type is %d", cs_node->ch.node_type); -+ goto out_err; -+ } -+ if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) { -+ dbg_err("CS node cmt_no %llu != current cmt_no %llu", -+ (unsigned long long)le64_to_cpu(cs_node->cmt_no), -+ c->cmt_no); -+ goto out_err; -+ } -+ *cs_sqnum = le64_to_cpu(cs_node->ch.sqnum); -+ dbg_rcvry("commit start sqnum %llu", *cs_sqnum); -+ kfree(cs_node); -+ return 0; -+ -+out_err: -+ err = -EINVAL; -+out_free: -+ ubifs_err("failed to get CS sqnum"); -+ kfree(cs_node); -+ return err; -+} -+ -+/** -+ * ubifs_recover_log_leb - scan and recover a log LEB. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number -+ * @offs: offset -+ * @sbuf: LEB-sized buffer to use -+ * -+ * This function does a scan of a LEB, but caters for errors that might have -+ * been caused by the unclean unmount from which we are attempting to recover. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, -+ int offs, void *sbuf) -+{ -+ struct ubifs_scan_leb *sleb; -+ int next_lnum; -+ -+ dbg_rcvry("LEB %d", lnum); -+ next_lnum = lnum + 1; -+ if (next_lnum >= UBIFS_LOG_LNUM + c->log_lebs) -+ next_lnum = UBIFS_LOG_LNUM; -+ if (next_lnum != c->ltail_lnum) { -+ /* -+ * We can only recover at the end of the log, so check that the -+ * next log LEB is empty or out of date. -+ */ -+ sleb = ubifs_scan(c, next_lnum, 0, sbuf); -+ if (IS_ERR(sleb)) -+ return sleb; -+ if (sleb->nodes_cnt) { -+ struct ubifs_scan_node *snod; -+ unsigned long long cs_sqnum = c->cs_sqnum; -+ -+ snod = list_entry(sleb->nodes.next, -+ struct ubifs_scan_node, list); -+ if (cs_sqnum == 0) { -+ int err; -+ -+ err = get_cs_sqnum(c, lnum, offs, &cs_sqnum); -+ if (err) { -+ ubifs_scan_destroy(sleb); -+ return ERR_PTR(err); -+ } -+ } -+ if (snod->sqnum > cs_sqnum) { -+ ubifs_err("unrecoverable log corruption " -+ "in LEB %d", lnum); -+ ubifs_scan_destroy(sleb); -+ return ERR_PTR(-EUCLEAN); -+ } -+ } -+ ubifs_scan_destroy(sleb); -+ } -+ return ubifs_recover_leb(c, lnum, offs, sbuf, 0); -+} -+ -+/** -+ * recover_head - recover a head. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of head to recover -+ * @offs: offset of head to recover -+ * @sbuf: LEB-sized buffer to use -+ * -+ * This function ensures that there is no data on the flash at a head location. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int recover_head(const struct ubifs_info *c, int lnum, int offs, -+ void *sbuf) -+{ -+ int len, err, need_clean = 0; -+ -+ if (c->min_io_size > 1) -+ len = c->min_io_size; -+ else -+ len = 512; -+ if (offs + len > c->leb_size) -+ len = c->leb_size - offs; -+ -+ if (!len) -+ return 0; -+ -+ /* Read at the head location and check it is empty flash */ -+ err = ubi_read(c->ubi, lnum, sbuf, offs, len); -+ if (err) -+ need_clean = 1; -+ else { -+ uint8_t *p = sbuf; -+ -+ while (len--) -+ if (*p++ != 0xff) { -+ need_clean = 1; -+ break; -+ } -+ } -+ -+ if (need_clean) { -+ dbg_rcvry("cleaning head at %d:%d", lnum, offs); -+ if (offs == 0) -+ return ubifs_leb_unmap(c, lnum); -+ err = ubi_read(c->ubi, lnum, sbuf, 0, offs); -+ if (err) -+ return err; -+ return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN); -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubifs_recover_inl_heads - recover index and LPT heads. -+ * @c: UBIFS file-system description object -+ * @sbuf: LEB-sized buffer to use -+ * -+ * This function ensures that there is no data on the flash at the index and -+ * LPT head locations. -+ * -+ * This deals with the recovery of a half-completed journal commit. UBIFS is -+ * careful never to overwrite the last version of the index or the LPT. Because -+ * the index and LPT are wandering trees, data from a half-completed commit will -+ * not be referenced anywhere in UBIFS. The data will be either in LEBs that are -+ * assumed to be empty and will be unmapped anyway before use, or in the index -+ * and LPT heads. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf) -+{ -+ int err; -+ -+ ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY) || c->remounting_rw); -+ -+ dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs); -+ err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf); -+ if (err) -+ return err; -+ -+ dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs); -+ err = recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+/** -+ * clean_an_unclean_leb - read and write a LEB to remove corruption. -+ * @c: UBIFS file-system description object -+ * @ucleb: unclean LEB information -+ * @sbuf: LEB-sized buffer to use -+ * -+ * This function reads a LEB up to a point pre-determined by the mount recovery, -+ * checks the nodes, and writes the result back to the flash, thereby cleaning -+ * off any following corruption, or non-fatal ECC errors. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int clean_an_unclean_leb(const struct ubifs_info *c, -+ struct ubifs_unclean_leb *ucleb, void *sbuf) -+{ -+ int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1; -+ void *buf = sbuf; -+ -+ dbg_rcvry("LEB %d len %d", lnum, len); -+ -+ if (len == 0) { -+ /* Nothing to read, just unmap it */ -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ return 0; -+ } -+ -+ err = ubi_read(c->ubi, lnum, buf, offs, len); -+ if (err && err != -EBADMSG) -+ return err; -+ -+ while (len >= 8) { -+ int ret; -+ -+ cond_resched(); -+ -+ /* Scan quietly until there is an error */ -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet); -+ -+ if (ret == SCANNED_A_NODE) { -+ /* A valid node, and not a padding node */ -+ struct ubifs_ch *ch = buf; -+ int node_len; -+ -+ node_len = ALIGN(le32_to_cpu(ch->len), 8); -+ offs += node_len; -+ buf += node_len; -+ len -= node_len; -+ continue; -+ } -+ -+ if (ret > 0) { -+ /* Padding bytes or a valid padding node */ -+ offs += ret; -+ buf += ret; -+ len -= ret; -+ continue; -+ } -+ -+ if (ret == SCANNED_EMPTY_SPACE) { -+ ubifs_err("unexpected empty space at %d:%d", -+ lnum, offs); -+ return -EUCLEAN; -+ } -+ -+ if (quiet) { -+ /* Redo the last scan but noisily */ -+ quiet = 0; -+ continue; -+ } -+ -+ ubifs_scanned_corruption(c, lnum, offs, buf); -+ return -EUCLEAN; -+ } -+ -+ /* Pad to min_io_size */ -+ len = ALIGN(ucleb->endpt, c->min_io_size); -+ if (len > ucleb->endpt) { -+ int pad_len = len - ALIGN(ucleb->endpt, 8); -+ -+ if (pad_len > 0) { -+ buf = c->sbuf + len - pad_len; -+ ubifs_pad(c, buf, pad_len); -+ } -+ } -+ -+ /* Write back the LEB atomically */ -+ err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN); -+ if (err) -+ return err; -+ -+ dbg_rcvry("cleaned LEB %d", lnum); -+ -+ return 0; -+} -+ -+/** -+ * ubifs_clean_lebs - clean LEBs recovered during read-only mount. -+ * @c: UBIFS file-system description object -+ * @sbuf: LEB-sized buffer to use -+ * -+ * This function cleans a LEB identified during recovery that needs to be -+ * written but was not because UBIFS was mounted read-only. This happens when -+ * remounting to read-write mode. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf) -+{ -+ dbg_rcvry("recovery"); -+ while (!list_empty(&c->unclean_leb_list)) { -+ struct ubifs_unclean_leb *ucleb; -+ int err; -+ -+ ucleb = list_entry(c->unclean_leb_list.next, -+ struct ubifs_unclean_leb, list); -+ err = clean_an_unclean_leb(c, ucleb, sbuf); -+ if (err) -+ return err; -+ list_del(&ucleb->list); -+ kfree(ucleb); -+ } -+ return 0; -+} -+ -+/** -+ * ubifs_recover_gc_lnum - recover the GC LEB number. -+ * @c: UBIFS file-system description object -+ * -+ * Out-of-place garbage collection requires always one empty LEB with which to -+ * start garbage collection. The LEB number is recorded in c->gc_lnum and is -+ * written to the master node on unmounting. In the case of an unclean unmount -+ * the value of gc_lnum recorded in the master node is out of date and cannot -+ * be used. Instead, recovery must allocate an empty LEB for this purpose. -+ * However, there may not be enough empty space, in which case it must be -+ * possible to GC the dirtiest LEB into the GC head LEB. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_recover_gc_lnum(struct ubifs_info *c) -+{ -+ struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; -+ struct ubifs_lprops lp; -+ int lnum, err; -+ -+ c->gc_lnum = -1; -+ if (wbuf->lnum == -1) { -+ dbg_rcvry("no GC head LEB"); -+ goto find_free; -+ } -+ /* -+ * See whether the used space in the dirtiest LEB fits in the GC head -+ * LEB. -+ */ -+ err = ubifs_find_dirty_leb(c, &lp, c->dead_wm, 2); -+ if (err) { -+ if (err == -ENOSPC) -+ dbg_err("could not find a dirty LEB"); -+ return err; -+ } -+ ubifs_assert(!(lp.flags & LPROPS_INDEX)); -+ lnum = lp.lnum; -+ if (lp.free + lp.dirty == c->leb_size) { -+ /* An empty LEB was returned */ -+ if (lp.free != c->leb_size) { -+ err = ubifs_change_one_lp(c, lnum, c->leb_size, -+ 0, 0, 0, 0); -+ if (err) -+ return err; -+ } -+ err = ubifs_leb_unmap(c, lnum); -+ if (err) -+ return err; -+ c->gc_lnum = lnum; -+ dbg_rcvry("allocated LEB %d for GC", lnum); -+ return 0; -+ } -+ /* -+ * There was no empty LEB so the used space in the dirtiest LEB must fit -+ * in the GC head LEB. -+ */ -+ if (lp.free + lp.dirty < wbuf->offs) { -+ dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d", -+ lnum, wbuf->lnum, wbuf->offs); -+ err = ubifs_return_leb(c, lnum); -+ if (err) -+ return err; -+ goto find_free; -+ } -+ /* It fits, so GC it - use locking to keep 'ubifs_assert()' happy */ -+ dbg_rcvry("GC'ing LEB %d", lnum); -+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); -+ err = ubifs_garbage_collect_leb(c, &lp); -+ if (err >= 0) { -+ int err2 = ubifs_wbuf_sync_nolock(wbuf); -+ -+ if (err2) -+ err = err2; -+ } -+ mutex_unlock(&wbuf->io_mutex); -+ if (err < 0) { -+ dbg_err("GC failed, error %d", err); -+ if (err == -EAGAIN) -+ err = -EINVAL; -+ return err; -+ } -+ if (err != LEB_RETAINED) { -+ dbg_err("GC returned %d", err); -+ return -EINVAL; -+ } -+ err = ubifs_leb_unmap(c, c->gc_lnum); -+ if (err) -+ return err; -+ dbg_rcvry("allocated LEB %d for GC", lnum); -+ return 0; -+ -+find_free: -+ /* -+ * There is no GC head LEB or the free space in the GC head LEB is too -+ * small. Allocate gc_lnum by calling 'ubifs_find_free_leb_for_idx()' so -+ * GC is not run. -+ */ -+ lnum = ubifs_find_free_leb_for_idx(c); -+ if (lnum < 0) { -+ dbg_err("could not find an empty LEB"); -+ return lnum; -+ } -+ /* And reset the index flag */ -+ err = ubifs_change_one_lp(c, lnum, -1, -1, 0, LPROPS_INDEX, 0); -+ if (err) -+ return err; -+ c->gc_lnum = lnum; -+ dbg_rcvry("allocated LEB %d for GC", lnum); -+ return 0; -+} -+ -+/** -+ * struct size_entry - inode size information for recovery. -+ * @rb: link in the RB-tree of sizes -+ * @inum: inode number -+ * @i_size: size on inode -+ * @d_size: maximum size based on data nodes -+ * @exists: indicates whether the inode exists -+ * @inode: inode if pinned in memory awaiting rw mode to fix it -+ */ -+struct size_entry { -+ struct rb_node rb; -+ ino_t inum; -+ loff_t i_size; -+ loff_t d_size; -+ int exists; -+ struct inode *inode; -+}; -+ -+/** -+ * add_ino - add an entry to the size tree. -+ * @c: UBIFS file-system description object -+ * @inum: inode number -+ * @i_size: size on inode -+ * @d_size: maximum size based on data nodes -+ * @exists: indicates whether the inode exists -+ */ -+static int add_ino(struct ubifs_info *c, ino_t inum, loff_t i_size, -+ loff_t d_size, int exists) -+{ -+ struct rb_node **p = &c->size_tree.rb_node, *parent = NULL; -+ struct size_entry *e; -+ -+ while (*p) { -+ parent = *p; -+ e = rb_entry(parent, struct size_entry, rb); -+ if (inum < e->inum) -+ p = &(*p)->rb_left; -+ else -+ p = &(*p)->rb_right; -+ } -+ -+ e = kzalloc(sizeof(struct size_entry), GFP_KERNEL); -+ if (!e) -+ return -ENOMEM; -+ -+ e->inum = inum; -+ e->i_size = i_size; -+ e->d_size = d_size; -+ e->exists = exists; -+ -+ rb_link_node(&e->rb, parent, p); -+ rb_insert_color(&e->rb, &c->size_tree); -+ -+ return 0; -+} -+ -+/** -+ * find_ino - find an entry on the size tree. -+ * @c: UBIFS file-system description object -+ * @inum: inode number -+ */ -+static struct size_entry *find_ino(struct ubifs_info *c, ino_t inum) -+{ -+ struct rb_node *p = c->size_tree.rb_node; -+ struct size_entry *e; -+ -+ while (p) { -+ e = rb_entry(p, struct size_entry, rb); -+ if (inum < e->inum) -+ p = p->rb_left; -+ else if (inum > e->inum) -+ p = p->rb_right; -+ else -+ return e; -+ } -+ return NULL; -+} -+ -+/** -+ * remove_ino - remove an entry from the size tree. -+ * @c: UBIFS file-system description object -+ * @inum: inode number -+ */ -+static void remove_ino(struct ubifs_info *c, ino_t inum) -+{ -+ struct size_entry *e = find_ino(c, inum); -+ -+ if (!e) -+ return; -+ rb_erase(&e->rb, &c->size_tree); -+ kfree(e); -+} -+ -+/** -+ * ubifs_destroy_size_tree - free resources related to the size tree. -+ * @c: UBIFS file-system description object -+ */ -+void ubifs_destroy_size_tree(struct ubifs_info *c) -+{ -+ struct rb_node *this = c->size_tree.rb_node; -+ struct size_entry *e; -+ -+ while (this) { -+ if (this->rb_left) { -+ this = this->rb_left; -+ continue; -+ } else if (this->rb_right) { -+ this = this->rb_right; -+ continue; -+ } -+ e = rb_entry(this, struct size_entry, rb); -+ if (e->inode) -+ iput(e->inode); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &e->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(e); -+ } -+ c->size_tree = RB_ROOT; -+} -+ -+/** -+ * ubifs_recover_size_accum - accumulate inode sizes for recovery. -+ * @c: UBIFS file-system description object -+ * @key: node key -+ * @deletion: node is for a deletion -+ * @new_size: inode size -+ * -+ * This function has two purposes: -+ * 1) to ensure there are no data nodes that fall outside the inode size -+ * 2) to ensure there are no data nodes for inodes that do not exist -+ * To accomplish those purposes, a rb-tree is constructed containing an entry -+ * for each inode number in the journal that has not been deleted, and recording -+ * the size from the inode node, the maximum size of any data node (also altered -+ * by truncations) and a flag indicating a inode number for which no inode node -+ * was present in the journal. -+ * -+ * Note that there is still the possibility that there are data nodes that have -+ * been committed that are beyond the inode size, however the only way to find -+ * them would be to scan the entire index. Alternatively, some provision could -+ * be made to record the size of inodes at the start of commit, which would seem -+ * very cumbersome for a scenario that is quite unlikely and the only negative -+ * consequence of which is wasted space. -+ * -+ * This functions returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, -+ int deletion, loff_t new_size) -+{ -+ ino_t inum = key_ino(c, key); -+ struct size_entry *e; -+ int err; -+ -+ switch (key_type(c, key)) { -+ case UBIFS_INO_KEY: -+ if (deletion) -+ remove_ino(c, inum); -+ else { -+ e = find_ino(c, inum); -+ if (e) { -+ e->i_size = new_size; -+ e->exists = 1; -+ } else { -+ err = add_ino(c, inum, new_size, 0, 1); -+ if (err) -+ return err; -+ } -+ } -+ break; -+ case UBIFS_DATA_KEY: -+ e = find_ino(c, inum); -+ if (e) { -+ if (new_size > e->d_size) -+ e->d_size = new_size; -+ } else { -+ err = add_ino(c, inum, 0, new_size, 0); -+ if (err) -+ return err; -+ } -+ break; -+ case UBIFS_TRUN_KEY: -+ e = find_ino(c, inum); -+ if (e) -+ e->d_size = new_size; -+ break; -+ } -+ return 0; -+} -+ -+/** -+ * fix_size_in_place - fix inode size in place on flash. -+ * @c: UBIFS file-system description object -+ * @e: inode size information for recovery -+ */ -+static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) -+{ -+ struct ubifs_ino_node *ino = c->sbuf; -+ unsigned char *p; -+ union ubifs_key key; -+ int err, lnum, offs, len; -+ loff_t i_size; -+ uint32_t crc; -+ -+ /* Locate the inode node LEB number and offset */ -+ ino_key_init(c, &key, e->inum); -+ err = ubifs_tnc_locate(c, &key, ino, &lnum, &offs); -+ if (err) -+ goto out; -+ /* -+ * If the size recorded on the inode node is greater than the size that -+ * was calculated from nodes in the journal then don't change the inode. -+ */ -+ i_size = le64_to_cpu(ino->size); -+ if (i_size >= e->d_size) -+ return 0; -+ /* Read the LEB */ -+ err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size); -+ if (err) -+ goto out; -+ /* Change the size field and recalculate the CRC */ -+ ino = c->sbuf + offs; -+ ino->size = cpu_to_le64(e->d_size); -+ len = le32_to_cpu(ino->ch.len); -+ crc = crc32(UBIFS_CRC32_INIT, (void *)ino + 8, len - 8); -+ ino->ch.crc = cpu_to_le32(crc); -+ /* Work out where data in the LEB ends and free space begins */ -+ p = c->sbuf; -+ len = c->leb_size - 1; -+ while (p[len] == 0xff) -+ len -= 1; -+ len = ALIGN(len + 1, c->min_io_size); -+ /* Atomically write the fixed LEB back again */ -+ err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); -+ if (err) -+ goto out; -+ dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ", e->inum, lnum, offs, -+ i_size, e->d_size); -+ return 0; -+ -+out: -+ ubifs_warn("inode %lu failed to fix size %lld -> %lld error %d", -+ e->inum, e->i_size, e->d_size, err); -+ return err; -+} -+ -+/** -+ * ubifs_recover_size - recover inode size. -+ * @c: UBIFS file-system description object -+ * -+ * This function attempts to fix inode size discrepancies identified by the -+ * 'ubifs_recover_size_accum()' function. -+ * -+ * This functions returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_recover_size(struct ubifs_info *c) -+{ -+ struct rb_node *this = rb_first(&c->size_tree); -+ -+ while (this) { -+ struct size_entry *e; -+ int err; -+ -+ e = rb_entry(this, struct size_entry, rb); -+ if (!e->exists) { -+ union ubifs_key key; -+ -+ ino_key_init(c, &key, e->inum); -+ err = ubifs_tnc_lookup(c, &key, c->sbuf); -+ if (err && err != -ENOENT) -+ return err; -+ if (err == -ENOENT) { -+ /* Remove data nodes that have no inode */ -+ dbg_rcvry("removing ino %lu", e->inum); -+ err = ubifs_tnc_remove_ino(c, e->inum); -+ if (err) -+ return err; -+ /* -+ * If we later unmount cleanly without -+ * committing, the TNC changes will be lost, -+ * hence we set a flag to ensure a commit is -+ * done. -+ */ -+ c->recovery_needs_commit = 1; -+ } else { -+ struct ubifs_ino_node *ino = c->sbuf; -+ -+ e->exists = 1; -+ e->i_size = le64_to_cpu(ino->size); -+ } -+ } -+ if (e->exists && e->i_size < e->d_size) { -+ if (!e->inode && (c->vfs_sb->s_flags & MS_RDONLY)) { -+ /* Fix the inode size and pin it in memory */ -+ struct inode *inode; -+ -+ inode = ubifs_iget(c->vfs_sb, e->inum); -+ if (IS_ERR(inode)) -+ return PTR_ERR(inode); -+ if (inode->i_size < e->d_size) { -+ dbg_rcvry("ino %lu size %lld -> %lld", -+ e->inum, e->d_size, -+ inode->i_size); -+ inode->i_size = e->d_size; -+ e->inode = inode; -+ this = rb_next(this); -+ continue; -+ } -+ iput(inode); -+ } else { -+ /* Fix the size in place */ -+ err = fix_size_in_place(c, e); -+ if (err) { -+ if (e->inode) -+ /* -+ * We have changed the inode -+ * size in memory but failed to -+ * fix it on flash. Mark it -+ * dirty without budgeting, and -+ * hope we don't run out of -+ * space. -+ */ -+ mark_inode_dirty_sync(e->inode); -+ /* -+ * We consider that failing to recover -+ * the size is not fatal, because it -+ * only affects files that were being -+ * written without synchronization and -+ * the only down side is that some space -+ * may be wasted. -+ */ -+ err = 0; -+ } -+ if (e->inode) -+ iput(e->inode); -+ } -+ } -+ this = rb_next(this); -+ rb_erase(&e->rb, &c->size_tree); -+ kfree(e); -+ } -+ return 0; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/replay.c linux-2.6.24.7/fs/ubifs/replay.c ---- linux-2.6.24.7.old/fs/ubifs/replay.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/replay.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1049 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file contains journal replay code. It runs when the file-system is being -+ * mounted and requires no locking. -+ * -+ * The larger is the journal, the longer it takes to scan it, so the longer it -+ * takes to mount UBIFS. This is why the journal has limited size which may be -+ * changed depending on the system requirements. But a larger journal gives -+ * faster I/O speed because it writes the index less frequently. So this is a -+ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the -+ * larger is the journal, the more memory its index may consume. -+ */ -+ -+#include "ubifs.h" -+ -+/* -+ * Replay flags. -+ * -+ * REPLAY_DELETION: node was deleted -+ * REPLAY_REF: node is a reference node -+ */ -+enum { -+ REPLAY_DELETION = 1, -+ REPLAY_REF = 2, -+}; -+ -+/** -+ * struct replay_entry - replay tree entry. -+ * @lnum: logical eraseblock number of the node -+ * @offs: node offset -+ * @len: node length -+ * @sqnum: node sequence number -+ * @flags: replay flags -+ * @rb: links the replay tree -+ * @key: node key -+ * @nm: directory entry name -+ * @old_size: truncation old size -+ * @new_size: truncation new size -+ * @free: amount of free space in a bud -+ * @dirty: amount of dirty space in a bud from padding and deletion nodes -+ * -+ * UBIFS journal replay must compare node sequence numbers, which means it must -+ * build a tree of node information to insert into the TNC. -+ */ -+struct replay_entry { -+ int lnum; -+ int offs; -+ int len; -+ unsigned long long sqnum; -+ int flags; -+ struct rb_node rb; -+ union ubifs_key key; -+ union { -+ struct qstr nm; -+ struct { -+ loff_t old_size; -+ loff_t new_size; -+ }; -+ struct { -+ int free; -+ int dirty; -+ }; -+ }; -+}; -+ -+/** -+ * struct bud_entry - entry in the list of buds to replay. -+ * @list: next bud in the list -+ * @bud: bud description object -+ * @free: free bytes in the bud -+ * @sqnum: reference node sequence number -+ */ -+struct bud_entry { -+ struct list_head list; -+ struct ubifs_bud *bud; -+ int free; -+ unsigned long long sqnum; -+}; -+ -+/** -+ * set_bud_lprops - set free and dirty space used by a bud. -+ * @c: UBIFS file-system description object -+ * @r: replay entry of bud -+ */ -+static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r) -+{ -+ const struct ubifs_lprops *lp; -+ int err = 0, dirty; -+ -+ ubifs_get_lprops(c); -+ -+ lp = ubifs_lpt_lookup_dirty(c, r->lnum); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ dirty = lp->dirty; -+ if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) { -+ dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum, -+ lp->free, lp->dirty); -+ dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum, -+ lp->free, lp->dirty); -+ dirty -= c->leb_size - lp->free; -+ if (dirty != 0) -+ dbg_msg("LEB %d lp: %d free %d dirty " -+ "replay: %d free %d dirty", r->lnum, lp->free, -+ lp->dirty, r->free, r->dirty); -+ } -+ lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty, -+ lp->flags | LPROPS_TAKEN, 0); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * trun_remove_range - apply a replay entry for a truncation to the TNC. -+ * @c: UBIFS file-system description object -+ * @r: replay entry of truncation -+ */ -+static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r) -+{ -+ unsigned min_blk, max_blk; -+ union ubifs_key min_key, max_key; -+ ino_t ino; -+ -+ min_blk = r->new_size / UBIFS_BLOCK_SIZE; -+ if (r->new_size & (UBIFS_BLOCK_SIZE - 1)) -+ min_blk += 1; -+ -+ max_blk = r->old_size / UBIFS_BLOCK_SIZE; -+ if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0) -+ max_blk -= 1; -+ -+ ino = key_ino(c, &r->key); -+ -+ data_key_init(c, &min_key, ino, min_blk); -+ data_key_init(c, &max_key, ino, max_blk); -+ -+ return ubifs_tnc_remove_range(c, &min_key, &max_key); -+} -+ -+/** -+ * apply_replay_entry - apply a replay entry to the TNC. -+ * @c: UBIFS file-system description object -+ * @r: replay entry to apply -+ * -+ * Apply a replay entry to the TNC. -+ */ -+static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) -+{ -+ int err, deletion = ((r->flags & REPLAY_DELETION) != 0); -+ -+ dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum, -+ r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key)); -+ -+ /* Set c->replay_sqnum to help deal with dangling branches. */ -+ c->replay_sqnum = r->sqnum; -+ -+ if (r->flags & REPLAY_REF) -+ err = set_bud_lprops(c, r); -+ else if (is_hash_key(c, &r->key)) { -+ if (deletion) -+ err = ubifs_tnc_remove_nm(c, &r->key, &r->nm); -+ else -+ err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs, -+ r->len, &r->nm); -+ } else { -+ if (deletion) -+ switch (key_type(c, &r->key)) { -+ case UBIFS_INO_KEY: -+ { -+ ino_t inum = key_ino(c, &r->key); -+ -+ err = ubifs_tnc_remove_ino(c, inum); -+ break; -+ } -+ case UBIFS_TRUN_KEY: -+ err = trun_remove_range(c, r); -+ break; -+ default: -+ err = ubifs_tnc_remove(c, &r->key); -+ break; -+ } -+ else -+ err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs, -+ r->len); -+ if (err) -+ return err; -+ -+ if (c->need_recovery) -+ err = ubifs_recover_size_accum(c, &r->key, deletion, -+ r->new_size); -+ } -+ -+ return err; -+} -+ -+/** -+ * destroy_replay_tree - destroy the replay. -+ * @c: UBIFS file-system description object -+ * -+ * Destroy the replay tree. -+ */ -+static void destroy_replay_tree(struct ubifs_info *c) -+{ -+ struct rb_node *this = c->replay_tree.rb_node; -+ struct replay_entry *r; -+ -+ while (this) { -+ if (this->rb_left) { -+ this = this->rb_left; -+ continue; -+ } else if (this->rb_right) { -+ this = this->rb_right; -+ continue; -+ } -+ r = rb_entry(this, struct replay_entry, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &r->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ if (is_hash_key(c, &r->key)) -+ kfree(r->nm.name); -+ kfree(r); -+ } -+ c->replay_tree = RB_ROOT; -+} -+ -+/** -+ * apply_replay_tree - apply the replay tree to the TNC. -+ * @c: UBIFS file-system description object -+ * -+ * Apply the replay tree. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int apply_replay_tree(struct ubifs_info *c) -+{ -+ struct rb_node *this = rb_first(&c->replay_tree); -+ -+ while (this) { -+ struct replay_entry *r; -+ int err; -+ -+ cond_resched(); -+ -+ r = rb_entry(this, struct replay_entry, rb); -+ err = apply_replay_entry(c, r); -+ if (err) -+ return err; -+ this = rb_next(this); -+ } -+ return 0; -+} -+ -+/** -+ * insert_node - insert a node to the replay tree. -+ * @c: UBIFS file-system description object -+ * @lnum: node logical eraseblock number -+ * @offs: node offset -+ * @len: node length -+ * @key: node key -+ * @sqnum: sequence number -+ * @deletion: non-zero if this is a deletion -+ * @used: number of bytes in use in a LEB -+ * @old_size: truncation old size -+ * @new_size: truncation new size -+ * -+ * This function inserts a scanned non-direntry node to the replay tree. The -+ * replay tree is an RB-tree containing @struct replay_entry elements which are -+ * indexed by the sequence number. The replay tree is applied at the very end -+ * of the replay process. Since the tree is sorted in sequence number order, -+ * the older modifications are applied first. This function returns zero in -+ * case of success and a negative error code in case of failure. -+ */ -+static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, -+ union ubifs_key *key, unsigned long long sqnum, -+ int deletion, int *used, loff_t old_size, -+ loff_t new_size) -+{ -+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; -+ struct replay_entry *r; -+ -+ if (key_ino(c, key) >= c->highest_inum) -+ c->highest_inum = key_ino(c, key); -+ -+ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); -+ while (*p) { -+ parent = *p; -+ r = rb_entry(parent, struct replay_entry, rb); -+ if (sqnum < r->sqnum) { -+ p = &(*p)->rb_left; -+ continue; -+ } else if (sqnum > r->sqnum) { -+ p = &(*p)->rb_right; -+ continue; -+ } -+ ubifs_err("duplicate sqnum in replay"); -+ return -EINVAL; -+ } -+ -+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); -+ if (!r) -+ return -ENOMEM; -+ -+ if (!deletion) -+ *used += ALIGN(len, 8); -+ r->lnum = lnum; -+ r->offs = offs; -+ r->len = len; -+ r->sqnum = sqnum; -+ r->flags = (deletion ? REPLAY_DELETION : 0); -+ r->old_size = old_size; -+ r->new_size = new_size; -+ key_copy(c, key, &r->key); -+ -+ rb_link_node(&r->rb, parent, p); -+ rb_insert_color(&r->rb, &c->replay_tree); -+ return 0; -+} -+ -+/** -+ * insert_dent - insert a directory entry node into the replay tree. -+ * @c: UBIFS file-system description object -+ * @lnum: node logical eraseblock number -+ * @offs: node offset -+ * @len: node length -+ * @key: node key -+ * @name: directory entry name -+ * @nlen: directory entry name length -+ * @sqnum: sequence number -+ * @deletion: non-zero if this is a deletion -+ * @used: number of bytes in use in a LEB -+ * -+ * This function inserts a scanned directory entry node to the replay tree. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ * -+ * This function is also used for extended attribute entries because they are -+ * implemented as directory entry nodes. -+ */ -+static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, -+ union ubifs_key *key, const char *name, int nlen, -+ unsigned long long sqnum, int deletion, int *used) -+{ -+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; -+ struct replay_entry *r; -+ char *nbuf; -+ -+ if (key_ino(c, key) >= c->highest_inum) -+ c->highest_inum = key_ino(c, key); -+ -+ dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key)); -+ while (*p) { -+ parent = *p; -+ r = rb_entry(parent, struct replay_entry, rb); -+ if (sqnum < r->sqnum) { -+ p = &(*p)->rb_left; -+ continue; -+ } -+ if (sqnum > r->sqnum) { -+ p = &(*p)->rb_right; -+ continue; -+ } -+ ubifs_err("duplicate sqnum in replay"); -+ return -EINVAL; -+ } -+ -+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); -+ if (!r) -+ return -ENOMEM; -+ nbuf = kmalloc(nlen + 1, GFP_KERNEL); -+ if (!nbuf) { -+ kfree(r); -+ return -ENOMEM; -+ } -+ -+ if (!deletion) -+ *used += ALIGN(len, 8); -+ r->lnum = lnum; -+ r->offs = offs; -+ r->len = len; -+ r->sqnum = sqnum; -+ r->nm.len = nlen; -+ memcpy(nbuf, name, nlen); -+ nbuf[nlen] = '\0'; -+ r->nm.name = nbuf; -+ r->flags = (deletion ? REPLAY_DELETION : 0); -+ key_copy(c, key, &r->key); -+ -+ ubifs_assert(!*p); -+ rb_link_node(&r->rb, parent, p); -+ rb_insert_color(&r->rb, &c->replay_tree); -+ return 0; -+} -+ -+/** -+ * ubifs_validate_entry - validate directory or extended attribute entry node. -+ * @c: UBIFS file-system description object -+ * @dent: the node to validate -+ * -+ * This function validates directory or extended attribute entry node @dent. -+ * Returns zero if the node is all right and a %-EINVAL if not. -+ */ -+int ubifs_validate_entry(struct ubifs_info *c, -+ const struct ubifs_dent_node *dent) -+{ -+ int key_type = key_type_flash(c, dent->key); -+ int nlen = le16_to_cpu(dent->nlen); -+ -+ if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 || -+ dent->type >= UBIFS_ITYPES_CNT || -+ nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 || -+ strnlen(dent->name, nlen) != nlen || -+ le64_to_cpu(dent->inum) > MAX_INUM) { -+ ubifs_err("bad %s node", key_type == UBIFS_DENT_KEY ? -+ "directory entry" : "extended attribute entry"); -+ return -EINVAL; -+ } -+ -+ if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) { -+ ubifs_err("bad key type %d", key_type); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * replay_bud - replay a bud logical eraseblock. -+ * @c: UBIFS file-system description object -+ * @lnum: bud logical eraseblock number to replay -+ * @offs: bud start offset -+ * @jhead: journal head to which this bud belongs -+ * @free: amount of free space in the bud is returned here -+ * @dirty: amount of dirty space from padding and deletion nodes is returned -+ * here -+ * -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, -+ int *free, int *dirty) -+{ -+ int err = 0, used = 0; -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ struct ubifs_bud *bud; -+ -+ dbg_mnt("replay bud LEB %d, head %d", lnum, jhead); -+ if (c->need_recovery) -+ sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD); -+ else -+ sleb = ubifs_scan(c, lnum, offs, c->sbuf); -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ -+ /* -+ * The bud does not have to start from offset zero - the beginning of -+ * the 'lnum' LEB may contain previously committed data. One of the -+ * things we have to do in replay is to correctly update lprops with -+ * newer information about this LEB. -+ * -+ * At this point lprops thinks that this LEB has 'c->leb_size - offs' -+ * bytes of free space because it only contain information about -+ * committed data. -+ * -+ * But we know that real amount of free space is 'c->leb_size - -+ * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and -+ * 'sleb->endpt' is used by bud data. We have to correctly calculate -+ * how much of these data are dirty and update lprops with this -+ * information. -+ * -+ * The dirt in that LEB region is comprised of padding nodes, deletion -+ * nodes, truncation nodes and nodes which are obsoleted by subsequent -+ * nodes in this LEB. So instead of calculating clean space, we -+ * calculate used space ('used' variable). -+ */ -+ -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ int deletion = 0; -+ -+ cond_resched(); -+ -+ if (snod->sqnum >= SQNUM_WATERMARK) { -+ ubifs_err("file system's life ended"); -+ goto out_dump; -+ } -+ -+ if (snod->sqnum > c->max_sqnum) -+ c->max_sqnum = snod->sqnum; -+ -+ switch (snod->type) { -+ case UBIFS_INO_NODE: -+ { -+ struct ubifs_ino_node *ino = snod->node; -+ loff_t new_size = le64_to_cpu(ino->size); -+ -+ if (le32_to_cpu(ino->nlink) == 0) -+ deletion = 1; -+ err = insert_node(c, lnum, snod->offs, snod->len, -+ &snod->key, snod->sqnum, deletion, -+ &used, 0, new_size); -+ break; -+ } -+ case UBIFS_DATA_NODE: -+ { -+ struct ubifs_data_node *dn = snod->node; -+ loff_t new_size = le32_to_cpu(dn->size) + -+ key_block(c, &snod->key) * -+ UBIFS_BLOCK_SIZE; -+ -+ err = insert_node(c, lnum, snod->offs, snod->len, -+ &snod->key, snod->sqnum, deletion, -+ &used, 0, new_size); -+ break; -+ } -+ case UBIFS_DENT_NODE: -+ case UBIFS_XENT_NODE: -+ { -+ struct ubifs_dent_node *dent = snod->node; -+ -+ err = ubifs_validate_entry(c, dent); -+ if (err) -+ goto out_dump; -+ -+ err = insert_dent(c, lnum, snod->offs, snod->len, -+ &snod->key, dent->name, -+ le16_to_cpu(dent->nlen), snod->sqnum, -+ !le64_to_cpu(dent->inum), &used); -+ break; -+ } -+ case UBIFS_TRUN_NODE: -+ { -+ struct ubifs_trun_node *trun = snod->node; -+ loff_t old_size = le64_to_cpu(trun->old_size); -+ loff_t new_size = le64_to_cpu(trun->new_size); -+ -+ /* Validate truncation node */ -+ if (old_size < 0 || old_size > c->max_inode_sz || -+ new_size < 0 || new_size > c->max_inode_sz || -+ old_size <= new_size) { -+ ubifs_err("bad truncation node"); -+ goto out_dump; -+ } -+ -+ err = insert_node(c, lnum, snod->offs, snod->len, -+ &snod->key, snod->sqnum, 1, &used, -+ old_size, new_size); -+ break; -+ } -+ default: -+ ubifs_err("unexpected node type %d in bud LEB %d:%d", -+ snod->type, lnum, snod->offs); -+ err = -EINVAL; -+ goto out_dump; -+ } -+ if (err) -+ goto out; -+ } -+ -+ bud = ubifs_search_bud(c, lnum); -+ if (!bud) -+ BUG(); -+ -+ ubifs_assert(sleb->endpt - offs >= used); -+ ubifs_assert(sleb->endpt % c->min_io_size == 0); -+ -+ if (sleb->endpt + c->min_io_size <= c->leb_size && -+ !(c->vfs_sb->s_flags & MS_RDONLY)) -+ err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum, -+ sleb->endpt, UBI_SHORTTERM); -+ -+ *dirty = sleb->endpt - offs - used; -+ *free = c->leb_size - sleb->endpt; -+ -+out: -+ ubifs_scan_destroy(sleb); -+ return err; -+ -+out_dump: -+ ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs); -+ dbg_dump_node(c, snod->node); -+ ubifs_scan_destroy(sleb); -+ return -EINVAL; -+} -+ -+/** -+ * insert_ref_node - insert a reference node to the replay tree. -+ * @c: UBIFS file-system description object -+ * @lnum: node logical eraseblock number -+ * @offs: node offset -+ * @sqnum: sequence number -+ * @free: amount of free space in bud -+ * @dirty: amount of dirty space from padding and deletion nodes -+ * -+ * This function inserts a reference node to the replay tree and returns zero -+ * in case of success ort a negative error code in case of failure. -+ */ -+static int insert_ref_node(struct ubifs_info *c, int lnum, int offs, -+ unsigned long long sqnum, int free, int dirty) -+{ -+ struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL; -+ struct replay_entry *r; -+ -+ dbg_mnt("add ref LEB %d:%d", lnum, offs); -+ while (*p) { -+ parent = *p; -+ r = rb_entry(parent, struct replay_entry, rb); -+ if (sqnum < r->sqnum) { -+ p = &(*p)->rb_left; -+ continue; -+ } else if (sqnum > r->sqnum) { -+ p = &(*p)->rb_right; -+ continue; -+ } -+ ubifs_err("duplicate sqnum in replay tree"); -+ return -EINVAL; -+ } -+ -+ r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL); -+ if (!r) -+ return -ENOMEM; -+ -+ r->lnum = lnum; -+ r->offs = offs; -+ r->sqnum = sqnum; -+ r->flags = REPLAY_REF; -+ r->free = free; -+ r->dirty = dirty; -+ -+ rb_link_node(&r->rb, parent, p); -+ rb_insert_color(&r->rb, &c->replay_tree); -+ return 0; -+} -+ -+/** -+ * replay_buds - replay all buds. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int replay_buds(struct ubifs_info *c) -+{ -+ struct bud_entry *b; -+ int err, uninitialized_var(free), uninitialized_var(dirty); -+ -+ list_for_each_entry(b, &c->replay_buds, list) { -+ err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead, -+ &free, &dirty); -+ if (err) -+ return err; -+ err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum, -+ free, dirty); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * destroy_bud_list - destroy the list of buds to replay. -+ * @c: UBIFS file-system description object -+ */ -+static void destroy_bud_list(struct ubifs_info *c) -+{ -+ struct bud_entry *b; -+ -+ while (!list_empty(&c->replay_buds)) { -+ b = list_entry(c->replay_buds.next, struct bud_entry, list); -+ list_del(&b->list); -+ kfree(b); -+ } -+} -+ -+/** -+ * add_replay_bud - add a bud to the list of buds to replay. -+ * @c: UBIFS file-system description object -+ * @lnum: bud logical eraseblock number to replay -+ * @offs: bud start offset -+ * @jhead: journal head to which this bud belongs -+ * @sqnum: reference node sequence number -+ * -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, -+ unsigned long long sqnum) -+{ -+ struct ubifs_bud *bud; -+ struct bud_entry *b; -+ -+ dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead); -+ -+ bud = kmalloc(sizeof(struct ubifs_bud), GFP_KERNEL); -+ if (!bud) -+ return -ENOMEM; -+ -+ b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL); -+ if (!b) { -+ kfree(bud); -+ return -ENOMEM; -+ } -+ -+ bud->lnum = lnum; -+ bud->start = offs; -+ bud->jhead = jhead; -+ ubifs_add_bud(c, bud); -+ -+ b->bud = bud; -+ b->sqnum = sqnum; -+ list_add_tail(&b->list, &c->replay_buds); -+ -+ return 0; -+} -+ -+/** -+ * validate_ref - validate a reference node. -+ * @c: UBIFS file-system description object -+ * @ref: the reference node to validate -+ * @ref_lnum: LEB number of the reference node -+ * @ref_offs: reference node offset -+ * -+ * This function returns %1 if a bud reference already exists for the LEB. %0 is -+ * returned if the reference node is new, otherwise %-EINVAL is returned if -+ * validation failed. -+ */ -+static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref) -+{ -+ struct ubifs_bud *bud; -+ int lnum = le32_to_cpu(ref->lnum); -+ unsigned int offs = le32_to_cpu(ref->offs); -+ unsigned int jhead = le32_to_cpu(ref->jhead); -+ -+ /* -+ * ref->offs may point to the end of LEB when the journal head points -+ * to the end of LEB and we write reference node for it during commit. -+ * So this is why we require 'offs > c->leb_size'. -+ */ -+ if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt || -+ lnum < c->main_first || offs > c->leb_size || -+ offs & (c->min_io_size - 1)) -+ return -EINVAL; -+ -+ /* Make sure we have not already looked at this bud */ -+ bud = ubifs_search_bud(c, lnum); -+ if (bud) { -+ if (bud->jhead == jhead && bud->start <= offs) -+ return 1; -+ ubifs_err("bud at LEB %d:%d was already referred", lnum, offs); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * replay_log_leb - replay a log logical eraseblock. -+ * @c: UBIFS file-system description object -+ * @lnum: log logical eraseblock to replay -+ * @offs: offset to start replaying from -+ * @sbuf: scan buffer -+ * -+ * This function replays a log LEB and returns zero in case of success, %1 if -+ * this is the last LEB in the log, and a negative error code in case of -+ * failure. -+ */ -+static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) -+{ -+ int err; -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ const struct ubifs_cs_node *node; -+ -+ dbg_mnt("replay log LEB %d:%d", lnum, offs); -+ sleb = ubifs_scan(c, lnum, offs, sbuf); -+ if (IS_ERR(sleb)) { -+ if (c->need_recovery) -+ sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ } -+ -+ if (sleb->nodes_cnt == 0) { -+ err = 1; -+ goto out; -+ } -+ -+ node = sleb->buf; -+ -+ snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); -+ if (c->cs_sqnum == 0) { -+ /* -+ * This is the first log LEB we are looking at, make sure that -+ * the first node is a commit start node. Also record its -+ * sequence number so that UBIFS can determine where the log -+ * ends, because all nodes which were have higher sequence -+ * numbers. -+ */ -+ if (snod->type != UBIFS_CS_NODE) { -+ dbg_err("first log node at LEB %d:%d is not CS node", -+ lnum, offs); -+ goto out_dump; -+ } -+ if (le64_to_cpu(node->cmt_no) != c->cmt_no) { -+ dbg_err("first CS node at LEB %d:%d has wrong " -+ "commit number %llu expected %llu", -+ lnum, offs, -+ (unsigned long long)le64_to_cpu(node->cmt_no), -+ c->cmt_no); -+ goto out_dump; -+ } -+ -+ c->cs_sqnum = le64_to_cpu(node->ch.sqnum); -+ dbg_mnt("commit start sqnum %llu", c->cs_sqnum); -+ } -+ -+ if (snod->sqnum < c->cs_sqnum) { -+ /* -+ * This means that we reached end of log and now -+ * look to the older log data, which was already -+ * committed but the eraseblock was not erased (UBIFS -+ * only unmaps it). So this basically means we have to -+ * exit with "end of log" code. -+ */ -+ err = 1; -+ goto out; -+ } -+ -+ /* Make sure the first node sits at offset zero of the LEB */ -+ if (snod->offs != 0) { -+ dbg_err("first node is not at zero offset"); -+ goto out_dump; -+ } -+ -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ -+ cond_resched(); -+ -+ if (snod->sqnum >= SQNUM_WATERMARK) { -+ ubifs_err("file system's life ended"); -+ goto out_dump; -+ } -+ -+ if (snod->sqnum < c->cs_sqnum) { -+ dbg_err("bad sqnum %llu, commit sqnum %llu", -+ snod->sqnum, c->cs_sqnum); -+ goto out_dump; -+ } -+ -+ if (snod->sqnum > c->max_sqnum) -+ c->max_sqnum = snod->sqnum; -+ -+ switch (snod->type) { -+ case UBIFS_REF_NODE: { -+ const struct ubifs_ref_node *ref = snod->node; -+ -+ err = validate_ref(c, ref); -+ if (err == 1) -+ break; /* Already have this bud */ -+ if (err) -+ goto out_dump; -+ -+ err = add_replay_bud(c, le32_to_cpu(ref->lnum), -+ le32_to_cpu(ref->offs), -+ le32_to_cpu(ref->jhead), -+ snod->sqnum); -+ if (err) -+ goto out; -+ -+ break; -+ } -+ case UBIFS_CS_NODE: -+ /* Make sure it sits at the beginning of LEB */ -+ if (snod->offs != 0) { -+ ubifs_err("unexpected node in log"); -+ goto out_dump; -+ } -+ break; -+ default: -+ ubifs_err("unexpected node in log"); -+ goto out_dump; -+ } -+ } -+ -+ if (sleb->endpt || c->lhead_offs >= c->leb_size) { -+ c->lhead_lnum = lnum; -+ c->lhead_offs = sleb->endpt; -+ } -+ -+ err = !sleb->endpt; -+out: -+ ubifs_scan_destroy(sleb); -+ return err; -+ -+out_dump: -+ ubifs_err("log error detected while replying the log at LEB %d:%d", -+ lnum, offs + snod->offs); -+ dbg_dump_node(c, snod->node); -+ ubifs_scan_destroy(sleb); -+ return -EINVAL; -+} -+ -+/** -+ * take_ihead - update the status of the index head in lprops to 'taken'. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns the amount of free space in the index head LEB or a -+ * negative error code. -+ */ -+static int take_ihead(struct ubifs_info *c) -+{ -+ const struct ubifs_lprops *lp; -+ int err, free; -+ -+ ubifs_get_lprops(c); -+ -+ lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ free = lp->free; -+ -+ lp = ubifs_change_lp(c, lp, -1, -1, lp->flags | LPROPS_TAKEN, 0); -+ if (IS_ERR(lp)) { -+ err = PTR_ERR(lp); -+ goto out; -+ } -+ -+ err = free; -+out: -+ ubifs_release_lprops(c); -+ return err; -+} -+ -+/** -+ * ubifs_replay_journal - replay journal. -+ * @c: UBIFS file-system description object -+ * -+ * This function scans the journal, replays and cleans it up. It makes sure all -+ * memory data structures related to uncommitted journal are built (dirty TNC -+ * tree, tree of buds, modified lprops, etc). -+ */ -+int ubifs_replay_journal(struct ubifs_info *c) -+{ -+ int err, i, lnum, offs, free; -+ void *sbuf = NULL; -+ -+ /* Update the status of the index head in lprops to 'taken' */ -+ free = take_ihead(c); -+ if (free < 0) -+ return free; /* Error code */ -+ -+ if (c->ihead_offs != c->leb_size - free) { -+ ubifs_err("bad index head LEB %d:%d", c->ihead_lnum, -+ c->ihead_offs); -+ return -EINVAL; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ sbuf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ sbuf = vmalloc(c->leb_size); -+#endif -+ if (!sbuf) -+ return -ENOMEM; -+ -+ dbg_mnt("start replaying the journal"); -+ -+ c->replaying = 1; -+ -+ lnum = c->ltail_lnum = c->lhead_lnum; -+ offs = c->lhead_offs; -+ -+ for (i = 0; i < c->log_lebs; i++, lnum++) { -+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) { -+ /* -+ * The log is logically circular, we reached the last -+ * LEB, switch to the first one. -+ */ -+ lnum = UBIFS_LOG_LNUM; -+ offs = 0; -+ } -+ err = replay_log_leb(c, lnum, offs, sbuf); -+ if (err == 1) -+ /* We hit the end of the log */ -+ break; -+ if (err) -+ goto out; -+ offs = 0; -+ } -+ -+ err = replay_buds(c); -+ if (err) -+ goto out; -+ -+ err = apply_replay_tree(c); -+ if (err) -+ goto out; -+ -+ ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery); -+ dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, " -+ "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum, -+ c->highest_inum); -+out: -+ destroy_replay_tree(c); -+ destroy_bud_list(c); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(sbuf); -+#else -+ vfree(sbuf); -+#endif -+ c->replaying = 0; -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/sb.c linux-2.6.24.7/fs/ubifs/sb.c ---- linux-2.6.24.7.old/fs/ubifs/sb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/sb.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,617 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS superblock. The superblock is stored at the first -+ * LEB of the volume and is never changed by UBIFS. Only user-space tools may -+ * change it. The superblock node mostly contains geometry information. -+ */ -+ -+#include "ubifs.h" -+ -+/* -+ * Default journal size in logical eraseblocks as a percent of total -+ * flash size. -+ */ -+#define DEFAULT_JNL_PERCENT 5 -+ -+/* Default maximum journal size in bytes */ -+#define DEFAULT_MAX_JNL (32*1024*1024) -+ -+/* Default indexing tree fanout */ -+#define DEFAULT_FANOUT 8 -+ -+/* Default number of LEBs for orphan information */ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+#define DEFAULT_ORPHAN_LEBS 2 /* 2 is better for testing */ -+#else -+#define DEFAULT_ORPHAN_LEBS 1 -+#endif -+ -+/* Default number of journal heads */ -+#define DEFAULT_JHEADS_CNT 1 -+ -+/* Default positions of different LEBs in the main area */ -+#define DEFAULT_IDX_LEB 0 -+#define DEFAULT_DATA_LEB 1 -+#define DEFAULT_GC_LEB 2 -+ -+/* Default number of LEB numbers in LPT's save table */ -+#define DEFAULT_LSAVE_CNT 256 -+ -+/* Default reserved pool size as a percent of maximum free space */ -+#define DEFAULT_RP_PERCENT 5 -+ -+/* The default maximum size of reserved pool in bytes */ -+#define DEFAULT_MAX_RP_SIZE (5*1024*1024) -+ -+/* Default UBIFS compressor */ -+#define DEFAULT_COMPRESSOR UBIFS_COMPR_LZO -+ -+/* Default time granularity in nanoseconds */ -+#define DEFAULT_TIME_GRAN 1000000000 -+ -+/** -+ * create_default_filesystem - format empty UBI volume. -+ * @c: UBIFS file-system description object -+ * -+ * This function creates default empty file-system. Returns zero in case of -+ * success and a negative error code in case of failure. -+ */ -+static int create_default_filesystem(struct ubifs_info *c) -+{ -+ struct ubifs_sb_node *sup; -+ struct ubifs_mst_node *mst; -+ struct ubifs_idx_node *idx; -+ struct ubifs_branch *br; -+ struct ubifs_ino_node *ino; -+ struct ubifs_cs_node *cs; -+ union ubifs_key key; -+ int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; -+ int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; -+ uint64_t tmp64, main_bytes; -+ -+ /* Some functions called from here depend on the @c->key_len filed */ -+ c->key_len = UBIFS_SK_LEN; -+ -+ /* -+ * First of all, we have to calculate default file-system geometry - -+ * log size, journal size, etc. -+ */ -+ c->max_leb_cnt = c->leb_cnt; -+ if (c->leb_cnt < 0x7FFFFFFF / DEFAULT_JNL_PERCENT) -+ /* We can first multiply then divide and have no overflow */ -+ jnl_lebs = c->leb_cnt * DEFAULT_JNL_PERCENT / 100; -+ else -+ jnl_lebs = (c->leb_cnt / 100) * DEFAULT_JNL_PERCENT; -+ -+ if (jnl_lebs < UBIFS_MIN_JNL_LEBS) -+ jnl_lebs = UBIFS_MIN_JNL_LEBS; -+ if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL) -+ jnl_lebs = DEFAULT_MAX_JNL / c->leb_size; -+ -+ /* -+ * The log should be large enough to fit reference nodes for all bud -+ * LEBs. Because buds do not have to start from the beginning of LEBs -+ * (half of the LEB may contain committed data), the log should -+ * generally be larger, make it twice as large. -+ */ -+ tmp = 2 * (c->ref_node_alsz * jnl_lebs) + c->leb_size - 1; -+ log_lebs = tmp / c->leb_size; -+ /* Plus one LEB reserved for commit */ -+ log_lebs += 1; -+ /* And some extra space to allow writes while committing */ -+ log_lebs += 1; -+ -+ max_buds = jnl_lebs - log_lebs; -+ if (max_buds < UBIFS_MIN_BUD_LEBS) -+ max_buds = UBIFS_MIN_BUD_LEBS; -+ -+ /* -+ * Orphan nodes are stored in a separate area. One node can store a lot -+ * of orphan inode numbers, but when new orphan comes we just add a new -+ * orphan node. At some point the nodes are consolidated into one -+ * orphan node. -+ */ -+ orph_lebs = DEFAULT_ORPHAN_LEBS; -+ -+ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs; -+ main_lebs -= orph_lebs; -+ -+ lpt_first = UBIFS_LOG_LNUM + log_lebs; -+ c->lsave_cnt = DEFAULT_LSAVE_CNT; -+ err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs, -+ &big_lpt); -+ if (err) -+ return err; -+ -+ dbg_gen("LEB Properties Tree created (LEBs %d-%d)", lpt_first, -+ lpt_first + lpt_lebs - 1); -+ -+ main_first = c->leb_cnt - main_lebs; -+ -+ /* Create default superblock */ -+ tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); -+ sup = kzalloc(tmp, GFP_KERNEL); -+ if (!sup) -+ return -ENOMEM; -+ -+ tmp64 = (uint64_t)max_buds * c->leb_size; -+ if (big_lpt) -+ sup_flags |= UBIFS_FLG_BIGLPT; -+ -+ sup->ch.node_type = UBIFS_SB_NODE; -+ sup->key_hash = UBIFS_KEY_HASH_R5; -+ sup->flags = cpu_to_le32(sup_flags); -+ sup->min_io_size = cpu_to_le32(c->min_io_size); -+ sup->leb_size = cpu_to_le32(c->leb_size); -+ sup->leb_cnt = cpu_to_le32(c->leb_cnt); -+ sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt); -+ sup->max_bud_bytes = cpu_to_le64(tmp64); -+ sup->log_lebs = cpu_to_le32(log_lebs); -+ sup->lpt_lebs = cpu_to_le32(lpt_lebs); -+ sup->orph_lebs = cpu_to_le32(orph_lebs); -+ sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT); -+ sup->fanout = cpu_to_le32(DEFAULT_FANOUT); -+ sup->lsave_cnt = cpu_to_le32(c->lsave_cnt); -+ sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); -+ sup->default_compr = cpu_to_le16(DEFAULT_COMPRESSOR); -+ sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); -+ -+ main_bytes = (uint64_t)main_lebs * c->leb_size; -+ tmp64 = main_bytes * DEFAULT_RP_PERCENT; -+ do_div(tmp64, 100); -+ if (tmp64 > DEFAULT_MAX_RP_SIZE) -+ tmp64 = DEFAULT_MAX_RP_SIZE; -+ sup->rp_size = cpu_to_le64(tmp64); -+ -+ err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM); -+ kfree(sup); -+ if (err) -+ return err; -+ -+ dbg_gen("default superblock created at LEB 0:0"); -+ -+ /* Create default master node */ -+ mst = kzalloc(c->mst_node_alsz, GFP_KERNEL); -+ if (!mst) -+ return -ENOMEM; -+ -+ mst->ch.node_type = UBIFS_MST_NODE; -+ mst->log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); -+ mst->highest_inum = cpu_to_le64(UBIFS_FIRST_INO); -+ mst->cmt_no = 0; -+ mst->root_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); -+ mst->root_offs = 0; -+ tmp = ubifs_idx_node_sz(c, 1); -+ mst->root_len = cpu_to_le32(tmp); -+ mst->gc_lnum = cpu_to_le32(main_first + DEFAULT_GC_LEB); -+ mst->ihead_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB); -+ mst->ihead_offs = cpu_to_le32(ALIGN(tmp, c->min_io_size)); -+ mst->index_size = cpu_to_le64(ALIGN(tmp, 8)); -+ mst->lpt_lnum = cpu_to_le32(c->lpt_lnum); -+ mst->lpt_offs = cpu_to_le32(c->lpt_offs); -+ mst->nhead_lnum = cpu_to_le32(c->nhead_lnum); -+ mst->nhead_offs = cpu_to_le32(c->nhead_offs); -+ mst->ltab_lnum = cpu_to_le32(c->ltab_lnum); -+ mst->ltab_offs = cpu_to_le32(c->ltab_offs); -+ mst->lsave_lnum = cpu_to_le32(c->lsave_lnum); -+ mst->lsave_offs = cpu_to_le32(c->lsave_offs); -+ mst->lscan_lnum = cpu_to_le32(main_first); -+ mst->empty_lebs = cpu_to_le32(main_lebs - 2); -+ mst->idx_lebs = cpu_to_le32(1); -+ mst->leb_cnt = cpu_to_le32(c->leb_cnt); -+ -+ /* Calculate lprops statistics */ -+ tmp64 = main_bytes; -+ tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); -+ tmp64 -= ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); -+ mst->total_free = cpu_to_le64(tmp64); -+ -+ tmp64 = ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size); -+ ino_waste = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size) - -+ UBIFS_INO_NODE_SZ; -+ tmp64 += ino_waste; -+ tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), 8); -+ mst->total_dirty = cpu_to_le64(tmp64); -+ -+ /* The indexing LEB does not contribute to dark space */ -+ tmp64 = (c->main_lebs - 1) * c->dark_wm; -+ mst->total_dark = cpu_to_le64(tmp64); -+ -+ mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ); -+ -+ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0, -+ UBI_UNKNOWN); -+ if (err) { -+ kfree(mst); -+ return err; -+ } -+ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0, -+ UBI_UNKNOWN); -+ kfree(mst); -+ if (err) -+ return err; -+ -+ dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM); -+ -+ /* Create the root indexing node */ -+ tmp = ubifs_idx_node_sz(c, 1); -+ idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL); -+ if (!idx) -+ return -ENOMEM; -+ -+ c->key_fmt = UBIFS_SIMPLE_KEY_FMT; -+ c->key_hash = key_r5_hash; -+ -+ idx->ch.node_type = UBIFS_IDX_NODE; -+ idx->child_cnt = cpu_to_le16(1); -+ ino_key_init(c, &key, UBIFS_ROOT_INO); -+ br = ubifs_idx_branch(c, idx, 0); -+ key_write_idx(c, &key, &br->key); -+ br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB); -+ br->len = cpu_to_le32(UBIFS_INO_NODE_SZ); -+ err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0, -+ UBI_UNKNOWN); -+ kfree(idx); -+ if (err) -+ return err; -+ -+ dbg_gen("default root indexing node created LEB %d:0", -+ main_first + DEFAULT_IDX_LEB); -+ -+ /* Create default root inode */ -+ tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); -+ ino = kzalloc(tmp, GFP_KERNEL); -+ if (!ino) -+ return -ENOMEM; -+ -+ ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO); -+ ino->ch.node_type = UBIFS_INO_NODE; -+ ino->creat_sqnum = cpu_to_le64(++c->max_sqnum); -+ ino->nlink = cpu_to_le32(2); -+ tmp = cpu_to_le64(CURRENT_TIME_SEC.tv_sec); -+ ino->atime_sec = tmp; -+ ino->ctime_sec = tmp; -+ ino->mtime_sec = tmp; -+ ino->atime_nsec = 0; -+ ino->ctime_nsec = 0; -+ ino->mtime_nsec = 0; -+ ino->mode = cpu_to_le32(S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO); -+ ino->size = cpu_to_le64(UBIFS_INO_NODE_SZ); -+ -+ /* Set compression enabled by default */ -+ ino->flags = cpu_to_le32(UBIFS_COMPR_FL); -+ -+ err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ, -+ main_first + DEFAULT_DATA_LEB, 0, -+ UBI_UNKNOWN); -+ kfree(ino); -+ if (err) -+ return err; -+ -+ dbg_gen("root inode created at LEB %d:0", -+ main_first + DEFAULT_DATA_LEB); -+ -+ /* -+ * The first node in the log has to be the commit start node. This is -+ * always the case during normal file-system operation. Write a fake -+ * commit start node to the log. -+ */ -+ tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size); -+ cs = kzalloc(tmp, GFP_KERNEL); -+ if (!cs) -+ return -ENOMEM; -+ -+ cs->ch.node_type = UBIFS_CS_NODE; -+ err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, -+ 0, UBI_UNKNOWN); -+ kfree(cs); -+ -+ ubifs_msg("default file-system created"); -+ return 0; -+} -+ -+/** -+ * validate_sb - validate superblock node. -+ * @c: UBIFS file-system description object -+ * @sup: superblock node -+ * -+ * This function validates superblock node @sup. Since most of data was read -+ * from the superblock and stored in @c, the function validates fields in @c -+ * instead. Returns zero in case of success and %-EINVAL in case of validation -+ * failure. -+ */ -+static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup) -+{ -+ long long max_bytes; -+ int err = 1; -+ -+ if (!c->key_hash) { -+ err = 2; -+ goto failed; -+ } -+ -+ if (sup->key_fmt != UBIFS_SIMPLE_KEY_FMT) { -+ err = 3; -+ goto failed; -+ } -+ -+ if (le32_to_cpu(sup->min_io_size) != c->min_io_size) { -+ ubifs_err("min. I/O unit mismatch: %d in superblock, %d real", -+ le32_to_cpu(sup->min_io_size), c->min_io_size); -+ goto failed; -+ } -+ -+ if (le32_to_cpu(sup->leb_size) != c->leb_size) { -+ ubifs_err("LEB size mismatch: %d in superblock, %d real", -+ le32_to_cpu(sup->leb_size), c->leb_size); -+ goto failed; -+ } -+ -+ if (c->leb_cnt < UBIFS_MIN_LEB_CNT || c->leb_cnt > c->vi.size) { -+ ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, " -+ "%d minimum required", c->leb_cnt, c->vi.size, -+ UBIFS_MIN_LEB_CNT); -+ goto failed; -+ } -+ -+ if (c->max_leb_cnt < c->leb_cnt) { -+ ubifs_err("max. LEB count %d less than LEB count %d", -+ c->max_leb_cnt, c->leb_cnt); -+ goto failed; -+ } -+ -+ if (c->log_lebs < UBIFS_MIN_LOG_LEBS || -+ c->lpt_lebs < UBIFS_MIN_LPT_LEBS || -+ c->orph_lebs < UBIFS_MIN_ORPH_LEBS || -+ c->main_lebs < UBIFS_MIN_MAIN_LEBS) { -+ err = 6; -+ goto failed; -+ } -+ -+ if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) { -+ err = 7; -+ goto failed; -+ } -+ -+ if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS || -+ c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) { -+ err = 8; -+ goto failed; -+ } -+ -+ if (c->jhead_cnt < NONDATA_JHEADS_CNT + 1 || -+ c->jhead_cnt > NONDATA_JHEADS_CNT + UBIFS_MAX_JHEADS) { -+ err = 9; -+ goto failed; -+ } -+ -+ if (c->fanout < UBIFS_MIN_FANOUT || -+ ubifs_idx_node_sz(c, c->fanout) > c->leb_size) { -+ err = 10; -+ goto failed; -+ } -+ -+ if (c->lsave_cnt < 0 || (c->lsave_cnt > DEFAULT_LSAVE_CNT && -+ c->lsave_cnt > c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - -+ c->log_lebs - c->lpt_lebs - c->orph_lebs)) { -+ err = 11; -+ goto failed; -+ } -+ -+ if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs + -+ c->orph_lebs + c->main_lebs != c->leb_cnt) { -+ err = 12; -+ goto failed; -+ } -+ -+ if (c->default_compr < 0 || c->default_compr >= UBIFS_COMPR_TYPES_CNT) { -+ err = 13; -+ goto failed; -+ } -+ -+ max_bytes = c->main_lebs * (long long)c->leb_size; -+ if (c->rp_size < 0 || max_bytes < c->rp_size) { -+ err = 14; -+ goto failed; -+ } -+ -+ if (le32_to_cpu(sup->time_gran) > 1000000000 || -+ le32_to_cpu(sup->time_gran) < 1) { -+ err = 15; -+ goto failed; -+ } -+ -+ return 0; -+ -+failed: -+ ubifs_err("bad superblock, error %d", err); -+ dbg_dump_node(c, sup); -+ return -EINVAL; -+} -+ -+/** -+ * ubifs_read_sb_node - read superblock node. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns a pointer to the superblock node or a negative error -+ * code. -+ */ -+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) -+{ -+ struct ubifs_sb_node *sup; -+ int err; -+ -+ sup = kmalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_NOFS); -+ if (!sup) -+ return ERR_PTR(-ENOMEM); -+ -+ err = ubifs_read_node(c, sup, UBIFS_SB_NODE, UBIFS_SB_NODE_SZ, -+ UBIFS_SB_LNUM, 0); -+ if (err) { -+ kfree(sup); -+ return ERR_PTR(err); -+ } -+ -+ return sup; -+} -+ -+/** -+ * ubifs_write_sb_node - write superblock node. -+ * @c: UBIFS file-system description object -+ * @sup: superblock node read with 'ubifs_read_sb_node()' -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup) -+{ -+ int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); -+ -+ ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1); -+ return ubi_leb_change(c->ubi, UBIFS_SB_LNUM, sup, len, UBI_LONGTERM); -+} -+ -+/** -+ * ubifs_read_superblock - read superblock. -+ * @c: UBIFS file-system description object -+ * -+ * This function finds, reads and checks the superblock. If an empty UBI volume -+ * is being mounted, this function creates default superblock. Returns zero in -+ * case of success, and a negative error code in case of failure. -+ */ -+int ubifs_read_superblock(struct ubifs_info *c) -+{ -+ int err, sup_flags; -+ struct ubifs_sb_node *sup; -+ -+ if (c->empty) { -+ err = create_default_filesystem(c); -+ if (err) -+ return err; -+ } -+ -+ sup = ubifs_read_sb_node(c); -+ if (IS_ERR(sup)) -+ return PTR_ERR(sup); -+ -+ /* -+ * The software supports all previous versions but not future versions, -+ * due to the unavailability of time-travelling equipment. -+ */ -+ c->fmt_version = le32_to_cpu(sup->fmt_version); -+ if (c->fmt_version > UBIFS_FORMAT_VERSION) { -+ ubifs_err("on-flash format version is %d, but software only " -+ "supports up to version %d", c->fmt_version, -+ UBIFS_FORMAT_VERSION); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (c->fmt_version == 1) { -+ ubifs_err("on-flash format version %d is not supported", -+ c->fmt_version); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ switch (sup->key_hash) { -+ case UBIFS_KEY_HASH_R5: -+ /* TODO: this should die soon */ -+ if (c->fmt_version == 2) -+ c->key_hash = tmp_key_r5_hash; -+ else -+ c->key_hash = key_r5_hash; -+ c->key_hash_type = UBIFS_KEY_HASH_R5; -+ break; -+ -+ case UBIFS_KEY_HASH_TEST: -+ c->key_hash = key_test_hash; -+ c->key_hash_type = UBIFS_KEY_HASH_TEST; -+ break; -+ }; -+ -+ c->key_fmt = sup->key_fmt; -+ -+ switch (c->key_fmt) { -+ case UBIFS_SIMPLE_KEY_FMT: -+ c->key_len = UBIFS_SK_LEN; -+ break; -+ default: -+ ubifs_err("unsupported key format"); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ c->leb_cnt = le32_to_cpu(sup->leb_cnt); -+ c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt); -+ c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes); -+ c->log_lebs = le32_to_cpu(sup->log_lebs); -+ c->lpt_lebs = le32_to_cpu(sup->lpt_lebs); -+ c->orph_lebs = le32_to_cpu(sup->orph_lebs); -+ c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT; -+ c->fanout = le32_to_cpu(sup->fanout); -+ c->lsave_cnt = le32_to_cpu(sup->lsave_cnt); -+ c->default_compr = le16_to_cpu(sup->default_compr); -+ c->rp_size = le64_to_cpu(sup->rp_size); -+ c->rp_uid = le32_to_cpu(sup->rp_uid); -+ c->rp_gid = le32_to_cpu(sup->rp_gid); -+ sup_flags = le32_to_cpu(sup->flags); -+ -+ c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran); -+ -+ c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT); -+ -+ /* Automatically increase file system size to the maximum size */ -+ c->old_leb_cnt = c->leb_cnt; -+ if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) { -+ c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size); -+ if (c->vfs_sb->s_flags & MS_RDONLY) -+ dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs", -+ c->old_leb_cnt, c->leb_cnt); -+ else { -+ dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs", -+ c->old_leb_cnt, c->leb_cnt); -+ sup->leb_cnt = cpu_to_le32(c->leb_cnt); -+ err = ubifs_write_sb_node(c, sup); -+ if (err) -+ goto out; -+ c->old_leb_cnt = c->leb_cnt; -+ } -+ } -+ -+ c->log_bytes = (long long)c->log_lebs * c->leb_size; -+ c->log_last = UBIFS_LOG_LNUM + c->log_lebs - 1; -+ c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs; -+ c->lpt_last = c->lpt_first + c->lpt_lebs - 1; -+ c->orph_first = c->lpt_last + 1; -+ c->orph_last = c->orph_first + c->orph_lebs - 1; -+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; -+ c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs; -+ c->main_first = c->leb_cnt - c->main_lebs; -+ c->report_rp_size = ubifs_reported_space(c, c->rp_size); -+ -+ err = validate_sb(c, sup); -+out: -+ kfree(sup); -+ return err; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/scan.c linux-2.6.24.7/fs/ubifs/scan.c ---- linux-2.6.24.7.old/fs/ubifs/scan.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/scan.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,362 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements the scan which is a general-purpose function for -+ * determining what nodes are in an eraseblock. The scan is used to replay the -+ * journal, to do garbage collection. for the TNC in-the-gaps method, and by -+ * debugging functions. -+ */ -+ -+#include "ubifs.h" -+ -+/** -+ * scan_padding_bytes - scan for padding bytes. -+ * @buf: buffer to scan -+ * @len: length of buffer -+ * -+ * This function returns the number of padding bytes on success and -+ * %SCANNED_GARBAGE on failure. -+ */ -+static int scan_padding_bytes(void *buf, int len) -+{ -+ int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len); -+ uint8_t *p = buf; -+ -+ dbg_scan("not a node"); -+ -+ while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE) -+ pad_len += 1; -+ -+ if (!pad_len || (pad_len & 7)) -+ return SCANNED_GARBAGE; -+ -+ dbg_scan("%d padding bytes", pad_len); -+ -+ return pad_len; -+} -+ -+/** -+ * ubifs_scan_a_node - scan for a node or padding. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to scan -+ * @len: length of buffer -+ * @lnum: logical eraseblock number -+ * @offs: offset within the logical eraseblock -+ * @quiet: print no messages -+ * -+ * This function returns a scanning code to indicate what was scanned. -+ */ -+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum, -+ int offs, int quiet) -+{ -+ struct ubifs_ch *ch = buf; -+ uint32_t magic; -+ -+ magic = le32_to_cpu(ch->magic); -+ -+ if (magic == 0xFFFFFFFF) { -+ dbg_scan("hit empty space"); -+ return SCANNED_EMPTY_SPACE; -+ } -+ -+ if (magic != UBIFS_NODE_MAGIC) -+ return scan_padding_bytes(buf, len); -+ -+ if (len < UBIFS_CH_SZ) -+ return SCANNED_GARBAGE; -+ -+ dbg_scan("scanning %s", dbg_ntype(ch->node_type)); -+ -+ if (ubifs_check_node(c, buf, lnum, offs, quiet)) -+ return SCANNED_A_CORRUPT_NODE; -+ -+ if (ch->node_type == UBIFS_PAD_NODE) { -+ struct ubifs_pad_node *pad = buf; -+ int pad_len = le32_to_cpu(pad->pad_len); -+ int node_len = le32_to_cpu(ch->len); -+ -+ /* Validate the padding node */ -+ if (pad_len < 0 || -+ offs + node_len + pad_len > c->leb_size) { -+ if (!quiet) { -+ ubifs_err("bad pad node at LEB %d:%d", -+ lnum, offs); -+ dbg_dump_node(c, pad); -+ } -+ return SCANNED_A_BAD_PAD_NODE; -+ } -+ -+ /* Make the node pads to 8-byte boundary */ -+ if ((node_len + pad_len) & 7) { -+ if (!quiet) { -+ dbg_err("bad padding length %d - %d", -+ offs, offs + node_len + pad_len); -+ } -+ return SCANNED_A_BAD_PAD_NODE; -+ } -+ -+ dbg_scan("%d bytes padded, offset now %d", -+ pad_len, ALIGN(offs + node_len + pad_len, 8)); -+ -+ return node_len + pad_len; -+ } -+ -+ return SCANNED_A_NODE; -+} -+ -+/** -+ * ubifs_start_scan - create LEB scanning information at start of scan. -+ * @c: UBIFS file-system description object -+ * @lnum: logical eraseblock number -+ * @offs: offset to start at (usually zero) -+ * @sbuf: scan buffer (must be c->leb_size) -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum, -+ int offs, void *sbuf) -+{ -+ struct ubifs_scan_leb *sleb; -+ int err; -+ -+ dbg_scan("scan LEB %d:%d", lnum, offs); -+ -+ sleb = kzalloc(sizeof(struct ubifs_scan_leb), GFP_NOFS); -+ if (!sleb) -+ return ERR_PTR(-ENOMEM); -+ -+ sleb->lnum = lnum; -+ INIT_LIST_HEAD(&sleb->nodes); -+ sleb->buf = sbuf; -+ -+ err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs); -+ if (err && err != -EBADMSG) { -+ ubifs_err("cannot read %d bytes from LEB %d:%d," -+ " error %d", c->leb_size - offs, lnum, offs, err); -+ kfree(sleb); -+ return ERR_PTR(err); -+ } -+ -+ if (err == -EBADMSG) -+ sleb->ecc = 1; -+ -+ return sleb; -+} -+ -+/** -+ * ubifs_end_scan - update LEB scanning information at end of scan. -+ * @c: UBIFS file-system description object -+ * @sleb: scanning information -+ * @lnum: logical eraseblock number -+ * @offs: offset to start at (usually zero) -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ int lnum, int offs) -+{ -+ lnum = lnum; -+ dbg_scan("stop scanning LEB %d at offset %d", lnum, offs); -+ ubifs_assert(offs % c->min_io_size == 0); -+ -+ sleb->endpt = ALIGN(offs, c->min_io_size); -+} -+ -+/** -+ * ubifs_add_snod - add a scanned node to LEB scanning information. -+ * @c: UBIFS file-system description object -+ * @sleb: scanning information -+ * @buf: buffer containing node -+ * @offs: offset of node on flash -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ void *buf, int offs) -+{ -+ struct ubifs_ch *ch = buf; -+ struct ubifs_ino_node *ino = buf; -+ struct ubifs_scan_node *snod; -+ -+ snod = kzalloc(sizeof(struct ubifs_scan_node), GFP_NOFS); -+ if (!snod) -+ return -ENOMEM; -+ -+ snod->sqnum = le64_to_cpu(ch->sqnum); -+ snod->type = ch->node_type; -+ snod->offs = offs; -+ snod->len = le32_to_cpu(ch->len); -+ snod->node = buf; -+ -+ switch (ch->node_type) { -+ case UBIFS_INO_NODE: -+ case UBIFS_DENT_NODE: -+ case UBIFS_XENT_NODE: -+ case UBIFS_DATA_NODE: -+ case UBIFS_TRUN_NODE: -+ /* -+ * The key is in the same place in all keyed -+ * nodes. -+ */ -+ key_read(c, &ino->key, &snod->key); -+ break; -+ } -+ list_add_tail(&snod->list, &sleb->nodes); -+ sleb->nodes_cnt += 1; -+ return 0; -+} -+ -+/** -+ * ubifs_scanned_corruption - print information after UBIFS scanned corruption. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of corruption -+ * @offs: offset of corruption -+ * @buf: buffer containing corruption -+ */ -+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, -+ void *buf) -+{ -+ int len; -+ -+ ubifs_err("corrupted data at LEB %d:%d", lnum, offs); -+ if (dbg_failure_mode) -+ return; -+ len = c->leb_size - offs; -+ if (len > 4096) -+ len = 4096; -+ dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); -+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); -+} -+ -+/** -+ * ubifs_scan - scan a logical eraseblock. -+ * @c: UBIFS file-system description object -+ * @lnum: logical eraseblock number -+ * @offs: offset to start at (usually zero) -+ * @sbuf: scan buffer (must be c->leb_size) -+ * -+ * This function scans LEB number @lnum and returns complete information about -+ * its contents. Returns an error code in case of failure. -+ */ -+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, -+ int offs, void *sbuf) -+{ -+ void *buf = sbuf + offs; -+ int err, len = c->leb_size - offs; -+ struct ubifs_scan_leb *sleb; -+ -+ sleb = ubifs_start_scan(c, lnum, offs, sbuf); -+ if (IS_ERR(sleb)) -+ return sleb; -+ -+ while (len >= 8) { -+ struct ubifs_ch *ch = buf; -+ int node_len, ret; -+ -+ dbg_scan("look at LEB %d:%d (%d bytes left)", -+ lnum, offs, len); -+ -+ cond_resched(); -+ -+ ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); -+ -+ if (ret > 0) { -+ /* Padding bytes or a valid padding node */ -+ offs += ret; -+ buf += ret; -+ len -= ret; -+ continue; -+ } -+ -+ if (ret == SCANNED_EMPTY_SPACE) -+ /* Empty space is checked later */ -+ break; -+ -+ switch (ret) { -+ case SCANNED_GARBAGE: -+ dbg_err("garbage"); -+ goto corrupted; -+ case SCANNED_A_NODE: -+ break; -+ case SCANNED_A_CORRUPT_NODE: -+ case SCANNED_A_BAD_PAD_NODE: -+ dbg_err("bad node"); -+ goto corrupted; -+ default: -+ dbg_err("unknown"); -+ goto corrupted; -+ } -+ -+ err = ubifs_add_snod(c, sleb, buf, offs); -+ if (err) -+ goto error; -+ -+ node_len = ALIGN(le32_to_cpu(ch->len), 8); -+ offs += node_len; -+ buf += node_len; -+ len -= node_len; -+ } -+ -+ if (offs % c->min_io_size) -+ goto corrupted; -+ -+ ubifs_end_scan(c, sleb, lnum, offs); -+ -+ for (; len > 4; offs += 4, buf = buf + 4, len -= 4) -+ if (*(uint32_t *)buf != 0xffffffff) -+ break; -+ for (; len; offs++, buf++, len--) -+ if (*(uint8_t *)buf != 0xff) { -+ ubifs_err("corrupt empty space at LEB %d:%d", -+ lnum, offs); -+ goto corrupted; -+ } -+ -+ return sleb; -+ -+corrupted: -+ ubifs_scanned_corruption(c, lnum, offs, buf); -+ err = -EUCLEAN; -+error: -+ ubifs_err("LEB %d scanning failed", lnum); -+ ubifs_scan_destroy(sleb); -+ return ERR_PTR(err); -+} -+ -+/** -+ * ubifs_scan_destroy - destroy LEB scanning information. -+ * @sleb: scanning information to free -+ */ -+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb) -+{ -+ struct ubifs_scan_node *node; -+ struct list_head *head; -+ -+ head = &sleb->nodes; -+ while (!list_empty(head)) { -+ node = list_entry(head->next, struct ubifs_scan_node, list); -+ list_del(&node->list); -+ kfree(node); -+ } -+ kfree(sleb); -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/shrinker.c linux-2.6.24.7/fs/ubifs/shrinker.c ---- linux-2.6.24.7.old/fs/ubifs/shrinker.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/shrinker.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,322 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS shrinker which evicts clean znodes from the TNC -+ * tree when Linux VM needs more RAM. -+ * -+ * We do not implement any LRU lists to find oldest znodes to free because it -+ * would add additional overhead to the file system fast paths. So the shrinker -+ * just walks the TNC tree when searching for znodes to free. -+ * -+ * If the root of a TNC sub-tree is clean and old enough, then the children are -+ * also clean and old enough. So the shrinker walks the TNC in level order and -+ * dumps entire sub-trees. -+ * -+ * The age of znodes is just the time-stamp when they were last looked at. -+ * The current shrinker first tries to evict old znodes, then young ones. -+ * -+ * Since the shrinker is global, it has to protect against races with FS -+ * un-mounts, which is done by the 'ubifs_infos_lock' and 'c->umount_mutex'. -+ */ -+ -+#include "ubifs.h" -+ -+/* List of all UBIFS file-system instances */ -+LIST_HEAD(ubifs_infos); -+ -+/* -+ * We number each shrinker run and record the number on the ubifs_info structure -+ * so that we can easily work out which ubifs_info structures have already been -+ * done by the current run. -+ */ -+static unsigned int shrinker_run_no; -+ -+/* Protects 'ubifs_infos' list */ -+DEFINE_SPINLOCK(ubifs_infos_lock); -+ -+/* Global clean znode counter (for all mounted UBIFS instances) */ -+atomic_long_t ubifs_clean_zn_cnt; -+ -+/** -+ * shrink_tnc - shrink TNC tree. -+ * @c: UBIFS file-system description object -+ * @nr: number of znodes to free -+ * @age: the age of znodes to free -+ * @contention: if any contention, this is set to %1 -+ * -+ * This function traverses TNC tree and frees clean znodes. It does not free -+ * clean znodes which younger then @age. Returns number of freed znodes. -+ */ -+static int shrink_tnc(struct ubifs_info *c, int nr, int age, int *contention) -+{ -+ int total_freed = 0; -+ struct ubifs_znode *znode, *zprev; -+ int time = get_seconds(); -+ -+ ubifs_assert(mutex_is_locked(&c->umount_mutex)); -+ ubifs_assert(mutex_is_locked(&c->tnc_mutex)); -+ -+ if (!c->zroot.znode || atomic_long_read(&c->clean_zn_cnt) == 0) -+ return 0; -+ -+ /* -+ * Traverse the TNC tree in levelorder manner, so that it is possible -+ * to destroy large sub-trees. Indeed, if a znode is old, then all its -+ * children are older or of the same age. -+ * -+ * Note, we are holding 'c->tnc_mutex', so we do not have to lock the -+ * 'c->space_lock' when _reading_ 'c->clean_zn_cnt', because it is -+ * changed only when the 'c->tnc_mutex' is held. -+ */ -+ zprev = NULL; -+ znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); -+ while (znode && total_freed < nr && -+ atomic_long_read(&c->clean_zn_cnt) > 0) { -+ int freed; -+ -+ /* -+ * If the znode is clean, but it is in the 'c->cnext' list, this -+ * means that this znode has just been written to flash as a -+ * part of commit and was marked clean. They will be removed -+ * from the list at end commit. We cannot change the list, -+ * because it is not protected by any mutex (design decision to -+ * make commit really independent and parallel to main I/O). So -+ * we just skip these znodes. -+ * -+ * Note, the 'clean_zn_cnt' counters are not updated until -+ * after the commit, so the UBIFS shrinker does not report -+ * the znodes which are in the 'c->cnext' list as freeable. -+ * -+ * Also note, if the root of a sub-tree is not in 'c->cnext', -+ * then the whole sub-tree is not in 'c->cnext' as well, so it -+ * is safe to dump whole sub-tree. -+ */ -+ -+ if (znode->cnext) { -+ /* -+ * Very soon these znodes will be removed from the list -+ * and become freeable. -+ */ -+ *contention = 1; -+ } else if (!ubifs_zn_dirty(znode) && -+ abs(time - znode->time) >= age) { -+ if (znode->parent) -+ znode->parent->zbranch[znode->iip].znode = NULL; -+ else -+ c->zroot.znode = NULL; -+ -+ freed = ubifs_destroy_tnc_subtree(znode); -+ atomic_long_sub(freed, &ubifs_clean_zn_cnt); -+ atomic_long_sub(freed, &c->clean_zn_cnt); -+ ubifs_assert(atomic_long_read(&c->clean_zn_cnt) >= 0); -+ total_freed += freed; -+ znode = zprev; -+ } -+ -+ if (unlikely(!c->zroot.znode)) -+ break; -+ -+ zprev = znode; -+ znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode); -+ cond_resched(); -+ } -+ -+ return total_freed; -+} -+ -+/** -+ * shrink_tnc_trees - shrink UBIFS TNC trees. -+ * @nr: number of znodes to free -+ * @age: the age of znodes to free -+ * @contention: if any contention, this is set to %1 -+ * -+ * This function walks the list of mounted UBIFS file-systems and frees clean -+ * znodes which are older then @age, until at least @nr znodes are freed. -+ * Returns the number of freed znodes. -+ */ -+static int shrink_tnc_trees(int nr, int age, int *contention) -+{ -+ struct ubifs_info *c; -+ struct list_head *p; -+ unsigned int run_no; -+ int freed = 0; -+ -+ spin_lock(&ubifs_infos_lock); -+ do -+ run_no = ++shrinker_run_no; -+ while (run_no == 0); -+ /* Iterate over all mounted UBIFS file-systems and try to shrink them */ -+ p = ubifs_infos.next; -+ while (p != &ubifs_infos) { -+ c = list_entry(p, struct ubifs_info, infos_list); -+ /* -+ * We move the ones we do to the end of the list, so we stop -+ * when we see one we have already done. -+ */ -+ if (c->shrinker_run_no == run_no) -+ break; -+ if (!mutex_trylock(&c->umount_mutex)) { -+ /* Some un-mount is in progress, try next FS */ -+ *contention = 1; -+ p = p->next; -+ continue; -+ } -+ /* -+ * We're holding 'c->umount_mutex', so the file-system won't go -+ * away. -+ */ -+ if (!mutex_trylock(&c->tnc_mutex)) { -+ mutex_unlock(&c->umount_mutex); -+ *contention = 1; -+ p = p->next; -+ continue; -+ } -+ spin_unlock(&ubifs_infos_lock); -+ /* -+ * OK, now we have TNC locked, the file-system cannot go away - -+ * it is safe to reap the cache. -+ */ -+ c->shrinker_run_no = run_no; -+ freed += shrink_tnc(c, nr, age, contention); -+ mutex_unlock(&c->tnc_mutex); -+ spin_lock(&ubifs_infos_lock); -+ /* Get the next list element before we move this one */ -+ p = p->next; -+ /* -+ * Move this one to the end of the list to provide some -+ * fairness. -+ */ -+ list_del(&c->infos_list); -+ list_add_tail(&c->infos_list, &ubifs_infos); -+ mutex_unlock(&c->umount_mutex); -+ if (freed >= nr) -+ break; -+ } -+ spin_unlock(&ubifs_infos_lock); -+ return freed; -+} -+ -+/** -+ * kick_a_thread - kick a background thread to start commit. -+ * -+ * This function kicks a background thread to start background commit. Returns -+ * %-1 if a thread was kicked or there is another reason to assume the memory -+ * will soon be freed or become freeable. If there are no dirty znodes, returns -+ * %0. -+ */ -+static int kick_a_thread(void) -+{ -+ int i; -+ struct ubifs_info *c; -+ -+ /* -+ * Iterate over all mounted UBIFS file-systems and find out if there is -+ * already an ongoing commit operation there. If no, then iterate for -+ * the second time and initiate background commit. -+ */ -+ spin_lock(&ubifs_infos_lock); -+ for (i = 0; i < 2; i++) { -+ list_for_each_entry(c, &ubifs_infos, infos_list) { -+ long dirty_zn_cnt; -+ -+ if (!mutex_trylock(&c->umount_mutex)) { -+ /* -+ * Some un-mount is in progress, it will -+ * certainly free memory, so just return. -+ */ -+ spin_unlock(&ubifs_infos_lock); -+ return -1; -+ } -+ -+ dirty_zn_cnt = atomic_long_read(&c->dirty_zn_cnt); -+ -+ if (!dirty_zn_cnt || c->cmt_state == COMMIT_BROKEN || -+ c->ro_media) { -+ mutex_unlock(&c->umount_mutex); -+ continue; -+ } -+ -+ if (c->cmt_state != COMMIT_RESTING) { -+ spin_unlock(&ubifs_infos_lock); -+ mutex_unlock(&c->umount_mutex); -+ return -1; -+ } -+ -+ if (i == 1) { -+ list_del(&c->infos_list); -+ list_add_tail(&c->infos_list, &ubifs_infos); -+ spin_unlock(&ubifs_infos_lock); -+ -+ ubifs_request_bg_commit(c); -+ mutex_unlock(&c->umount_mutex); -+ return -1; -+ } -+ mutex_unlock(&c->umount_mutex); -+ } -+ } -+ spin_unlock(&ubifs_infos_lock); -+ -+ return 0; -+} -+ -+int ubifs_shrinker(int nr, gfp_t gfp_mask) -+{ -+ int freed, contention = 0; -+ long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt); -+ -+ if (nr == 0) -+ return clean_zn_cnt; -+ -+ if (!clean_zn_cnt) { -+ /* -+ * No clean znodes, nothing to reap. All we can do in this case -+ * is to kick background threads to start commit, which will -+ * probably make clean znodes which, in turn, will be freeable. -+ * And we return -1 which means will make VM call us again -+ * later. -+ */ -+ dbg_tnc("no clean znodes, kick a thread"); -+ return kick_a_thread(); -+ } -+ -+ freed = shrink_tnc_trees(nr, OLD_ZNODE_AGE, &contention); -+ if (freed >= nr) -+ goto out; -+ -+ dbg_tnc("not enough old znodes, try to free young ones"); -+ freed += shrink_tnc_trees(nr - freed, YOUNG_ZNODE_AGE, &contention); -+ if (freed >= nr) -+ goto out; -+ -+ dbg_tnc("not enough young znodes, free all"); -+ freed += shrink_tnc_trees(nr - freed, 0, &contention); -+ -+ if (!freed && contention) { -+ dbg_tnc("freed nothing, but contention"); -+ return -1; -+ } -+ -+out: -+ dbg_tnc("%d znodes were freed, requested %d", freed, nr); -+ return freed; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/super.c linux-2.6.24.7/fs/ubifs/super.c ---- linux-2.6.24.7.old/fs/ubifs/super.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/super.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2016 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS initialization and VFS superblock operations. Some -+ * initialization stuff which is rather large and complex is placed at -+ * corresponding subsystems, but most of it is here. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubifs.h" -+ -+/* Slab cache for UBIFS inodes */ -+struct kmem_cache *ubifs_inode_slab; -+ -+#ifndef UBIFS_COMPAT_NO_SHRINKER -+/* UBIFS TNC shrinker description */ -+static struct shrinker ubifs_shrinker_info = { -+ .shrink = ubifs_shrinker, -+ .seeks = DEFAULT_SEEKS, -+}; -+#endif -+ -+/** -+ * validate_inode - validate inode. -+ * @c: UBIFS file-system description object -+ * @inode: the inode to validate -+ * -+ * This is a helper function for 'ubifs_iget()' which validates various fields -+ * of a newly built inode to make sure they contain sane values and prevent -+ * possible vulnerabilities. Returns zero if the inode is all right and -+ * a non-zero error code if not. -+ */ -+#ifndef UBIFS_COMPAT_USE_OLD_IGET -+static int validate_inode(struct ubifs_info *c, const struct inode *inode) -+#else -+int validate_inode(struct ubifs_info *c, const struct inode *inode) -+#endif -+{ -+ int err; -+ const struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ if (inode->i_size > c->max_inode_sz) { -+ ubifs_err("inode is too large (%lld)", -+ (long long)inode->i_size); -+ return 1; -+ } -+ -+ if (ui->compr_type < 0 || ui->compr_type >= UBIFS_COMPR_TYPES_CNT) { -+ ubifs_err("unknown compression type %d", ui->compr_type); -+ return 2; -+ } -+ -+ if (ui->xattr_cnt < 0) -+ return 3; -+ -+ if (ui->xattr_size < 0) -+ return 4; -+ -+ if (ui->xattr_names < 0 || -+ ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX) -+ return 5; -+ -+ if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA) -+ return 6; -+ -+ if (!ubifs_compr_present(ui->compr_type)) { -+ ubifs_warn("inode %lu uses '%s' compression, but it was not " -+ "compiled in", inode->i_ino, -+ ubifs_compr_name(ui->compr_type)); -+ } -+ -+ err = dbg_check_dir_size(c, inode); -+ return err; -+} -+ -+#ifndef UBIFS_COMPAT_USE_OLD_IGET -+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) -+{ -+ int err; -+ union ubifs_key key; -+ struct ubifs_ino_node *ino; -+ struct ubifs_info *c = sb->s_fs_info; -+ struct inode *inode; -+ struct ubifs_inode *ui; -+ -+ dbg_gen("inode %lu", inum); -+ -+ inode = iget_locked(sb, inum); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ if (!(inode->i_state & I_NEW)) -+ return inode; -+ ui = ubifs_inode(inode); -+ -+ ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); -+ if (!ino) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ ino_key_init(c, &key, inode->i_ino); -+ -+ err = ubifs_tnc_lookup(c, &key, ino); -+ if (err) -+ goto out_ino; -+ -+ inode->i_flags |= (S_NOCMTIME | S_NOATIME); -+ inode->i_nlink = le32_to_cpu(ino->nlink); -+ inode->i_uid = le32_to_cpu(ino->uid); -+ inode->i_gid = le32_to_cpu(ino->gid); -+ inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec); -+ inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec); -+ inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec); -+ inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec); -+ inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec); -+ inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec); -+ inode->i_mode = le32_to_cpu(ino->mode); -+ inode->i_size = le64_to_cpu(ino->size); -+ -+ ui->data_len = le32_to_cpu(ino->data_len); -+ ui->flags = le32_to_cpu(ino->flags); -+ ui->compr_type = le16_to_cpu(ino->compr_type); -+ ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum); -+ ui->xattr_cnt = le32_to_cpu(ino->xattr_cnt); -+ ui->xattr_size = le64_to_cpu(ino->xattr_size); -+ ui->xattr_names = le32_to_cpu(ino->xattr_names); -+ -+ err = validate_inode(c, inode); -+ if (err) -+ goto out_invalid; -+ -+ /* Disable readahead */ -+ inode->i_mapping->backing_dev_info = &ubifs_backing_dev_info; -+ -+ switch (inode->i_mode & S_IFMT) { -+ case S_IFREG: -+ inode->i_mapping->a_ops = &ubifs_file_address_operations; -+ inode->i_op = &ubifs_file_inode_operations; -+ inode->i_fop = &ubifs_file_operations; -+ if (ui->data_len != 0) { -+ err = 10; -+ goto out_invalid; -+ } -+ break; -+ case S_IFDIR: -+ inode->i_op = &ubifs_dir_inode_operations; -+ inode->i_fop = &ubifs_dir_operations; -+ if (ui->data_len != 0) { -+ err = 11; -+ goto out_invalid; -+ } -+ break; -+ case S_IFLNK: -+ inode->i_op = &ubifs_symlink_inode_operations; -+ if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { -+ err = 12; -+ goto out_invalid; -+ } -+ ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_ino; -+ } -+ memcpy(ui->data, ino->data, ui->data_len); -+ ((char *)ui->data)[ui->data_len] = '\0'; -+ break; -+ case S_IFBLK: -+ case S_IFCHR: -+ { -+ dev_t rdev; -+ union ubifs_dev_desc *dev; -+ -+ ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_ino; -+ } -+ -+ dev = (union ubifs_dev_desc *)ino->data; -+ if (ui->data_len == sizeof(dev->new)) -+ rdev = new_decode_dev(le32_to_cpu(dev->new)); -+ else if (ui->data_len == sizeof(dev->huge)) -+ rdev = huge_decode_dev(le64_to_cpu(dev->huge)); -+ else { -+ err = 13; -+ goto out_invalid; -+ } -+ memcpy(ui->data, ino->data, ui->data_len); -+ inode->i_op = &ubifs_file_inode_operations; -+ init_special_inode(inode, inode->i_mode, rdev); -+ break; -+ } -+ case S_IFSOCK: -+ case S_IFIFO: -+ inode->i_op = &ubifs_file_inode_operations; -+ init_special_inode(inode, inode->i_mode, 0); -+ if (ui->data_len != 0) { -+ err = 14; -+ goto out_invalid; -+ } -+ break; -+ default: -+ err = 15; -+ goto out_invalid; -+ } -+ -+ kfree(ino); -+ ubifs_set_inode_flags(inode); -+ unlock_new_inode(inode); -+ return inode; -+ -+out_invalid: -+ ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err); -+ dbg_dump_node(c, ino); -+ dbg_dump_inode(c, inode); -+ err = -EINVAL; -+out_ino: -+ kfree(ino); -+out: -+ ubifs_err("failed to read inode %lu, error %d", inode->i_ino, err); -+ iget_failed(inode); -+ return ERR_PTR(err); -+} -+ -+#endif /* UBIFS_COMPAT_USE_OLD_IGET */ -+ -+static struct inode *ubifs_alloc_inode(struct super_block *sb) -+{ -+ struct ubifs_inode *ui; -+ -+ ui = kmem_cache_alloc(ubifs_inode_slab, GFP_NOFS); -+ if (!ui) -+ return NULL; -+ -+ memset((void *)ui + sizeof(struct inode), 0, -+ sizeof(struct ubifs_inode) - sizeof(struct inode)); -+ mutex_init(&ui->budg_mutex); -+ return &ui->vfs_inode; -+}; -+ -+static void ubifs_destroy_inode(struct inode *inode) -+{ -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ kfree(ui->data); -+ kmem_cache_free(ubifs_inode_slab, inode); -+} -+ -+/* -+ * Note, Linux write-back code calls this without 'i_mutex'. -+ */ -+static int ubifs_write_inode(struct inode *inode, int wait) -+{ -+ int err; -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_budget_req req = {.dd_growth = c->inode_budget, -+ .dirtied_ino_d = ui->data_len}; -+ -+ ubifs_assert(!ui->xattr); -+ if (is_bad_inode(inode)) -+ return 0; -+ -+ mutex_lock(&ui->budg_mutex); -+ -+ /* -+ * Due to races between write-back forced by budgeting -+ * (see 'sync_some_inodes()') and pdflush write-back, the inode may -+ * have already been synchronized, do not do this again. -+ * -+ * This might also happen if it was synchronized in e.g. ubifs_link()', -+ * etc. -+ */ -+ if (!ui->dirty) { -+ mutex_unlock(&ui->budg_mutex); -+ return 0; -+ } -+ -+ ubifs_assert(ui->budgeted); -+ dbg_gen("inode %lu", inode->i_ino); -+ -+ err = ubifs_jnl_write_inode(c, inode, 0, IS_SYNC(inode)); -+ if (err) -+ ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); -+ -+ ui->dirty = 0; -+ UBIFS_DBG(ui->budgeted = 0); -+ atomic_long_dec(&c->dirty_ino_cnt); -+ -+ ubifs_release_budget(c, &req); -+ mutex_unlock(&ui->budg_mutex); -+ -+ return err; -+} -+ -+static void ubifs_delete_inode(struct inode *inode) -+{ -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_budget_req req = {.dd_growth = c->inode_budget, -+ .dirtied_ino_d = ui->data_len}; -+ int err; -+ -+ if (ui->xattr) { -+ /* -+ * Extended attribute inode deletions are fully handled in -+ * 'ubifs_removexattr()'. These inodes are special and have -+ * limited usage, so there is nothing to do here. -+ */ -+ ubifs_assert(!ui->dirty); -+ goto out; -+ } -+ -+ dbg_gen("inode %lu", inode->i_ino); -+ ubifs_assert(!atomic_read(&inode->i_count)); -+ ubifs_assert(inode->i_nlink == 0); -+ -+ truncate_inode_pages(&inode->i_data, 0); -+ if (is_bad_inode(inode)) -+ goto out; -+ -+ mutex_lock(&ui->budg_mutex); -+ -+ inode->i_size = 0; -+ -+ err = ubifs_jnl_write_inode(c, inode, 1, IS_SYNC(inode)); -+ if (err) -+ /* -+ * Worst case we have a lost orphan inode wasting space, so a -+ * simple error message is ok here. -+ */ -+ ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); -+ -+ if (ui->dirty) { -+ ubifs_assert(ui->budgeted); -+ atomic_long_dec(&c->dirty_ino_cnt); -+ ui->dirty = 0; -+ UBIFS_DBG(ui->budgeted = 0); -+ ubifs_release_budget(c, &req); -+ } -+ -+ mutex_unlock(&ui->budg_mutex); -+out: -+ clear_inode(inode); -+} -+ -+static void ubifs_dirty_inode(struct inode *inode) -+{ -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ -+ ubifs_assert(mutex_is_locked(&ui->budg_mutex)); -+ if (!ui->dirty) { -+ struct ubifs_info *c = inode->i_sb->s_fs_info; -+ -+ ui->dirty = 1; -+ atomic_long_inc(&c->dirty_ino_cnt); -+ dbg_gen("inode %lu", inode->i_ino); -+ } -+} -+ -+static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct ubifs_info *c = dentry->d_sb->s_fs_info; -+ unsigned long long free; -+ -+ free = ubifs_budg_get_free_space(c); -+ dbg_gen("free space %lld bytes (%lld blocks)", -+ free, free >> UBIFS_BLOCK_SHIFT); -+ -+ buf->f_type = UBIFS_SUPER_MAGIC; -+ buf->f_bsize = UBIFS_BLOCK_SIZE; -+ buf->f_blocks = c->block_cnt; -+ buf->f_bfree = free >> UBIFS_BLOCK_SHIFT; -+ if (free > c->report_rp_size) -+ buf->f_bavail = (free - c->report_rp_size) >> UBIFS_BLOCK_SHIFT; -+ else -+ buf->f_bavail = 0; -+ buf->f_files = 0; -+ buf->f_ffree = 0; -+ buf->f_namelen = UBIFS_MAX_NLEN; -+ -+ return 0; -+} -+ -+static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt) -+{ -+ struct ubifs_info *c = mnt->mnt_sb->s_fs_info; -+ -+ if (c->mount_opts.unmount_mode == 2) -+ seq_printf(s, ",fast_unmount"); -+ else if (c->mount_opts.unmount_mode == 1) -+ seq_printf(s, ",norm_unmount"); -+ -+ return 0; -+} -+ -+static int ubifs_sync_fs(struct super_block *sb, int wait) -+{ -+ struct ubifs_info *c = sb->s_fs_info; -+ int i, ret = 0, err; -+ -+ if (c->jheads) -+ for (i = 0; i < c->jhead_cnt; i++) { -+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ if (err && !ret) -+ ret = err; -+ } -+ /* -+ * We ought to call sync for c->ubi but it does not have one. If it had -+ * it would in turn call mtd->sync, however mtd operations are -+ * synchronous anyway, so we don't lose any sleep here. -+ */ -+ return ret; -+} -+ -+/** -+ * init_constants_early - initialize UBIFS constants. -+ * @c: UBIFS file-system description object -+ * -+ * This function initialize UBIFS constants which do not need the superblock to -+ * be read. It also checks that the UBI volume satisfies basic UBIFS -+ * requirements. Returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int init_constants_early(struct ubifs_info *c) -+{ -+ if (c->vi.corrupted) { -+ ubifs_warn("UBI volume is corrupted - read-only mode"); -+ c->ro_media = 1; -+ } -+ -+ if (c->di.ro_mode) { -+ ubifs_msg("read-only UBI device"); -+ c->ro_media = 1; -+ } -+ -+ if (c->vi.vol_type == UBI_STATIC_VOLUME) { -+ ubifs_msg("static UBI volume - read-only mode"); -+ c->ro_media = 1; -+ } -+ -+ c->leb_cnt = c->vi.size; -+ c->leb_size = c->vi.usable_leb_size; -+ c->half_leb_size = c->leb_size / 2; -+ c->min_io_size = c->di.min_io_size; -+ c->min_io_shift = fls(c->min_io_size) - 1; -+ -+ if (c->leb_size < UBIFS_MIN_LEB_SZ) { -+ ubifs_err("too small LEBs (%d bytes), min. is %d bytes", -+ c->leb_size, UBIFS_MIN_LEB_SZ); -+ return -EINVAL; -+ } -+ -+ if (c->leb_cnt < UBIFS_MIN_LEB_CNT) { -+ ubifs_err("too few LEBs (%d), min. is %d", -+ c->leb_cnt, UBIFS_MIN_LEB_CNT); -+ return -EINVAL; -+ } -+ -+ if (!is_power_of_2(c->min_io_size)) { -+ ubifs_err("bad min. I/O size %d", c->min_io_size); -+ return -EINVAL; -+ } -+ -+ /* -+ * UBIFS aligns all node to 8-byte boundary, so to make function in -+ * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is -+ * less than 8. -+ */ -+ if (c->min_io_size < 8) { -+ c->min_io_size = 8; -+ c->min_io_shift = 3; -+ } -+ -+ c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); -+ c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size); -+ -+ /* -+ * Initialize node length ranges which are mostly needed for node -+ * length validation. -+ */ -+ c->ranges[UBIFS_PAD_NODE].len = UBIFS_PAD_NODE_SZ; -+ c->ranges[UBIFS_SB_NODE].len = UBIFS_SB_NODE_SZ; -+ c->ranges[UBIFS_MST_NODE].len = UBIFS_MST_NODE_SZ; -+ c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; -+ c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; -+ c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; -+ -+ c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; -+ c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; -+ c->ranges[UBIFS_ORPH_NODE].min_len = -+ UBIFS_ORPH_NODE_SZ + sizeof(__le64); -+ c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size; -+ c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ; -+ c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ; -+ c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ; -+ c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ; -+ c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ; -+ c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ; -+ /* -+ * Minimum indexing node size is amended later when superblock is -+ * read and the key length is known. -+ */ -+ c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ; -+ /* -+ * Maximum indexing node size is amended later when superblock is -+ * read and the fanout is known. -+ */ -+ c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX; -+ -+ /* -+ * Initialize dead and dark LEB space watermarks. -+ * -+ * Dead space is the space which cannot be used. Its watermark is -+ * equivalent to min. I/O unit or minimum node size if it is greater -+ * then min. I/O unit. -+ * -+ * Dark space is the space which might be used, or might not, depending -+ * on which node should be written to the LEB. Its watermark is -+ * equivalent to maximum UBIFS node size. -+ */ -+ c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); -+ c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); -+ -+ return 0; -+} -+ -+/** -+ * bud_wbuf_callback - bud LEB write-buffer synchronization call-back. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB the write-buffer was synchronized to -+ * @free: how many free bytes left in this LEB -+ * @pad: how many bytes were padded -+ * -+ * This is a callback function which is called by the I/O unit when the -+ * write-buffer is synchronized. We need this to correctly maintain space -+ * accounting in bud logical eraseblocks. This function returns zero in case of -+ * success and a negative error code in case of failure. -+ * -+ * This function actually belongs to the journal, but we keep it here because -+ * we want to keep it static. -+ */ -+static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad) -+{ -+ return ubifs_update_one_lp(c, lnum, free, pad, 0, 0); -+} -+ -+/* -+ * init_constants_late - initialize UBIFS constants. -+ * @c: UBIFS file-system description object -+ * -+ * This is a helper function which initializes various UBIFS constants after -+ * the superblock has been read. It also checks various UBIFS parameters and -+ * makes sure they are all right. Returns zero in case of success and a -+ * negative error code in case of failure. -+ */ -+static int init_constants_late(struct ubifs_info *c) -+{ -+ int tmp, err; -+ uint64_t tmp64; -+ -+ c->main_bytes = c->main_lebs * c->leb_size; -+ -+ c->max_znode_sz = sizeof(struct ubifs_znode) + -+ c->fanout * sizeof(struct ubifs_zbranch); -+ -+ tmp = ubifs_idx_node_sz(c, 1); -+ c->ranges[UBIFS_IDX_NODE].min_len = tmp; -+ c->min_idx_node_sz = ALIGN(tmp, 8); -+ -+ tmp = ubifs_idx_node_sz(c, c->fanout); -+ c->ranges[UBIFS_IDX_NODE].max_len = tmp; -+ c->max_idx_node_sz = ALIGN(tmp, 8); -+ -+ /* Make sure LEB size is large enough to fit full commit */ -+ tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt; -+ tmp = ALIGN(tmp, c->min_io_size); -+ if (tmp > c->leb_size) { -+ dbg_err("too small LEB size %d, at least %d needed", -+ c->leb_size, tmp); -+ return -EINVAL; -+ } -+ -+ /* -+ * Make sure that the log is large enough to fit reference nodes for -+ * all buds plus one reserved LEB. -+ */ -+ tmp64 = c->max_bud_bytes; -+ tmp = do_div(tmp64, c->leb_size); -+ c->max_bud_cnt = tmp64 + !!tmp; -+ tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1); -+ tmp /= c->leb_size; -+ tmp += 1; -+ if (c->log_lebs < tmp) { -+ dbg_err("too small log %d LEBs, required min. %d LEBs", -+ c->log_lebs, tmp); -+ return -EINVAL; -+ } -+ -+ /* -+ * When budgeting we assume worst-case scenarios when the pages are not -+ * be compressed and direntries are of the maximum size. -+ * -+ * Note, data, which may be stored in inodes is budgeted separately, so -+ * it is not included into 'c->inode_budget'. -+ */ -+ c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE; -+ c->inode_budget = UBIFS_INO_NODE_SZ; -+ c->dent_budget = UBIFS_MAX_DENT_NODE_SZ; -+ -+ /* -+ * When the amount of flash space used by buds becomes -+ * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit. -+ * The writers are unblocked when the commit is finished. To avoid -+ * writers to be blocked UBIFS initiates background commit in advance, -+ * when number of bud bytes becomes above the limit defined below. -+ */ -+ c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4; -+ -+ /* -+ * Ensure minimum journal size. All the bytes in the journal heads are -+ * considered to be used, when calculating the current journal usage. -+ * Consequently, if the journal is too small, UBIFS will treat it as -+ * always full. -+ */ -+ tmp64 = (uint64_t)(c->jhead_cnt + 1) * c->leb_size + 1; -+ if (c->bg_bud_bytes < tmp64) -+ c->bg_bud_bytes = tmp64; -+ if (c->max_bud_bytes < tmp64 + c->leb_size) -+ c->max_bud_bytes = tmp64 + c->leb_size; -+ -+ err = ubifs_calc_lpt_geom(c); -+ if (err) -+ return err; -+ -+ c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); -+ -+ /* -+ * Calculate total amount of FS blocks. This number is not used -+ * internally because it does not make much sense for UBIFS, but it is -+ * necessary to report something for the 'statfs()' call. -+ * -+ * Subtract the LEB reserved for GC and the LEB which is reserved for -+ * deletions. -+ * -+ * Review 'ubifs_calc_available()' if changing this calculation. -+ */ -+ tmp64 = c->main_lebs - 2; -+ tmp64 *= c->leb_size - c->dark_wm; -+ tmp64 = ubifs_reported_space(c, tmp64); -+ c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; -+ -+ return 0; -+} -+ -+/** -+ * care_about_gc_lnum - take care about reserved GC LEB. -+ * @c: UBIFS file-system description object -+ * -+ * This function ensures that the LEB reserved for garbage collection is -+ * unmapped and is marked as "taken" in lprops. We also have to set free space -+ * to LEB size and dirty space to zero, because lprops may contain out-of-date -+ * information if the file-system was un-mounted before it has been committed. -+ * This function returns zero in case of success and a negative error code in -+ * case of failure. -+ */ -+static int care_about_gc_lnum(struct ubifs_info *c) -+{ -+ int err; -+ -+ if (c->gc_lnum == -1) { -+ ubifs_err("no LEB for GC"); -+ return -EINVAL; -+ } -+ -+ err = ubifs_leb_unmap(c, c->gc_lnum); -+ if (err) -+ return err; -+ -+ /* And we have to tell lprops that this LEB is taken */ -+ err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0, -+ LPROPS_TAKEN, 0, 0); -+ return err; -+} -+ -+/** -+ * alloc_wbufs - allocate write-buffers. -+ * @c: UBIFS file-system description object -+ * -+ * This helper function allocates and initializes UBIFS write-buffers. Returns -+ * zero in case of success and %-ENOMEM in case of failure. -+ */ -+static int alloc_wbufs(struct ubifs_info *c) -+{ -+ int i, err; -+ -+ c->jheads = kzalloc(c->jhead_cnt * sizeof(struct ubifs_jhead), -+ GFP_KERNEL); -+ if (!c->jheads) -+ return -ENOMEM; -+ -+ /* Initialize journal heads */ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ INIT_LIST_HEAD(&c->jheads[i].buds_list); -+ err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); -+ if (err) -+ return err; -+ -+ c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; -+ c->jheads[i].wbuf.jhead = i; -+ } -+ -+ c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM; -+ /* -+ * Garbage Collector head likely contains long-term data and -+ * does not need to be synchronized by timer. -+ */ -+ c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; -+ c->jheads[GCHD].wbuf.timeout = 0; -+ -+ return 0; -+} -+ -+/** -+ * free_wbufs - free write-buffers. -+ * @c: UBIFS file-system description object -+ */ -+static void free_wbufs(struct ubifs_info *c) -+{ -+ int i; -+ -+ if (c->jheads) { -+ for (i = 0; i < c->jhead_cnt; i++) { -+ kfree(c->jheads[i].wbuf.buf); -+ kfree(c->jheads[i].wbuf.inodes); -+ } -+ kfree(c->jheads); -+ c->jheads = NULL; -+ } -+} -+ -+/** -+ * free_orphans - free orphans. -+ * @c: UBIFS file-system description object -+ */ -+static void free_orphans(struct ubifs_info *c) -+{ -+ struct ubifs_orphan *orph; -+ -+ while (c->orph_dnext) { -+ orph = c->orph_dnext; -+ c->orph_dnext = orph->dnext; -+ list_del(&orph->list); -+ kfree(orph); -+ } -+ -+ while (!list_empty(&c->orph_list)) { -+ orph = list_entry(c->orph_list.next, struct ubifs_orphan, list); -+ list_del(&orph->list); -+ kfree(orph); -+ dbg_err("orphan list not empty at unmount"); -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->orph_buf); -+#else -+ vfree(c->orph_buf); -+#endif -+ c->orph_buf = NULL; -+} -+ -+/** -+ * free_buds - free per-bud objects. -+ * @c: UBIFS file-system description object -+ */ -+static void free_buds(struct ubifs_info *c) -+{ -+ struct rb_node *this = c->buds.rb_node; -+ struct ubifs_bud *bud; -+ -+ while (this) { -+ if (this->rb_left) -+ this = this->rb_left; -+ else if (this->rb_right) -+ this = this->rb_right; -+ else { -+ bud = rb_entry(this, struct ubifs_bud, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &bud->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(bud); -+ } -+ } -+} -+ -+/** -+ * check_volume_empty - check if the UBI volume is empty. -+ * @c: UBIFS file-system description object -+ * -+ * This function checks if the UBIFS volume is empty by looking if its LEBs are -+ * mapped or not. The result of checking is stored in the @c->empty variable. -+ * Returns zero in case of success and a negative error code in case of -+ * failure. -+ */ -+static int check_volume_empty(struct ubifs_info *c) -+{ -+ int lnum, err; -+ -+ c->empty = 1; -+ for (lnum = 0; lnum < c->leb_cnt; lnum++) { -+ err = ubi_is_mapped(c->ubi, lnum); -+ if (unlikely(err < 0)) -+ return err; -+ if (err == 1) { -+ c->empty = 0; -+ break; -+ } -+ -+ cond_resched(); -+ } -+ -+ return 0; -+} -+ -+/* -+ * UBIFS mount options. -+ * -+ * Opt_fast_unmount: do not run a journal commit before un-mounting -+ * Opt_norm_unmount: run a journal commit before un-mounting -+ * Opt_err: just end of array marker -+ */ -+enum { -+ Opt_fast_unmount, -+ Opt_norm_unmount, -+ Opt_err, -+}; -+ -+static match_table_t tokens = { -+ {Opt_fast_unmount, "fast_unmount"}, -+ {Opt_norm_unmount, "norm_unmount"}, -+ {Opt_err, NULL}, -+}; -+ -+/** -+ * ubifs_parse_options - parse mount parameters. -+ * @c: UBIFS file-system description object -+ * @options: parameters to parse -+ * @is_remount: non-zero if this is FS re-mount -+ * -+ * This function parses UBIFS mount options and returns zero in case success -+ * and a negative error code in case of failure. -+ */ -+static int ubifs_parse_options(struct ubifs_info *c, char *options, -+ int is_remount) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ if (!options) -+ return 0; -+ -+ while ((p = strsep(&options, ","))) { -+ int token; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, tokens, args); -+ switch (token) { -+ case Opt_fast_unmount: -+ c->mount_opts.unmount_mode = 2; -+ c->fast_unmount = 1; -+ break; -+ case Opt_norm_unmount: -+ c->mount_opts.unmount_mode = 1; -+ c->fast_unmount = 0; -+ break; -+ default: -+ ubifs_err("unrecognized mount option \"%s\" " -+ "or missing value", p); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * destroy_journal - destroy journal data structures. -+ * @c: UBIFS file-system description object -+ * -+ * This function destroys journal data structures including those that may have -+ * been created by recovery functions. -+ */ -+static void destroy_journal(struct ubifs_info *c) -+{ -+ while (!list_empty(&c->unclean_leb_list)) { -+ struct ubifs_unclean_leb *ucleb; -+ -+ ucleb = list_entry(c->unclean_leb_list.next, -+ struct ubifs_unclean_leb, list); -+ list_del(&ucleb->list); -+ kfree(ucleb); -+ } -+ while (!list_empty(&c->old_buds)) { -+ struct ubifs_bud *bud; -+ -+ bud = list_entry(c->old_buds.next, struct ubifs_bud, list); -+ list_del(&bud->list); -+ kfree(bud); -+ } -+ ubifs_destroy_idx_gc(c); -+ ubifs_destroy_size_tree(c); -+ ubifs_tnc_close(c); -+ free_buds(c); -+} -+ -+/** -+ * mount_ubifs - mount UBIFS file-system. -+ * @c: UBIFS file-system description object -+ * -+ * This function mounts UBIFS file system. Returns zero in case of success and -+ * a negative error code in case of failure. -+ * -+ * Note, the function does not de-allocate resources it it fails half way -+ * through, and the caller has to do this instead. -+ */ -+static int mount_ubifs(struct ubifs_info *c) -+{ -+ struct super_block *sb = c->vfs_sb; -+ int err, mounted_read_only = (sb->s_flags & MS_RDONLY); -+ unsigned long long x; -+ size_t sz; -+ -+ err = init_constants_early(c); -+ if (err) -+ return err; -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->dbg_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->dbg_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->dbg_buf) -+ return -ENOMEM; -+#endif -+ -+ err = check_volume_empty(c); -+ if (err) -+ goto out_free; -+ -+ if (c->empty && (mounted_read_only || c->ro_media)) { -+ /* -+ * This UBI volume is empty, and read-only, or the file system -+ * is mounted read-only - we cannot format it. -+ */ -+ ubifs_err("can't format empty UBI volume: read-only %s", -+ c->ro_media ? "UBI volume" : "mount"); -+ err = -EROFS; -+ goto out_free; -+ } -+ -+ if (c->ro_media && !mounted_read_only) { -+ ubifs_err("cannot mount read-write - read-only media"); -+ err = -EROFS; -+ goto out_free; -+ } -+ -+ /* -+ * The requirement for the buffer is that it should fit indexing B-tree -+ * height amount of integers. We assume the height if the TNC tree will -+ * never exceed 64. -+ */ -+ err = -ENOMEM; -+ c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL); -+ if (!c->bottom_up_buf) -+ goto out_free; -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->sbuf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->sbuf = vmalloc(c->leb_size); -+#endif -+ if (!c->sbuf) -+ goto out_free; -+ -+ if (!mounted_read_only) { -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ileb_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->ileb_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->ileb_buf) -+ goto out_free; -+ } -+ -+ err = ubifs_read_superblock(c); -+ if (err) -+ goto out_free; -+ -+ /* -+ * Make sure the compressor which is set as the default on in the -+ * superblock was actually compiled in. -+ */ -+ if (!ubifs_compr_present(c->default_compr)) { -+ ubifs_warn("'%s' compressor is set by superblock, but not " -+ "compiled in", ubifs_compr_name(c->default_compr)); -+ c->default_compr = UBIFS_COMPR_NONE; -+ } -+ -+ dbg_failure_mode_registration(c); -+ -+ err = init_constants_late(c); -+ if (err) -+ goto out_dereg; -+ -+ sz = ALIGN(c->max_idx_node_sz, c->min_io_size); -+ sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size); -+ c->cbuf = kmalloc(sz, GFP_NOFS); -+ if (!c->cbuf) { -+ err = -ENOMEM; -+ goto out_dereg; -+ } -+ -+ if (!mounted_read_only) { -+ err = alloc_wbufs(c); -+ if (err) -+ goto out_cbuf; -+ -+ /* Create background thread */ -+ sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, -+ c->vi.vol_id); -+ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); -+ if (!c->bgt) -+ c->bgt = ERR_PTR(-EINVAL); -+ if (IS_ERR(c->bgt)) { -+ err = PTR_ERR(c->bgt); -+ c->bgt = NULL; -+ ubifs_err("cannot spawn \"%s\", error %d", -+ c->bgt_name, err); -+ goto out_wbufs; -+ } -+ wake_up_process(c->bgt); -+ } -+ -+ err = ubifs_read_master(c); -+ if (err) -+ goto out_stop; -+ -+ if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) { -+ ubifs_msg("recovery needed"); -+ c->need_recovery = 1; -+ if (!mounted_read_only) { -+ err = ubifs_recover_inl_heads(c, c->sbuf); -+ if (err) -+ goto out_master; -+ } -+ } else if (!mounted_read_only) { -+ /* -+ * Set the "dirty" flag so that if we reboot uncleanly we -+ * will notice this immediately on the next mount. -+ */ -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ err = ubifs_write_master(c); -+ if (err) -+ goto out_master; -+ } -+ -+ err = ubifs_lpt_init(c, 1, !mounted_read_only); -+ if (err) -+ goto out_master; -+ -+ err = dbg_check_idx_size(c, c->old_idx_sz); -+ if (err) -+ goto out_lpt; -+ -+ err = ubifs_replay_journal(c); -+ if (err) -+ goto out_journal; -+ -+ if (!mounted_read_only) { -+ int lnum; -+ -+ err = ubifs_mount_orphans(c, c->need_recovery); -+ if (err) -+ goto out_journal; -+ -+ if (c->need_recovery) -+ err = ubifs_recover_gc_lnum(c); -+ else -+ err = care_about_gc_lnum(c); -+ if (err) -+ goto out_orphans; -+ -+ /* Check for enough log space */ -+ lnum = c->lhead_lnum + 1; -+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) -+ lnum = UBIFS_LOG_LNUM; -+ if (lnum == c->ltail_lnum) { -+ err = ubifs_consolidate_log(c); -+ if (err) -+ goto out_orphans; -+ } -+ -+ /* Check for enough free space */ -+ if (ubifs_calc_available(c) <= 0) { -+ ubifs_err("insufficient available space"); -+ err = -EINVAL; -+ goto out_orphans; -+ } -+ -+ err = dbg_check_lprops(c); -+ if (err) -+ goto out_orphans; -+ } -+ -+ if (c->need_recovery) { -+ err = ubifs_recover_size(c); -+ if (err) -+ goto out_orphans; -+ } -+ -+ spin_lock(&ubifs_infos_lock); -+ list_add_tail(&c->infos_list, &ubifs_infos); -+ spin_unlock(&ubifs_infos_lock); -+ -+ if (c->need_recovery) { -+ if (mounted_read_only) -+ ubifs_msg("recovery deferred"); -+ else { -+ c->need_recovery = 0; -+ ubifs_msg("recovery completed"); -+ } -+ } -+ -+ ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num, -+ c->vi.vol_id); -+ if (mounted_read_only) -+ ubifs_msg("mounted read-only"); -+ ubifs_msg("minimal I/O unit size: %d bytes", c->min_io_size); -+ ubifs_msg("logical eraseblock size: %d bytes (%d KiB)", -+ c->leb_size, c->leb_size / 1024); -+ x = (unsigned long long)c->main_lebs * c->leb_size; -+ ubifs_msg("file system size: %lld bytes (%lld KiB, %lld MiB, " -+ "%d LEBs)", x, x >> 10, x >> 20, c->main_lebs); -+ x = (unsigned long long)c->log_lebs * c->leb_size + c->max_bud_bytes; -+ ubifs_msg("journal size: %lld bytes (%lld KiB, %lld MiB, " -+ "%d LEBs)", x, x >> 10, x >> 20, -+ c->log_lebs + c->max_bud_cnt); -+ ubifs_msg("data journal heads: %d", -+ c->jhead_cnt - NONDATA_JHEADS_CNT); -+ ubifs_msg("default compressor: %s", -+ ubifs_compr_name(c->default_compr)); -+ ubifs_msg("media format %d, latest format %d", -+ c->fmt_version, UBIFS_FORMAT_VERSION); -+ -+ dbg_msg("compiled on: " __DATE__ " at " __TIME__); -+ dbg_msg("fast unmount: %d", c->fast_unmount); -+ dbg_msg("big_lpt %d", c->big_lpt); -+ dbg_msg("log LEBs: %d (%d - %d)", -+ c->log_lebs, UBIFS_LOG_LNUM, c->log_last); -+ dbg_msg("LPT area LEBs: %d (%d - %d)", -+ c->lpt_lebs, c->lpt_first, c->lpt_last); -+ dbg_msg("orphan area LEBs: %d (%d - %d)", -+ c->orph_lebs, c->orph_first, c->orph_last); -+ dbg_msg("main area LEBs: %d (%d - %d)", -+ c->main_lebs, c->main_first, c->leb_cnt - 1); -+ dbg_msg("index LEBs: %d", c->lst.idx_lebs); -+ dbg_msg("total index bytes: %lld (%lld KiB, %lld MiB)", -+ c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20); -+ dbg_msg("key hash type: %d", c->key_hash_type); -+ dbg_msg("tree fanout: %d", c->fanout); -+ dbg_msg("reserved GC LEB: %d", c->gc_lnum); -+ dbg_msg("first main LEB: %d", c->main_first); -+ dbg_msg("dead watermark: %d", c->dead_wm); -+ dbg_msg("dark watermark: %d", c->dark_wm); -+ x = c->main_lebs * c->dark_wm; -+ dbg_msg("max. dark space: %lld (%lld KiB, %lld MiB)", -+ x, x >> 10, x >> 20); -+ dbg_msg("maximum bud bytes: %lld (%lld KiB, %lld MiB)", -+ c->max_bud_bytes, c->max_bud_bytes >> 10, -+ c->max_bud_bytes >> 20); -+ dbg_msg("BG commit bud bytes: %lld (%lld KiB, %lld MiB)", -+ c->bg_bud_bytes, c->bg_bud_bytes >> 10, -+ c->bg_bud_bytes >> 20); -+ dbg_msg("current bud bytes %lld (%lld KiB, %lld MiB)", -+ c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20); -+ dbg_msg("max. seq. number: %llu", c->max_sqnum); -+ dbg_msg("commit number: %llu", c->cmt_no); -+ -+ return 0; -+ -+out_orphans: -+ free_orphans(c); -+out_journal: -+ destroy_journal(c); -+out_lpt: -+ ubifs_lpt_free(c, 0); -+out_master: -+ kfree(c->mst_node); -+ kfree(c->rcvrd_mst_node); -+out_stop: -+ if (c->bgt) -+ kthread_stop(c->bgt); -+out_wbufs: -+ free_wbufs(c); -+out_cbuf: -+ kfree(c->cbuf); -+out_dereg: -+ dbg_failure_mode_deregistration(c); -+out_free: -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ileb_buf); -+ kfree(c->sbuf); -+ UBIFS_DBG(kfree(c->dbg_buf)); -+#else -+ vfree(c->ileb_buf); -+ vfree(c->sbuf); -+ UBIFS_DBG(vfree(c->dbg_buf)); -+#endif -+ kfree(c->bottom_up_buf); -+ return err; -+} -+ -+/** -+ * ubifs_umount - un-mount UBIFS file-system. -+ * @c: UBIFS file-system description object -+ * -+ * Note, this function is called to free allocated resourced when un-mounting, -+ * as well as free resources when an error occurred while we were half way -+ * through mounting (error path cleanup function). So it has to make sure the -+ * resource was actually allocated before freeing it. -+ */ -+static void ubifs_umount(struct ubifs_info *c) -+{ -+ dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, -+ c->vi.vol_id); -+ -+ if (c->bgt) -+ kthread_stop(c->bgt); -+ -+ destroy_journal(c); -+ free_wbufs(c); -+ free_orphans(c); -+ ubifs_lpt_free(c, 0); -+ -+ kfree(c->cbuf); -+ kfree(c->rcvrd_mst_node); -+ kfree(c->mst_node); -+ kfree(c->bottom_up_buf); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->sbuf); -+ UBIFS_DBG(kfree(c->dbg_buf)); -+ kfree(c->ileb_buf); -+#else -+ vfree(c->sbuf); -+ UBIFS_DBG(vfree(c->dbg_buf)); -+ vfree(c->ileb_buf); -+#endif -+ dbg_failure_mode_deregistration(c); -+} -+ -+/** -+ * ubifs_remount_rw - re-mount in read-write mode. -+ * @c: UBIFS file-system description object -+ * -+ * UBIFS avoids allocating many unnecessary resources when mounted in read-only -+ * mode. This function allocates the needed resources and re-mounts UBIFS in -+ * read-write mode. -+ */ -+static int ubifs_remount_rw(struct ubifs_info *c) -+{ -+ int err, lnum; -+ -+ if (c->ro_media) -+ return -EINVAL; -+ -+ mutex_lock(&c->umount_mutex); -+ c->remounting_rw = 1; -+ -+ /* Check for enough free space */ -+ if (ubifs_calc_available(c) <= 0) { -+ ubifs_err("insufficient available space"); -+ err = -EINVAL; -+ goto out; -+ } -+ -+ if (c->old_leb_cnt != c->leb_cnt) { -+ struct ubifs_sb_node *sup; -+ -+ sup = ubifs_read_sb_node(c); -+ if (IS_ERR(sup)) { -+ err = PTR_ERR(sup); -+ goto out; -+ } -+ sup->leb_cnt = cpu_to_le32(c->leb_cnt); -+ err = ubifs_write_sb_node(c, sup); -+ if (err) -+ goto out; -+ } -+ -+ if (c->need_recovery) { -+ ubifs_msg("completing deferred recovery"); -+ err = ubifs_write_rcvrd_mst_node(c); -+ if (err) -+ goto out; -+ err = ubifs_recover_size(c); -+ if (err) -+ goto out; -+ err = ubifs_clean_lebs(c, c->sbuf); -+ if (err) -+ goto out; -+ err = ubifs_recover_inl_heads(c, c->sbuf); -+ if (err) -+ goto out; -+ } -+ -+ if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) { -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); -+ err = ubifs_write_master(c); -+ if (err) -+ goto out; -+ } -+ -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ c->ileb_buf = kmalloc(c->leb_size, GFP_KERNEL); -+#else -+ c->ileb_buf = vmalloc(c->leb_size); -+#endif -+ if (!c->ileb_buf) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ err = ubifs_lpt_init(c, 0, 1); -+ if (err) -+ goto out; -+ -+ err = alloc_wbufs(c); -+ if (err) -+ goto out; -+ -+ ubifs_create_buds_lists(c); -+ -+ /* Create background thread */ -+ c->bgt = kthread_create(ubifs_bg_thread, c, c->bgt_name); -+ if (!c->bgt) -+ c->bgt = ERR_PTR(-EINVAL); -+ if (IS_ERR(c->bgt)) { -+ err = PTR_ERR(c->bgt); -+ c->bgt = NULL; -+ ubifs_err("cannot spawn \"%s\", error %d", -+ c->bgt_name, err); -+ return err; -+ } -+ wake_up_process(c->bgt); -+ -+ err = ubifs_mount_orphans(c, c->need_recovery); -+ if (err) -+ goto out; -+ -+ if (c->need_recovery) -+ err = ubifs_recover_gc_lnum(c); -+ else -+ err = care_about_gc_lnum(c); -+ if (err) -+ goto out; -+ -+ /* Check for enough log space */ -+ lnum = c->lhead_lnum + 1; -+ if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) -+ lnum = UBIFS_LOG_LNUM; -+ if (lnum == c->ltail_lnum) { -+ err = ubifs_consolidate_log(c); -+ if (err) -+ goto out; -+ } -+ -+ if (c->need_recovery) { -+ c->need_recovery = 0; -+ ubifs_msg("deferred recovery completed"); -+ } -+ -+ dbg_gen("re-mounted read-write"); -+ c->vfs_sb->s_flags &= ~MS_RDONLY; -+ c->remounting_rw = 0; -+ mutex_unlock(&c->umount_mutex); -+ return 0; -+ -+out: -+ free_orphans(c); -+ if (c->bgt) { -+ kthread_stop(c->bgt); -+ c->bgt = NULL; -+ } -+ free_wbufs(c); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ileb_buf); -+#else -+ vfree(c->ileb_buf); -+#endif -+ c->ileb_buf = NULL; -+ ubifs_lpt_free(c, 1); -+ c->remounting_rw = 0; -+ mutex_unlock(&c->umount_mutex); -+ return err; -+} -+ -+/** -+ * commit_on_unmount - commit the journal when un-mounting. -+ * @c: UBIFS file-system description object -+ * -+ * This function is called during un-mounting and it commits the journal unless -+ * the "fast unmount" mode is enabled. It also avoids committing the journal if -+ * it contains too few data. -+ * -+ * Sometimes recovery requires the journal to be committed at least once, and -+ * this function takes care about this. -+ */ -+static void commit_on_unmount(struct ubifs_info *c) -+{ -+ if (!c->fast_unmount) { -+ long long bud_bytes; -+ -+ spin_lock(&c->buds_lock); -+ bud_bytes = c->bud_bytes; -+ spin_unlock(&c->buds_lock); -+ if (bud_bytes > c->leb_size) -+ ubifs_run_commit(c); -+ } -+ -+ if (c->recovery_needs_commit) -+ ubifs_recovery_commit(c); -+} -+ -+/** -+ * ubifs_remount_ro - re-mount in read-only mode. -+ * @c: UBIFS file-system description object -+ * -+ * We rely on VFS to have stopped writing. Possibly the background thread could -+ * be running a commit, however kthread_stop will wait in that case. -+ */ -+static void ubifs_remount_ro(struct ubifs_info *c) -+{ -+ int i, err; -+ -+ ubifs_assert(!c->need_recovery); -+ commit_on_unmount(c); -+ -+ mutex_lock(&c->umount_mutex); -+ if (c->bgt) { -+ kthread_stop(c->bgt); -+ c->bgt = NULL; -+ } -+ -+ for (i = 0; i < c->jhead_cnt; i++) { -+ ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ del_timer_sync(&c->jheads[i].wbuf.timer); -+ } -+ -+ if (!c->ro_media) { -+ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); -+ err = ubifs_write_master(c); -+ if (err) -+ ubifs_ro_mode(c, err); -+ } -+ -+ ubifs_destroy_idx_gc(c); -+ free_wbufs(c); -+ free_orphans(c); -+#if defined(CONFIG_MTD_NAND_DMA) && !defined(CONFIG_MTD_NAND_DMABUF) -+ kfree(c->ileb_buf); -+#else -+ vfree(c->ileb_buf); -+#endif -+ c->ileb_buf = NULL; -+ ubifs_lpt_free(c, 1); -+ mutex_unlock(&c->umount_mutex); -+} -+ -+static void ubifs_put_super(struct super_block *sb) -+{ -+ int i; -+ struct ubifs_info *c = sb->s_fs_info; -+ -+ ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num, -+ c->vi.vol_id); -+ /* -+ * The following asserts are only valid if there has not been a failure -+ * of the media. For example, there will be dirty inodes if we failed -+ * to write them back because of I/O errors. -+ */ -+ ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); -+ ubifs_assert(atomic_long_read(&c->dirty_ino_cnt) == 0); -+ ubifs_assert(c->budg_idx_growth == 0); -+ ubifs_assert(c->budg_data_growth == 0); -+ -+ /* -+ * The 'c->umount_lock' prevents races between UBIFS memory shrinker -+ * and file system un-mount. Namely, it prevents the shrinker from -+ * picking this superblock for shrinking - it will be just skipped if -+ * the mutex is locked. -+ */ -+ mutex_lock(&c->umount_mutex); -+ -+ spin_lock(&ubifs_infos_lock); -+ list_del(&c->infos_list); -+ spin_unlock(&ubifs_infos_lock); -+ -+ if (!(c->vfs_sb->s_flags & MS_RDONLY)) { -+ /* -+ * First of all kill the background thread to make sure it does -+ * not interfere with un-mounting and freeing resources. -+ */ -+ if (c->bgt) { -+ kthread_stop(c->bgt); -+ c->bgt = NULL; -+ } -+ -+ /* Synchronize write-buffers */ -+ if (c->jheads) -+ for (i = 0; i < c->jhead_cnt; i++) { -+ ubifs_wbuf_sync(&c->jheads[i].wbuf); -+ del_timer_sync(&c->jheads[i].wbuf.timer); -+ } -+ -+ /* -+ * On fatal errors c->ro_media is set to 1, in which case we do -+ * not write the master node. -+ */ -+ if (!c->ro_media) { -+ /* -+ * We are being cleanly unmounted which means the -+ * orphans were killed - indicate this in the master -+ * node. Also save the reserved GC LEB number. -+ */ -+ int err; -+ -+ c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); -+ c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); -+ c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); -+ err = ubifs_write_master(c); -+ if (err) -+ /* -+ * Recovery will attempt to fix the master area -+ * next mount, so we just print a message and -+ * continue to unmount normally. -+ */ -+ ubifs_err("failed to write master node, " -+ "error %d", err); -+ } -+ } -+ -+ ubifs_umount(c); -+ ubi_close_volume(c->ubi); -+ mutex_unlock(&c->umount_mutex); -+ kfree(c); -+} -+ -+static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) -+{ -+ int err; -+ struct ubifs_info *c = sb->s_fs_info; -+ -+ dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags); -+ -+ err = ubifs_parse_options(c, data, 1); -+ if (err) { -+ ubifs_err("invalid or unknown remount parameter"); -+ return err; -+ } -+ if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { -+ err = ubifs_remount_rw(c); -+ if (err) -+ return err; -+ } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) -+ ubifs_remount_ro(c); -+ -+ return 0; -+} -+ -+struct super_operations ubifs_super_operations = { -+#ifdef UBIFS_COMPAT_USE_OLD_IGET -+ .read_inode = ubifs_read_inode, -+#endif -+ .alloc_inode = ubifs_alloc_inode, -+ .destroy_inode = ubifs_destroy_inode, -+ .put_super = ubifs_put_super, -+ .write_inode = ubifs_write_inode, -+ .delete_inode = ubifs_delete_inode, -+ .statfs = ubifs_statfs, -+ .dirty_inode = ubifs_dirty_inode, -+ .remount_fs = ubifs_remount_fs, -+ .show_options = ubifs_show_options, -+ .sync_fs = ubifs_sync_fs, -+}; -+ -+/** -+ * open_ubi - parse UBI device name string and open the UBI device. -+ * @name: UBI volume name -+ * @mode: UBI volume open mode -+ * -+ * There are several ways to specify UBI volumes when mounting UBIFS: -+ * o ubiX_Y - UBI device number X, volume Y; -+ * o ubiY - UBI device number 0, volume Y; -+ * o ubiX:NAME - mount UBI device X, volume with name NAME; -+ * o ubi:NAME - mount UBI device 0, volume with name NAME. -+ * -+ * Alternative '!' separator may be used instead of ':' (because some shells -+ * like busybox may interpret ':' as an NFS host name separator). This function -+ * returns ubi volume object in case of success and a negative error code in -+ * case of failure. -+ */ -+static struct ubi_volume_desc *open_ubi(const char *name, int mode) -+{ -+ int dev, vol; -+ char *endptr; -+ -+ if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') -+ return ERR_PTR(-EINVAL); -+ -+ /* ubi:NAME method */ -+ if ((name[3] == ':' || name[3] == '!') && name[4] != '\0') -+ return ubi_open_volume_nm(0, name + 4, mode); -+ -+ if (!isdigit(name[3])) -+ return ERR_PTR(-EINVAL); -+ -+ dev = simple_strtoul(name + 3, &endptr, 0); -+ -+ /* ubiY method */ -+ if (*endptr == '\0') -+ return ubi_open_volume(0, dev, mode); -+ -+ /* ubiX_Y method */ -+ if (*endptr == '_' && isdigit(endptr[1])) { -+ vol = simple_strtoul(endptr + 1, &endptr, 0); -+ if (*endptr != '\0') -+ return ERR_PTR(-EINVAL); -+ return ubi_open_volume(dev, vol, mode); -+ } -+ -+ /* ubiX:NAME method */ -+ if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0') -+ return ubi_open_volume_nm(dev, ++endptr, mode); -+ -+ return ERR_PTR(-EINVAL); -+} -+ -+static int ubifs_fill_super(struct super_block *sb, void *data, int silent) -+{ -+ struct ubi_volume_desc *ubi = sb->s_fs_info; -+ struct ubifs_info *c; -+ struct inode *root; -+ int err; -+ -+ c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); -+ if (!c) -+ return -ENOMEM; -+ -+ spin_lock_init(&c->cnt_lock); -+ spin_lock_init(&c->cs_lock); -+ spin_lock_init(&c->buds_lock); -+ spin_lock_init(&c->space_lock); -+ spin_lock_init(&c->orphan_lock); -+ init_rwsem(&c->commit_sem); -+ mutex_init(&c->lp_mutex); -+ mutex_init(&c->tnc_mutex); -+ mutex_init(&c->log_mutex); -+ mutex_init(&c->mst_mutex); -+ mutex_init(&c->umount_mutex); -+ init_waitqueue_head(&c->cmt_wq); -+ c->buds = RB_ROOT; -+ c->old_idx = RB_ROOT; -+ c->size_tree = RB_ROOT; -+ c->orph_tree = RB_ROOT; -+ INIT_LIST_HEAD(&c->infos_list); -+ INIT_LIST_HEAD(&c->idx_gc); -+ INIT_LIST_HEAD(&c->replay_list); -+ INIT_LIST_HEAD(&c->replay_buds); -+ INIT_LIST_HEAD(&c->uncat_list); -+ INIT_LIST_HEAD(&c->empty_list); -+ INIT_LIST_HEAD(&c->freeable_list); -+ INIT_LIST_HEAD(&c->frdi_idx_list); -+ INIT_LIST_HEAD(&c->unclean_leb_list); -+ INIT_LIST_HEAD(&c->old_buds); -+ INIT_LIST_HEAD(&c->orph_list); -+ INIT_LIST_HEAD(&c->orph_new); -+ -+ c->highest_inum = UBIFS_FIRST_INO; -+ get_random_bytes(&c->vfs_gen, sizeof(int)); -+ c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; -+ -+ ubi_get_volume_info(ubi, &c->vi); -+ ubi_get_device_info(c->vi.ubi_num, &c->di); -+ -+ /* Re-open the UBI device in read-write mode */ -+ c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); -+ if (IS_ERR(c->ubi)) { -+ err = PTR_ERR(c->ubi); -+ goto out_free; -+ } -+ -+ err = ubifs_parse_options(c, data, 0); -+ if (err) -+ goto out_close; -+ -+ c->vfs_sb = sb; -+ -+ sb->s_fs_info = c; -+ sb->s_magic = UBIFS_SUPER_MAGIC; -+ sb->s_blocksize = UBIFS_BLOCK_SIZE; -+ sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; -+ sb->s_dev = c->vi.cdev; -+ sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c); -+ if (c->max_inode_sz > MAX_LFS_FILESIZE) -+ sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; -+ sb->s_op = &ubifs_super_operations; -+ -+ mutex_lock(&c->umount_mutex); -+ err = mount_ubifs(c); -+ if (err) { -+ ubifs_assert(err < 0); -+ goto out_unlock; -+ } -+ -+ /* Read the root inode */ -+ root = ubifs_iget(sb, UBIFS_ROOT_INO); -+ if (IS_ERR(root)) { -+ err = PTR_ERR(root); -+ goto out_umount; -+ } -+ -+ sb->s_root = d_alloc_root(root); -+ if (!sb->s_root) -+ goto out_iput; -+ -+ mutex_unlock(&c->umount_mutex); -+ -+ return 0; -+ -+out_iput: -+ iput(root); -+out_umount: -+ spin_lock(&ubifs_infos_lock); -+ list_del(&c->infos_list); -+ spin_unlock(&ubifs_infos_lock); -+ ubifs_umount(c); -+out_unlock: -+ mutex_unlock(&c->umount_mutex); -+out_close: -+ ubi_close_volume(c->ubi); -+out_free: -+ kfree(c); -+ return err; -+} -+ -+static int sb_test(struct super_block *sb, void *data) -+{ -+ dev_t *dev = data; -+ -+ return sb->s_dev == *dev; -+} -+ -+static int sb_set(struct super_block *sb, void *data) -+{ -+ dev_t *dev = data; -+ -+ sb->s_dev = *dev; -+ return 0; -+} -+ -+static int ubifs_get_sb(struct file_system_type *fs_type, int flags, -+ const char *name, void *data, struct vfsmount *mnt) -+{ -+ struct ubi_volume_desc *ubi; -+ struct ubi_volume_info vi; -+ struct super_block *sb; -+ int err; -+ -+ dbg_gen("name %s, flags %#x", name, flags); -+ -+ /* -+ * Get UBI device number and volume ID. Mount it read-only so far -+ * because this might be a new mount point, and UBI allows only one -+ * read-write user at a time. -+ */ -+ ubi = open_ubi(name, UBI_READONLY); -+ if (IS_ERR(ubi)) { -+ ubifs_err("cannot open \"%s\", error %d", -+ name, (int)PTR_ERR(ubi)); -+ return PTR_ERR(ubi); -+ } -+ ubi_get_volume_info(ubi, &vi); -+ -+ dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); -+ -+ sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev); -+ if (IS_ERR(sb)) { -+ err = PTR_ERR(sb); -+ goto out_close; -+ } -+ -+ if (sb->s_root) { -+ /* A new mount point for already mounted UBIFS */ -+ dbg_gen("this ubi volume is already mounted"); -+ if ((flags ^ sb->s_flags) & MS_RDONLY) { -+ err = -EBUSY; -+ goto out_deact; -+ } -+ } else { -+ sb->s_flags = flags; -+ /* -+ * Pass 'ubi' to 'fill_super()' in sb->s_fs_info where it is -+ * replaced by 'c'. -+ */ -+ sb->s_fs_info = ubi; -+ err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); -+ if (err) -+ goto out_deact; -+ /* We do not support atime */ -+ sb->s_flags |= MS_ACTIVE | MS_NOATIME; -+ } -+ -+ /* 'fill_super()' opens ubi again so we must close it here */ -+ ubi_close_volume(ubi); -+ -+ return simple_set_mnt(mnt, sb); -+ -+out_deact: -+ up_write(&sb->s_umount); -+ deactivate_super(sb); -+out_close: -+ ubi_close_volume(ubi); -+ return err; -+} -+ -+static void ubifs_kill_sb(struct super_block *sb) -+{ -+ struct ubifs_info *c = sb->s_fs_info; -+ -+ /* -+ * We do 'commit_on_unmount()' here instead of 'ubifs_put_super()' -+ * in order to be outside BKL. -+ */ -+ if (sb->s_root && !(sb->s_flags & MS_RDONLY)) -+ commit_on_unmount(c); -+ /* The un-mount routine is actually done in put_super() */ -+ generic_shutdown_super(sb); -+} -+ -+static struct file_system_type ubifs_fs_type = { -+ .name = "ubifs", -+ .owner = THIS_MODULE, -+ .get_sb = ubifs_get_sb, -+ .kill_sb = ubifs_kill_sb -+}; -+ -+/* -+ * Inode slab cache constructor. -+ */ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -+static void inode_slab_ctor(void *obj, struct kmem_cache *cachep, -+ unsigned long flags) -+#else -+static void inode_slab_ctor(struct kmem_cache *cachep, void *obj) -+#endif -+{ -+ struct ubifs_inode *inode = obj; -+ inode_init_once(&inode->vfs_inode); -+} -+ -+static int __init ubifs_init(void) -+{ -+ int err; -+ -+ BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24); -+ -+ /* Make sure node sizes are 8-byte aligned */ -+ BUILD_BUG_ON(UBIFS_CH_SZ & 7); -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_CS_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7); -+ -+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ & 7); -+ BUILD_BUG_ON(UBIFS_MAX_NODE_SZ & 7); -+ BUILD_BUG_ON(MIN_WRITE_SZ & 7); -+ -+ /* Check min. node size */ -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ); -+ BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ); -+ -+ BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ > UBIFS_MAX_NODE_SZ); -+ -+ /* Defined node sizes */ -+ BUILD_BUG_ON(UBIFS_SB_NODE_SZ != 4096); -+ BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512); -+ BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160); -+ BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64); -+ -+ /* -+ * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to -+ * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2. -+ */ -+ if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) { -+ ubifs_err("VFS page cache size is %u bytes, but UBIFS requires" -+ " at least 4096 bytes", -+ (unsigned int)PAGE_CACHE_SIZE); -+ return -EINVAL; -+ } -+ -+ err = bdi_init(&ubifs_backing_dev_info); -+ if (err) -+ return err; -+ -+ err = register_filesystem(&ubifs_fs_type); -+ if (err) { -+ ubifs_err("cannot register file system, error %d", err); -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab", -+ sizeof(struct ubifs_inode), 0, -+ SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT, -+ &inode_slab_ctor UBIFSCOMPATNULL); -+ if (!ubifs_inode_slab) -+ goto out_reg; -+ -+ register_shrinker(&ubifs_shrinker_info); -+ -+ err = ubifs_compressors_init(); -+ if (err) -+ goto out_compr; -+ -+ return 0; -+ -+out_compr: -+ unregister_shrinker(&ubifs_shrinker_info); -+ kmem_cache_destroy(ubifs_inode_slab); -+out_reg: -+ unregister_filesystem(&ubifs_fs_type); -+out: -+ bdi_destroy(&ubifs_backing_dev_info); -+ return err; -+} -+/* late_initcall to let compressors initialize first */ -+late_initcall(ubifs_init); -+ -+static void __exit ubifs_exit(void) -+{ -+ ubifs_assert(list_empty(&ubifs_infos)); -+ ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0); -+ -+ ubifs_compressors_exit(); -+ unregister_shrinker(&ubifs_shrinker_info); -+ kmem_cache_destroy(ubifs_inode_slab); -+ unregister_filesystem(&ubifs_fs_type); -+ bdi_destroy(&ubifs_backing_dev_info); -+} -+module_exit(ubifs_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(__stringify(UBIFS_VERSION)); -+MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); -+MODULE_DESCRIPTION("UBIFS - UBI File System"); -diff -urN linux-2.6.24.7.old/fs/ubifs/tnc.c linux-2.6.24.7/fs/ubifs/tnc.c ---- linux-2.6.24.7.old/fs/ubifs/tnc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/tnc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3300 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file implements TNC (Tree Node Cache) which caches indexing nodes of -+ * the UBIFS B-tree. -+ * -+ * At the moment the locking rules of the TNC tree are quite simple and -+ * straightforward. We just have a mutex and lock it when we traverse the -+ * tree. If a znode is not in memory, we read it from flash while still having -+ * the mutex locked. -+ */ -+ -+#include -+#include "ubifs.h" -+ -+/* -+ * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions. -+ * @NAME_LESS: name corresponding to the first argument is less than second -+ * @NAME_MATCHES: names match -+ * @NAME_GREATER: name corresponding to the second argument is greater than -+ * first -+ * @NOT_ON_MEDIA: node referred by zbranch does not exist on the media -+ * -+ * These constants were introduce to improve readability. -+ */ -+enum { -+ NAME_LESS = 0, -+ NAME_MATCHES = 1, -+ NAME_GREATER = 2, -+ NOT_ON_MEDIA = 3, -+}; -+ -+/** -+ * insert_old_idx - record an index node obsoleted since the last commit start. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of obsoleted index node -+ * @offs: offset of obsoleted index node -+ * -+ * Returns %0 on success, and a negative error code on failure. -+ * -+ * For recovery, there must always be a complete intact version of the index on -+ * flash at all times. That is called the "old index". It is the index as at the -+ * time of the last successful commit. Many of the index nodes in the old index -+ * may be dirty, but they must not be erased until the next successful commit -+ * (at which point that index becomes the old index). -+ * -+ * That means that the garbage collection and the in-the-gaps method of -+ * committing must be able to determine if an index node is in the old index. -+ * Most of the old index nodes can be found by looking up the TNC using the -+ * 'lookup_znode()' function. However, some of the old index nodes may have -+ * been deleted from the current index or may have been changed so much that -+ * they cannot be easily found. In those cases, an entry is added to an RB-tree. -+ * That is what this function does. The RB-tree is ordered by LEB number and -+ * offset because they uniquely identify the old index node. -+ */ -+static int insert_old_idx(struct ubifs_info *c, int lnum, int offs) -+{ -+ struct ubifs_old_idx *old_idx, *o; -+ struct rb_node **p, *parent = NULL; -+ -+ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS); -+ if (unlikely(!old_idx)) -+ return -ENOMEM; -+ old_idx->lnum = lnum; -+ old_idx->offs = offs; -+ -+ p = &c->old_idx.rb_node; -+ while (*p) { -+ parent = *p; -+ o = rb_entry(parent, struct ubifs_old_idx, rb); -+ if (lnum < o->lnum) -+ p = &(*p)->rb_left; -+ else if (lnum > o->lnum) -+ p = &(*p)->rb_right; -+ else if (offs < o->offs) -+ p = &(*p)->rb_left; -+ else if (offs > o->offs) -+ p = &(*p)->rb_right; -+ else { -+ ubifs_err("old idx added twice!"); -+ kfree(old_idx); -+ return 0; -+ } -+ } -+ rb_link_node(&old_idx->rb, parent, p); -+ rb_insert_color(&old_idx->rb, &c->old_idx); -+ return 0; -+} -+ -+/** -+ * insert_old_idx_znode - record a znode obsoleted since last commit start. -+ * @c: UBIFS file-system description object -+ * @znode: znode of obsoleted index node -+ * -+ * Returns %0 on success, and a negative error code on failure. -+ */ -+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode) -+{ -+ if (znode->parent) { -+ struct ubifs_zbranch *zbr; -+ -+ zbr = &znode->parent->zbranch[znode->iip]; -+ if (zbr->len) -+ return insert_old_idx(c, zbr->lnum, zbr->offs); -+ } else -+ if (c->zroot.len) -+ return insert_old_idx(c, c->zroot.lnum, -+ c->zroot.offs); -+ return 0; -+} -+ -+/** -+ * ins_clr_old_idx_znode - record a znode obsoleted since last commit start. -+ * @c: UBIFS file-system description object -+ * @znode: znode of obsoleted index node -+ * -+ * Returns %0 on success, and a negative error code on failure. -+ */ -+static int ins_clr_old_idx_znode(struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ int err; -+ -+ if (znode->parent) { -+ struct ubifs_zbranch *zbr; -+ -+ zbr = &znode->parent->zbranch[znode->iip]; -+ if (zbr->len) { -+ err = insert_old_idx(c, zbr->lnum, zbr->offs); -+ if (err) -+ return err; -+ zbr->lnum = 0; -+ zbr->offs = 0; -+ zbr->len = 0; -+ } -+ } else -+ if (c->zroot.len) { -+ err = insert_old_idx(c, c->zroot.lnum, c->zroot.offs); -+ if (err) -+ return err; -+ c->zroot.lnum = 0; -+ c->zroot.offs = 0; -+ c->zroot.len = 0; -+ } -+ return 0; -+} -+ -+/** -+ * destroy_old_idx - destroy the old_idx RB-tree. -+ * @c: UBIFS file-system description object -+ * -+ * During start commit, the old_idx RB-tree is used to avoid overwriting index -+ * nodes that were in the index last commit but have since been deleted. This -+ * is necessary for recovery i.e. the old index must be kept intact until the -+ * new index is successfully written. The old-idx RB-tree is used for the -+ * in-the-gaps method of writing index nodes and is destroyed every commit. -+ */ -+void destroy_old_idx(struct ubifs_info *c) -+{ -+ struct rb_node *this = c->old_idx.rb_node; -+ struct ubifs_old_idx *old_idx; -+ -+ while (this) { -+ if (this->rb_left) { -+ this = this->rb_left; -+ continue; -+ } else if (this->rb_right) { -+ this = this->rb_right; -+ continue; -+ } -+ old_idx = rb_entry(this, struct ubifs_old_idx, rb); -+ this = rb_parent(this); -+ if (this) { -+ if (this->rb_left == &old_idx->rb) -+ this->rb_left = NULL; -+ else -+ this->rb_right = NULL; -+ } -+ kfree(old_idx); -+ } -+ c->old_idx = RB_ROOT; -+} -+ -+/** -+ * read_znode - read an indexing node from flash and fill znode. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB of the indexing node to read -+ * @offs: node offset -+ * @len: node length -+ * @znode: znode to read to -+ * -+ * This function reads an indexing node from the flash media and fills znode -+ * with the read data. Returns zero in case of success and a negative error -+ * code in case of failure. The read indexing node is validated and if anything -+ * is wrong with it, this function prints complaint messages and returns -+ * %-EINVAL. -+ */ -+static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, -+ struct ubifs_znode *znode) -+{ -+ int i, err, type, cmp; -+ struct ubifs_idx_node *idx; -+ -+ idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); -+ if (!idx) -+ return -ENOMEM; -+ -+ err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); -+ if (err < 0) -+ goto out; -+ -+ znode->child_cnt = le16_to_cpu(idx->child_cnt); -+ znode->level = le16_to_cpu(idx->level); -+ -+ dbg_tnc("LEB %d:%d, level %d, %d branch", -+ lnum, offs, znode->level, znode->child_cnt); -+ -+ if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) { -+ dbg_err("current fanout %d, branch count %d", -+ c->fanout, znode->child_cnt); -+ dbg_err("max levels %d, znode level %d", -+ UBIFS_MAX_LEVELS, znode->level); -+ goto out_dump; -+ } -+ -+ for (i = 0; i < znode->child_cnt; i++) { -+ const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); -+ struct ubifs_zbranch *zbr = &znode->zbranch[i]; -+ -+ key_read(c, &br->key, &zbr->key); -+ zbr->lnum = le32_to_cpu(br->lnum); -+ zbr->offs = le32_to_cpu(br->offs); -+ zbr->len = le32_to_cpu(br->len); -+ zbr->znode = NULL; -+ -+ /* Validate branch */ -+ -+ if (zbr->lnum < c->main_first || -+ zbr->lnum >= c->leb_cnt || zbr->offs < 0 || -+ zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) { -+ dbg_err("bad branch %d", i); -+ goto out_dump; -+ } -+ -+ switch (key_type(c, &zbr->key)) { -+ case UBIFS_INO_KEY: -+ case UBIFS_DATA_KEY: -+ case UBIFS_DENT_KEY: -+ case UBIFS_XENT_KEY: -+ break; -+ default: -+ dbg_msg("bad key type at slot %d: %s", i, -+ DBGKEY(&zbr->key)); -+ goto out_dump; -+ } -+ -+ if (znode->level) -+ continue; -+ -+ type = key_type(c, &zbr->key); -+ if (c->ranges[type].max_len == 0) { -+ if (zbr->len != c->ranges[type].len) { -+ dbg_err("bad target node (type %d) length (%d)", -+ type, zbr->len); -+ dbg_err("have to be %d", c->ranges[type].len); -+ goto out_dump; -+ } -+ } else if (zbr->len < c->ranges[type].min_len || -+ zbr->len > c->ranges[type].max_len) { -+ dbg_err("bad target node (type %d) length (%d)", -+ type, zbr->len); -+ dbg_err("have to be in range of %d-%d", -+ c->ranges[type].min_len, -+ c->ranges[type].max_len); -+ goto out_dump; -+ } -+ } -+ -+ /* -+ * Ensure that the next key is greater or equivalent to the -+ * previous one. -+ */ -+ for (i = 0; i < znode->child_cnt - 1; i++) { -+ const union ubifs_key *key1, *key2; -+ -+ key1 = &znode->zbranch[i].key; -+ key2 = &znode->zbranch[i + 1].key; -+ -+ cmp = keys_cmp(c, key1, key2); -+ if (cmp > 0) { -+ dbg_err("bad key order (keys %d and %d)", i, i + 1); -+ goto out_dump; -+ } else if (cmp == 0 && !is_hash_key(c, key1)) { -+ /* These can only be keys with colliding hash */ -+ dbg_err("keys %d and %d are not hashed but equivalent", -+ i, i + 1); -+ goto out_dump; -+ } -+ } -+ -+ kfree(idx); -+ return 0; -+ -+out: -+ kfree(idx); -+ return err; -+ -+out_dump: -+ ubifs_err("bad indexing node at LEB %d:%d", lnum, offs); -+ dbg_dump_node(c, idx); -+ kfree(idx); -+ return -EINVAL; -+} -+ -+/** -+ * load_znode - load znode to TNC cache. -+ * @c: UBIFS file-system description object -+ * @zbr: znode branch -+ * @parent: znode's parent -+ * @iip: index in parent -+ * -+ * This function loads znode pointed to by @zbr into the TNC cache and -+ * returns pointer to it in case of success and a negative error code in case -+ * of failure. -+ */ -+static struct ubifs_znode *load_znode(struct ubifs_info *c, -+ struct ubifs_zbranch *zbr, -+ struct ubifs_znode *parent, int iip) -+{ -+ int err; -+ struct ubifs_znode *znode; -+ -+ ubifs_assert(!zbr->znode); -+ /* -+ * A slab cache is not presently used for znodes because the znode size -+ * depends on the fanout which is stored in the superblock. -+ */ -+ znode = kzalloc(c->max_znode_sz, GFP_NOFS); -+ if (!znode) -+ return ERR_PTR(-ENOMEM); -+ -+ err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode); -+ if (err) -+ goto out; -+ -+ atomic_long_inc(&c->clean_zn_cnt); -+ -+ /* -+ * Increment the global clean znode counter as well. It is OK that -+ * global and per-FS clean znode counters may be inconsistent for some -+ * short time (because we might be preempted at this point), the global -+ * one is only used in shrinker. -+ */ -+ atomic_long_inc(&ubifs_clean_zn_cnt); -+ -+ zbr->znode = znode; -+ znode->parent = parent; -+ znode->time = get_seconds(); -+ znode->iip = iip; -+ -+ return znode; -+ -+out: -+ kfree(znode); -+ return ERR_PTR(err); -+} -+ -+/** -+ * copy_znode - copy a dirty znode. -+ * @c: UBIFS file-system description object -+ * @znode: znode to copy -+ * -+ * A dirty znode being committed may not be changed, so it is copied. -+ */ -+static struct ubifs_znode *copy_znode(struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ struct ubifs_znode *zn; -+ -+ zn = kmalloc(c->max_znode_sz, GFP_NOFS); -+ if (unlikely(!zn)) -+ return ERR_PTR(-ENOMEM); -+ -+ memcpy(zn, znode, c->max_znode_sz); -+ zn->cnext = NULL; -+ __set_bit(DIRTY_ZNODE, &zn->flags); -+ __clear_bit(COW_ZNODE, &zn->flags); -+ -+ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); -+ __set_bit(OBSOLETE_ZNODE, &znode->flags); -+ -+ if (znode->level != 0) { -+ int i; -+ const int n = zn->child_cnt; -+ -+ /* The children now have new parent */ -+ for (i = 0; i < n; i++) { -+ struct ubifs_zbranch *zbr = &zn->zbranch[i]; -+ -+ if (zbr->znode) -+ zbr->znode->parent = zn; -+ } -+ } -+ -+ atomic_long_inc(&c->dirty_zn_cnt); -+ return zn; -+} -+ -+/** -+ * add_idx_dirt - add dirt due to a dirty znode. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of index node -+ * @dirt: size of index node -+ * -+ * This function updates lprops dirty space and the new size of the index. -+ */ -+static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt) -+{ -+ c->calc_idx_sz -= ALIGN(dirt, 8); -+ return ubifs_add_dirt(c, lnum, dirt); -+} -+ -+/** -+ * dirty_cow_znode - ensure a znode is not being committed. -+ * @c: UBIFS file-system description object -+ * @zbr: branch of znode to check -+ * -+ * Returns dirtied znode on success or negative error code on failure. -+ */ -+static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, -+ struct ubifs_zbranch *zbr) -+{ -+ struct ubifs_znode *znode = zbr->znode; -+ struct ubifs_znode *zn; -+ int err; -+ -+ if (!test_bit(COW_ZNODE, &znode->flags)) { -+ /* znode is not being committed */ -+ if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) { -+ atomic_long_inc(&c->dirty_zn_cnt); -+ atomic_long_dec(&c->clean_zn_cnt); -+ atomic_long_dec(&ubifs_clean_zn_cnt); -+ err = add_idx_dirt(c, zbr->lnum, zbr->len); -+ if (unlikely(err)) -+ return ERR_PTR(err); -+ } -+ return znode; -+ } -+ -+ zn = copy_znode(c, znode); -+ if (unlikely(IS_ERR(zn))) -+ return zn; -+ -+ if (zbr->len) { -+ err = insert_old_idx(c, zbr->lnum, zbr->offs); -+ if (unlikely(err)) -+ return ERR_PTR(err); -+ err = add_idx_dirt(c, zbr->lnum, zbr->len); -+ } else -+ err = 0; -+ -+ zbr->znode = zn; -+ zbr->lnum = 0; -+ zbr->offs = 0; -+ zbr->len = 0; -+ -+ if (unlikely(err)) -+ return ERR_PTR(err); -+ return zn; -+} -+ -+/** -+ * lnc_add - add a leaf node to the leaf node cache. -+ * @c: UBIFS file-system description object -+ * @zbr: zbranch of leaf node -+ * @node: leaf node -+ * -+ * Leaf nodes are non-index nodes directory entry nodes or data nodes. The -+ * purpose of the leaf node cache is to save re-reading the same leaf node over -+ * and over again. Most things are cached by VFS, however the file system must -+ * cache directory entries for readdir and for resolving hash collisions. The -+ * present implementation of the leaf node cache is extremely simple, and -+ * allows for error returns that are not used but that may be needed if a more -+ * complex implementation is created. -+ * -+ * Note, this function does not add the @node object to LNC directly, but -+ * allocates a copy of the object and adds the copy to LNC. The reason for this -+ * is that @node has been allocated outside of the TNC subsystem and will be -+ * used with @c->tnc_mutex unlock upon return from the TNC subsystem. But LNC -+ * may be changed at any time, e.g. freed by the shrinker. -+ */ -+static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ const void *node) -+{ -+ int err; -+ void *lnc_node; -+ const struct ubifs_dent_node *dent = node; -+ -+ ubifs_assert(!zbr->leaf); -+ ubifs_assert(zbr->len != 0); -+ ubifs_assert(is_hash_key(c, &zbr->key)); -+ -+ err = ubifs_validate_entry(c, dent); -+ if (err) { -+ dbg_dump_stack(); -+ dbg_dump_node(c, dent); -+ return err; -+ } -+ -+ lnc_node = kmalloc(zbr->len, GFP_NOFS); -+ if (!lnc_node) -+ /* We don't have to have the cache, so no error */ -+ return 0; -+ -+ memcpy(lnc_node, node, zbr->len); -+ zbr->leaf = lnc_node; -+ return 0; -+} -+ -+ /** -+ * lnc_add_directly - add a leaf node to the leaf-node-cache. -+ * @c: UBIFS file-system description object -+ * @zbr: zbranch of leaf node -+ * @node: leaf node -+ * -+ * This function is similar to 'lnc_add()', but it does not create a copy of -+ * @node but inserts @node to TNC directly. -+ */ -+static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *node) -+{ -+ int err; -+ -+ ubifs_assert(!zbr->leaf); -+ ubifs_assert(zbr->len != 0); -+ -+ err = ubifs_validate_entry(c, node); -+ if (err) { -+ dbg_dump_stack(); -+ dbg_dump_node(c, node); -+ return err; -+ } -+ -+ zbr->leaf = node; -+ return 0; -+} -+ -+/** -+ * lnc_free - remove a leaf node from the leaf node cache. -+ * @zbr: zbranch of leaf node -+ * @node: leaf node -+ */ -+static void lnc_free(struct ubifs_zbranch *zbr) -+{ -+ if (!zbr->leaf) -+ return; -+ kfree(zbr->leaf); -+ zbr->leaf = NULL; -+} -+ -+/** -+ * tnc_read_node - read a leaf node from the flash media. -+ * @c: UBIFS file-system description object -+ * @zbr: key and position of the node -+ * @node: node is returned here -+ * -+ * This function reads a node defined by @zbr from the flash media. Returns -+ * zero in case of success or a negative negative error code in case of -+ * failure. -+ */ -+static int tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *node) -+{ -+ union ubifs_key key1, *key = &zbr->key; -+ int err, type = key_type(c, key); -+ struct ubifs_wbuf *wbuf; -+ -+ ubifs_assert(!zbr->leaf); -+ -+ /* -+ * 'zbr' has to point to on-flash node. The node may sit in a bud and -+ * may even be in a write buffer, so we have to take care about this. -+ */ -+ wbuf = ubifs_get_wbuf(c, zbr->lnum); -+ if (wbuf) -+ err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len, -+ zbr->lnum, zbr->offs); -+ else -+ err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum, -+ zbr->offs); -+ -+ if (err) { -+ dbg_tnc("key %s", DBGKEY(key)); -+ return err; -+ } -+ -+ /* Make sure the key of the read node is correct */ -+ key_read(c, key, &key1); -+ if (memcmp(node + UBIFS_KEY_OFFSET, &key1, c->key_len)) { -+ ubifs_err("bad key in node at LEB %d:%d", -+ zbr->lnum, zbr->offs); -+ dbg_tnc("looked for key %s found node's key %s", -+ DBGKEY(key), DBGKEY1(&key1)); -+ dbg_dump_node(c, node); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * tnc_read_node_nm - read a "hashed" leaf node. -+ * @c: UBIFS file-system description object -+ * @zbr: key and position of the node -+ * @node: node is returned here -+ * -+ * This function reads a "hashed" node defined by @zbr from the leaf node cache -+ * (in it is there) or from the hash media, in which case the node is also -+ * added to LNC. Returns zero in case of success or a negative negative error -+ * code in case of failure. -+ */ -+static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *node) -+{ -+ int err; -+ -+ ubifs_assert(is_hash_key(c, &zbr->key)); -+ -+ if (zbr->leaf) { -+ /* Read from the leaf node cache */ -+ ubifs_assert(zbr->len != 0); -+ memcpy(node, zbr->leaf, zbr->len); -+ return 0; -+ } -+ -+ err = tnc_read_node(c, zbr, node); -+ if (err) -+ return err; -+ -+ /* Add the node to the leaf node cache */ -+ err = lnc_add(c, zbr, node); -+ return err; -+} -+ -+/** -+ * try_read_node - read a node if it is a node. -+ * @c: UBIFS file-system description object -+ * @buf: buffer to read to -+ * @type: node type -+ * @len: node length (not aligned) -+ * @lnum: LEB number of node to read -+ * @offs: offset of node to read -+ * -+ * This function tries to read a node of known type and length, checks it and -+ * stores it in @buf. This function returns %1 if a node is present and %0 if -+ * a node is not present. A negative error code is returned for I/O errors. -+ * This function performs that same function as ubifs_read_node except that -+ * it does not require that there is actually a node present and instead -+ * the return code indicates if a node was read. -+ */ -+static int try_read_node(const struct ubifs_info *c, void *buf, int type, -+ int len, int lnum, int offs) -+{ -+ int err, node_len; -+ struct ubifs_ch *ch = buf; -+ uint32_t crc, node_crc; -+ -+ dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); -+ -+ err = ubi_read(c->ubi, lnum, buf, offs, len); -+ if (err) { -+ ubifs_err("cannot read node type %d from LEB %d:%d, error %d", -+ type, lnum, offs, err); -+ return err; -+ } -+ -+ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) -+ return 0; -+ -+ if (ch->node_type != type) -+ return 0; -+ -+ node_len = le32_to_cpu(ch->len); -+ if (node_len != len) -+ return 0; -+ -+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); -+ node_crc = le32_to_cpu(ch->crc); -+ if (crc != node_crc) -+ return 0; -+ -+ return 1; -+} -+ -+/** -+ * fallible_read_node - try to read a leaf node. -+ * @c: UBIFS file-system description object -+ * @key: key of node to read -+ * @zbr: position of node -+ * @node: node returned -+ * -+ * This function tries to read a node and returns %1 if the node is read, %0 -+ * if the node is not present, and a negative error code in the case of error. -+ */ -+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, -+ struct ubifs_zbranch *zbr, void *node) -+{ -+ int ret; -+ -+ dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key)); -+ -+ ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum, -+ zbr->offs); -+ if (ret == 1) { -+ union ubifs_key node_key; -+ struct ubifs_dent_node *dent = node; -+ -+ /* All nodes have key in the same place */ -+ key_read(c, &dent->key, &node_key); -+ if (keys_cmp(c, key, &node_key) != 0) -+ ret = 0; -+ } -+ if (ret == 0) -+ dbg_mnt("dangling branch LEB %d:%d len %d, key %s", -+ zbr->lnum, zbr->offs, zbr->len, DBGKEY(key)); -+ return ret; -+} -+ -+/** -+ * matches_name - determine if a directory or extended attribute entry matches -+ * a given name. -+ * @c: UBIFS file-system description object -+ * @zbr: zbranch of dent -+ * @nm: name to match -+ * -+ * This function checks if xentry/direntry referred by zbranch @zbr matches name -+ * @nm. Returns %NAME_MATCHES if it does, %NAME_LESS if the name referred by -+ * @zbr is less than @nm, and %NAME_GREATER if it is greater than @nm. In case -+ * of failure, a negative error code is returned. -+ */ -+static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ const struct qstr *nm) -+{ -+ struct ubifs_dent_node *dent; -+ int nlen, err; -+ -+ /* If possible, match against the dent in the leaf node cache */ -+ if (!zbr->leaf) { -+ dent = kmalloc(zbr->len, GFP_NOFS); -+ if (!dent) -+ return -ENOMEM; -+ -+ err = tnc_read_node(c, zbr, dent); -+ if (err) -+ goto out_free; -+ -+ /* Add the node to the leaf node cache */ -+ err = lnc_add_directly(c, zbr, dent); -+ if (err) -+ goto out_free; -+ } else -+ dent = zbr->leaf; -+ -+ nlen = le16_to_cpu(dent->nlen); -+ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); -+ if (err == 0) { -+ if (nlen == nm->len) -+ return NAME_MATCHES; -+ else if (nlen < nm->len) -+ return NAME_LESS; -+ else -+ return NAME_GREATER; -+ } else if (err < 0) -+ return NAME_LESS; -+ else -+ return NAME_GREATER; -+ -+out_free: -+ kfree(dent); -+ return err; -+} -+ -+/** -+ * get_znode - get a TNC znode that may not be loaded yet. -+ * @c: UBIFS file-system description object -+ * @znode: parent znode -+ * @n: znode branch slot number -+ * -+ * This function returns the znode or a negative error code. -+ */ -+static struct ubifs_znode *get_znode(struct ubifs_info *c, -+ struct ubifs_znode *znode, int n) -+{ -+ struct ubifs_zbranch *zbr; -+ -+ zbr = &znode->zbranch[n]; -+ if (zbr->znode) -+ znode = zbr->znode; -+ else -+ znode = load_znode(c, zbr, znode, n); -+ return znode; -+} -+ -+/** -+ * tnc_next - find next TNC entry. -+ * @c: UBIFS file-system description object -+ * @zn: znode is passed and returned here -+ * @n: znode branch slot number is passed and returned here -+ * -+ * This function returns %0 if the next TNC entry is found, %-ENOENT if there is -+ * no next entry, or a negative error code otherwise. -+ */ -+static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n) -+{ -+ struct ubifs_znode *znode = *zn; -+ int nn = *n; -+ -+ nn += 1; -+ if (nn < znode->child_cnt) { -+ *n = nn; -+ return 0; -+ } -+ while (1) { -+ struct ubifs_znode *zp; -+ -+ zp = znode->parent; -+ if (!zp) -+ return -ENOENT; -+ nn = znode->iip + 1; -+ znode = zp; -+ if (nn < znode->child_cnt) { -+ znode = get_znode(c, znode, nn); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ while (znode->level != 0) { -+ znode = get_znode(c, znode, 0); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ nn = 0; -+ break; -+ } -+ } -+ *zn = znode; -+ *n = nn; -+ return 0; -+} -+ -+/** -+ * tnc_prev - find previous TNC entry. -+ * @c: UBIFS file-system description object -+ * @zn: znode is returned here -+ * @n: znode branch slot number is passed and returned here -+ * -+ * This function returns %0 if the previous TNC entry is found, %-ENOENT if -+ * there is no next entry, or a negative error code otherwise. -+ */ -+static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n) -+{ -+ struct ubifs_znode *znode = *zn; -+ int nn = *n; -+ -+ if (nn > 0) { -+ *n = nn - 1; -+ return 0; -+ } -+ while (1) { -+ struct ubifs_znode *zp; -+ -+ zp = znode->parent; -+ if (!zp) -+ return -ENOENT; -+ nn = znode->iip - 1; -+ znode = zp; -+ if (nn >= 0) { -+ znode = get_znode(c, znode, nn); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ while (znode->level != 0) { -+ nn = znode->child_cnt - 1; -+ znode = get_znode(c, znode, nn); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ nn = znode->child_cnt - 1; -+ break; -+ } -+ } -+ *zn = znode; -+ *n = nn; -+ return 0; -+} -+ -+/** -+ * resolve_collision - resolve a collision. -+ * @c: UBIFS file-system description object -+ * @key: key of a directory or extended attribute entry -+ * @zn: znode is returned here -+ * @n: zbranch number is passed and returned here -+ * @nm: name of the entry -+ * -+ * This function is called for "hashed" keys to make sure that the found key -+ * really corresponds to the looked up node (directory or extended attribute -+ * entry). It returns %1 and sets @zn and @n if the collision is resolved. -+ * %0 is returned if @nm is not found and @zn and @n are set to the previous -+ * entry, i.e. to the entry after which @nm could follow if it were in TNC. -+ * This means that @n may be set to %-1 if the leftmost key in @zn is the -+ * previous one. A negative error code is returned on failures. -+ */ -+static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key, -+ struct ubifs_znode **zn, int *n, -+ const struct qstr *nm) -+{ -+ int err; -+ -+ err = matches_name(c, &(*zn)->zbranch[*n], nm); -+ if (unlikely(err < 0)) -+ return err; -+ if (err == NAME_MATCHES) -+ return 1; -+ -+ if (err == NAME_GREATER) { -+ /* Look left */ -+ while (1) { -+ err = tnc_prev(c, zn, n); -+ if (err == -ENOENT) { -+ ubifs_assert(*n == 0); -+ *n = -1; -+ return 0; -+ } -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) { -+ /* -+ * We have found the branch after which we would -+ * like to insert, but inserting in this znode -+ * may still be wrong. Consider the following 3 -+ * znodes, in the case where we are resolving a -+ * collision with Key2. -+ * -+ * znode zp -+ * ---------------------- -+ * level 1 | Key0 | Key1 | -+ * ----------------------- -+ * | | -+ * znode za | | znode zb -+ * ------------ ------------ -+ * level 0 | Key0 | | Key2 | -+ * ------------ ------------ -+ * -+ * The lookup finds Key2 in znode zb. Lets say -+ * there is no match and the name is greater so -+ * we look left. When we find Key0, we end up -+ * here. If we return now, we will insert into -+ * znode za at slot n = 1. But that is invalid -+ * according to the parent's keys. Key2 must -+ * be inserted into znode zb. -+ * -+ * Note, this problem is not relevant for the -+ * case when we go right, because -+ * 'tnc_insert()' would correct the parent key. -+ */ -+ if (*n == (*zn)->child_cnt - 1) { -+ err = tnc_next(c, zn, n); -+ if (err) { -+ /* Should be impossible */ -+ ubifs_assert(0); -+ if (err == -ENOENT) -+ err = -EINVAL; -+ return err; -+ } -+ ubifs_assert(*n == 0); -+ *n = -1; -+ } -+ return 0; -+ } -+ err = matches_name(c, &(*zn)->zbranch[*n], nm); -+ if (err < 0) -+ return err; -+ if (err == NAME_LESS) -+ return 0; -+ if (err == NAME_MATCHES) -+ return 1; -+ ubifs_assert(err == NAME_GREATER); -+ } -+ } else { -+ int nn = *n; -+ struct ubifs_znode *znode = *zn; -+ -+ /* Look right */ -+ while (1) { -+ err = tnc_next(c, &znode, &nn); -+ if (err == -ENOENT) -+ return 0; -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &znode->zbranch[nn].key, key)) -+ return 0; -+ err = matches_name(c, &znode->zbranch[nn], nm); -+ if (err < 0) -+ return err; -+ if (err == NAME_GREATER) -+ return 0; -+ *zn = znode; -+ *n = nn; -+ if (err == NAME_MATCHES) -+ return 1; -+ ubifs_assert(err == NAME_LESS); -+ } -+ } -+} -+ -+/** -+ * fallible_matches_name - determine if a dent matches a given name. -+ * @c: UBIFS file-system description object -+ * @zbr: zbranch of dent -+ * @nm: name to match -+ * -+ * This is a "fallible" version of 'matches_name()' function which does not -+ * panic if the direntry/xentry referred by @zbr does not exist on the media. -+ * -+ * This function checks if xentry/direntry referred by zbranch @zbr matches name -+ * @nm. Returns %NAME_MATCHES it does, %NAME_LESS if the name referred by @zbr -+ * is less than @nm, %NAME_GREATER if it is greater than @nm, and @NOT_ON_MEDIA -+ * if xentry/direntry referred by @zbr does not exist on the media. A negative -+ * error code is returned in case of failure. -+ */ -+static int fallible_matches_name(struct ubifs_info *c, -+ struct ubifs_zbranch *zbr, -+ const struct qstr *nm) -+{ -+ struct ubifs_dent_node *dent; -+ int nlen, err; -+ -+ /* If possible, match against the dent in the leaf node cache */ -+ if (!zbr->leaf) { -+ dent = kmalloc(zbr->len, GFP_NOFS); -+ if (!dent) -+ return -ENOMEM; -+ -+ err = fallible_read_node(c, &zbr->key, zbr, dent); -+ if (err < 0) -+ goto out_free; -+ if (err == 0) { -+ /* The node was not present */ -+ err = NOT_ON_MEDIA; -+ goto out_free; -+ } -+ ubifs_assert(err == 1); -+ -+ err = lnc_add_directly(c, zbr, dent); -+ if (err) -+ goto out_free; -+ } else -+ dent = zbr->leaf; -+ -+ nlen = le16_to_cpu(dent->nlen); -+ err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); -+ if (err == 0) { -+ if (nlen == nm->len) -+ return NAME_MATCHES; -+ else if (nlen < nm->len) -+ return NAME_LESS; -+ else -+ return NAME_GREATER; -+ } else if (err < 0) -+ return NAME_LESS; -+ else -+ return NAME_GREATER; -+ -+out_free: -+ kfree(dent); -+ return err; -+} -+ -+/** -+ * fallible_resolve_collision - resolve a collision even if nodes are missing. -+ * @c: UBIFS file-system description object -+ * @key: key -+ * @zn: znode is returned here -+ * @n: branch number is passed and returned here -+ * @nm: name of directory entry -+ * @adding: indicates caller is adding a key to the TNC -+ * -+ * This is a "fallible" version of the 'resolve_collision()' function which -+ * does not panic if one of the nodes referred to by TNC does not exist on the -+ * media. This may happen when replaying the journal if a deleted node was -+ * Garbage-collected and the commit was not done. A branch that refers to a node -+ * that is not present is called a dangling branch. The following are the return -+ * codes for this function: -+ * o if @nm was found, %1 is returned and @zn and @n are set to the found -+ * branch; -+ * o if we are @adding and @nm was not found, %0 is returned; -+ * o if we are not @adding and @nm was not found, but a dangling branch was -+ * found, then %1 is returned and @zn and @n are set to the dangling branch; -+ * o a negative error code is returned in case of failure. -+ */ -+static int fallible_resolve_collision(struct ubifs_info *c, -+ const union ubifs_key *key, -+ struct ubifs_znode **zn, int *n, -+ const struct qstr *nm, int adding) -+{ -+ struct ubifs_znode *o_znode = NULL, *znode = *zn; -+ int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n; -+ -+ cmp = fallible_matches_name(c, &znode->zbranch[nn], nm); -+ if (unlikely(cmp < 0)) -+ return cmp; -+ if (cmp == NAME_MATCHES) -+ return 1; -+ if (cmp == NOT_ON_MEDIA) { -+ o_znode = znode; -+ o_n = nn; -+ /* -+ * We are unlucky and hit a dangling branch straight away. -+ * Now we do not really know where to go to find the needed -+ * branch - to the left or to the right. Well, let's try left. -+ */ -+ unsure = 1; -+ } else if (!adding) -+ unsure = 1; /* Remove a dangling branch wherever it is */ -+ -+ if (cmp == NAME_GREATER || unsure) { -+ /* Look left */ -+ while (1) { -+ err = tnc_prev(c, zn, n); -+ if (err == -ENOENT) { -+ ubifs_assert(*n == 0); -+ *n = -1; -+ break; -+ } -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &(*zn)->zbranch[*n].key, key)) { -+ /* See comments in 'resolve_collision()' */ -+ if (*n == (*zn)->child_cnt - 1) { -+ err = tnc_next(c, zn, n); -+ if (err) { -+ /* Should be impossible */ -+ ubifs_assert(0); -+ if (err == -ENOENT) -+ err = -EINVAL; -+ return err; -+ } -+ ubifs_assert(*n == 0); -+ *n = -1; -+ } -+ break; -+ } -+ err = fallible_matches_name(c, &(*zn)->zbranch[*n], nm); -+ if (err < 0) -+ return err; -+ if (err == NAME_MATCHES) -+ return 1; -+ if (err == NOT_ON_MEDIA) { -+ o_znode = *zn; -+ o_n = *n; -+ continue; -+ } -+ if (!adding) -+ continue; -+ if (err == NAME_LESS) -+ break; -+ else -+ unsure = 0; -+ } -+ } -+ -+ if (cmp == NAME_LESS || unsure) { -+ /* Look right */ -+ *zn = znode; -+ *n = nn; -+ while (1) { -+ err = tnc_next(c, &znode, &nn); -+ if (err == -ENOENT) -+ break; -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &znode->zbranch[nn].key, key)) -+ break; -+ err = fallible_matches_name(c, &znode->zbranch[nn], nm); -+ if (err < 0) -+ return err; -+ if (err == NAME_GREATER) -+ break; -+ *zn = znode; -+ *n = nn; -+ if (err == NAME_MATCHES) -+ return 1; -+ if (err == NOT_ON_MEDIA) { -+ o_znode = znode; -+ o_n = nn; -+ } -+ } -+ } -+ -+ /* Never match a dangling branch when adding */ -+ if (adding || !o_znode) -+ return 0; -+ -+ dbg_mnt("dangling match LEB %d:%d len %d %s", -+ o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs, -+ o_znode->zbranch[o_n].len, DBGKEY(key)); -+ *zn = o_znode; -+ *n = o_n; -+ return 1; -+} -+ -+/** -+ * matches_position - determine if a zbranch matches a given position. -+ * @zbr: zbranch of dent -+ * @lnum: LEB number of dent to match -+ * @offs: offset of dent to match -+ * -+ * This function returns %1 if @lnum:@offs matches, and %0 otherwise. -+ */ -+static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs) -+{ -+ if (zbr->lnum == lnum && zbr->offs == offs) -+ return 1; -+ else -+ return 0; -+} -+ -+/** -+ * resolve_collision_directly - resolve a collision directly. -+ * @c: UBIFS file-system description object -+ * @key: key of directory entry -+ * @zn: znode is passed and returned here -+ * @n: zbranch number is passed and returned here -+ * @lnum: LEB number of dent node to match -+ * @offs: offset of dent node to match -+ * -+ * This function is used for "hashed" keys to make sure the found directory or -+ * extended attribute entry node is what was looked for. It is used when the -+ * flash address of the right node is known (@lnum:@offs) which makes it much -+ * easier to resolve collisions (no need to read entries and match full -+ * names). This function returns %1 and sets @zn and @n if the collision is -+ * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the -+ * previous directory entry. Otherwise a negative error code is returned. -+ */ -+static int resolve_collision_directly(struct ubifs_info *c, -+ const union ubifs_key *key, -+ struct ubifs_znode **zn, int *n, -+ int lnum, int offs) -+{ -+ struct ubifs_znode *znode; -+ int nn, err; -+ -+ znode = *zn; -+ nn = *n; -+ if (matches_position(&znode->zbranch[nn], lnum, offs)) -+ return 1; -+ -+ /* Look left */ -+ while (1) { -+ err = tnc_prev(c, &znode, &nn); -+ if (err == -ENOENT) -+ break; -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &znode->zbranch[nn].key, key)) -+ break; -+ if (matches_position(&znode->zbranch[nn], lnum, offs)) { -+ *zn = znode; -+ *n = nn; -+ return 1; -+ } -+ } -+ -+ /* Look right */ -+ znode = *zn; -+ nn = *n; -+ while (1) { -+ err = tnc_next(c, &znode, &nn); -+ if (err == -ENOENT) -+ return 0; -+ if (err < 0) -+ return err; -+ if (keys_cmp(c, &znode->zbranch[nn].key, key)) -+ return 0; -+ *zn = znode; -+ *n = nn; -+ if (matches_position(&znode->zbranch[nn], lnum, offs)) -+ return 1; -+ } -+} -+ -+/** -+ * dirty_cow_bottom_up - dirty a znode and its ancestors. -+ * @c: UBIFS file-system description object -+ * @znode: znode to dirty -+ * -+ * If we do not have a unique key that resides in a znode, then we cannot -+ * dirty that znode from the top down (i.e. by using lookup_level0_dirty) -+ * This function records the path back to the last dirty ancestor, and then -+ * dirties the znodes on that path. -+ */ -+static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ struct ubifs_znode *zp; -+ int *path = c->bottom_up_buf, p = 0; -+ -+ ubifs_assert(c->zroot.znode); -+ ubifs_assert(znode); -+ if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) { -+ kfree(c->bottom_up_buf); -+ c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int), -+ GFP_NOFS); -+ if (!c->bottom_up_buf) -+ return ERR_PTR(-ENOMEM); -+ path = c->bottom_up_buf; -+ } -+ if (c->zroot.znode->level) { -+ /* Go up until parent is dirty */ -+ while (1) { -+ int n; -+ -+ zp = znode->parent; -+ if (!zp) -+ break; -+ n = znode->iip; -+ ubifs_assert(p < c->zroot.znode->level); -+ path[p++] = n; -+ if (!zp->cnext && ubifs_zn_dirty(znode)) -+ break; -+ znode = zp; -+ } -+ } -+ -+ /* Come back down, dirtying as we go */ -+ while (1) { -+ struct ubifs_zbranch *zbr; -+ -+ zp = znode->parent; -+ if (zp) { -+ ubifs_assert(path[p - 1] >= 0); -+ ubifs_assert(path[p - 1] < zp->child_cnt); -+ zbr = &zp->zbranch[path[--p]]; -+ znode = dirty_cow_znode(c, zbr); -+ } else { -+ ubifs_assert(znode == c->zroot.znode); -+ znode = dirty_cow_znode(c, &c->zroot); -+ } -+ if (unlikely(IS_ERR(znode)) || !p) -+ break; -+ ubifs_assert(path[p - 1] >= 0); -+ ubifs_assert(path[p - 1] < znode->child_cnt); -+ znode = znode->zbranch[path[p - 1]].znode; -+ } -+ -+ return znode; -+} -+ -+/** -+ * lookup_level0 - search for zero-level znode. -+ * @c: UBIFS file-system description object -+ * @key: key to lookup -+ * @zn: znode is returned here -+ * @n: znode branch slot number is returned here -+ * -+ * This function looks up the TNC tree and search for zero-level znode which -+ * refers key @key. The found zero-level znode is returned in @zn. There are 3 -+ * cases: -+ * o exact match, i.e. the found zero-level znode contains key @key, then %1 -+ * is returned and slot number of the matched branch is stored in @n; -+ * o not exact match, which means that zero-level znode does not contain -+ * @key, then %0 is returned and slot number of the closed branch is stored -+ * in @n; -+ * o @key is so small that it is even less than the lowest key of the -+ * leftmost zero-level node, then %0 is returned and %0 is stored in @n. -+ * -+ * Note, when the TNC tree is traversed, some znodes may be absent, then this -+ * function reads corresponding indexing nodes and inserts them to TNC. In -+ * case of failure, a negative error code is returned. -+ */ -+static int lookup_level0(struct ubifs_info *c, const union ubifs_key *key, -+ struct ubifs_znode **zn, int *n) -+{ -+ int err, exact; -+ struct ubifs_znode *znode; -+ unsigned long time = get_seconds(); -+ -+ dbg_tnc("search key %s", DBGKEY(key)); -+ -+ znode = c->zroot.znode; -+ if (unlikely(!znode)) { -+ znode = load_znode(c, &c->zroot, NULL, 0); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ -+ znode->time = time; -+ -+ while (1) { -+ struct ubifs_zbranch *zbr; -+ -+ exact = ubifs_search_zbranch(c, znode, key, n); -+ -+ if (znode->level == 0) -+ break; -+ -+ if (*n < 0) -+ *n = 0; -+ zbr = &znode->zbranch[*n]; -+ -+ if (zbr->znode) { -+ znode->time = time; -+ znode = zbr->znode; -+ continue; -+ } -+ -+ /* znode is not in TNC cache, load it from the media */ -+ znode = load_znode(c, zbr, znode, *n); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ -+ *zn = znode; -+ if (exact || !is_hash_key(c, key) || *n != -1) { -+ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n); -+ return exact; -+ } -+ -+ /* -+ * Here is a tricky place. We have not found the key and this is a -+ * "hashed" key, which may collide. The rest of the code deals with -+ * situations like this: -+ * -+ * | 3 | 5 | -+ * / \ -+ * | 3 | 5 | | 6 | 7 | (x) -+ * -+ * Or more a complex example: -+ * -+ * | 1 | 5 | -+ * / \ -+ * | 1 | 3 | | 5 | 8 | -+ * \ / -+ * | 5 | 5 | | 6 | 7 | (x) -+ * -+ * In the examples, if we are looking for key "5", we may reach nodes -+ * marked with "(x)". In this case what we have do is to look at the -+ * left and see if there is "5" key there. If there is, we have to -+ * return it. -+ * -+ * Note, this whole situation is possible because we allow to have -+ * elements which are equivalent to the next key in the parent in the -+ * children of current znode. For example, this happens if we split a -+ * znode like this: | 3 | 5 | 5 | 6 | 7 |, which results in something -+ * like this: -+ * | 3 | 5 | -+ * / \ -+ * | 3 | 5 | | 5 | 6 | 7 | -+ * ^ -+ * And this becomes what is at the first "picture" after key "5" marked -+ * with "^" is removed. What could be done is we could prohibit -+ * splitting in the middle of the colliding sequence. Also, when -+ * removing the leftmost key, we would have to correct the key of the -+ * parent node, which would introduce additional complications. Namely, -+ * if we changed the the leftmost key of the parent znode, the garbage -+ * collector would be unable to find it (GC is doing this when GC'ing -+ * indexing LEBs). Although we already have an additional RB-tree where -+ * we save such changed znodes (see 'ins_clr_old_idx_znode()') until -+ * after the commit. But anyway, this does not look easy to implement -+ * so we did not try this. -+ */ -+ err = tnc_prev(c, &znode, n); -+ if (err == -ENOENT) { -+ dbg_tnc("found 0, lvl %d, n -1", znode->level); -+ *n = -1; -+ return 0; -+ } -+ if (unlikely(err < 0)) -+ return err; -+ if (keys_cmp(c, key, &znode->zbranch[*n].key)) { -+ dbg_tnc("found 0, lvl %d, n -1", znode->level); -+ *n = -1; -+ return 0; -+ } -+ -+ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n); -+ *zn = znode; -+ return 1; -+} -+ -+/** -+ * lookup_level0_dirty - search for zero-level znode dirtying. -+ * @c: UBIFS file-system description object -+ * @key: key to lookup -+ * @zn: znode is returned here -+ * @n: znode branch slot number is returned here -+ * -+ * This function looks up the TNC tree and search for zero-level znode which -+ * refers key @key. The found zero-level znode is returned in @zn. There are 3 -+ * cases: -+ * o exact match, i.e. the found zero-level znode contains key @key, then %1 -+ * is returned and slot number of the matched branch is stored in @n; -+ * o not exact match, which means that zero-level znode does not contain @key -+ * then %0 is returned and slot number of the closed branch is stored in -+ * @n; -+ * o @key is so small that it is even less than the lowest key of the -+ * leftmost zero-level node, then %0 is returned and %-1 is stored in @n. -+ * -+ * Additionally all znodes in the path from the root to the located zero-level -+ * znode are marked as dirty. -+ * -+ * Note, when the TNC tree is traversed, some znodes may be absent, then this -+ * function reads corresponding indexing nodes and inserts them to TNC. In -+ * case of failure, a negative error code is returned. -+ */ -+static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key, -+ struct ubifs_znode **zn, int *n) -+{ -+ int err, exact; -+ struct ubifs_znode *znode; -+ unsigned long time = get_seconds(); -+ -+ dbg_tnc("search and dirty key %s", DBGKEY(key)); -+ -+ znode = c->zroot.znode; -+ if (unlikely(!znode)) { -+ znode = load_znode(c, &c->zroot, NULL, 0); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ -+ znode = dirty_cow_znode(c, &c->zroot); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ -+ znode->time = time; -+ -+ while (1) { -+ struct ubifs_zbranch *zbr; -+ -+ exact = ubifs_search_zbranch(c, znode, key, n); -+ -+ if (znode->level == 0) -+ break; -+ -+ if (*n < 0) -+ *n = 0; -+ zbr = &znode->zbranch[*n]; -+ -+ if (zbr->znode) { -+ znode->time = time; -+ znode = dirty_cow_znode(c, zbr); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ continue; -+ } -+ -+ /* znode is not in TNC cache, load it from the media */ -+ znode = load_znode(c, zbr, znode, *n); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ znode = dirty_cow_znode(c, zbr); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ -+ *zn = znode; -+ if (exact || !is_hash_key(c, key) || *n != -1) { -+ dbg_tnc("found %d, lvl %d, n %d", exact, znode->level, *n); -+ return exact; -+ } -+ -+ /* -+ * See huge comment at 'lookup_level0_dirty()' what is the rest of the -+ * code. -+ */ -+ err = tnc_prev(c, &znode, n); -+ if (err == -ENOENT) { -+ *n = -1; -+ dbg_tnc("found 0, lvl %d, n -1", znode->level); -+ return 0; -+ } -+ if (unlikely(err < 0)) -+ return err; -+ if (keys_cmp(c, key, &znode->zbranch[*n].key)) { -+ *n = -1; -+ dbg_tnc("found 0, lvl %d, n -1", znode->level); -+ return 0; -+ } -+ -+ if (znode->cnext || !ubifs_zn_dirty(znode)) { -+ znode = dirty_cow_bottom_up(c, znode); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ } -+ -+ dbg_tnc("found 1, lvl %d, n %d", znode->level, *n); -+ *zn = znode; -+ return 1; -+} -+ -+/** -+ * ubifs_tnc_lookup - look up a file-system node. -+ * @c: UBIFS file-system description object -+ * @key: node key to lookup -+ * @node: the node is returned here -+ * -+ * This function look up and reads node with key @key. The caller has to make -+ * sure the @node buffer is large enough to fit the node. Returns zero in case -+ * of success, %-ENOENT if the node was not found, and a negative error code in -+ * case of failure. -+ */ -+int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, -+ void *node) -+{ -+ int found, n, err; -+ struct ubifs_znode *znode; -+ struct ubifs_zbranch zbr, *zt; -+ -+ mutex_lock(&c->tnc_mutex); -+ found = lookup_level0(c, key, &znode, &n); -+ if (!found) { -+ err = -ENOENT; -+ goto out; -+ } else if (found < 0) { -+ err = found; -+ goto out; -+ } -+ zt = &znode->zbranch[n]; -+ if (is_hash_key(c, key)) { -+ /* -+ * In this case the leaf node cache gets used, so we pass the -+ * address of the zbranch and keep the mutex locked -+ */ -+ err = tnc_read_node_nm(c, zt, node); -+ goto out; -+ } -+ zbr = znode->zbranch[n]; -+ mutex_unlock(&c->tnc_mutex); -+ -+ err = tnc_read_node(c, &zbr, node); -+ return err; -+ -+out: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_tnc_locate - look up a file-system node and return it and its location. -+ * @c: UBIFS file-system description object -+ * @key: node key to lookup -+ * @node: the node is returned here -+ * @lnum: LEB number is returned here -+ * @offs: offset is returned here -+ * -+ * This function is the same as 'ubifs_tnc_lookup()' but it returns the node -+ * location also. See 'ubifs_tnc_lookup()'. -+ */ -+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, -+ void *node, int *lnum, int *offs) -+{ -+ int found, n, err; -+ struct ubifs_znode *znode; -+ struct ubifs_zbranch zbr, *zt; -+ -+ mutex_lock(&c->tnc_mutex); -+ found = lookup_level0(c, key, &znode, &n); -+ if (!found) { -+ err = -ENOENT; -+ goto out; -+ } else if (found < 0) { -+ err = found; -+ goto out; -+ } -+ zt = &znode->zbranch[n]; -+ if (is_hash_key(c, key)) { -+ /* -+ * In this case the leaf node cache gets used, so we pass the -+ * address of the zbranch and keep the mutex locked -+ */ -+ *lnum = zt->lnum; -+ *offs = zt->offs; -+ err = tnc_read_node_nm(c, zt, node); -+ goto out; -+ } -+ zbr = znode->zbranch[n]; -+ mutex_unlock(&c->tnc_mutex); -+ -+ *lnum = zbr.lnum; -+ *offs = zbr.offs; -+ -+ err = tnc_read_node(c, &zbr, node); -+ return err; -+ -+out: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * do_lookup_nm- look up a "hashed" node. -+ * directory entry file-system node. -+ * @c: UBIFS file-system description object -+ * @key: node key to lookup -+ * @node: the node is returned here -+ * @nm: node name -+ * -+ * This function look up and reads a node which contains name hash in the key. -+ * Since the hash may have collisions, there may be many nodes with the same -+ * key, so we have to sequentially look to all of them until the needed one is -+ * found. This function returns zero in case of success, %-ENOENT if the node -+ * was not found, and a negative error code in case of failure. -+ */ -+static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, -+ void *node, const struct qstr *nm) -+{ -+ int found, n, err; -+ struct ubifs_znode *znode; -+ struct ubifs_zbranch zbr; -+ -+ dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key)); -+ mutex_lock(&c->tnc_mutex); -+ found = lookup_level0(c, key, &znode, &n); -+ if (!found) { -+ err = -ENOENT; -+ goto out_unlock; -+ } else if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ -+ ubifs_assert(n >= 0); -+ -+ err = resolve_collision(c, key, &znode, &n, nm); -+ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n); -+ if (unlikely(err < 0)) -+ goto out_unlock; -+ if (err == 0) { -+ err = -ENOENT; -+ goto out_unlock; -+ } -+ -+ zbr = znode->zbranch[n]; -+ mutex_unlock(&c->tnc_mutex); -+ -+ err = tnc_read_node_nm(c, &zbr, node); -+ return err; -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_tnc_lookup_nm- look up a "hashed" node. -+ * directory entry file-system node. -+ * @c: UBIFS file-system description object -+ * @key: node key to lookup -+ * @node: the node is returned here -+ * @nm: node name -+ * -+ * This function look up and reads a node which contains name hash in the key. -+ * Since the hash may have collisions, there may be many nodes with the same -+ * key, so we have to sequentially look to all of them until the needed one is -+ * found. This function returns zero in case of success, %-ENOENT if the node -+ * was not found, and a negative error code in case of failure. -+ */ -+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, -+ void *node, const struct qstr *nm) -+{ -+ int err, len; -+ const struct ubifs_dent_node *dent = node; -+ -+ /* -+ * We assume that in most of the cases there are no name collisions and -+ * 'ubifs_tnc_lookup()' returns us the right direntry. -+ */ -+ err = ubifs_tnc_lookup(c, key, node); -+ if (err) -+ return err; -+ -+ len = le16_to_cpu(dent->nlen); -+ if (nm->len == len && !memcmp(dent->name, nm->name, len)) -+ return 0; -+ -+ /* -+ * Unluckily, there are hash collisions and we have to iterate over -+ * them look at each direntry with colliding name hash sequentially. -+ */ -+ return do_lookup_nm(c, key, node, nm); -+} -+ -+/** -+ * correct_parent_keys - correct parent znodes' keys. -+ * @c: UBIFS file-system description object -+ * @znode: znode to correct parent znodes for -+ * -+ * This is a helper function for 'tnc_insert()'. When the key of the leftmost -+ * zbranch changes, keys of parent znodes have to be corrected. This helper -+ * function is called in such situations and corrects the keys if needed. -+ */ -+static void correct_parent_keys(const struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ union ubifs_key *key, *key1; -+ -+ ubifs_assert(znode->parent); -+ ubifs_assert(znode->iip == 0); -+ -+ key = &znode->zbranch[0].key; -+ key1 = &znode->parent->zbranch[0].key; -+ -+ while (keys_cmp(c, key, key1) < 0) { -+ key_copy(c, key, key1); -+ znode = znode->parent; -+ if (!znode->parent || znode->iip) -+ break; -+ key1 = &znode->parent->zbranch[0].key; -+ } -+} -+ -+/** -+ * insert_zbranch - insert a zbranch into a znode. -+ * @znode: znode into which to insert -+ * @zbr: zbranch to insert -+ * @n: slot number to insert to -+ * -+ * This is a helper function for 'tnc_insert()'. UBIFS does not allow "gaps" in -+ * znode's array of zbranches and keeps zbranches consolidated, so when a new -+ * zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th -+ * slot, zbranches starting from @n have to be moved right. -+ */ -+static void insert_zbranch(struct ubifs_znode *znode, -+ const struct ubifs_zbranch *zbr, int n) -+{ -+ int i; -+ -+ ubifs_assert(ubifs_zn_dirty(znode)); -+ -+ if (znode->level) { -+ for (i = znode->child_cnt; i > n; i--) { -+ znode->zbranch[i] = znode->zbranch[i - 1]; -+ if (znode->zbranch[i].znode) -+ znode->zbranch[i].znode->iip = i; -+ } -+ if (zbr->znode) -+ zbr->znode->iip = n; -+ } else -+ for (i = znode->child_cnt; i > n; i--) -+ znode->zbranch[i] = znode->zbranch[i - 1]; -+ -+ znode->zbranch[n] = *zbr; -+ znode->child_cnt += 1; -+ -+ /* -+ * After inserting at slot zero, the lower bound of the key range of -+ * this znode may have changed. If this znode is subsequently split -+ * then the upper bound of the key range may change, and furthermore -+ * it could change to be lower than the original lower bound. If that -+ * happens, then it will no longer be possible to find this znode in the -+ * TNC using the key from the index node on flash. That is bad because -+ * if it is not found, we will assume it is obsolete and may overwrite -+ * it. Then if there is an unclean unmount, we will start using the -+ * old index which will be broken. -+ * -+ * So we first mark znodes that have insertions at slot zero, and then -+ * if they are split we add their lnum/offs to the old_idx tree. -+ */ -+ if (n == 0) -+ znode->alt = 1; -+} -+ -+/** -+ * tnc_insert - insert a node into TNC. -+ * @c: UBIFS file-system description object -+ * @znode: znode to insert into -+ * @zbr: branch to insert -+ * @n: slot number to insert new zbranch to -+ * -+ * This function inserts a new node described by @zbr into znode @znode. If -+ * znode does not have a free slot for new zbranch, it is split. Parent znodes -+ * are splat as well if needed. Returns zero in case of success or a negative -+ * error code in case of failure. -+ */ -+static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode, -+ struct ubifs_zbranch *zbr, int n) -+{ -+ struct ubifs_znode *zn, *zi, *zp; -+ int i, keep, move, appending = 0; -+ union ubifs_key *key = &zbr->key; -+ -+ ubifs_assert(n >= 0 && n <= c->fanout); -+ -+ /* Implement naive insert for now */ -+again: -+ zp = znode->parent; -+ if (znode->child_cnt < c->fanout) { -+ ubifs_assert(n != c->fanout); -+ dbg_tnc("inserted at %d level %d, key %s", n, znode->level, -+ DBGKEY(key)); -+ -+ insert_zbranch(znode, zbr, n); -+ -+ /* Ensure parent's key is correct */ -+ if (n == 0 && zp && znode->iip == 0) -+ correct_parent_keys(c, znode); -+ -+ return 0; -+ } -+ -+ /* -+ * Unfortunately, @znode does not have more empty slots and we have to -+ * split it. -+ */ -+ dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key)); -+ -+ if (znode->alt) -+ /* -+ * We can no longer be sure of finding this znode by key, so we -+ * record it in the old_idx tree. -+ */ -+ ins_clr_old_idx_znode(c, znode); -+ -+ zn = kzalloc(c->max_znode_sz, GFP_NOFS); -+ if (!zn) -+ return -ENOMEM; -+ zn->parent = zp; -+ zn->level = znode->level; -+ -+ /* Decide where to split */ -+ if (znode->level == 0 && n == c->fanout && -+ key_type(c, key) == UBIFS_DATA_KEY) { -+ union ubifs_key *key1; -+ -+ /* -+ * If this is an inode which is being appended - do not split -+ * it because no other zbranches can be inserted between -+ * zbranches of consecutive data nodes anyway. -+ */ -+ key1 = &znode->zbranch[n - 1].key; -+ if (key_ino(c, key1) == key_ino(c, key) && -+ key_type(c, key1) == UBIFS_DATA_KEY && -+ key_block(c, key1) == key_block(c, key) - 1) -+ appending = 1; -+ } -+ -+ if (appending) { -+ keep = c->fanout; -+ move = 0; -+ } else { -+ keep = (c->fanout + 1) / 2; -+ move = c->fanout - keep; -+ } -+ -+ /* -+ * Although we don't at present, we could look at the neighbors and see -+ * if we can move some zbranches there. -+ */ -+ -+ if (n < keep) { -+ /* Insert into existing znode */ -+ zi = znode; -+ move += 1; -+ keep -= 1; -+ } else { -+ /* Insert into new znode */ -+ zi = zn; -+ n -= keep; -+ /* Re-parent */ -+ if (zn->level != 0) -+ zbr->znode->parent = zn; -+ } -+ -+ __set_bit(DIRTY_ZNODE, &zn->flags); -+ atomic_long_inc(&c->dirty_zn_cnt); -+ -+ zn->child_cnt = move; -+ znode->child_cnt = keep; -+ -+ dbg_tnc("moving %d, keeping %d", move, keep); -+ -+ /* Move zbranch */ -+ for (i = 0; i < move; i++) { -+ zn->zbranch[i] = znode->zbranch[keep + i]; -+ /* Re-parent */ -+ if (zn->level != 0) -+ if (zn->zbranch[i].znode) { -+ zn->zbranch[i].znode->parent = zn; -+ zn->zbranch[i].znode->iip = i; -+ } -+ } -+ -+ /* Insert new key and branch */ -+ dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key)); -+ -+ insert_zbranch(zi, zbr, n); -+ -+ /* Insert new znode (produced by spitting) into the parent */ -+ if (zp) { -+ i = n; -+ /* Locate insertion point */ -+ n = znode->iip + 1; -+ if (appending && n != c->fanout) -+ appending = 0; -+ -+ if (i == 0 && zi == znode && znode->iip == 0) -+ correct_parent_keys(c, znode); -+ -+ /* Tail recursion */ -+ zbr->key = zn->zbranch[0].key; -+ zbr->znode = zn; -+ zbr->lnum = 0; -+ zbr->offs = 0; -+ zbr->len = 0; -+ znode = zp; -+ -+ goto again; -+ } -+ -+ /* We have to split root znode */ -+ dbg_tnc("creating new zroot at level %d", znode->level + 1); -+ -+ zi = kzalloc(c->max_znode_sz, GFP_NOFS); -+ if (!zi) -+ return -ENOMEM; -+ -+ zi->child_cnt = 2; -+ zi->level = znode->level + 1; -+ -+ __set_bit(DIRTY_ZNODE, &zi->flags); -+ atomic_long_inc(&c->dirty_zn_cnt); -+ -+ zi->zbranch[0].key = znode->zbranch[0].key; -+ zi->zbranch[0].znode = znode; -+ zi->zbranch[0].lnum = c->zroot.lnum; -+ zi->zbranch[0].offs = c->zroot.offs; -+ zi->zbranch[0].len = c->zroot.len; -+ zi->zbranch[1].key = zn->zbranch[0].key; -+ zi->zbranch[1].znode = zn; -+ -+ c->zroot.lnum = 0; -+ c->zroot.offs = 0; -+ c->zroot.len = 0; -+ c->zroot.znode = zi; -+ -+ zn->parent = zi; -+ zn->iip = 1; -+ znode->parent = zi; -+ znode->iip = 0; -+ -+ return 0; -+} -+ -+/** -+ * ubifs_tnc_add - add a node to TNC. -+ * @c: UBIFS file-system description object -+ * @key: key to add -+ * @lnum: LEB number of node -+ * @offs: node offset -+ * @len: node length -+ * -+ * This function adds a node with key @key to TNC. The node may be new or it may -+ * obsolete some existing one. Returns %0 on success or negative error code on -+ * failure. -+ */ -+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, -+ int offs, int len) -+{ -+ int found, n, err = 0; -+ struct ubifs_znode *znode; -+ -+ mutex_lock(&c->tnc_mutex); -+ dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key)); -+ found = lookup_level0_dirty(c, key, &znode, &n); -+ if (!found) { -+ struct ubifs_zbranch zbr; -+ -+ zbr.znode = NULL; -+ zbr.lnum = lnum; -+ zbr.offs = offs; -+ zbr.len = len; -+ key_copy(c, key, &zbr.key); -+ err = tnc_insert(c, znode, &zbr, n + 1); -+ } else if (found == 1) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[n]; -+ -+ lnc_free(zbr); -+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ } else -+ err = found; -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ mutex_unlock(&c->tnc_mutex); -+ -+ return err; -+} -+ -+/** -+ * ubifs_tnc_replace - replace a node in the TNC only if the old node is found. -+ * @c: UBIFS file-system description object -+ * @key: key to add -+ * @old_lnum: LEB number of old node -+ * @old_offs: old node offset -+ * @lnum: LEB number of node -+ * @offs: node offset -+ * @len: node length -+ * -+ * This function replaces a node with key @key in the TNC only if the old node -+ * is found. This function is called by garbage collection when node are moved. -+ * Returns %0 on success or negative error code on failure. -+ */ -+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, -+ int old_lnum, int old_offs, int lnum, int offs, int len) -+{ -+ int found, n, err = 0; -+ struct ubifs_znode *znode; -+ -+ mutex_lock(&c->tnc_mutex); -+ dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum, -+ old_offs, lnum, offs, len, DBGKEY(key)); -+ found = lookup_level0_dirty(c, key, &znode, &n); -+ if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ -+ if (found == 1) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[n]; -+ -+ found = 0; -+ if (zbr->lnum == old_lnum && zbr->offs == old_offs) { -+ lnc_free(zbr); -+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); -+ if (err) -+ goto out_unlock; -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ found = 1; -+ } else if (is_hash_key(c, key)) { -+ found = resolve_collision_directly(c, key, &znode, &n, -+ old_lnum, old_offs); -+ dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d", -+ found, znode, n, old_lnum, old_offs); -+ if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ -+ if (found) { -+ /* Ensure the znode is dirtied */ -+ if (znode->cnext || !ubifs_zn_dirty(znode)) { -+ znode = dirty_cow_bottom_up(c, -+ znode); -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ } -+ zbr = &znode->zbranch[n]; -+ lnc_free(zbr); -+ err = ubifs_add_dirt(c, zbr->lnum, -+ zbr->len); -+ if (err) -+ goto out_unlock; -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ } -+ } -+ } -+ -+ if (!found) -+ err = ubifs_add_dirt(c, lnum, len); -+ -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_tnc_add_nm - add a "hashed" node to TNC. -+ * @c: UBIFS file-system description object -+ * @key: key to add -+ * @lnum: LEB number of node -+ * @offs: node offset -+ * @len: node length -+ * @nm: node name -+ * -+ * This is the same as 'ubifs_tnc_add()' but it should be used with keys which -+ * may have collisions, like directory entry keys. -+ */ -+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, -+ int lnum, int offs, int len, const struct qstr *nm) -+{ -+ int found, n, err = 0; -+ struct ubifs_znode *znode; -+ -+ mutex_lock(&c->tnc_mutex); -+ dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name, -+ DBGKEY(key)); -+ found = lookup_level0_dirty(c, key, &znode, &n); -+ if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ -+ if (found == 1) { -+ if (c->replaying) -+ found = fallible_resolve_collision(c, key, &znode, &n, -+ nm, 1); -+ else -+ found = resolve_collision(c, key, &znode, &n, nm); -+ dbg_tnc("rc returned %d, znode %p, n %d", found, znode, n); -+ if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ -+ /* Ensure the znode is dirtied */ -+ if (znode->cnext || !ubifs_zn_dirty(znode)) { -+ znode = dirty_cow_bottom_up(c, znode); -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ } -+ -+ if (found == 1) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[n]; -+ -+ lnc_free(zbr); -+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ goto out_unlock; -+ } -+ } -+ -+ if (!found) { -+ struct ubifs_zbranch zbr; -+ -+ zbr.znode = NULL; -+ zbr.lnum = lnum; -+ zbr.offs = offs; -+ zbr.len = len; -+ key_copy(c, key, &zbr.key); -+ err = tnc_insert(c, znode, &zbr, n + 1); -+ if (err) -+ goto out_unlock; -+ if (c->replaying && c->replay_sqnum < c->cs_sqnum) { -+ /* -+ * This node was moved by garbage collection. We can -+ * tell because it is in the journal but it has a -+ * sequence number earlier than the last commit-start. -+ * We did not find it in the index so there may be a -+ * dangling branch still in the index. So we remove it -+ * by passing 'ubifs_tnc_remove_nm()' the same key but -+ * an unmatchable name. -+ */ -+ struct qstr noname = { .len = 0, .name = "" }; -+ -+ err = dbg_check_tnc(c, 0); -+ mutex_unlock(&c->tnc_mutex); -+ if (err) -+ return err; -+ return ubifs_tnc_remove_nm(c, key, &noname); -+ } -+ } -+ -+out_unlock: -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * tnc_delete - delete a znode form TNC. -+ * @c: UBIFS file-system description object -+ * @znode: znode to delete from -+ * @n: zbranch slot number to delete -+ * -+ * This function deletes a leaf node from @n-th slot of @znode. Returns zero in -+ * case of success and a negative error code in case of failure. -+ */ -+static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) -+{ -+ struct ubifs_zbranch *zbr; -+ struct ubifs_znode *zp; -+ int i, err; -+ -+ /* Delete without merge for now */ -+ ubifs_assert(znode->level == 0); -+ ubifs_assert(n >= 0 && n < c->fanout); -+ dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key)); -+ -+ zbr = &znode->zbranch[n]; -+ lnc_free(zbr); -+ -+ err = ubifs_add_dirt(c, zbr->lnum, zbr->len); -+ if (err) { -+ dbg_dump_znode(c, znode); -+ return err; -+ } -+ -+ /* We do not "gap" zbranch slots */ -+ for (i = n; i < znode->child_cnt - 1; i++) -+ znode->zbranch[i] = znode->zbranch[i + 1]; -+ znode->child_cnt -= 1; -+ -+ if (znode->child_cnt > 0) -+ return 0; -+ -+ /* -+ * This was the last zbranch, we have to delete this znode from the -+ * parent. -+ */ -+ -+ do { -+ ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); -+ ubifs_assert(ubifs_zn_dirty(znode)); -+ -+ zp = znode->parent; -+ n = znode->iip; -+ -+ atomic_long_dec(&c->dirty_zn_cnt); -+ -+ err = insert_old_idx_znode(c, znode); -+ if (err) -+ return err; -+ -+ if (znode->cnext) { -+ __set_bit(OBSOLETE_ZNODE, &znode->flags); -+ atomic_long_inc(&c->clean_zn_cnt); -+ atomic_long_inc(&ubifs_clean_zn_cnt); -+ } else -+ kfree(znode); -+ znode = zp; -+ } while (znode->child_cnt == 1); /* while removing last child */ -+ -+ /* Remove from znode, entry n - 1 */ -+ znode->child_cnt -= 1; -+ ubifs_assert(znode->level != 0); -+ for (i = n; i < znode->child_cnt; i++) { -+ znode->zbranch[i] = znode->zbranch[i + 1]; -+ if (znode->zbranch[i].znode) -+ znode->zbranch[i].znode->iip = i; -+ } -+ -+ /* -+ * If this is the root and it has only 1 child then -+ * collapse the tree. -+ */ -+ if (!znode->parent) { -+ while (znode->child_cnt == 1 && znode->level != 0) { -+ zp = znode; -+ zbr = &znode->zbranch[0]; -+ znode = get_znode(c, znode, 0); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ znode = dirty_cow_znode(c, zbr); -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ znode->parent = NULL; -+ znode->iip = 0; -+ if (c->zroot.len) { -+ err = insert_old_idx(c, c->zroot.lnum, -+ c->zroot.offs); -+ if (err) -+ return err; -+ } -+ c->zroot.lnum = zbr->lnum; -+ c->zroot.offs = zbr->offs; -+ c->zroot.len = zbr->len; -+ c->zroot.znode = znode; -+ ubifs_assert(!test_bit(OBSOLETE_ZNODE, -+ &zp->flags)); -+ ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags)); -+ atomic_long_dec(&c->dirty_zn_cnt); -+ -+ if (zp->cnext) { -+ __set_bit(OBSOLETE_ZNODE, &zp->flags); -+ atomic_long_inc(&c->clean_zn_cnt); -+ atomic_long_inc(&ubifs_clean_zn_cnt); -+ } else -+ kfree(zp); -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * ubifs_tnc_remove - remove an index entry of a node. -+ * @c: UBIFS file-system description object -+ * @key: key of node -+ * -+ * Returns %0 on success or negative error code on failure. -+ */ -+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key) -+{ -+ int found, n, err = 0; -+ struct ubifs_znode *znode; -+ -+ mutex_lock(&c->tnc_mutex); -+ dbg_tnc("key %s", DBGKEY(key)); -+ found = lookup_level0_dirty(c, key, &znode, &n); -+ if (found < 0) { -+ err = found; -+ goto out_unlock; -+ } -+ if (found == 1) -+ err = tnc_delete(c, znode, n); -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_tnc_remove_nm - remove an index entry for a "hashed" node. -+ * @c: UBIFS file-system description object -+ * @key: key of node -+ * @nm: directory entry name -+ * -+ * Returns %0 on success or negative error code on failure. -+ */ -+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, -+ const struct qstr *nm) -+{ -+ int n, err; -+ struct ubifs_znode *znode; -+ -+ mutex_lock(&c->tnc_mutex); -+ dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key)); -+ err = lookup_level0_dirty(c, key, &znode, &n); -+ if (err < 0) -+ goto out_unlock; -+ -+ if (err) { -+ if (c->replaying) -+ err = fallible_resolve_collision(c, key, &znode, &n, -+ nm, 0); -+ else -+ err = resolve_collision(c, key, &znode, &n, nm); -+ dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n); -+ if (err < 0) -+ goto out_unlock; -+ if (err) { -+ /* Ensure the znode is dirtied */ -+ if (znode->cnext || !ubifs_zn_dirty(znode)) { -+ znode = dirty_cow_bottom_up(c, znode); -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ } -+ err = tnc_delete(c, znode, n); -+ } -+ } -+ -+out_unlock: -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * key_in_range - determine if a key falls within a range of keys. -+ * @c: UBIFS file-system description object -+ * @key: key to check -+ * @from_key: lowest key in range -+ * @to_key: highest key in range -+ * -+ * This function returns %1 if the key is in range and %0 otherwise. -+ */ -+static int key_in_range(struct ubifs_info *c, union ubifs_key *key, -+ union ubifs_key *from_key, union ubifs_key *to_key) -+{ -+ if (keys_cmp(c, key, from_key) < 0) -+ return 0; -+ if (keys_cmp(c, key, to_key) > 0) -+ return 0; -+ return 1; -+} -+ -+/** -+ * ubifs_tnc_remove_range - remove index entries in range. -+ * @c: UBIFS file-system description object -+ * @from_key: lowest key to remove -+ * @to_key: highest key to remove -+ * -+ * This function removes index entries starting at @from_key and ending at -+ * @to_key. This function returns zero in case of success and a negative error -+ * code in case of failure. -+ */ -+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, -+ union ubifs_key *to_key) -+{ -+ int i, n, k, err = 0; -+ struct ubifs_znode *znode; -+ union ubifs_key *key; -+ -+ mutex_lock(&c->tnc_mutex); -+ while (1) { -+ /* Find first level 0 znode that contains keys to remove */ -+ err = lookup_level0(c, from_key, &znode, &n); -+ if (err < 0) -+ goto out_unlock; -+ -+ if (err) -+ key = from_key; -+ else { -+ err = tnc_next(c, &znode, &n); -+ if (err == -ENOENT) { -+ err = 0; -+ goto out_unlock; -+ } -+ if (err < 0) -+ goto out_unlock; -+ key = &znode->zbranch[n].key; -+ if (!key_in_range(c, key, from_key, to_key)) { -+ err = 0; -+ goto out_unlock; -+ } -+ } -+ -+ /* Ensure the znode is dirtied */ -+ if (znode->cnext || !ubifs_zn_dirty(znode)) { -+ znode = dirty_cow_bottom_up(c, znode); -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ } -+ -+ /* Remove all keys in range except the first */ -+ for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) { -+ key = &znode->zbranch[i].key; -+ if (!key_in_range(c, key, from_key, to_key)) -+ break; -+ lnc_free(&znode->zbranch[i]); -+ err = ubifs_add_dirt(c, znode->zbranch[i].lnum, -+ znode->zbranch[i].len); -+ if (err) { -+ dbg_dump_znode(c, znode); -+ goto out_unlock; -+ } -+ dbg_tnc("removing %s", DBGKEY(key)); -+ } -+ if (k) { -+ for (i = n + 1 + k; i < znode->child_cnt; i++) -+ znode->zbranch[i - k] = znode->zbranch[i]; -+ znode->child_cnt -= k; -+ } -+ -+ /* Now delete the first */ -+ err = tnc_delete(c, znode, n); -+ if (err) -+ goto out_unlock; -+ } -+ -+out_unlock: -+ if (!err) -+ err = dbg_check_tnc(c, 0); -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_tnc_remove_ino - remove an inode from TNC. -+ * @c: UBIFS file-system description object -+ * @inum: inode number to remove -+ * -+ * This function remove inode @inum and all the extended attributes associated -+ * with the anode from TNC and returns zero in case of success or a negative -+ * error code in case of failure. -+ */ -+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) -+{ -+ union ubifs_key key1, key2; -+ struct ubifs_dent_node *xent, *pxent = NULL; -+ struct qstr nm = { .name = NULL }; -+ -+ dbg_tnc("ino %lu", inum); -+ -+ /* -+ * Walk all extended attribute entries and remove them together with -+ * corresponding extended attribute inodes. -+ */ -+ lowest_xent_key(c, &key1, inum); -+ while (1) { -+ ino_t xattr_inum; -+ int err; -+ -+ xent = ubifs_tnc_next_ent(c, &key1, &nm); -+ if (IS_ERR(xent)) { -+ err = PTR_ERR(xent); -+ if (err == -ENOENT) -+ break; -+ return err; -+ } -+ -+ xattr_inum = le64_to_cpu(xent->inum); -+ dbg_tnc("xent '%s', ino %lu", xent->name, xattr_inum); -+ -+ nm.name = xent->name; -+ nm.len = le16_to_cpu(xent->nlen); -+ err = ubifs_tnc_remove_nm(c, &key1, &nm); -+ if (err) { -+ kfree(xent); -+ return err; -+ } -+ -+ lowest_ino_key(c, &key1, xattr_inum); -+ highest_ino_key(c, &key2, xattr_inum); -+ err = ubifs_tnc_remove_range(c, &key1, &key2); -+ if (err) { -+ kfree(xent); -+ return err; -+ } -+ -+ kfree(pxent); -+ pxent = xent; -+ key_read(c, &xent->key, &key1); -+ } -+ -+ kfree(pxent); -+ lowest_ino_key(c, &key1, inum); -+ highest_ino_key(c, &key2, inum); -+ -+ return ubifs_tnc_remove_range(c, &key1, &key2); -+} -+ -+/** -+ * ubifs_tnc_next_ent - walk directory or extended attribute entries. -+ * @c: UBIFS file-system description object -+ * @key: key of last entry -+ * @nm: name of last entry found or %NULL -+ * -+ * This function finds and reads the next directory or extended attribute entry -+ * after the given key (@key) if there is one. @nm is used to resolve -+ * collisions. -+ * -+ * If the name of the current entry is not known and only the key is known, -+ * @nm->name has to be %NULL. In this case the semantics of this function is a -+ * little bit different and it returns the entry corresponding to this key, not -+ * the next one. If the key was not found, the closest "right" entry is -+ * returned. -+ * -+ * If the fist entry has to be found, @key has to contain the lowest possible -+ * key value for this inode and @name has to be %NULL. -+ * -+ * This function returns the found directory or extended attribute entry node -+ * in case of success, %-ENOENT is returned if no entry was found, and a -+ * negative error code is returned in case of failure. -+ */ -+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, -+ union ubifs_key *key, -+ const struct qstr *nm) -+{ -+ int n, err, type = key_type(c, key); -+ struct ubifs_znode *znode; -+ struct ubifs_dent_node *dent; -+ struct ubifs_zbranch *zbr; -+ union ubifs_key *dkey; -+ -+ dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key)); -+ ubifs_assert(is_hash_key(c, key)); -+ -+ mutex_lock(&c->tnc_mutex); -+ err = lookup_level0(c, key, &znode, &n); -+ if (unlikely(err < 0)) -+ goto out_unlock; -+ -+ if (nm->name) { -+ if (err) { -+ /* Handle collisions */ -+ err = resolve_collision(c, key, &znode, &n, nm); -+ dbg_tnc("rc returned %d, znode %p, n %d", -+ err, znode, n); -+ if (unlikely(err < 0)) -+ goto out_unlock; -+ } -+ -+ /* Now find next entry */ -+ err = tnc_next(c, &znode, &n); -+ if (unlikely(err)) -+ goto out_unlock; -+ } else { -+ /* -+ * The full name of the entry was not given, in which case the -+ * behavior of this function is a little different and it -+ * returns current entry, not the next one. -+ */ -+ if (!err) { -+ /* -+ * However, the given key does not exist in the TNC -+ * tree and @znode/@n variables contain the closest -+ * "preceding" element. Switch to the next one. -+ */ -+ err = tnc_next(c, &znode, &n); -+ if (err) -+ goto out_unlock; -+ } -+ } -+ -+ zbr = &znode->zbranch[n]; -+ dent = kmalloc(zbr->len, GFP_NOFS); -+ if (unlikely(!dent)) { -+ err = -ENOMEM; -+ goto out_unlock; -+ } -+ -+ /* -+ * The above 'tnc_next()' call could lead us to the next inode, check -+ * this. -+ */ -+ dkey = &zbr->key; -+ if (key_ino(c, dkey) != key_ino(c, key) || -+ key_type(c, dkey) != type) { -+ err = -ENOENT; -+ goto out_free; -+ } -+ -+ err = tnc_read_node_nm(c, zbr, dent); -+ if (unlikely(err)) -+ goto out_free; -+ -+ mutex_unlock(&c->tnc_mutex); -+ return dent; -+ -+out_free: -+ kfree(dent); -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return ERR_PTR(err); -+} -+ -+/** -+ * tnc_destroy_cnext - destroy left-over obsolete znodes from a failed commit. -+ * @c: UBIFS file-system description object -+ * -+ * Destroy left-over obsolete znodes from a failed commit. -+ */ -+static void tnc_destroy_cnext(struct ubifs_info *c) -+{ -+ struct ubifs_znode *cnext; -+ -+ if (!c->cnext) -+ return; -+ ubifs_assert(c->cmt_state == COMMIT_BROKEN); -+ cnext = c->cnext; -+ do { -+ struct ubifs_znode *znode = cnext; -+ -+ cnext = cnext->cnext; -+ if (test_bit(OBSOLETE_ZNODE, &znode->flags)) -+ kfree(znode); -+ } while (cnext && cnext != c->cnext); -+} -+ -+/** -+ * ubifs_tnc_close - close TNC subsystem and free all related resources. -+ * @c: UBIFS file-system description object -+ */ -+void ubifs_tnc_close(struct ubifs_info *c) -+{ -+ long clean_freed; -+ -+ tnc_destroy_cnext(c); -+ if (c->zroot.znode) { -+ clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode); -+ atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt); -+ } -+ kfree(c->gap_lebs); -+ kfree(c->ilebs); -+ destroy_old_idx(c); -+} -+ -+/** -+ * left_znode - get the znode to the left. -+ * @c: UBIFS file-system description object -+ * @znode: znode -+ * -+ * This function returns a pointer to the znode to the left of @znode or NULL if -+ * there is not one. A negative error code is returned on failure. -+ */ -+static struct ubifs_znode *left_znode(struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ int level = znode->level; -+ -+ while (1) { -+ int n = znode->iip - 1; -+ -+ /* Go up until we can go left */ -+ znode = znode->parent; -+ if (!znode) -+ return NULL; -+ if (n >= 0) { -+ /* Now go down the rightmost branch to 'level' */ -+ znode = get_znode(c, znode, n); -+ if (IS_ERR(znode)) -+ return znode; -+ while (znode->level != level) { -+ n = znode->child_cnt - 1; -+ znode = get_znode(c, znode, n); -+ if (IS_ERR(znode)) -+ return znode; -+ } -+ break; -+ } -+ } -+ return znode; -+} -+ -+/** -+ * right_znode - get the znode to the right. -+ * @c: UBIFS file-system description object -+ * @znode: znode -+ * -+ * This function returns a pointer to the znode to the right of @znode or NULL -+ * if there is not one. A negative error code is returned on failure. -+ */ -+static struct ubifs_znode *right_znode(struct ubifs_info *c, -+ struct ubifs_znode *znode) -+{ -+ int level = znode->level; -+ -+ while (1) { -+ int n = znode->iip + 1; -+ -+ /* Go up until we can go right */ -+ znode = znode->parent; -+ if (!znode) -+ return NULL; -+ if (n < znode->child_cnt) { -+ /* Now go down the leftmost branch to 'level' */ -+ znode = get_znode(c, znode, n); -+ if (IS_ERR(znode)) -+ return znode; -+ while (znode->level != level) { -+ znode = get_znode(c, znode, 0); -+ if (IS_ERR(znode)) -+ return znode; -+ } -+ break; -+ } -+ } -+ return znode; -+} -+ -+/** -+ * lookup_znode - find a particular indexing node from TNC. -+ * @c: UBIFS file-system description object -+ * @key: index node key to lookup -+ * @level: index node level -+ * @lnum: index node LEB number -+ * @offs: index node offset -+ * -+ * This function searches an indexing node by its first key @key and its -+ * address @lnum:@offs. It looks up the indexing tree by pulling all indexing -+ * nodes it traverses to TNC. This function is called fro indexing nodes which -+ * were found on the media by scanning, for example when garbage-collecting or -+ * when doing in-the-gaps commit. This means that the indexing node which is -+ * looked for does not have to have exactly the same leftmost key @key, because -+ * the leftmost key may have been changed, in which case TNC will contain a -+ * dirty znode which still refers the same @lnum:@offs. This function is clever -+ * enough to recognize such indexing nodes. -+ * -+ * Note, if a znode was deleted or changed too much, then this function will -+ * not find it. For situations like this UBIFS has the old index RB-tree -+ * (indexed by @lnum:@offs). -+ * -+ * This function returns a pointer to the znode found or %NULL if it is not -+ * found. A negative error code is returned on failure. -+ */ -+static struct ubifs_znode *lookup_znode(struct ubifs_info *c, -+ union ubifs_key *key, int level, -+ int lnum, int offs) -+{ -+ struct ubifs_znode *znode, *zn; -+ int n, nn; -+ -+ /* -+ * The arguments have probably been read off flash, so don't assume -+ * they are valid. -+ */ -+ if (level < 0) -+ return ERR_PTR(-EINVAL); -+ -+ /* Get the root znode */ -+ znode = c->zroot.znode; -+ if (!znode) { -+ znode = load_znode(c, &c->zroot, NULL, 0); -+ if (IS_ERR(znode)) -+ return znode; -+ } -+ /* Check if it is the one we are looking for */ -+ if (c->zroot.lnum == lnum && c->zroot.offs == offs) -+ return znode; -+ /* Descend to the parent level i.e. (level + 1) */ -+ if (level >= znode->level) -+ return NULL; -+ while (1) { -+ ubifs_search_zbranch(c, znode, key, &n); -+ if (n < 0) { -+ /* -+ * We reached a znode where the leftmost key is greater -+ * than the key we are searching for. This is the same -+ * situation as the one described in a huge comment at -+ * the end of the 'lookup_level0()' function. And for -+ * exactly the same reasons we have to try to look left -+ * before giving up. -+ */ -+ znode = left_znode(c, znode); -+ if (!znode) -+ return NULL; -+ if (IS_ERR(znode)) -+ return znode; -+ ubifs_search_zbranch(c, znode, key, &n); -+ ubifs_assert(n >= 0); -+ } -+ if (znode->level == level + 1) -+ break; -+ znode = get_znode(c, znode, n); -+ if (IS_ERR(znode)) -+ return znode; -+ } -+ /* Check if the child is the one we are looking for */ -+ if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs) -+ return get_znode(c, znode, n); -+ /* If the key is unique, there is nowhere else to look */ -+ if (!is_hash_key(c, key)) -+ return NULL; -+ /* -+ * The key is not unique and so may be also in the znodes to either -+ * side. -+ */ -+ zn = znode; -+ nn = n; -+ /* Look left */ -+ while (1) { -+ /* Move one branch to the left */ -+ if (n) -+ n -= 1; -+ else { -+ znode = left_znode(c, znode); -+ if (!znode) -+ break; -+ if (IS_ERR(znode)) -+ return znode; -+ n = znode->child_cnt - 1; -+ } -+ /* Check it */ -+ if (znode->zbranch[n].lnum == lnum && -+ znode->zbranch[n].offs == offs) -+ return get_znode(c, znode, n); -+ /* Stop if the key is less than the one we are looking for */ -+ if (keys_cmp(c, &znode->zbranch[n].key, key) < 0) -+ break; -+ } -+ /* Back to the middle */ -+ znode = zn; -+ n = nn; -+ /* Look right */ -+ while (1) { -+ /* Move one branch to the right */ -+ if (++n >= znode->child_cnt) { -+ znode = right_znode(c, znode); -+ if (!znode) -+ break; -+ if (IS_ERR(znode)) -+ return znode; -+ n = 0; -+ } -+ /* Check it */ -+ if (znode->zbranch[n].lnum == lnum && -+ znode->zbranch[n].offs == offs) -+ return get_znode(c, znode, n); -+ /* Stop if the key is greater than the one we are looking for */ -+ if (keys_cmp(c, &znode->zbranch[n].key, key) > 0) -+ break; -+ } -+ return NULL; -+} -+ -+/** -+ * is_idx_node_in_tnc - determine if an index node is in the TNC. -+ * @c: UBIFS file-system description object -+ * @key: key of index node -+ * @level: index node level -+ * @lnum: LEB number of index node -+ * @offs: offset of index node -+ * -+ * This function returns %0 if the index node is not referred to in the TNC, %1 -+ * if the index node is referred to in the TNC and the corresponding znode is -+ * dirty, %2 if an index node is referred to in the TNC and the corresponding -+ * znode is clean, and a negative error code in case of failure. -+ * -+ * Note, the @key argument has to be the key of the first child. Also note, -+ * this function relies on the fact that 0:0 is never a valid LEB number and -+ * offset for a main-area node. -+ */ -+int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs) -+{ -+ struct ubifs_znode *znode; -+ -+ znode = lookup_znode(c, key, level, lnum, offs); -+ if (!znode) -+ return 0; -+ if (IS_ERR(znode)) -+ return PTR_ERR(znode); -+ -+ return ubifs_zn_dirty(znode) ? 1 : 2; -+} -+ -+/** -+ * is_leaf_node_in_tnc - determine if a non-indexing not is in the TNC. -+ * @c: UBIFS file-system description object -+ * @key: node key -+ * @lnum: node LEB number -+ * @offs: node offset -+ * -+ * This function returns %1 if the node is referred to in the TNC, %0 if it is -+ * not, and a negative error code in case of failure. -+ * -+ * Note, this function relies on the fact that 0:0 is never a valid LEB number -+ * and offset for a main-area node. -+ */ -+static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, -+ int lnum, int offs) -+{ -+ struct ubifs_zbranch *zbr; -+ struct ubifs_znode *znode, *zn; -+ int n, found, err, nn; -+ const int unique = !is_hash_key(c, key); -+ -+ found = lookup_level0(c, key, &znode, &n); -+ if (found < 0) -+ return found; /* Error code */ -+ if (!found) -+ return 0; -+ zbr = &znode->zbranch[n]; -+ if (lnum == zbr->lnum && offs == zbr->offs) -+ return 1; /* Found it */ -+ if (unique) -+ return 0; -+ /* -+ * Because the key is not unique, we have to look left -+ * and right as well -+ */ -+ zn = znode; -+ nn = n; -+ /* Look left */ -+ while (1) { -+ err = tnc_prev(c, &znode, &n); -+ if (err == -ENOENT) -+ break; -+ if (err) -+ return err; -+ if (keys_cmp(c, key, &znode->zbranch[n].key)) -+ break; -+ zbr = &znode->zbranch[n]; -+ if (lnum == zbr->lnum && offs == zbr->offs) -+ return 1; /* Found it */ -+ } -+ /* Look right */ -+ znode = zn; -+ n = nn; -+ while (1) { -+ err = tnc_next(c, &znode, &n); -+ if (err) { -+ if (err == -ENOENT) -+ return 0; -+ return err; -+ } -+ if (keys_cmp(c, key, &znode->zbranch[n].key)) -+ break; -+ zbr = &znode->zbranch[n]; -+ if (lnum == zbr->lnum && offs == zbr->offs) -+ return 1; /* Found it */ -+ } -+ return 0; -+} -+ -+/** -+ * ubifs_tnc_has_node - determine whether a node is in the TNC. -+ * @c: UBIFS file-system description object -+ * @key: node key -+ * @level: index node level (if it is an index node) -+ * @lnum: node LEB number -+ * @offs: node offset -+ * @is_idx: non-zero if the node is an index node -+ * -+ * This function returns %1 if the node is in the TNC, %0 if it is not, and a -+ * negative error code in case of failure. For index nodes, @key has to be the -+ * key of the first child. An index node is considered to be in the TNC only if -+ * the corresponding znode is clean or has not been loaded. -+ */ -+int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs, int is_idx) -+{ -+ int err; -+ -+ mutex_lock(&c->tnc_mutex); -+ if (is_idx) { -+ err = is_idx_node_in_tnc(c, key, level, lnum, offs); -+ if (err < 0) -+ goto out_unlock; -+ if (err == 1) -+ /* The index node was found but it was dirty */ -+ err = 0; -+ else if (err == 2) -+ /* The index node was found and it was clean */ -+ err = 1; -+ else -+ BUG_ON(err != 0); -+ } else -+ err = is_leaf_node_in_tnc(c, key, lnum, offs); -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * ubifs_dirty_idx_node - dirty an index node. -+ * @c: UBIFS file-system description object -+ * @key: index node key -+ * @level: index node level -+ * @lnum: index node LEB number -+ * @offs: index node offset -+ * -+ * This function loads and dirties an index node so that it can be garbage -+ * collected. The @key argument has to be the key of the first child. This -+ * function relies on the fact that 0:0 is never a valid LEB number and offset -+ * for a main-area node. Returns %0 on success and a negative error code on -+ * failure. -+ */ -+int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs) -+{ -+ struct ubifs_znode *znode; -+ int err = 0; -+ -+ mutex_lock(&c->tnc_mutex); -+ znode = lookup_znode(c, key, level, lnum, offs); -+ if (!znode) -+ goto out_unlock; -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ znode = dirty_cow_bottom_up(c, znode); -+ if (IS_ERR(znode)) { -+ err = PTR_ERR(znode); -+ goto out_unlock; -+ } -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ -+/** -+ * dbg_walk_sub_tree - walk index subtree. -+ * @c: UBIFS file-system description object -+ * @znode: root znode of the subtree to walk -+ * @leaf_cb: called for each leaf node -+ * @znode_cb: called for each indexing node -+ * @priv: private date which is passed to callbacks -+ * -+ * This is a helper function which recursively walks the UBIFS index, reading -+ * each indexing node from the media if needed. Returns zero in case of success -+ * and a negative error code in case of failure. -+ */ -+static int dbg_walk_sub_tree(struct ubifs_info *c, struct ubifs_znode *znode, -+ dbg_leaf_callback leaf_cb, -+ dbg_znode_callback znode_cb, void *priv) -+{ -+ int n, err; -+ -+ cond_resched(); -+ -+ if (znode_cb) { -+ err = znode_cb(c, znode, priv); -+ if (err) -+ return err; -+ } -+ -+ if (znode->level == 0) { -+ if (!leaf_cb) -+ return 0; -+ -+ for (n = 0; n < znode->child_cnt; n++) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[n]; -+ -+ err = leaf_cb(c, zbr, priv); -+ if (err) -+ return err; -+ } -+ } else -+ for (n = 0; n < znode->child_cnt; n++) { -+ struct ubifs_znode *zn; -+ -+ zn = get_znode(c, znode, n); -+ if (IS_ERR(zn)) -+ return PTR_ERR(zn); -+ err = dbg_walk_sub_tree(c, zn, leaf_cb, znode_cb, priv); -+ if (err) -+ return err; -+ } -+ -+ return 0; -+} -+ -+/** -+ * dbg_walk_index - walk the on-flash index. -+ * @c: UBIFS file-system description object -+ * @leaf_cb: called for each leaf node -+ * @znode_cb: called for each indexing node -+ * @priv: private date which is passed to callbacks -+ * -+ * This function walks the UBIFS index and calls the @leaf_cb for each leaf -+ * node and @znode_cb for each indexing node. Returns zero in case of success -+ * and a negative error code in case of failure. -+ * -+ * Because 'dbg_walk_sub_tree()' is recursive, it runs the risk of exceeding the -+ * stack space. -+ * -+ * It would be better if this function removed every znode it pulled to into -+ * the TNC, so that the behavior more closely matched the non-debugging -+ * behavior. -+ */ -+int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, -+ dbg_znode_callback znode_cb, void *priv) -+{ -+ int err = 0; -+ -+ mutex_lock(&c->tnc_mutex); -+ if (!c->zroot.znode) { -+ c->zroot.znode = load_znode(c, &c->zroot, NULL, 0); -+ if (IS_ERR(c->zroot.znode)) { -+ err = PTR_ERR(c->zroot.znode); -+ c->zroot.znode = NULL; -+ goto out_unlock; -+ } -+ } -+ -+ err = dbg_walk_sub_tree(c, c->zroot.znode, leaf_cb, znode_cb, priv); -+ -+out_unlock: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+int dbg_read_leaf_nolock(struct ubifs_info *c, struct ubifs_zbranch *zbr, -+ void *node) -+{ -+ ubifs_assert(mutex_is_locked(&c->tnc_mutex)); -+ if (is_hash_key(c, &zbr->key)) -+ return tnc_read_node_nm(c, zbr, node); -+ return tnc_read_node(c, zbr, node); -+} -+ -+#endif /* CONFIG_UBIFS_FS_DEBUG */ -diff -urN linux-2.6.24.7.old/fs/ubifs/tnc_commit.c linux-2.6.24.7/fs/ubifs/tnc_commit.c ---- linux-2.6.24.7.old/fs/ubifs/tnc_commit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/tnc_commit.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1105 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* This file implements TNC functions for committing */ -+ -+#include "ubifs.h" -+ -+/** -+ * make_idx_node - make an index node for fill-the-gaps method of TNC commit. -+ * @c: UBIFS file-system description object -+ * @idx: buffer in which to place new index node -+ * @znode: znode from which to make new index node -+ * @lnum: LEB number where new index node will be written -+ * @offs: offset where new index node will be written -+ * @len: length of new index node -+ */ -+static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, -+ struct ubifs_znode *znode, int lnum, int offs, int len) -+{ -+ struct ubifs_znode *zp; -+ int i, err; -+ -+ /* Make index node */ -+ idx->ch.node_type = UBIFS_IDX_NODE; -+ idx->child_cnt = cpu_to_le16(znode->child_cnt); -+ idx->level = cpu_to_le16(znode->level); -+ for (i = 0; i < znode->child_cnt; i++) { -+ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); -+ struct ubifs_zbranch *zbr = &znode->zbranch[i]; -+ -+ key_write_idx(c, &zbr->key, &br->key); -+ br->lnum = cpu_to_le32(zbr->lnum); -+ br->offs = cpu_to_le32(zbr->offs); -+ br->len = cpu_to_le32(zbr->len); -+ if (!zbr->lnum || !zbr->len) { -+ ubifs_err("bad ref in znode"); -+ dbg_dump_znode(c, znode); -+ if (zbr->znode) -+ dbg_dump_znode(c, zbr->znode); -+ } -+ } -+ ubifs_prepare_node(c, idx, len, 0); -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ znode->lnum = lnum; -+ znode->offs = offs; -+ znode->len = len; -+#endif -+ -+ err = insert_old_idx_znode(c, znode); -+ -+ /* Update the parent */ -+ zp = znode->parent; -+ if (zp) { -+ struct ubifs_zbranch *zbr; -+ -+ zbr = &zp->zbranch[znode->iip]; -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ } else { -+ c->zroot.lnum = lnum; -+ c->zroot.offs = offs; -+ c->zroot.len = len; -+ } -+ c->calc_idx_sz += ALIGN(len, 8); -+ -+ atomic_long_dec(&c->dirty_zn_cnt); -+ -+ ubifs_assert(ubifs_zn_dirty(znode)); -+ ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); -+ -+ __clear_bit(DIRTY_ZNODE, &znode->flags); -+ __clear_bit(COW_ZNODE, &znode->flags); -+ -+ return err; -+} -+ -+/** -+ * fill_gap - make index nodes in gaps in dirty index LEBs. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number that gap appears in -+ * @gap_start: offset of start of gap -+ * @gap_end: offset of end of gap -+ * @dirt: adds dirty space to this -+ * -+ * This function returns the number of index nodes written into the gap. -+ */ -+static int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end, -+ int *dirt) -+{ -+ int len, gap_remains, gap_pos, written, pad_len; -+ -+ ubifs_assert((gap_start & 7) == 0); -+ ubifs_assert((gap_end & 7) == 0); -+ ubifs_assert(gap_end >= gap_start); -+ -+ gap_remains = gap_end - gap_start; -+ if (!gap_remains) -+ return 0; -+ gap_pos = gap_start; -+ written = 0; -+ while (c->enext) { -+ len = ubifs_idx_node_sz(c, c->enext->child_cnt); -+ if (len < gap_remains) { -+ struct ubifs_znode *znode = c->enext; -+ const int alen = ALIGN(len, 8); -+ int err; -+ -+ ubifs_assert(alen <= gap_remains); -+ err = make_idx_node(c, c->ileb_buf + gap_pos, znode, -+ lnum, gap_pos, len); -+ if (err) -+ return err; -+ gap_remains -= alen; -+ gap_pos += alen; -+ c->enext = znode->cnext; -+ if (c->enext == c->cnext) -+ c->enext = NULL; -+ written += 1; -+ } else -+ break; -+ } -+ if (gap_end == c->leb_size) { -+ c->ileb_len = ALIGN(gap_pos, c->min_io_size); -+ /* Pad to end of min_io_size */ -+ pad_len = c->ileb_len - gap_pos; -+ } else -+ /* Pad to end of gap */ -+ pad_len = gap_remains; -+ dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d", -+ lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len); -+ ubifs_pad(c, c->ileb_buf + gap_pos, pad_len); -+ *dirt += pad_len; -+ return written; -+} -+ -+/** -+ * find_old_idx - find an index node obsoleted since the last commit start. -+ * @c: UBIFS file-system description object -+ * @lnum: LEB number of obsoleted index node -+ * @offs: offset of obsoleted index node -+ * -+ * Returns %1 if found and %0 otherwise. -+ */ -+static int find_old_idx(struct ubifs_info *c, int lnum, int offs) -+{ -+ struct ubifs_old_idx *o; -+ struct rb_node *p; -+ -+ p = c->old_idx.rb_node; -+ while (p) { -+ o = rb_entry(p, struct ubifs_old_idx, rb); -+ if (lnum < o->lnum) -+ p = p->rb_left; -+ else if (lnum > o->lnum) -+ p = p->rb_right; -+ else if (offs < o->offs) -+ p = p->rb_left; -+ else if (offs > o->offs) -+ p = p->rb_right; -+ else -+ return 1; -+ } -+ return 0; -+} -+ -+/** -+ * is_idx_node_in_use - determine if an index node can be overwritten. -+ * @c: UBIFS file-system description object -+ * @key: key of index node -+ * @level: index node level -+ * @lnum: LEB number of index node -+ * @offs: offset of index node -+ * -+ * If @key / @lnum / @offs identify an index node that was not part of the old -+ * index, then this function returns %0 (obsolete). Else if the index node was -+ * part of the old index but is now dirty %1 is returned, else if it is clean %2 -+ * is returned. A negative error code is returned on failure. -+ */ -+static int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key, -+ int level, int lnum, int offs) -+{ -+ int ret; -+ -+ ret = is_idx_node_in_tnc(c, key, level, lnum, offs); -+ if (ret < 0) -+ return ret; /* Error code */ -+ if (ret == 0) -+ if (find_old_idx(c, lnum, offs)) -+ return 1; -+ return ret; -+} -+ -+/** -+ * layout_leb_in_gaps - layout index nodes using in-the-gaps method. -+ * @c: UBIFS file-system description object -+ * @p: return LEB number here -+ * -+ * This function lays out new index nodes for dirty znodes using in-the-gaps -+ * method of TNC commit. -+ * This function merely puts the next znode into the next gap, making no attempt -+ * to try to maximise the number of znodes that fit. -+ * This function returns the number of index nodes written into the gaps, or a -+ * negative error code on failure. -+ */ -+static int layout_leb_in_gaps(struct ubifs_info *c, int *p) -+{ -+ struct ubifs_scan_leb *sleb; -+ struct ubifs_scan_node *snod; -+ int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written; -+ -+ tot_written = 0; -+ /* Get an index LEB with lots of obsolete index nodes */ -+ lnum = ubifs_find_dirty_idx_leb(c); -+ if (lnum < 0) -+ /* -+ * There also may be dirt in the index head that could be -+ * filled, however we do not check there at present. -+ */ -+ return lnum; /* Error code */ -+ *p = lnum; -+ dbg_gc("LEB %d", lnum); -+ /* -+ * Scan the index LEB. We use the generic scan for this even though -+ * it is more comprehensive and less efficient than is needed for this -+ * purpose. -+ */ -+ sleb = ubifs_scan(c, lnum, 0, c->ileb_buf); -+ c->ileb_len = 0; -+ if (IS_ERR(sleb)) -+ return PTR_ERR(sleb); -+ gap_start = 0; -+ list_for_each_entry(snod, &sleb->nodes, list) { -+ struct ubifs_idx_node *idx; -+ int in_use, level; -+ -+ ubifs_assert(snod->type == UBIFS_IDX_NODE); -+ idx = snod->node; -+ key_read(c, ubifs_idx_key(c, idx), &snod->key); -+ level = le16_to_cpu(idx->level); -+ /* Determine if the index node is in use (not obsolete) */ -+ in_use = is_idx_node_in_use(c, &snod->key, level, lnum, -+ snod->offs); -+ if (in_use < 0) { -+ ubifs_scan_destroy(sleb); -+ return in_use; /* Error code */ -+ } -+ if (in_use) { -+ if (in_use == 1) -+ dirt += ALIGN(snod->len, 8); -+ /* -+ * The obsolete index nodes form gaps that can be -+ * overwritten. This gap has ended because we have -+ * found an index node that is still in use -+ * i.e. not obsolete -+ */ -+ gap_end = snod->offs; -+ /* Try to fill gap */ -+ written = fill_gap(c, lnum, gap_start, gap_end, &dirt); -+ if (written < 0) { -+ ubifs_scan_destroy(sleb); -+ return written; /* Error code */ -+ } -+ tot_written += written; -+ gap_start = ALIGN(snod->offs + snod->len, 8); -+ } -+ } -+ ubifs_scan_destroy(sleb); -+ c->ileb_len = c->leb_size; -+ gap_end = c->leb_size; -+ /* Try to fill gap */ -+ written = fill_gap(c, lnum, gap_start, gap_end, &dirt); -+ if (written < 0) -+ return written; /* Error code */ -+ tot_written += written; -+ if (tot_written == 0) { -+ struct ubifs_lprops lp; -+ -+ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); -+ err = ubifs_read_one_lp(c, lnum, &lp); -+ if (err) -+ return err; -+ if (lp.free == c->leb_size) { -+ /* -+ * We must have snatched this LEB from the idx_gc list -+ * so we need to correct the free and dirty space. -+ */ -+ err = ubifs_change_one_lp(c, lnum, -+ c->leb_size - c->ileb_len, -+ dirt, 0, 0, 0); -+ if (err) -+ return err; -+ } -+ return 0; -+ } -+ err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt, -+ 0, 0, 0); -+ if (err) -+ return err; -+ err = ubi_leb_change(c->ubi, lnum, c->ileb_buf, c->ileb_len, -+ UBI_SHORTTERM); -+ if (err) { -+ ubifs_err("ubi_leb_change failed, error %d", err); -+ return err; -+ } -+ dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); -+ return tot_written; -+} -+ -+/** -+ * get_leb_cnt - calculate the number of empty LEBs needed to commit. -+ * @c: UBIFS file-system description object -+ * @cnt: number of znodes to commit -+ * -+ * This function returns the number of empty LEBs needed to commit @cnt znodes -+ * to the current index head. The number is not exact and may be more than -+ * needed. -+ */ -+static int get_leb_cnt(struct ubifs_info *c, int cnt) -+{ -+ int d; -+ -+ /* Assume maximum index node size (i.e. overestimate space needed) */ -+ cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz; -+ if (cnt < 0) -+ cnt = 0; -+ d = c->leb_size / c->max_idx_node_sz; -+ return DIV_ROUND_UP(cnt, d); -+} -+ -+/** -+ * layout_in_gaps - in-the-gaps method of committing TNC. -+ * @c: UBIFS file-system description object -+ * @cnt: number of dirty znodes to commit. -+ * -+ * This function lays out new index nodes for dirty znodes using in-the-gaps -+ * method of TNC commit. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int layout_in_gaps(struct ubifs_info *c, int cnt) -+{ -+ int err, leb_needed_cnt, written, *p; -+ -+ dbg_gc("%d znodes to write", cnt); -+ -+ c->gap_lebs = kmalloc(sizeof(int) * (c->lst.idx_lebs + 1), GFP_NOFS); -+ if (!c->gap_lebs) -+ return -ENOMEM; -+ -+ p = c->gap_lebs; -+ do { -+ ubifs_assert(p < c->gap_lebs + sizeof(int) * c->lst.idx_lebs); -+ written = layout_leb_in_gaps(c, p); -+ if (written < 0) { -+ err = written; -+ if (err == -ENOSPC) { -+ if (!dbg_force_in_the_gaps_enabled) { -+ /* -+ * Do not print scary warnings if the -+ * debugging option which forces -+ * in-the-gaps is enabled. -+ */ -+ ubifs_err("out of space"); -+ spin_lock(&c->space_lock); -+ dbg_dump_budg(c); -+ spin_unlock(&c->space_lock); -+ dbg_dump_lprops(c); -+ } -+ /* Try to commit anyway */ -+ err = 0; -+ break; -+ } -+ kfree(c->gap_lebs); -+ c->gap_lebs = NULL; -+ return err; -+ } -+ p++; -+ cnt -= written; -+ leb_needed_cnt = get_leb_cnt(c, cnt); -+ dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt, -+ leb_needed_cnt, c->ileb_cnt); -+ } while (leb_needed_cnt > c->ileb_cnt); -+ -+ *p = -1; -+ return 0; -+} -+ -+/** -+ * layout_in_empty_space - layout index nodes in empty space. -+ * @c: UBIFS file-system description object -+ * -+ * This function lays out new index nodes for dirty znodes using empty LEBs. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int layout_in_empty_space(struct ubifs_info *c) -+{ -+ struct ubifs_znode *znode, *cnext, *zp; -+ int lnum, offs, len, next_len, buf_len, buf_offs, used, avail; -+ int wlen, blen, err; -+ -+ cnext = c->enext; -+ if (!cnext) -+ return 0; -+ -+ lnum = c->ihead_lnum; -+ buf_offs = c->ihead_offs; -+ -+ buf_len = ubifs_idx_node_sz(c, c->fanout); -+ buf_len = ALIGN(buf_len, c->min_io_size); -+ used = 0; -+ avail = buf_len; -+ -+ /* Ensure there is enough room for first write */ -+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); -+ if (buf_offs + next_len > c->leb_size) -+ lnum = -1; -+ -+ while (1) { -+ znode = cnext; -+ -+ len = ubifs_idx_node_sz(c, znode->child_cnt); -+ -+ /* Determine the index node position */ -+ if (lnum == -1) { -+ if (c->ileb_nxt >= c->ileb_cnt) { -+ ubifs_err("out of space"); -+ return -ENOSPC; -+ } -+ lnum = c->ilebs[c->ileb_nxt++]; -+ buf_offs = 0; -+ used = 0; -+ avail = buf_len; -+ } -+ -+ offs = buf_offs + used; -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ znode->lnum = lnum; -+ znode->offs = offs; -+ znode->len = len; -+#endif -+ -+ /* Update the parent */ -+ zp = znode->parent; -+ if (zp) { -+ struct ubifs_zbranch *zbr; -+ int i; -+ -+ i = znode->iip; -+ zbr = &zp->zbranch[i]; -+ zbr->lnum = lnum; -+ zbr->offs = offs; -+ zbr->len = len; -+ } else { -+ c->zroot.lnum = lnum; -+ c->zroot.offs = offs; -+ c->zroot.len = len; -+ } -+ c->calc_idx_sz += ALIGN(len, 8); -+ -+ /* -+ * Once lprops is updated, we can decrease the dirty znode count -+ * but it is easier to just do it here. -+ */ -+ atomic_long_dec(&c->dirty_zn_cnt); -+ -+ /* -+ * Calculate the next index node length to see if there is -+ * enough room for it -+ */ -+ cnext = znode->cnext; -+ if (cnext == c->cnext) -+ next_len = 0; -+ else -+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); -+ -+ if (c->min_io_size == 1) { -+ buf_offs += ALIGN(len, 8); -+ if (next_len) { -+ if (buf_offs + next_len <= c->leb_size) -+ continue; -+ err = ubifs_update_one_lp(c, lnum, 0, -+ c->leb_size - buf_offs, 0, 0); -+ if (err) -+ return err; -+ lnum = -1; -+ continue; -+ } -+ err = ubifs_update_one_lp(c, lnum, -+ c->leb_size - buf_offs, 0, 0, 0); -+ if (err) -+ return err; -+ break; -+ } -+ -+ /* Update buffer positions */ -+ wlen = used + len; -+ used += ALIGN(len, 8); -+ avail -= ALIGN(len, 8); -+ -+ if (next_len != 0 && -+ buf_offs + used + next_len <= c->leb_size && -+ avail > 0) -+ continue; -+ -+ if (avail <= 0 && next_len && -+ buf_offs + used + next_len <= c->leb_size) -+ blen = buf_len; -+ else -+ blen = ALIGN(wlen, c->min_io_size); -+ -+ /* The buffer is full or there are no more znodes to do */ -+ buf_offs += blen; -+ if (next_len) { -+ if (buf_offs + next_len > c->leb_size) { -+ err = ubifs_update_one_lp(c, lnum, -+ c->leb_size - buf_offs, blen - used, -+ 0, 0); -+ if (err) -+ return err; -+ lnum = -1; -+ } -+ used -= blen; -+ if (used < 0) -+ used = 0; -+ avail = buf_len - used; -+ continue; -+ } -+ err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs, -+ blen - used, 0, 0); -+ if (err) -+ return err; -+ break; -+ } -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ c->new_ihead_lnum = lnum; -+ c->new_ihead_offs = buf_offs; -+#endif -+ -+ return 0; -+} -+ -+/** -+ * layout_commit - determine positions of index nodes to commit. -+ * @c: UBIFS file-system description object -+ * @no_space: indicates that insufficient empty LEBs were allocated -+ * @cnt: number of znodes to commit -+ * -+ * Calculate and update the positions of index nodes to commit. If there were -+ * an insufficient number of empty LEBs allocated, then index nodes are placed -+ * into the gaps created by obsolete index nodes in non-empty index LEBs. For -+ * this purpose, an obsolete index node is one that was not in the index as at -+ * the end of the last commit. To write "in-the-gaps" requires that those index -+ * LEBs are updated atomically in-place. -+ */ -+static int layout_commit(struct ubifs_info *c, int no_space, int cnt) -+{ -+ int err; -+ -+ if (no_space) { -+ err = layout_in_gaps(c, cnt); -+ if (err) -+ return err; -+ } -+ err = layout_in_empty_space(c); -+ return err; -+} -+ -+/** -+ * find_first_dirty - find first dirty znode. -+ * @znode: znode to begin searching from -+ */ -+static struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode) -+{ -+ int i, cont; -+ -+ if (!znode) -+ return NULL; -+ -+ while (1) { -+ if (znode->level == 0) { -+ if (ubifs_zn_dirty(znode)) -+ return znode; -+ return NULL; -+ } -+ cont = 0; -+ for (i = 0; i < znode->child_cnt; i++) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[i]; -+ -+ if (zbr->znode && ubifs_zn_dirty(zbr->znode)) { -+ znode = zbr->znode; -+ cont = 1; -+ break; -+ } -+ } -+ if (!cont) { -+ if (ubifs_zn_dirty(znode)) -+ return znode; -+ return NULL; -+ } -+ } -+} -+ -+/** -+ * find_next_dirty - find next dirty znode. -+ * @znode: znode to begin searching from -+ */ -+static struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode) -+{ -+ int n = znode->iip + 1; -+ -+ znode = znode->parent; -+ if (!znode) -+ return NULL; -+ for (; n < znode->child_cnt; n++) { -+ struct ubifs_zbranch *zbr = &znode->zbranch[n]; -+ -+ if (zbr->znode && ubifs_zn_dirty(zbr->znode)) -+ return find_first_dirty(zbr->znode); -+ } -+ return znode; -+} -+ -+/** -+ * get_znodes_to_commit - create list of dirty znodes to commit. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns the number of znodes to commit. -+ */ -+static int get_znodes_to_commit(struct ubifs_info *c) -+{ -+ struct ubifs_znode *znode, *cnext; -+ int cnt = 0; -+ -+ c->cnext = find_first_dirty(c->zroot.znode); -+ znode = c->enext = c->cnext; -+ if (!znode) { -+ dbg_cmt("no znodes to commit"); -+ return 0; -+ } -+ cnt += 1; -+ while (1) { -+ ubifs_assert(!test_bit(COW_ZNODE, &znode->flags)); -+ __set_bit(COW_ZNODE, &znode->flags); -+ znode->alt = 0; -+ cnext = find_next_dirty(znode); -+ if (!cnext) { -+ znode->cnext = c->cnext; -+ break; -+ } -+ znode->cnext = cnext; -+ znode = cnext; -+ cnt += 1; -+ } -+ dbg_cmt("committing %d znodes", cnt); -+ ubifs_assert(cnt == atomic_long_read(&c->dirty_zn_cnt)); -+ return cnt; -+} -+ -+/** -+ * alloc_idx_lebs - allocate empty LEBs to be used to commit. -+ * @c: UBIFS file-system description object -+ * @cnt: number of znodes to commit -+ * -+ * This function returns %-ENOSPC if it cannot allocate a sufficient number of -+ * empty LEBs. %0 is returned on success, otherwise a negative error code -+ * is returned. -+ */ -+static int alloc_idx_lebs(struct ubifs_info *c, int cnt) -+{ -+ int i, leb_cnt, lnum; -+ -+ c->ileb_cnt = 0; -+ c->ileb_nxt = 0; -+ leb_cnt = get_leb_cnt(c, cnt); -+ dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt); -+ if (!leb_cnt) -+ return 0; -+ c->ilebs = kmalloc(leb_cnt * sizeof(int), GFP_NOFS); -+ if (!c->ilebs) -+ return -ENOMEM; -+ for (i = 0; i < leb_cnt; i++) { -+ lnum = ubifs_find_free_leb_for_idx(c); -+ if (lnum < 0) -+ return lnum; -+ c->ilebs[c->ileb_cnt++] = lnum; -+ dbg_cmt("LEB %d", lnum); -+ } -+ if (dbg_force_in_the_gaps()) -+ return -ENOSPC; -+ return 0; -+} -+ -+/** -+ * free_unused_idx_lebs - free unused LEBs that were allocated for the commit. -+ * @c: UBIFS file-system description object -+ * -+ * It is possible that we allocate more empty LEBs for the commit than we need. -+ * This functions frees the surplus. -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int free_unused_idx_lebs(struct ubifs_info *c) -+{ -+ int i, err = 0, lnum, er; -+ -+ for (i = c->ileb_nxt; i < c->ileb_cnt; i++) { -+ lnum = c->ilebs[i]; -+ dbg_cmt("LEB %d", lnum); -+ er = ubifs_change_one_lp(c, lnum, -1, -1, 0, -+ LPROPS_INDEX | LPROPS_TAKEN, 0); -+ if (!err) -+ err = er; -+ } -+ return err; -+} -+ -+/** -+ * free_idx_lebs - free unused LEBs after commit end. -+ * @c: UBIFS file-system description object -+ * -+ * This function returns %0 on success and a negative error code on failure. -+ */ -+static int free_idx_lebs(struct ubifs_info *c) -+{ -+ int err; -+ -+ err = free_unused_idx_lebs(c); -+ kfree(c->ilebs); -+ c->ilebs = NULL; -+ return err; -+} -+ -+/** -+ * ubifs_tnc_start_commit - start TNC commit. -+ * @c: UBIFS file-system description object -+ * @zroot: new index root position is returned here -+ * -+ * This function prepares the list of indexing nodes to commit and lays out -+ * their positions on flash. If there is not enough free space it uses the -+ * in-gap commit method. Returns zero in case of success and a negative error -+ * code in case of failure. -+ */ -+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot) -+{ -+ int err = 0, cnt; -+ -+ mutex_lock(&c->tnc_mutex); -+ err = dbg_check_tnc(c, 1); -+ if (err) -+ goto out; -+ cnt = get_znodes_to_commit(c); -+ if (cnt != 0) { -+ int no_space = 0; -+ -+ err = alloc_idx_lebs(c, cnt); -+ if (err == -ENOSPC) -+ no_space = 1; -+ else if (err) -+ goto out_free; -+ err = layout_commit(c, no_space, cnt); -+ if (err) -+ goto out_free; -+ ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0); -+ err = free_unused_idx_lebs(c); -+ if (err) -+ goto out; -+ } -+ destroy_old_idx(c); -+ memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch)); -+ -+ err = ubifs_save_dirty_idx_lnums(c); -+ if (err) -+ goto out; -+ -+ spin_lock(&c->space_lock); -+ /* -+ * Although we have not finished committing yet, update size of the -+ * committed index ('c->old_idx_sz') and zero out the index growth -+ * budget. It is OK to do this now, because we've reserved all the -+ * space which is needed to commit the index, and it is save for the -+ * budgeting subsystem to assume the index is already committed, -+ * even though it is not. -+ */ -+ c->old_idx_sz = c->calc_idx_sz; -+ c->budg_uncommitted_idx = 0; -+ spin_unlock(&c->space_lock); -+ mutex_unlock(&c->tnc_mutex); -+ -+ dbg_cmt("number of index LEBs %d", c->lst.idx_lebs); -+ dbg_cmt("size of index %llu", c->calc_idx_sz); -+ return err; -+ -+out_free: -+ free_idx_lebs(c); -+out: -+ mutex_unlock(&c->tnc_mutex); -+ return err; -+} -+ -+/** -+ * write_index - write index nodes. -+ * @c: UBIFS file-system description object -+ * -+ * This function writes the index nodes whose positions were laid out in the -+ * layout_in_empty_space function. -+ */ -+static int write_index(struct ubifs_info *c) -+{ -+ struct ubifs_idx_node *idx; -+ struct ubifs_znode *znode, *cnext; -+ int i, lnum, offs, len, next_len, buf_len, buf_offs, used; -+ int avail, wlen, err, lnum_pos = 0; -+ -+ cnext = c->enext; -+ if (!cnext) -+ return 0; -+ -+ /* -+ * Always write index nodes to the index head so that index nodes and -+ * other types of nodes are never mixed in the same erase block. -+ */ -+ lnum = c->ihead_lnum; -+ buf_offs = c->ihead_offs; -+ -+ /* Allocate commit buffer */ -+ buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size); -+ used = 0; -+ avail = buf_len; -+ -+ /* Ensure there is enough room for first write */ -+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); -+ if (buf_offs + next_len > c->leb_size) { -+ err = ubifs_update_one_lp(c, lnum, -1, -1, 0, LPROPS_TAKEN); -+ if (err) -+ return err; -+ lnum = -1; -+ } -+ -+ while (1) { -+ cond_resched(); -+ -+ znode = cnext; -+ idx = c->cbuf + used; -+ -+ /* Make index node */ -+ idx->ch.node_type = UBIFS_IDX_NODE; -+ idx->child_cnt = cpu_to_le16(znode->child_cnt); -+ idx->level = cpu_to_le16(znode->level); -+ for (i = 0; i < znode->child_cnt; i++) { -+ struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); -+ struct ubifs_zbranch *zbr = &znode->zbranch[i]; -+ -+ key_write_idx(c, &zbr->key, &br->key); -+ br->lnum = cpu_to_le32(zbr->lnum); -+ br->offs = cpu_to_le32(zbr->offs); -+ br->len = cpu_to_le32(zbr->len); -+ if (!zbr->lnum || !zbr->len) { -+ ubifs_err("bad ref in znode"); -+ dbg_dump_znode(c, znode); -+ if (zbr->znode) -+ dbg_dump_znode(c, zbr->znode); -+ } -+ } -+ len = ubifs_idx_node_sz(c, znode->child_cnt); -+ ubifs_prepare_node(c, idx, len, 0); -+ -+ /* Determine the index node position */ -+ if (lnum == -1) { -+ lnum = c->ilebs[lnum_pos++]; -+ buf_offs = 0; -+ used = 0; -+ avail = buf_len; -+ } -+ offs = buf_offs + used; -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ if (lnum != znode->lnum || offs != znode->offs || -+ len != znode->len) { -+ ubifs_err("inconsistent znode posn"); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Grab some stuff from znode while we still can */ -+ cnext = znode->cnext; -+ -+ ubifs_assert(ubifs_zn_dirty(znode)); -+ ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); -+ -+ /* -+ * It is important that other threads should see %DIRTY_ZNODE -+ * flag cleared before %COW_ZNODE. Specifically, it matters in -+ * the 'dirty_cow_znode()' function. This is the reason for the -+ * first barrier. Also, we want the bit changes to be seen to -+ * other threads ASAP, to avoid unnecesarry copying, which is -+ * the reason for the second barrier. -+ */ -+ clear_bit(DIRTY_ZNODE, &znode->flags); -+ smp_mb__before_clear_bit(); -+ clear_bit(COW_ZNODE, &znode->flags); -+ smp_mb__after_clear_bit(); -+ -+ /* Do not access znode from this point on */ -+ -+ /* Update buffer positions */ -+ wlen = used + len; -+ used += ALIGN(len, 8); -+ avail -= ALIGN(len, 8); -+ -+ /* -+ * Calculate the next index node length to see if there is -+ * enough room for it -+ */ -+ if (cnext == c->cnext) -+ next_len = 0; -+ else -+ next_len = ubifs_idx_node_sz(c, cnext->child_cnt); -+ -+ if (c->min_io_size == 1) { -+ /* -+ * Write the prepared index node immediately if there is -+ * no minimum IO size -+ */ -+ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, -+ wlen, UBI_SHORTTERM); -+ if (err) -+ return err; -+ buf_offs += ALIGN(wlen, 8); -+ if (next_len) { -+ used = 0; -+ avail = buf_len; -+ if (buf_offs + next_len > c->leb_size) { -+ err = ubifs_update_one_lp(c, lnum, -1, -+ -1, 0, -+ LPROPS_TAKEN); -+ if (err) -+ return err; -+ lnum = -1; -+ } -+ continue; -+ } -+ } else { -+ int blen, nxt_offs = buf_offs + used + next_len; -+ -+ if (next_len && nxt_offs <= c->leb_size) { -+ if (avail > 0) -+ continue; -+ else -+ blen = buf_len; -+ } else { -+ wlen = ALIGN(wlen, 8); -+ blen = ALIGN(wlen, c->min_io_size); -+ ubifs_pad(c, c->cbuf + wlen, blen - wlen); -+ } -+ /* -+ * The buffer is full or there are no more znodes -+ * to do -+ */ -+ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, -+ blen, UBI_SHORTTERM); -+ if (err) -+ return err; -+ buf_offs += blen; -+ if (next_len) { -+ if (nxt_offs > c->leb_size) { -+ err = ubifs_update_one_lp(c, lnum, -1, -+ -1, 0, -+ LPROPS_TAKEN); -+ if (err) -+ return err; -+ lnum = -1; -+ } -+ used -= blen; -+ if (used < 0) -+ used = 0; -+ avail = buf_len - used; -+ memmove(c->cbuf, c->cbuf + blen, used); -+ continue; -+ } -+ } -+ break; -+ } -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ if (lnum != c->new_ihead_lnum || buf_offs != c->new_ihead_offs) { -+ ubifs_err("inconsistent ihead"); -+ return -EINVAL; -+ } -+#endif -+ -+ c->ihead_lnum = lnum; -+ c->ihead_offs = buf_offs; -+ -+ return 0; -+} -+ -+/** -+ * free_obsolete_znodes - free obsolete znodes. -+ * @c: UBIFS file-system description object -+ * -+ * At the end of commit end, obsolete znodes are freed. -+ */ -+static void free_obsolete_znodes(struct ubifs_info *c) -+{ -+ struct ubifs_znode *znode, *cnext; -+ -+ cnext = c->cnext; -+ do { -+ znode = cnext; -+ cnext = znode->cnext; -+ if (test_bit(OBSOLETE_ZNODE, &znode->flags)) -+ kfree(znode); -+ else { -+ znode->cnext = NULL; -+ atomic_long_inc(&c->clean_zn_cnt); -+ atomic_long_inc(&ubifs_clean_zn_cnt); -+ } -+ } while (cnext != c->cnext); -+} -+ -+/** -+ * return_gap_lebs - return LEBs used by the in-gap commit method. -+ * @c: UBIFS file-system description object -+ * -+ * This function clears the "taken" flag for the LEBs which were used by the -+ * "commit in-the-gaps" method. -+ */ -+static int return_gap_lebs(struct ubifs_info *c) -+{ -+ int *p, err; -+ -+ if (!c->gap_lebs) -+ return 0; -+ -+ dbg_cmt(""); -+ for (p = c->gap_lebs; *p != -1; p++) { -+ err = ubifs_change_one_lp(c, *p, -1, -1, 0, LPROPS_TAKEN, 0); -+ if (err) -+ return err; -+ } -+ -+ kfree(c->gap_lebs); -+ c->gap_lebs = NULL; -+ return 0; -+} -+ -+/** -+ * ubifs_tnc_end_commit - update the TNC for commit end. -+ * @c: UBIFS file-system description object -+ * -+ * Write the dirty znodes. -+ */ -+int ubifs_tnc_end_commit(struct ubifs_info *c) -+{ -+ int err; -+ -+ if (!c->cnext) -+ return 0; -+ -+ err = return_gap_lebs(c); -+ if (err) -+ return err; -+ -+ err = write_index(c); -+ if (err) -+ return err; -+ -+ mutex_lock(&c->tnc_mutex); -+ -+ dbg_cmt("TNC height is %d", c->zroot.znode->level + 1); -+ -+ free_obsolete_znodes(c); -+ -+ c->cnext = NULL; -+ kfree(c->ilebs); -+ c->ilebs = NULL; -+ -+ mutex_unlock(&c->tnc_mutex); -+ -+ return 0; -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/tnc_misc.c linux-2.6.24.7/fs/ubifs/tnc_misc.c ---- linux-2.6.24.7.old/fs/ubifs/tnc_misc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/tnc_misc.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,259 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Adrian Hunter -+ * Artem Bityutskiy (Битюцкий Ðртём) -+ */ -+ -+/* -+ * This file contains miscelanious TNC-related functions shared betweend -+ * different files. This file does not form any logically separate TNC -+ * sub-system. The file was created because there is a lot of TNC code and -+ * putting it all in one file would make that file too big and unreadable. -+ * Nonetheless, this contains more or less "generic" code which may be used for -+ * more then one specific task. -+ */ -+ -+#include "ubifs.h" -+ -+/** -+ * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal. -+ * @zr: root of the subtree to traverse -+ * @znode: previous znode -+ * -+ * This function implements levelorder TNC traversal. The LNC is ignored. -+ * Returns the next element or %NULL if @znode is already the last one. -+ */ -+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr, -+ struct ubifs_znode *znode) -+{ -+ int level, iip, level_search = 0; -+ struct ubifs_znode *zn; -+ -+ ubifs_assert(zr); -+ -+ if (unlikely(!znode)) -+ return zr; -+ -+ if (unlikely(znode == zr)) { -+ if (znode->level == 0) -+ return NULL; -+ return ubifs_tnc_find_child(zr, 0); -+ } -+ -+ level = znode->level; -+ -+ iip = znode->iip; -+ while (1) { -+ ubifs_assert(znode->level <= zr->level); -+ -+ /* -+ * First walk up until there is a znode with next branch to -+ * look at. -+ */ -+ while (znode->parent != zr && iip >= znode->parent->child_cnt) { -+ znode = znode->parent; -+ iip = znode->iip; -+ } -+ -+ if (unlikely(znode->parent == zr && -+ iip >= znode->parent->child_cnt)) { -+ /* This level is done, switch to the lower one */ -+ level -= 1; -+ if (level_search || level < 0) -+ /* -+ * We were already looking for znode at lower -+ * level ('level_search'). As we are here -+ * again, it just does not exist. Or all levels -+ * were finished ('level < 0'). -+ */ -+ return NULL; -+ -+ level_search = 1; -+ iip = -1; -+ znode = ubifs_tnc_find_child(zr, 0); -+ ubifs_assert(znode); -+ } -+ -+ /* Switch to the next index */ -+ zn = ubifs_tnc_find_child(znode->parent, iip + 1); -+ if (!zn) { -+ /* No more children to look at, we have walk up */ -+ iip = znode->parent->child_cnt; -+ continue; -+ } -+ -+ /* Walk back down to the level we came from ('level') */ -+ while (zn->level != level) { -+ znode = zn; -+ zn = ubifs_tnc_find_child(zn, 0); -+ if (!zn) { -+ /* -+ * This path is not too deep so it does not -+ * reach 'level'. Try next path. -+ */ -+ iip = znode->iip; -+ break; -+ } -+ } -+ -+ if (zn) { -+ ubifs_assert(zn->level >= 0); -+ return zn; -+ } -+ } -+} -+ -+/** -+ * ubifs_search_zbranch - search znode branch. -+ * @c: UBIFS file-system description object -+ * @znode: znode to search in -+ * @key: key to search for -+ * @n: znode branch slot number is returned here -+ * -+ * This is a helper function which search branch with key @key in @znode using -+ * binary search. The result of the search may be: -+ * o exact match, then %1 is returned, and the slot number of the branch is -+ * stored in @n; -+ * o no exact match, then %0 is returned and the slot number of the left -+ * closest branch is returned in @n; the slot if all keys in this znode are -+ * greater than @key, then %-1 is returned in @n. -+ */ -+int ubifs_search_zbranch(const struct ubifs_info *c, -+ const struct ubifs_znode *znode, -+ const union ubifs_key *key, int *n) -+{ -+ int beg = 0, end = znode->child_cnt, uninitialized_var(mid); -+ int uninitialized_var(cmp); -+ const struct ubifs_zbranch *zbr = &znode->zbranch[0]; -+ -+ ubifs_assert(end > beg); -+ -+ while (end > beg) { -+ mid = (beg + end) >> 1; -+ cmp = keys_cmp(c, key, &zbr[mid].key); -+ if (cmp > 0) -+ beg = mid + 1; -+ else if (cmp < 0) -+ end = mid; -+ else { -+ *n = mid; -+ return 1; -+ } -+ } -+ -+ *n = end - 1; -+ -+ /* The insert point is after *n */ -+ ubifs_assert(*n >= -1 && *n < znode->child_cnt); -+ if (*n == -1) -+ ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0); -+ else -+ ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0); -+ if (*n + 1 < znode->child_cnt) -+ ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0); -+ -+ return 0; -+} -+ -+/** -+ * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal. -+ * @znode: znode to start at (root of the sub-tree to traverse) -+ * -+ * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is -+ * ignored. -+ */ -+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode) -+{ -+ if (unlikely(!znode)) -+ return NULL; -+ -+ while (znode->level > 0) { -+ struct ubifs_znode *child; -+ -+ child = ubifs_tnc_find_child(znode, 0); -+ if (!child) -+ return znode; -+ znode = child; -+ } -+ -+ return znode; -+} -+ -+/** -+ * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal. -+ * @znode: previous znode -+ * -+ * This function implements postorder TNC traversal. The LNC is ignored. -+ * Returns the next element or %NULL if @znode is already the last one. -+ */ -+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode) -+{ -+ struct ubifs_znode *zn; -+ -+ ubifs_assert(znode); -+ if (unlikely(!znode->parent)) -+ return NULL; -+ -+ /* Switch to the next index in the parent */ -+ zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1); -+ if (!zn) -+ /* This is in fact the last child, return parent */ -+ return znode->parent; -+ -+ /* Go to the first znode in this new subtree */ -+ return ubifs_tnc_postorder_first(zn); -+} -+ -+/** -+ * ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree. -+ * @znode: znode defining subtree to destroy -+ * -+ * This function destroys subtree of the TNC tree. Returns number of clean -+ * znodes in the subtree. -+ */ -+long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode) -+{ -+ struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode); -+ long clean_freed = 0; -+ int n; -+ -+ ubifs_assert(zn); -+ while (1) { -+ for (n = 0; n < zn->child_cnt; n++) { -+ if (!zn->zbranch[n].znode) -+ continue; -+ -+ if (zn->level > 0 && -+ !ubifs_zn_dirty(zn->zbranch[n].znode)) -+ clean_freed += 1; -+ -+ cond_resched(); -+ kfree(zn->zbranch[n].znode); -+ } -+ -+ if (zn == znode) { -+ if (!ubifs_zn_dirty(zn)) -+ clean_freed += 1; -+ kfree(zn); -+ return clean_freed; -+ } -+ -+ zn = ubifs_tnc_postorder_next(zn); -+ } -+} -diff -urN linux-2.6.24.7.old/fs/ubifs/ubifs-media.h linux-2.6.24.7/fs/ubifs/ubifs-media.h ---- linux-2.6.24.7.old/fs/ubifs/ubifs-media.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/ubifs-media.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,731 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file describes UBIFS on-flash format and contains definitions of all the -+ * relevant data structures and constants. -+ * -+ * All UBIFS on-flash objects are stored in the form of nodes. All nodes start -+ * with the UBIFS node magic number and have the same common header. Nodes -+ * always sit at 8-byte aligned positions on the media and node header sizes are -+ * also 8-byte aligned (except for the indexing node and the padding node). -+ */ -+ -+#ifndef __UBIFS_MEDIA_H__ -+#define __UBIFS_MEDIA_H__ -+ -+/* UBIFS node magic number (must not have the padding byte first or last) */ -+#define UBIFS_NODE_MAGIC 0x06101831 -+ -+/* UBIFS on-flash format version */ -+#define UBIFS_FORMAT_VERSION 3 -+ -+/* Minimum logical eraseblock size in bytes */ -+#define UBIFS_MIN_LEB_SZ (15*1024) -+ -+/* Initial CRC32 value used when calculating CRC checksums */ -+#define UBIFS_CRC32_INIT 0xFFFFFFFFU -+ -+/* -+ * UBIFS does not try to compress data if its length is less than the below -+ * constant. -+ */ -+#define UBIFS_MIN_COMPR_LEN 128 -+ -+/* Root inode number */ -+#define UBIFS_ROOT_INO 1 -+ -+/* Lowest inode number used for regular inodes (not UBIFS-only internal ones) */ -+#define UBIFS_FIRST_INO 64 -+ -+/* -+ * Maximum file name and extended attribute length (must be a multiple of 8, -+ * minus 1). -+ */ -+#define UBIFS_MAX_NLEN 255 -+ -+/* Maximum number of data journal heads */ -+#define UBIFS_MAX_JHEADS 1 -+ -+/* -+ * Size of UBIFS data block. Note, UBIFS is not a block oriented file-system, -+ * which means that it does not treat the underlying media as consisting of -+ * blocks like in case of hard drives. Do not be confused. UBIFS block is just -+ * the maximum amount of data which one data node can have or which can be -+ * attached to an inode node. -+ */ -+#define UBIFS_BLOCK_SIZE 4096 -+#define UBIFS_BLOCK_SHIFT 12 -+#define UBIFS_BLOCK_MASK 0x00000FFF -+ -+/* UBIFS padding byte pattern (must not be first or last byte of node magic) */ -+#define UBIFS_PADDING_BYTE 0xCE -+ -+/* Maximum possible key length */ -+#define UBIFS_MAX_KEY_LEN 16 -+ -+/* Key length ("simple" format) */ -+#define UBIFS_SK_LEN 8 -+ -+/* Minimum index tree fanout */ -+#define UBIFS_MIN_FANOUT 2 -+ -+/* Maximum number of levels in UBIFS indexing B-tree */ -+#define UBIFS_MAX_LEVELS 512 -+ -+/* Maximum amount of data attached to an inode in bytes */ -+#define UBIFS_MAX_INO_DATA UBIFS_BLOCK_SIZE -+ -+/* LEB Properties Tree fanout (must be power of 2) and fanout shift */ -+#define UBIFS_LPT_FANOUT 4 -+#define UBIFS_LPT_FANOUT_SHIFT 2 -+ -+/* LEB Properties Tree bit field sizes */ -+#define UBIFS_LPT_CRC_BITS 16 -+#define UBIFS_LPT_CRC_BYTES 2 -+#define UBIFS_LPT_TYPE_BITS 4 -+ -+/* The key is always at the same position in all keyed nodes */ -+#define UBIFS_KEY_OFFSET offsetof(struct ubifs_ino_node, key) -+ -+/* -+ * LEB Properties Tree node types. -+ * -+ * UBIFS_LPT_PNODE: LPT leaf node (contains LEB properties) -+ * UBIFS_LPT_NNODE: LPT internal node -+ * UBIFS_LPT_LTAB: LPT's own lprops table -+ * UBIFS_LPT_LSAVE: LPT's save table (big model only) -+ * UBIFS_LPT_NODE_CNT: count of LPT node types -+ * UBIFS_LPT_NOT_A_NODE: all ones (15 for 4 bits) is never a valid node type -+ */ -+enum { -+ UBIFS_LPT_PNODE, -+ UBIFS_LPT_NNODE, -+ UBIFS_LPT_LTAB, -+ UBIFS_LPT_LSAVE, -+ UBIFS_LPT_NODE_CNT, -+ UBIFS_LPT_NOT_A_NODE = (1 << UBIFS_LPT_TYPE_BITS) - 1, -+}; -+ -+/* -+ * UBIFS inode types. -+ * -+ * UBIFS_ITYPE_REG: regular file -+ * UBIFS_ITYPE_DIR: directory -+ * UBIFS_ITYPE_LNK: soft link -+ * UBIFS_ITYPE_BLK: block device node -+ * UBIFS_ITYPE_CHR: character device node -+ * UBIFS_ITYPE_FIFO: fifo -+ * UBIFS_ITYPE_SOCK: socket -+ * UBIFS_ITYPES_CNT: count of supported file types -+ */ -+enum { -+ UBIFS_ITYPE_REG, -+ UBIFS_ITYPE_DIR, -+ UBIFS_ITYPE_LNK, -+ UBIFS_ITYPE_BLK, -+ UBIFS_ITYPE_CHR, -+ UBIFS_ITYPE_FIFO, -+ UBIFS_ITYPE_SOCK, -+ UBIFS_ITYPES_CNT, -+}; -+ -+/* -+ * Supported key hash functions. -+ * -+ * UBIFS_KEY_HASH_R5: R5 hash -+ * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name -+ */ -+enum { -+ UBIFS_KEY_HASH_R5, -+ UBIFS_KEY_HASH_TEST, -+}; -+ -+/* -+ * Supported key formats. -+ * -+ * UBIFS_SIMPLE_KEY_FMT: simple key format -+ */ -+enum { -+ UBIFS_SIMPLE_KEY_FMT, -+}; -+ -+/* -+ * The simple key format uses 29 bits for storing UBIFS block number and hash -+ * value. -+ */ -+#define UBIFS_S_KEY_BLOCK_BITS 29 -+/* -+ * TODO: this is a temporary hach which was added to support old format and to -+ * avoid breaking binary compatibility. It is temporaty and should go. The -+ * define should be -+ * #define UBIFS_S_KEY_BLOCK_MASK 0x1FFFFFFF -+ */ -+#define UBIFS_S_KEY_BLOCK_MASK (c->fmt_version == 2 ? 0x01FFFFFF : 0x1FFFFFFF) -+#define UBIFS_S_KEY_HASH_BITS UBIFS_S_KEY_BLOCK_BITS -+#define UBIFS_S_KEY_HASH_MASK UBIFS_S_KEY_BLOCK_MASK -+ -+/* -+ * Key types. -+ * -+ * UBIFS_INO_KEY: inode node key -+ * UBIFS_DATA_KEY: data node key -+ * UBIFS_DENT_KEY: directory entry node key -+ * UBIFS_XENT_KEY: extended attribute entry key -+ * UBIFS_TRUN_KEY: truncation node key -+ * UBIFS_KEY_TYPES_CNT: number of supported key types -+ */ -+enum { -+ UBIFS_INO_KEY, -+ UBIFS_DATA_KEY, -+ UBIFS_DENT_KEY, -+ UBIFS_XENT_KEY, -+ UBIFS_TRUN_KEY, -+ UBIFS_KEY_TYPES_CNT, -+}; -+ -+/* Count of LEBs reserved for the superblock area */ -+#define UBIFS_SB_LEBS 1 -+/* Count of LEBs reserved for the master area */ -+#define UBIFS_MST_LEBS 2 -+ -+/* First LEB of the superblock area */ -+#define UBIFS_SB_LNUM 0 -+/* First LEB of the master area */ -+#define UBIFS_MST_LNUM (UBIFS_SB_LNUM + UBIFS_SB_LEBS) -+/* First LEB of the log area */ -+#define UBIFS_LOG_LNUM (UBIFS_MST_LNUM + UBIFS_MST_LEBS) -+ -+/* Minimum number of logical eraseblocks in the log */ -+#define UBIFS_MIN_LOG_LEBS 2 -+/* Minimum number of bud logical eraseblocks */ -+#define UBIFS_MIN_BUD_LEBS 2 -+/* Minimum number of journal logical eraseblocks */ -+#define UBIFS_MIN_JNL_LEBS (UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS) -+/* Minimum number of LPT area logical eraseblocks */ -+#define UBIFS_MIN_LPT_LEBS 2 -+/* Minimum number of orphan area logical eraseblocks */ -+#define UBIFS_MIN_ORPH_LEBS 1 -+/* Minimum number of main area logical eraseblocks */ -+#define UBIFS_MIN_MAIN_LEBS 8 -+ -+/* Minimum number of logical eraseblocks */ -+#define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ -+ UBIFS_MIN_LOG_LEBS + UBIFS_MIN_BUD_LEBS + \ -+ UBIFS_MIN_LPT_LEBS + UBIFS_MIN_ORPH_LEBS + \ -+ UBIFS_MIN_MAIN_LEBS) -+ -+/* Node sizes (N.B. these are guaranteed to be multiples of 8) */ -+#define UBIFS_CH_SZ sizeof(struct ubifs_ch) -+#define UBIFS_INO_NODE_SZ sizeof(struct ubifs_ino_node) -+#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node) -+#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node) -+#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node) -+#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node) -+#define UBIFS_SB_NODE_SZ sizeof(struct ubifs_sb_node) -+#define UBIFS_MST_NODE_SZ sizeof(struct ubifs_mst_node) -+#define UBIFS_REF_NODE_SZ sizeof(struct ubifs_ref_node) -+#define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node) -+#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node) -+#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node) -+/* Extended attribute entry nodes are identical to directory entry nodes */ -+#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ -+/* Only this does not have to be multiple of 8 bytes */ -+#define UBIFS_BRANCH_SZ sizeof(struct ubifs_branch) -+ -+/* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */ -+#define UBIFS_MAX_DATA_NODE_SZ (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE) -+#define UBIFS_MAX_INO_NODE_SZ (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA) -+#define UBIFS_MAX_DENT_NODE_SZ (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1) -+#define UBIFS_MAX_XENT_NODE_SZ UBIFS_MAX_DENT_NODE_SZ -+ -+/* The largest UBIFS node */ -+#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ -+ -+/* -+ * On-flash inode flags. -+ * -+ * UBIFS_COMPR_FL: use compression for this inode -+ * UBIFS_SYNC_FL: I/O on this inode has to be synchronous -+ * UBIFS_IMMUTABLE_FL: inode is immutable -+ * UBIFS_APPEND_FL: writes to the inode may only append data -+ * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous -+ * -+ * Note, these are on-flash flags which correspond to ioctl flags -+ * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not -+ * have to be the same. -+ */ -+enum { -+ UBIFS_COMPR_FL = 0x01, -+ UBIFS_SYNC_FL = 0x02, -+ UBIFS_IMMUTABLE_FL = 0x04, -+ UBIFS_APPEND_FL = 0x08, -+ UBIFS_DIRSYNC_FL = 0x10, -+}; -+ -+/* Inode flag bits used by UBIFS */ -+#define UBIFS_FL_MASK 0x0000001F -+ -+/* -+ * UBIFS compression types. -+ * -+ * UBIFS_COMPR_NONE: no compression -+ * UBIFS_COMPR_LZO: LZO compression -+ * UBIFS_COMPR_ZLIB: ZLIB compression -+ * UBIFS_COMPR_TYPES_CNT: count of supported compression types -+ */ -+enum { -+ UBIFS_COMPR_NONE, -+ UBIFS_COMPR_LZO, -+ UBIFS_COMPR_ZLIB, -+ UBIFS_COMPR_TYPES_CNT, -+}; -+ -+/* -+ * UBIFS node types. -+ * -+ * UBIFS_INO_NODE: inode node -+ * UBIFS_DATA_NODE: data node -+ * UBIFS_DENT_NODE: directory entry node -+ * UBIFS_XENT_NODE: extended attribute node -+ * UBIFS_TRUN_NODE: truncation node -+ * UBIFS_PAD_NODE: padding node -+ * UBIFS_SB_NODE: superblock node -+ * UBIFS_MST_NODE: master node -+ * UBIFS_REF_NODE: LEB reference node -+ * UBIFS_IDX_NODE: index node -+ * UBIFS_CS_NODE: commit start node -+ * UBIFS_ORPH_NODE: orphan node -+ * UBIFS_NODE_TYPES_CNT: count of supported node types -+ * -+ * Note, we index arrays by these numbers, so keep them low and contiguous. -+ * Node type constants for inodes, direntries and so on have to be the same as -+ * corresponding key type constants. -+ */ -+enum { -+ UBIFS_INO_NODE, -+ UBIFS_DATA_NODE, -+ UBIFS_DENT_NODE, -+ UBIFS_XENT_NODE, -+ UBIFS_TRUN_NODE, -+ UBIFS_PAD_NODE, -+ UBIFS_SB_NODE, -+ UBIFS_MST_NODE, -+ UBIFS_REF_NODE, -+ UBIFS_IDX_NODE, -+ UBIFS_CS_NODE, -+ UBIFS_ORPH_NODE, -+ UBIFS_NODE_TYPES_CNT, -+}; -+ -+/* -+ * Master node flags. -+ * -+ * UBIFS_MST_DIRTY: rebooted uncleanly - master node is dirty -+ * UBIFS_MST_NO_ORPHS: no orphan inodes present -+ * UBIFS_MST_RCVRY: written by recovery -+ */ -+enum { -+ UBIFS_MST_DIRTY = 1, -+ UBIFS_MST_NO_ORPHS = 2, -+ UBIFS_MST_RCVRY = 4, -+}; -+ -+/* -+ * Node group type (used by recovery to recover whole group or none). -+ * -+ * UBIFS_NO_NODE_GROUP: this node is not part of a group -+ * UBIFS_IN_NODE_GROUP: this node is a part of a group -+ * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group -+ */ -+enum { -+ UBIFS_NO_NODE_GROUP = 0, -+ UBIFS_IN_NODE_GROUP, -+ UBIFS_LAST_OF_NODE_GROUP, -+}; -+ -+/* -+ * Superblock flags. -+ * -+ * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set -+ */ -+enum { -+ UBIFS_FLG_BIGLPT = 0x02, -+}; -+ -+/** -+ * struct ubifs_ch - common header node. -+ * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) -+ * @crc: CRC-32 checksum of the node header -+ * @sqnum: sequence number -+ * @len: full node length -+ * @node_type: node type -+ * @group_type: node group type -+ * @padding: reserved for future, zeroes -+ * -+ * Every UBIFS node starts with this common part. If the node has a key, the -+ * key always goes next. -+ */ -+struct ubifs_ch { -+ __le32 magic; -+ __le32 crc; -+ __le64 sqnum; -+ __le32 len; -+ __u8 node_type; -+ __u8 group_type; -+ __u8 padding[2]; -+} __attribute__ ((packed)); -+ -+/** -+ * union ubifs_dev_desc - device node descriptor. -+ * @new: new type device descriptor -+ * @huge: huge type device descriptor -+ * -+ * This data structure describes major/minor numbers of a device node. In an -+ * inode is a device node then its data contains an object of this type. UBIFS -+ * uses standard Linux "new" and "huge" device node encodings. -+ */ -+union ubifs_dev_desc { -+ __le32 new; -+ __le64 huge; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_ino_node - inode node. -+ * @ch: common header -+ * @key: node key -+ * @creat_sqnum: sequence number at time of creation -+ * @size: inode size in bytes (amount of uncompressed data) -+ * @atime_sec: access time seconds -+ * @ctime_sec: creation time seconds -+ * @mtime_sec: modification time seconds -+ * @atime_nsec: access time nanoseconds -+ * @ctime_nsec: creation time nanoseconds -+ * @mtime_nsec: modification time nanoseconds -+ * @nlink: number of hard links -+ * @uid: owner ID -+ * @gid: group ID -+ * @mode: access flags -+ * @flags: per-inode flags (%UBIFS_COMPR_FL, %UBIFS_SYNC_FL, etc) -+ * @data_len: inode data length -+ * @xattr_cnt: count of extended attributes this inode has -+ * @xattr_size: summarized size of all extended attributes in bytes -+ * @xattr_names: sum of lengths of all extended attribute names belonging to -+ * this inode -+ * @compr_type: compression type used for this inode -+ * @padding: reserved for future, zeroes -+ * @data: data attached to the inode -+ * -+ * Note, even though inode compression type is defined by @compr_type, some -+ * nodes of this inode may be compressed with different compressor - this -+ * happens if compression type is changed while the inode already has data -+ * nodes. But @compr_type will be use for further writes to the inode. -+ * -+ * Note, do not forget to amend 'zero_ino_node_unused()' function when changing -+ * the padding fields. -+ */ -+struct ubifs_ino_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 creat_sqnum; -+ __le64 size; -+ __le64 atime_sec; -+ __le64 ctime_sec; -+ __le64 mtime_sec; -+ __le32 atime_nsec; -+ __le32 ctime_nsec; -+ __le32 mtime_nsec; -+ __le32 nlink; -+ __le32 uid; -+ __le32 gid; -+ __le32 mode; -+ __le32 flags; -+ __le32 data_len; -+ __le32 xattr_cnt; -+ __le64 xattr_size; -+ __le32 xattr_names; -+ __le16 compr_type; -+ __u8 padding[26]; /* Watch 'zero_ino_node_unused()' if changing! */ -+ __u8 data[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_dent_node - directory entry node. -+ * @ch: common header -+ * @key: node key -+ * @inum: target inode number -+ * @padding1: reserved for future, zeroes -+ * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc) -+ * @nlen: name length -+ * @padding2: reserved for future, zeroes -+ * @name: zero-terminated name -+ * -+ * Note, do not forget to amend 'zero_dent_node_unused()' function when -+ * changing the padding fields. -+ */ -+struct ubifs_dent_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 inum; -+ __u8 padding1; -+ __u8 type; -+ __le16 nlen; -+ __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */ -+ __u8 name[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_data_node - data node. -+ * @ch: common header -+ * @key: node key -+ * @size: uncompressed data size in bytes -+ * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc) -+ * @padding: reserved for future, zeroes -+ * @data: data -+ * -+ * Note, do not forget to amend 'zero_data_node_unused()' function when -+ * changing the padding fields. -+ */ -+struct ubifs_data_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le32 size; -+ __le16 compr_type; -+ __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */ -+ __u8 data[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_trun_node - truncation node. -+ * @ch: common header -+ * @key: truncation node key -+ * @old_size: size before truncation -+ * @new_size: size after truncation -+ * -+ * This node exists only in the journal and never goes to the main area. -+ */ -+struct ubifs_trun_node { -+ struct ubifs_ch ch; -+ __u8 key[UBIFS_MAX_KEY_LEN]; -+ __le64 old_size; -+ __le64 new_size; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_pad_node - padding node. -+ * @ch: common header -+ * @pad_len: how many bytes after this node are unused (because padded) -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_pad_node { -+ struct ubifs_ch ch; -+ __le32 pad_len; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_sb_node - superblock node. -+ * @ch: common header -+ * @padding: reserved for future, zeroes -+ * @key_hash: type of hash function used in keys -+ * @key_fmt: format of the key -+ * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) -+ * @min_io_size: minimal input/output unit size -+ * @leb_size: logical eraseblock size in bytes -+ * @leb_cnt: count of LEBs used by filesystem -+ * @max_leb_cnt: maximum count of LEBs used by filesystem -+ * @max_bud_bytes: maximum amount of data stored in buds -+ * @log_lebs: log size in logical eraseblocks -+ * @lpt_lebs: number of LEBs used for lprops table -+ * @orph_lebs: number of LEBs used for recording orphans -+ * @jhead_cnt: count of journal heads -+ * @fanout: tree fanout (max. number of links per indexing node) -+ * @lsave_cnt: number of LEB numbers in LPT's save table -+ * @fmt_version: UBIFS on-flash format version -+ * @default_compr: default compression -+ * @padding1: reserved for future, zeroes -+ * @rp_uid: reserve pool UID -+ * @rp_gid: reserve pool GID -+ * @rp_size: size of the reserved pool in bytes -+ * @padding2: reserved for future, zeroes -+ * @time_gran: time granularity in nanoseconds -+ */ -+struct ubifs_sb_node { -+ struct ubifs_ch ch; -+ __u8 padding[2]; -+ __u8 key_hash; -+ __u8 key_fmt; -+ __le32 flags; -+ __le32 min_io_size; -+ __le32 leb_size; -+ __le32 leb_cnt; -+ __le32 max_leb_cnt; -+ __le64 max_bud_bytes; -+ __le32 log_lebs; -+ __le32 lpt_lebs; -+ __le32 orph_lebs; -+ __le32 jhead_cnt; -+ __le32 fanout; -+ __le32 lsave_cnt; -+ __le32 fmt_version; -+ __le16 default_compr; -+ __u8 padding1[2]; -+ __le32 rp_uid; -+ __le32 rp_gid; -+ __le64 rp_size; -+ __le32 time_gran; -+ __u8 padding2[3988]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_mst_node - master node. -+ * @ch: common header -+ * @highest_inum: highest inode number in the committed index -+ * @cmt_no: commit number -+ * @flags: various flags (%UBIFS_MST_DIRTY, etc) -+ * @log_lnum: start of the log -+ * @root_lnum: LEB number of the root indexing node -+ * @root_offs: offset within @root_lnum -+ * @root_len: root indexing node length -+ * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was -+ * not reserved and should be reserved on mount) -+ * @ihead_lnum: LEB number of index head -+ * @ihead_offs: offset of index head -+ * @index_size: size of index on flash -+ * @total_free: total free space in bytes -+ * @total_dirty: total dirty space in bytes -+ * @total_used: total used space in bytes (includes only data LEBs) -+ * @total_dead: total dead space in bytes (includes only data LEBs) -+ * @total_dark: total dark space in bytes (includes only data LEBs) -+ * @lpt_lnum: LEB number of LPT root nnode -+ * @lpt_offs: offset of LPT root nnode -+ * @nhead_lnum: LEB number of LPT head -+ * @nhead_offs: offset of LPT head -+ * @ltab_lnum: LEB number of LPT's own lprops table -+ * @ltab_offs: offset of LPT's own lprops table -+ * @lsave_lnum: LEB number of LPT's save table (big model only) -+ * @lsave_offs: offset of LPT's save table (big model only) -+ * @lscan_lnum: LEB number of last LPT scan -+ * @empty_lebs: number of empty logical eraseblocks -+ * @idx_lebs: number of indexing logical eraseblocks -+ * @leb_cnt: count of LEBs used by filesystem -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_mst_node { -+ struct ubifs_ch ch; -+ __le64 highest_inum; -+ __le64 cmt_no; -+ __le32 flags; -+ __le32 log_lnum; -+ __le32 root_lnum; -+ __le32 root_offs; -+ __le32 root_len; -+ __le32 gc_lnum; -+ __le32 ihead_lnum; -+ __le32 ihead_offs; -+ __le64 index_size; -+ __le64 total_free; -+ __le64 total_dirty; -+ __le64 total_used; -+ __le64 total_dead; -+ __le64 total_dark; -+ __le32 lpt_lnum; -+ __le32 lpt_offs; -+ __le32 nhead_lnum; -+ __le32 nhead_offs; -+ __le32 ltab_lnum; -+ __le32 ltab_offs; -+ __le32 lsave_lnum; -+ __le32 lsave_offs; -+ __le32 lscan_lnum; -+ __le32 empty_lebs; -+ __le32 idx_lebs; -+ __le32 leb_cnt; -+ __u8 padding[344]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_ref_node - logical eraseblock reference node. -+ * @ch: common header -+ * @lnum: the referred logical eraseblock number -+ * @offs: start offset in the referred LEB -+ * @jhead: journal head number -+ * @padding: reserved for future, zeroes -+ */ -+struct ubifs_ref_node { -+ struct ubifs_ch ch; -+ __le32 lnum; -+ __le32 offs; -+ __le32 jhead; -+ __u8 padding[28]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_branch - key/reference/length branch -+ * @lnum: LEB number of the target node -+ * @offs: offset within @lnum -+ * @len: target node length -+ * @key: key -+ */ -+struct ubifs_branch { -+ __le32 lnum; -+ __le32 offs; -+ __le32 len; -+ __u8 key[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_idx_node - indexing node. -+ * @ch: common header -+ * @child_cnt: number of child index nodes -+ * @level: tree level -+ * @branches: LEB number / offset / length / key branches -+ */ -+struct ubifs_idx_node { -+ struct ubifs_ch ch; -+ __le16 child_cnt; -+ __le16 level; -+ __u8 branches[]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_cs_node - commit start node. -+ * @ch: common header -+ * @cmt_no: commit number -+ */ -+struct ubifs_cs_node { -+ struct ubifs_ch ch; -+ __le64 cmt_no; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubifs_orph_node - orphan node. -+ * @ch: common header -+ * @cmt_no: commit number (also top bit is set on the last node of the commit) -+ * @inos: inode numbers of orphans -+ */ -+struct ubifs_orph_node { -+ struct ubifs_ch ch; -+ __le64 cmt_no; -+ __le64 inos[]; -+} __attribute__ ((packed)); -+ -+#endif /* __UBIFS_MEDIA_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/ubifs.h linux-2.6.24.7/fs/ubifs/ubifs.h ---- linux-2.6.24.7.old/fs/ubifs/ubifs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/ubifs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1589 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* Implementation version 0.6 */ -+ -+#ifndef __UBIFS_H__ -+#define __UBIFS_H__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ubifs-media.h" -+#include "compat.h" -+ -+/* Version of this UBIFS implementation */ -+#define UBIFS_VERSION 1 -+ -+/* Normal UBIFS messages */ -+#define ubifs_msg(fmt, ...) \ -+ printk(KERN_NOTICE "UBIFS: " fmt "\n", ##__VA_ARGS__) -+/* UBIFS error messages */ -+#define ubifs_err(fmt, ...) \ -+ printk(KERN_ERR "UBIFS error (pid %d): %s: " fmt "\n", current->pid, \ -+ __func__, ##__VA_ARGS__) -+/* UBIFS warning messages */ -+#define ubifs_warn(fmt, ...) \ -+ printk(KERN_WARNING "UBIFS warning (pid %d): %s: " fmt "\n", \ -+ current->pid, __func__, ##__VA_ARGS__) -+ -+/* UBIFS file system VFS magic number */ -+#define UBIFS_SUPER_MAGIC 0x24051905 -+ -+/* Number of UBIFS blocks per VFS page */ -+#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE) -+#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT) -+ -+/* "File system end of life" sequence number watermark */ -+#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL -+#define SQNUM_WATERMARK 0xFFFFFFFFFF000000ULL -+ -+/* Minimum amount of data UBIFS writes to the flash */ -+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8) -+ -+/* -+ * Currently we do not support inode number overlapping and re-using, so this -+ * watermark defines dangerous inode number level. This should be fixed later, -+ * although it is difficult to exceed current limit. Another option is to use -+ * 64-bit inode numbers, but this means more overhead. -+ */ -+#define INUM_WARN_WATERMARK 0xFFF00000 -+#define INUM_WATERMARK 0xFFFFFF00 -+ -+/* Largest key size supported in this implementation */ -+#define CUR_MAX_KEY_LEN UBIFS_SK_LEN -+ -+/* Maximum number of entries in each LPT (LEB category) heap */ -+#define LPT_HEAP_SZ 256 -+ -+/* -+ * Background thread name pattern. The numbers are UBI device and volume -+ * numbers. -+ */ -+#define BGT_NAME_PATTERN "ubifs_bgt%d_%d" -+ -+/* Default write-buffer synchronization timeout (5 secs) */ -+#define DEFAULT_WBUF_TIMEOUT (5 * HZ) -+ -+/* Maximum possible inode number (only 32-bit inodes are supported now) */ -+#define MAX_INUM 0xFFFFFFFF -+ -+/* Number of non-data journal heads */ -+#define NONDATA_JHEADS_CNT 2 -+ -+/* Garbage collector head */ -+#define GCHD 0 -+/* Base journal head number */ -+#define BASEHD 1 -+/* First "general purpose" journal head */ -+#define DATAHD 2 -+ -+/* -+ * How much a directory entry/extended attribute entry adds to the parent/host -+ * inode. -+ */ -+#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8) -+ -+/* -+ * Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered -+ * "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are -+ * considered "young". This is used by shrinker when selecting znode to trim -+ * off. -+ */ -+#define OLD_ZNODE_AGE 20 -+#define YOUNG_ZNODE_AGE 5 -+ -+/* -+ * Some compressors, like LZO, may end up with more data then the input buffer. -+ * So UBIFS always allocates larger output buffer, to be sure the compressor -+ * will not corrupt memory in case of worst case compression. -+ */ -+#define WORST_COMPR_FACTOR 2 -+ -+/* Maximum expected tree height for use by bottom_up_buf */ -+#define BOTTOM_UP_HEIGHT 64 -+ -+/* -+ * Znode flags (actually, bit numbers which store the flags). -+ * -+ * DIRTY_ZNODE: znode is dirty -+ * COW_ZNODE: znode is being committed and a new instance of this znode has to -+ * be created before changing this znode -+ * OBSOLETE_ZNODE: znode is obsolete, which means it was deleted, but it is -+ * still in the commit list and the ongoing commit operation -+ * will commit it, and delete this znode after it is done -+ */ -+enum { -+ DIRTY_ZNODE = 0, -+ COW_ZNODE = 1, -+ OBSOLETE_ZNODE = 2 -+}; -+ -+/* -+ * Commit states. -+ * -+ * COMMIT_RESTING: commit is not wanted -+ * COMMIT_BACKGROUND: background commit has been requested -+ * COMMIT_REQUIRED: commit is required -+ * COMMIT_RUNNING_BACKGROUND: background commit is running -+ * COMMIT_RUNNING_REQUIRED: commit is running and it is required -+ * COMMIT_BROKEN: commit failed -+ */ -+enum { -+ COMMIT_RESTING = 0, -+ COMMIT_BACKGROUND, -+ COMMIT_REQUIRED, -+ COMMIT_RUNNING_BACKGROUND, -+ COMMIT_RUNNING_REQUIRED, -+ COMMIT_BROKEN, -+}; -+ -+/* -+ * 'ubifs_scan_a_node()' return values. -+ * -+ * SCANNED_GARBAGE: scanned garbage -+ * SCANNED_EMPTY_SPACE: scanned empty space -+ * SCANNED_A_NODE: scanned a valid node -+ * SCANNED_A_CORRUPT_NODE: scanned a corrupted node -+ * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length -+ * -+ * Greater than zero means: 'scanned that number of padding bytes' -+ */ -+enum { -+ SCANNED_GARBAGE = 0, -+ SCANNED_EMPTY_SPACE = -1, -+ SCANNED_A_NODE = -2, -+ SCANNED_A_CORRUPT_NODE = -3, -+ SCANNED_A_BAD_PAD_NODE = -4, -+}; -+ -+/* -+ * LPT cnode flag bits. -+ * -+ * DIRTY_CNODE: cnode is dirty -+ * COW_CNODE: cnode is being committed and must be copied before writing -+ * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted), -+ * so it can (and must) be freed when the commit is finished -+ */ -+enum { -+ DIRTY_CNODE = 0, -+ COW_CNODE = 1, -+ OBSOLETE_CNODE = 2, -+}; -+ -+/* -+ * Dirty flag bits (lpt_drty_flgs) for LPT special nodes. -+ * -+ * LTAB_DIRTY: ltab node is dirty -+ * LSAVE_DIRTY: lsave node is dirty -+ */ -+enum { -+ LTAB_DIRTY = 1, -+ LSAVE_DIRTY = 2, -+}; -+ -+/* -+ * Return codes used by the garbage collector. -+ * @LEB_FREED: the logical eraseblock was freed and is ready to use -+ * @LEB_FREED_IDX: indexing LEB was freed and can be used only after the commit -+ * @LEB_RETAINED: the logical eraseblock was freed and retained for GC purposes -+ */ -+enum { -+ LEB_FREED, -+ LEB_FREED_IDX, -+ LEB_RETAINED, -+}; -+ -+/** -+ * struct ubifs_old_idx - index node obsoleted since last commit start. -+ * @rb: rb-tree node -+ * @lnum: LEB number of obsoleted index node -+ * @offs: offset of obsoleted index node -+ */ -+struct ubifs_old_idx { -+ struct rb_node rb; -+ int lnum; -+ int offs; -+}; -+ -+/* The below union makes it easier to deal with keys */ -+union ubifs_key { -+ uint8_t u8[CUR_MAX_KEY_LEN]; -+ uint32_t u32[CUR_MAX_KEY_LEN/4]; -+ uint64_t u64[CUR_MAX_KEY_LEN/8]; -+ __le32 j32[CUR_MAX_KEY_LEN/4]; -+}; -+ -+/** -+ * struct ubifs_scan_node - UBIFS scanned node information. -+ * @list: list of scanned nodes -+ * @key: key of node scanned (if it has one) -+ * @sqnum: sequence number -+ * @type: type of node scanned -+ * @offs: offset with LEB of node scanned -+ * @len: length of node scanned -+ * @node: raw node -+ */ -+struct ubifs_scan_node { -+ struct list_head list; -+ union ubifs_key key; -+ unsigned long long sqnum; -+ int type; -+ int offs; -+ int len; -+ void *node; -+}; -+ -+/** -+ * struct ubifs_scan_leb - UBIFS scanned LEB information. -+ * @lnum: logical eraseblock number -+ * @nodes_cnt: number of nodes scanned -+ * @nodes: list of struct ubifs_scan_node -+ * @endpt: end point (and therefore the start of empty space) -+ * @ecc: read returned -EBADMSG -+ * @buf: buffer containing entire LEB scanned -+ */ -+struct ubifs_scan_leb { -+ int lnum; -+ int nodes_cnt; -+ struct list_head nodes; -+ int endpt; -+ int ecc; -+ void *buf; -+}; -+ -+/** -+ * struct ubifs_gced_idx_leb - garbage-collected indexing LEB. -+ * @list: list -+ * @lnum: LEB number -+ * @unmap: OK to unmap this LEB -+ * -+ * This data structure is used to temporary store garbage-collected indexing -+ * LEBs - they are not released immediately, but only after the next commit. -+ * This is needed to guarantee recoverability. -+ */ -+struct ubifs_gced_idx_leb { -+ struct list_head list; -+ int lnum; -+ int unmap; -+}; -+ -+/** -+ * struct ubifs_inode - UBIFS in-memory inode description. -+ * @vfs_inode: VFS inode description object -+ * @creat_sqnum: sequence number at time of creation -+ * @xattr_size: summarized size of all extended attributes in bytes, protected -+ * by @inode->i_lock -+ * @xattr_cnt: count of extended attributes this inode has -+ * @xattr_names: sum of lengths of all extended attribute names belonging to -+ * this inode -+ * @dirty: non-zero if the inode is dirty -+ * @xattr: non-zero if this is an extended attribute inode -+ * @budgeted: non-zero if the inode has been budgeted (used for debugging) -+ * @budg_mutex: serializes inode budgeting and write-back -+ * @flags: inode flags (@UBIFS_COMPR_FL, etc) -+ * @compr_type: default compression type used for this inode -+ * @data_len: length of the data attached to the inode -+ * @data: inode's data -+ * -+ * UBIFS has its own inode mutex, besides the VFS 'i_mutex'. The reason for -+ * this is budgeting - UBIFS has to budget each operation. So, if an operation -+ * is going to mark an inode dirty, it has to allocate budget for this. It -+ * cannot just mark it dirty because there is no guarantee there will be enough -+ * flash space when it is time to write the inode back. This means that UBIFS -+ * has to have full control over "clean <-> dirty" transitions of inodes (and -+ * pages actually, but it is easy for pages, because we have -+ * 'ubifs_prepare_write()' which is called _before_ every page change). But -+ * unfortunately, VFS marks inodes dirty in many places, and it does not ask -+ * the file-system if it is allowed to do so (there is a notifier, but it is -+ * not enough), i.e., there is no mechanism to synchronize with this. So we -+ * introduce our own dirty flag to UBIFS inodes and our own inode mutex to -+ * serialize "clean <-> dirty" transitions. -+ */ -+struct ubifs_inode { -+ struct inode vfs_inode; -+ unsigned long long creat_sqnum; -+ long long xattr_size; -+ int xattr_cnt; -+ int xattr_names; -+ unsigned int dirty:1; -+ unsigned int xattr:1; -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ unsigned int budgeted:1; -+#endif -+ struct mutex budg_mutex; -+ int flags; -+ int compr_type; -+ int data_len; -+ void *data; -+}; -+ -+/** -+ * struct ubifs_unclean_leb - records a LEB recovered under read-only mode. -+ * @list: list -+ * @lnum: LEB number of recovered LEB -+ * @endpt: offset where recovery ended -+ * -+ * This structure records a LEB identified during recovery that needs to be -+ * cleaned but was not because UBIFS was mounted read-only. The information -+ * is used to clean the LEB when remounting to read-write mode. -+ */ -+struct ubifs_unclean_leb { -+ struct list_head list; -+ int lnum; -+ int endpt; -+}; -+ -+/* -+ * LEB properties flags. -+ * -+ * LPROPS_UNCAT: not categorized -+ * LPROPS_DIRTY: dirty > 0, not index -+ * LPROPS_DIRTY_IDX: dirty + free > UBIFS_CH_SZ and index -+ * LPROPS_FREE: free > 0, not empty, not index -+ * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs -+ * LPROPS_EMPTY: LEB is empty, not taken -+ * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken -+ * LPROPS_FRDI_IDX: free + dirty == leb_size and index, may be taken -+ * LPROPS_CAT_MASK: mask for the LEB categories above -+ * LPROPS_TAKEN: LEB was taken (this flag is not saved on the media) -+ * LPROPS_INDEX: LEB contains indexing nodes (this flag also exists on flash) -+ */ -+enum { -+ LPROPS_UNCAT = 0, -+ LPROPS_DIRTY = 1, -+ LPROPS_DIRTY_IDX = 2, -+ LPROPS_FREE = 3, -+ LPROPS_HEAP_CNT = 3, -+ LPROPS_EMPTY = 4, -+ LPROPS_FREEABLE = 5, -+ LPROPS_FRDI_IDX = 6, -+ LPROPS_CAT_MASK = 15, -+ LPROPS_TAKEN = 16, -+ LPROPS_INDEX = 32, -+}; -+ -+/** -+ * struct ubifs_lprops - logical eraseblock properties. -+ * @free: amount of free space in bytes -+ * @dirty: amount of dirty space in bytes -+ * @flags: LEB properties flags (see above) -+ * @lnum: LEB number -+ * @list: list of same-category lprops (for LPROPS_EMPTY and LPROPS_FREEABLE) -+ * @hpos: heap position in heap of same-category lprops (other categories) -+ */ -+struct ubifs_lprops { -+ int free; -+ int dirty; -+ int flags; -+ int lnum; -+ union { -+ struct list_head list; -+ int hpos; -+ }; -+}; -+ -+/** -+ * struct ubifs_lpt_lprops - LPT logical eraseblock properties. -+ * @free: amount of free space in bytes -+ * @dirty: amount of dirty space in bytes -+ * @tgc: trivial GC flag (1 => unmap after commit end) -+ * @cmt: commit flag (1 => reserved for commit) -+ */ -+struct ubifs_lpt_lprops { -+ int free; -+ int dirty; -+ unsigned tgc : 1; -+ unsigned cmt : 1; -+}; -+ -+/** -+ * struct ubifs_lp_stats - statistics of eraseblocks in the main area. -+ * @empty_lebs: number of empty LEBs -+ * @taken_empty_lebs: number of taken LEBs -+ * @idx_lebs: number of indexing LEBs -+ * @total_free: total free space in bytes -+ * @total_dirty: total dirty space in bytes -+ * @total_used: total used space in bytes (includes only data LEBs) -+ * @total_dead: total dead space in bytes (includes only data LEBs) -+ * @total_dark: total dark space in bytes (includes only data LEBs) -+ * -+ * N.B. total_dirty and total_used are different to other total_* fields, -+ * because they account _all_ LEBs, not just data LEBs. -+ * -+ * 'taken_empty_lebs' counts the LEBs that are in the transient state of having -+ * been 'taken' for use but not yet written to. 'taken_empty_lebs' is needed -+ * to account correctly for gc_lnum, otherwise 'empty_lebs' could be used -+ * by itself (in which case 'unused_lebs' would be a better name). In the case -+ * of gc_lnum, it is 'taken' at mount time or whenever a LEB is retained by GC, -+ * but unlike other empty LEBs that are 'taken', it may not be written straight -+ * away (i.e. before the next commit start or unmount), so either gc_lnum must -+ * be specially accounted for, or the current approach followed i.e. count it -+ * under 'taken_empty_lebs'. -+ */ -+struct ubifs_lp_stats { -+ int empty_lebs; -+ int taken_empty_lebs; -+ int idx_lebs; -+ long long total_free; -+ long long total_dirty; -+ long long total_used; -+ long long total_dead; -+ long long total_dark; -+}; -+ -+struct ubifs_nnode; -+ -+/** -+ * struct ubifs_cnode - LEB Properties Tree common node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (zero for pnodes, greater than zero for nnodes) -+ * @num: node number -+ */ -+struct ubifs_cnode { -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+}; -+ -+/** -+ * struct ubifs_pnode - LEB Properties Tree leaf node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (always zero for pnodes) -+ * @num: node number -+ * @lprops: LEB properties array -+ */ -+struct ubifs_pnode { -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+ struct ubifs_lprops lprops[UBIFS_LPT_FANOUT]; -+}; -+ -+/** -+ * struct ubifs_nbranch - LEB Properties Tree internal node branch. -+ * @lnum: LEB number of child -+ * @offs: offset of child -+ * @nnode: nnode child -+ * @pnode: pnode child -+ * @cnode: cnode child -+ */ -+struct ubifs_nbranch { -+ int lnum; -+ int offs; -+ union { -+ struct ubifs_nnode *nnode; -+ struct ubifs_pnode *pnode; -+ struct ubifs_cnode *cnode; -+ }; -+}; -+ -+/** -+ * struct ubifs_nnode - LEB Properties Tree internal node. -+ * @parent: parent nnode -+ * @cnext: next cnode to commit -+ * @flags: flags (%DIRTY_LPT_NODE or %OBSOLETE_LPT_NODE) -+ * @iip: index in parent -+ * @level: level in the tree (always greater than zero for nnodes) -+ * @num: node number -+ * @nbranch: branches to child nodes -+ */ -+struct ubifs_nnode { -+ struct ubifs_nnode *parent; -+ struct ubifs_cnode *cnext; -+ unsigned long flags; -+ int iip; -+ int level; -+ int num; -+ struct ubifs_nbranch nbranch[UBIFS_LPT_FANOUT]; -+}; -+ -+/** -+ * struct ubifs_lpt_heap - heap of categorized lprops. -+ * @arr: heap array -+ * @cnt: number in heap -+ * @max_cnt: maximum number allowed in heap -+ * -+ * There are %LPROPS_HEAP_CNT heaps. -+ */ -+struct ubifs_lpt_heap { -+ struct ubifs_lprops **arr; -+ int cnt; -+ int max_cnt; -+}; -+ -+/* -+ * Return codes for LPT scan callback function. -+ * -+ * LPT_SCAN_CONTINUE: continue scanning -+ * LPT_SCAN_ADD: add the LEB properties scanned to the tree in memory -+ * LPT_SCAN_STOP: stop scanning -+ */ -+enum { -+ LPT_SCAN_CONTINUE = 0, -+ LPT_SCAN_ADD = 1, -+ LPT_SCAN_STOP = 2, -+}; -+ -+struct ubifs_info; -+ -+/* Callback used by the 'ubifs_lpt_scan_nolock()' function */ -+typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c, -+ const struct ubifs_lprops *lprops, -+ int in_tree, void *data); -+ -+/** -+ * struct ubifs_wbuf - UBIFS write-buffer. -+ * @c: UBIFS file-system description object -+ * @buf: write-buffer (of min. flash I/O unit size) -+ * @lnum: logical eraseblock number the write-buffer points to -+ * @offs: write-buffer offset in this logical eraseblock -+ * @avail: number of bytes available in the write-buffer -+ * @used: number of used bytes in the write-buffer -+ * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM, -+ * %UBI_UNKNOWN) -+ * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep -+ * up by 'mutex_lock_nested()). -+ * @sync_callback: write-buffer synchronization callback -+ * @io_mutex: serializes write-buffer I/O -+ * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes -+ * fields -+ * @timer: write-buffer timer -+ * @timeout: timer expire interval in jiffies -+ * @need_sync: it is set if its timer expired and needs sync -+ * @next_ino: points to the next position of the following inode number -+ * @inodes: stores the inode numbers of the nodes which are in wbuf -+ * -+ * The write-buffer synchronization callback is called when the write-buffer is -+ * synchronized in order to notify how much space was wasted due to -+ * write-buffer padding and how much free space is left in the LEB. -+ * -+ * Note: the fields @buf, @lnum, @offs, @avail and @used can be read under -+ * spin-lock or mutex because they are written under both mutex and spin-lock. -+ * @buf is appended to under mutex but overwritten under both mutex and -+ * spin-lock. Thus the data between @buf and @buf + @used can be read under -+ * spinlock. -+ */ -+struct ubifs_wbuf { -+ struct ubifs_info *c; -+ void *buf; -+ int lnum; -+ int offs; -+ int avail; -+ int used; -+ int dtype; -+ int jhead; -+ int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); -+ struct mutex io_mutex; -+ spinlock_t lock; -+ struct timer_list timer; -+ int timeout; -+ int need_sync; -+ int next_ino; -+ ino_t *inodes; -+}; -+ -+/** -+ * struct ubifs_bud - bud logical eraseblock. -+ * @lnum: logical eraseblock number -+ * @start: where the (uncommitted) bud data starts -+ * @jhead: journal head number this bud belongs to -+ * @list: link in the list buds belonging to the same journal head -+ * @rb: link in the tree of all buds -+ */ -+struct ubifs_bud { -+ int lnum; -+ int start; -+ int jhead; -+ struct list_head list; -+ struct rb_node rb; -+}; -+ -+/** -+ * struct ubifs_jhead - journal head. -+ * @wbuf: head's write-buffer -+ * @buds_list: list of bud LEBs belonging to this journal head -+ * -+ * Note, the @buds list is protected by the @c->buds_lock. -+ */ -+struct ubifs_jhead { -+ struct ubifs_wbuf wbuf; -+ struct list_head buds_list; -+}; -+ -+/** -+ * struct ubifs_zbranch - key/coordinate/length branch stored in znodes. -+ * @key: key -+ * @znode: znode address in memory -+ * @lnum: LEB number of the indexing node -+ * @offs: offset of the indexing node within @lnum -+ * @len: target node length -+ */ -+struct ubifs_zbranch { -+ union ubifs_key key; -+ union { -+ struct ubifs_znode *znode; -+ void *leaf; -+ }; -+ int lnum; -+ int offs; -+ int len; -+}; -+ -+/** -+ * struct ubifs_znode - in-memory representation of an indexing node. -+ * @parent: parent znode or NULL if it is the root -+ * @cnext: next znode to commit -+ * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE) -+ * @time: last access time (seconds) -+ * @level: level of the entry in the TNC tree -+ * @child_cnt: count of child znodes -+ * @iip: index in parent's zbranch array -+ * @alt: lower bound of key range has altered i.e. child inserted at slot 0 -+ * @lnum: LEB number of the corresponding indexing node -+ * @offs: offset of the corresponding indexing node -+ * @len: length of the corresponding indexing node -+ * @zbranch: array of znode branches (@c->fanout elements) -+ */ -+struct ubifs_znode { -+ struct ubifs_znode *parent; -+ struct ubifs_znode *cnext; -+ unsigned long flags; -+ unsigned long time; -+ int level; -+ int child_cnt; -+ int iip; -+ int alt; -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ int lnum, offs, len; -+#endif -+ struct ubifs_zbranch zbranch[]; -+}; -+ -+/** -+ * struct ubifs_node_range - node length range description data structure. -+ * @len: fixed node length -+ * @min_len: minimum possible node length -+ * @max_len: maximum possible node length -+ * -+ * If @max_len is %0, the node has fixed length @len. -+ */ -+struct ubifs_node_range { -+ union { -+ int len; -+ int min_len; -+ }; -+ int max_len; -+}; -+ -+/** -+ * struct ubifs_compressor - UBIFS compressor description structure. -+ * @compr_type: compressor type (%UBIFS_COMPR_LZO, etc) -+ * @cc: cryptoapi compressor handle -+ * @comp_mutex: mutex used during compression -+ * @decomp_mutex: mutex used during decompression -+ * @name: compressor name -+ * @capi_name: cryptoapi compressor name -+ */ -+struct ubifs_compressor { -+ int compr_type; -+ struct crypto_comp *cc; -+ struct mutex *comp_mutex; -+ struct mutex *decomp_mutex; -+ const char *name; -+ const char *capi_name; -+}; -+ -+/** -+ * struct ubifs_budget_req - budget requirements of an operation. -+ * -+ * @new_ino: non-zero if the operation adds a new inode -+ * @dirtied_ino: how many inodes the operation makes dirty -+ * @new_page: non-zero if the operation adds a new page -+ * @dirtied_page: non-zero if the operation makes a page dirty -+ * @new_dent: non-zero if the operation adds a new directory entry -+ * @mod_dent: non-zero if the operation removes or modifies an existing -+ * directory entry -+ * @new_ino_d: now much data newly created inode contains -+ * @dirtied_ino_d: now much data dirtied inode contains -+ * @idx_growth: how much the index will supposedly grow -+ * @data_growth: how much new data the operation will supposedly add -+ * @dd_growth: how much data that makes other data dirty the operation will -+ * supposedly add -+ * -+ * @idx_growth, @data_growth and @dd_growth are not used in budget request. The -+ * budgeting subsystem caches index and data growth values there to avoid -+ * re-calculating them when the budget is released. However, if @idx_growth is -+ * %-1, it is calculated by the release function using other fields. -+ * -+ * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d -+ * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made -+ * dirty by the re-name operation. -+ */ -+struct ubifs_budget_req { -+ unsigned int new_ino:1; -+ unsigned int dirtied_ino:4; -+ unsigned int new_page:1; -+ unsigned int dirtied_page:1; -+ unsigned int new_dent:1; -+ unsigned int mod_dent:1; -+/* TODO: remove compatibility stuff as late as possible */ -+#ifdef UBIFS_COMPAT_USE_OLD_PREPARE_WRITE -+ unsigned int locked_pg:1; -+#endif -+ unsigned int new_ino_d:13; -+ unsigned int dirtied_ino_d:15; -+ int idx_growth; -+ int data_growth; -+ int dd_growth; -+}; -+ -+/** -+ * struct ubifs_orphan - stores the inode number of an orphan. -+ * @rb: rb-tree node of rb-tree of orphans sorted by inode number -+ * @list: list head of list of orphans in order added -+ * @new_list: list head of list of orphans added since the last commit -+ * @cnext: next orphan to commit -+ * @dnext: next orphan to delete -+ * @inum: inode number -+ * @new: %1 => added since the last commit, otherwise %0 -+ */ -+struct ubifs_orphan { -+ struct rb_node rb; -+ struct list_head list; -+ struct list_head new_list; -+ struct ubifs_orphan *cnext; -+ struct ubifs_orphan *dnext; -+ ino_t inum; -+ int new; -+}; -+ -+/** -+ * struct ubifs_mount_opts - UBIFS-specific mount options information. -+ * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast) -+ */ -+struct ubifs_mount_opts { -+ unsigned int unmount_mode:2; -+}; -+ -+/** -+ * struct ubifs_info - UBIFS file-system description data structure -+ * (per-superblock). -+ * @vfs_sb: VFS @struct super_block object -+ * -+ * @highest_inum: highest used inode number -+ * @vfs_gen: VFS inode generation counter -+ * @max_sqnum: current global sequence number -+ * @cmt_no: commit number (last successfully completed commit) -+ * @cnt_lock: protects @highest_inum, @vfs_gen, and @max_sqnum counters -+ * @fmt_version: UBIFS on-flash format version -+ * -+ * @lhead_lnum: log head logical eraseblock number -+ * @lhead_offs: log head offset -+ * @ltail_lnum: log tail logical eraseblock number (offset is always 0) -+ * @log_mutex: protects the log, @lhead_lnum, @lhead_offs, @ltail_lnum, and -+ * @bud_bytes -+ * @min_log_bytes: minimum required number of bytes in the log -+ * @cmt_bud_bytes: used during commit to temporarily amount of bytes in -+ * committed buds -+ * -+ * @buds: tree of all buds indexed by bud LEB number -+ * @bud_bytes: how many bytes of flash is used by buds -+ * @buds_lock: protects the @buds tree, @bud_bytes, and per-journal head bud -+ * lists -+ * @jhead_cnt: count of journal heads -+ * @jheads: journal heads (head zero is base head) -+ * @max_bud_bytes: maximum number of bytes allowed in buds -+ * @bg_bud_bytes: number of bud bytes when background commit is initiated -+ * @old_buds: buds to be released after commit ends -+ * @max_bud_cnt: maximum number of buds -+ * -+ * @commit_sem: synchronizes committer with other processes -+ * @cmt_state: commit state -+ * @cs_lock: commit state lock -+ * @cmt_wq: wait queue to sleep on if the log is full and a commit is running -+ * @fast_unmount: do not run journal commit before unmounting -+ * @big_lpt: flag that LPT is too big to write whole during commit -+ * -+ * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and -+ * @calc_idx_sz -+ * @zroot: zbranch which points to the root index node and znode -+ * @cnext: next znode to commit -+ * @enext: next znode to commit to empty space -+ * @gap_lebs: array of LEBs used by the in-gaps commit method -+ * @cbuf: commit buffer -+ * @ileb_buf: buffer for commit in-the-gaps method -+ * @ileb_len: length of data in ileb_buf -+ * @ihead_lnum: LEB number of index head -+ * @ihead_offs: offset of index head -+ * @ilebs: pre-allocated index LEBs -+ * @ileb_cnt: number of pre-allocated index LEBs -+ * @ileb_nxt: next pre-allocated index LEBs -+ * @old_idx: tree of index nodes obsoleted since the last commit start -+ * @bottom_up_buf: a buffer which is used by 'dirty_cow_bottom_up()' in tnc.c -+ * @new_ihead_lnum: used by debugging to check ihead_lnum -+ * @new_ihead_offs: used by debugging to check ihead_offs -+ * -+ * @mst_node: master node -+ * @mst_offs: offset of valid master node -+ * @mst_mutex: protects the master node area, @mst_node, and @mst_offs -+ * -+ * @log_lebs: number of logical eraseblocks in the log -+ * @log_bytes: log size in bytes -+ * @log_last: last LEB of the log -+ * @lpt_lebs: number of LEBs used for lprops table -+ * @lpt_first: first LEB of the lprops table area -+ * @lpt_last: last LEB of the lprops table area -+ * @orph_lebs: number of LEBs used for the orphan area -+ * @orph_first: first LEB of the orphan area -+ * @orph_last: last LEB of the orphan area -+ * @main_lebs: count of LEBs in the main area -+ * @main_first: first LEB of the main area -+ * @main_bytes: main area size in bytes -+ * @default_compr: default compression type -+ * -+ * @key_hash_type: type of the key hash -+ * @key_hash: direntry key hash function -+ * @key_fmt: key format -+ * @key_len: key length -+ * @fanout: fanout of the index tree (number of links per indexing node) -+ * -+ * @min_io_size: minimal input/output unit size -+ * @min_io_shift: number of bits in @min_io_size minus one -+ * @leb_size: logical eraseblock size in bytes -+ * @half_leb_size: half LEB size -+ * @leb_cnt: count of logical eraseblocks -+ * @max_leb_cnt: maximum count of logical eraseblocks -+ * @old_leb_cnt: count of logical eraseblocks before resize -+ * @ro_media: the underlying UBI volume is read-only -+ * -+ * @dirty_pg_cnt: number of dirty pages (not used) -+ * @dirty_ino_cnt: number of dirty inodes (not used) -+ * @dirty_zn_cnt: number of dirty znodes -+ * @clean_zn_cnt: number of clean znodes -+ * -+ * @budg_idx_growth: amount of bytes budgeted for index growth -+ * @budg_data_growth: amount of bytes budgeted for cached data -+ * @budg_dd_growth: amount of bytes budgeted for cached data that will make -+ * other data dirty -+ * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index, -+ * but which still have to be taken into account because -+ * the index has not been committed so far -+ * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth, -+ * @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, and @lst; -+ * @min_idx_lebs: minimum number of LEBs required for the index -+ * @old_idx_sz: size of index on flash -+ * @calc_idx_sz: temporary variable which is used to calculate new index size -+ * (contains accurate new index size at end of TNC commit start) -+ * @lst: lprops statistics -+ * -+ * @page_budget: budget for a page -+ * @inode_budget: budget for an inode -+ * @dent_budget: budget for a directory entry -+ * -+ * @ref_node_alsz: size of the LEB reference node aligned to the min. flash -+ * I/O unit -+ * @mst_node_alsz: master node aligned size -+ * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary -+ * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary -+ * @max_inode_sz: maximum possible inode size in bytes -+ * @max_znode_sz: size of znode in bytes -+ * @dead_wm: LEB dead space watermark -+ * @dark_wm: LEB dark space watermark -+ * @block_cnt: count of 4KiB blocks on the FS -+ * -+ * @ranges: UBIFS node length ranges -+ * @ubi: UBI volume descriptor -+ * @di: UBI device information -+ * @vi: UBI volume information -+ * -+ * @orph_tree: rb-tree of orphan inode numbers -+ * @orph_list: list of orphan inode numbers in order added -+ * @orph_new: list of orphan inode numbers added since last commit -+ * @orph_cnext: next orphan to commit -+ * @orph_dnext: next orphan to delete -+ * @orphan_lock: lock for orph_tree and orph_new -+ * @orph_buf: buffer for orphan nodes -+ * @new_orphans: number of orphans since last commit -+ * @cmt_orphans: number of orphans being committed -+ * @tot_orphans: number of orphans in the rb_tree -+ * @max_orphans: maximum number of orphans allowed -+ * @ohead_lnum: orphan head LEB number -+ * @ohead_offs: orphan head offset -+ * @no_orphs: non-zero if there are no orphans -+ * -+ * @bgt: UBIFS background thread -+ * @bgt_name: background thread name -+ * @need_bgt: if background thread should run -+ * @need_wbuf_sync: if write-buffers have to be synchronized -+ * -+ * @gc_lnum: LEB number used for garbage collection -+ * @sbuf: a buffer of LEB size used by GC and replay for scanning -+ * @idx_gc: list of index LEBs that have been garbage collected -+ * @idx_gc_cnt: number of elements on the idx_gc list -+ * -+ * @infos_list: links all 'ubifs_info' objects -+ * @umount_mutex: serializes shrinker and un-mount -+ * @shrinker_run_no: shrinker run number -+ * -+ * @space_bits: number of bits needed to record free or dirty space -+ * @lpt_lnum_bits: number of bits needed to record a LEB number in the LPT -+ * @lpt_offs_bits: number of bits needed to record an offset in the LPT -+ * @lpt_spc_bits: number of bits needed to space in the LPT -+ * @pcnt_bits: number of bits needed to record pnode or nnode number -+ * @lnum_bits: number of bits needed to record LEB number -+ * @nnode_sz: size of on-flash nnode -+ * @pnode_sz: size of on-flash pnode -+ * @ltab_sz: size of on-flash LPT lprops table -+ * @lsave_sz: size of on-flash LPT save table -+ * @pnode_cnt: number of pnodes -+ * @nnode_cnt: number of nnodes -+ * @lpt_hght: height of the LPT -+ * @pnodes_have: number of pnodes in memory -+ * -+ * @lp_mutex: protects lprops table and all the other lprops-related fields -+ * @lpt_lnum: LEB number of the root nnode of the LPT -+ * @lpt_offs: offset of the root nnode of the LPT -+ * @nhead_lnum: LEB number of LPT head -+ * @nhead_offs: offset of LPT head -+ * @lpt_drty_flgs: dirty flags for LPT special nodes e.g. ltab -+ * @dirty_nn_cnt: number of dirty nnodes -+ * @dirty_pn_cnt: number of dirty pnodes -+ * @lpt_sz: LPT size -+ * @lpt_nod_buf: buffer for an on-flash nnode or pnode -+ * @lpt_buf: buffer of LEB size used by LPT -+ * @nroot: address in memory of the root nnode of the LPT -+ * @lpt_cnext: next LPT node to commit -+ * @lpt_heap: array of heaps of categorized lprops -+ * @dirty_idx: a (reverse sorted) copy of the LPROPS_DIRTY_IDX heap as at -+ * previous commit start -+ * @uncat_list: list of un-categorized LEBs -+ * @empty_list: list of empty LEBs -+ * @freeable_list: list of freeable non-index LEBs (free + dirty == leb_size) -+ * @frdi_idx_list: list of freeable index LEBs (free + dirty == leb_size) -+ * @freeable_cnt: number of freeable LEBs in @freeable_list -+ * -+ * @ltab_lnum: LEB number of LPT's own lprops table -+ * @ltab_offs: offset of LPT's own lprops table -+ * @ltab: LPT's own lprops table -+ * @ltab_cmt: LPT's own lprops table (commit copy) -+ * @lsave_cnt: number of LEB numbers in LPT's save table -+ * @lsave_lnum: LEB number of LPT's save table -+ * @lsave_offs: offset of LPT's save table -+ * @lsave: LPT's save table -+ * @lscan_lnum: LEB number of last LPT scan -+ * -+ * @rp_size: size of the reserved pool in bytes -+ * @report_rp_size: size of the reserved pool reported to userspace -+ * @rp_uid: reserved pool user ID -+ * @rp_gid: reserved pool group ID -+ * -+ * @empty: if the UBI device is empty -+ * @replay_tree: temporary tree used during journal replay -+ * @replay_list: temporary list used during journal replay -+ * @replay_buds: list of buds to replay -+ * @cs_sqnum: sequence number of first node in the log (commit start node) -+ * @replay_sqnum: sequence number of node currently being replayed -+ * @need_recovery: file-system needs recovery -+ * @replaying: set to %1 during journal replay -+ * @unclean_leb_list: LEBs to recover when mounting ro to rw -+ * @rcvrd_mst_node: recovered master node to write when mounting ro to rw -+ * @size_tree: inode size information for recovery -+ * @recovery_needs_commit: a commit must be done before unmounting -+ * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY) -+ * @mount_opts: UBIFS-specific mount options -+ * -+ * @dbg_buf: a buffer of LEB size used for debugging purposes -+ * @old_zroot: old index root - used by 'dbg_check_old_index()' -+ * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' -+ * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' -+ * @failure_mode: failure mode for recovery testing -+ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls -+ * @fail_timeout: time in jiffies when delay of failure mode expires -+ * @fail_cnt: current number of calls to failure mode I/O functions -+ * @fail_cnt_max: number of calls by which to delay failure mode -+ */ -+struct ubifs_info { -+ struct super_block *vfs_sb; -+ -+ ino_t highest_inum; -+ unsigned int vfs_gen; -+ unsigned long long max_sqnum; -+ unsigned long long cmt_no; -+ spinlock_t cnt_lock; -+ int fmt_version; -+ -+ int lhead_lnum; -+ int lhead_offs; -+ int ltail_lnum; -+ struct mutex log_mutex; -+ int min_log_bytes; -+ long long cmt_bud_bytes; -+ -+ struct rb_root buds; -+ long long bud_bytes; -+ spinlock_t buds_lock; -+ int jhead_cnt; -+ struct ubifs_jhead *jheads; -+ long long max_bud_bytes; -+ long long bg_bud_bytes; -+ struct list_head old_buds; -+ int max_bud_cnt; -+ -+ struct rw_semaphore commit_sem; -+ int cmt_state; -+ spinlock_t cs_lock; -+ wait_queue_head_t cmt_wq; -+ unsigned int fast_unmount:1; -+ unsigned int big_lpt:1; -+ -+ struct mutex tnc_mutex; -+ struct ubifs_zbranch zroot; -+ struct ubifs_znode *cnext; -+ struct ubifs_znode *enext; -+ int *gap_lebs; -+ void *cbuf; -+ void *ileb_buf; -+ int ileb_len; -+ int ihead_lnum; -+ int ihead_offs; -+ int *ilebs; -+ int ileb_cnt; -+ int ileb_nxt; -+ struct rb_root old_idx; -+ int *bottom_up_buf; -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ int new_ihead_lnum; -+ int new_ihead_offs; -+#endif -+ -+ struct ubifs_mst_node *mst_node; -+ int mst_offs; -+ struct mutex mst_mutex; -+ -+ int log_lebs; -+ long long log_bytes; -+ int log_last; -+ int lpt_lebs; -+ int lpt_first; -+ int lpt_last; -+ int orph_lebs; -+ int orph_first; -+ int orph_last; -+ int main_lebs; -+ int main_first; -+ long long main_bytes; -+ int default_compr; -+ -+ uint8_t key_hash_type; -+ uint32_t (*key_hash)(const char *str, int len); -+ int key_fmt; -+ int key_len; -+ int fanout; -+ -+ int min_io_size; -+ int min_io_shift; -+ int leb_size; -+ int half_leb_size; -+ int leb_cnt; -+ int max_leb_cnt; -+ int old_leb_cnt; -+ int ro_media; -+ -+ atomic_long_t dirty_pg_cnt; -+ atomic_long_t dirty_ino_cnt; -+ atomic_long_t dirty_zn_cnt; -+ atomic_long_t clean_zn_cnt; -+ -+ long long budg_idx_growth; -+ long long budg_data_growth; -+ long long budg_dd_growth; -+ long long budg_uncommitted_idx; -+ spinlock_t space_lock; -+ int min_idx_lebs; -+ unsigned long long old_idx_sz; -+ unsigned long long calc_idx_sz; -+ struct ubifs_lp_stats lst; -+ -+ int page_budget; -+ int inode_budget; -+ int dent_budget; -+ -+ int ref_node_alsz; -+ int mst_node_alsz; -+ int min_idx_node_sz; -+ int max_idx_node_sz; -+ long long max_inode_sz; -+ int max_znode_sz; -+ int dead_wm; -+ int dark_wm; -+ int block_cnt; -+ -+ struct ubifs_node_range ranges[UBIFS_NODE_TYPES_CNT]; -+ struct ubi_volume_desc *ubi; -+ struct ubi_device_info di; -+ struct ubi_volume_info vi; -+ -+ struct rb_root orph_tree; -+ struct list_head orph_list; -+ struct list_head orph_new; -+ struct ubifs_orphan *orph_cnext; -+ struct ubifs_orphan *orph_dnext; -+ spinlock_t orphan_lock; -+ void *orph_buf; -+ int new_orphans; -+ int cmt_orphans; -+ int tot_orphans; -+ int max_orphans; -+ int ohead_lnum; -+ int ohead_offs; -+ int no_orphs; -+ -+ struct task_struct *bgt; -+ char bgt_name[sizeof(BGT_NAME_PATTERN) + 9]; -+ int need_bgt; -+ int need_wbuf_sync; -+ -+ int gc_lnum; -+ void *sbuf; -+ struct list_head idx_gc; -+ int idx_gc_cnt; -+ -+ struct list_head infos_list; -+ struct mutex umount_mutex; -+ unsigned int shrinker_run_no; -+ -+ int space_bits; -+ int lpt_lnum_bits; -+ int lpt_offs_bits; -+ int lpt_spc_bits; -+ int pcnt_bits; -+ int lnum_bits; -+ int nnode_sz; -+ int pnode_sz; -+ int ltab_sz; -+ int lsave_sz; -+ int pnode_cnt; -+ int nnode_cnt; -+ int lpt_hght; -+ int pnodes_have; -+ -+ struct mutex lp_mutex; -+ int lpt_lnum; -+ int lpt_offs; -+ int nhead_lnum; -+ int nhead_offs; -+ int lpt_drty_flgs; -+ int dirty_nn_cnt; -+ int dirty_pn_cnt; -+ long long lpt_sz; -+ void *lpt_nod_buf; -+ void *lpt_buf; -+ struct ubifs_nnode *nroot; -+ struct ubifs_cnode *lpt_cnext; -+ struct ubifs_lpt_heap lpt_heap[LPROPS_HEAP_CNT]; -+ struct ubifs_lpt_heap dirty_idx; -+ struct list_head uncat_list; -+ struct list_head empty_list; -+ struct list_head freeable_list; -+ struct list_head frdi_idx_list; -+ int freeable_cnt; -+ -+ int ltab_lnum; -+ int ltab_offs; -+ struct ubifs_lpt_lprops *ltab; -+ struct ubifs_lpt_lprops *ltab_cmt; -+ int lsave_cnt; -+ int lsave_lnum; -+ int lsave_offs; -+ int *lsave; -+ int lscan_lnum; -+ -+ long long rp_size; -+ long long report_rp_size; -+ uid_t rp_uid; -+ gid_t rp_gid; -+ -+ /* The below fields are used only during mounting and re-mounting */ -+ int empty; -+ struct rb_root replay_tree; -+ struct list_head replay_list; -+ struct list_head replay_buds; -+ unsigned long long cs_sqnum; -+ unsigned long long replay_sqnum; -+ int need_recovery; -+ int replaying; -+ struct list_head unclean_leb_list; -+ struct ubifs_mst_node *rcvrd_mst_node; -+ struct rb_root size_tree; -+ int recovery_needs_commit; -+ int remounting_rw; -+ struct ubifs_mount_opts mount_opts; -+ -+#ifdef CONFIG_UBIFS_FS_DEBUG -+ void *dbg_buf; -+ struct ubifs_zbranch old_zroot; -+ int old_zroot_level; -+ unsigned long long old_zroot_sqnum; -+ int failure_mode; -+ int fail_delay; -+ unsigned long fail_timeout; -+ unsigned int fail_cnt; -+ unsigned int fail_cnt_max; -+#endif -+}; -+ -+extern struct list_head ubifs_infos; -+extern spinlock_t ubifs_infos_lock; -+extern atomic_long_t ubifs_clean_zn_cnt; -+extern struct kmem_cache *ubifs_inode_slab; -+extern struct super_operations ubifs_super_operations; -+extern struct address_space_operations ubifs_file_address_operations; -+extern struct file_operations ubifs_file_operations; -+extern struct inode_operations ubifs_file_inode_operations; -+extern struct file_operations ubifs_dir_operations; -+extern struct inode_operations ubifs_dir_inode_operations; -+extern struct inode_operations ubifs_symlink_inode_operations; -+extern struct backing_dev_info ubifs_backing_dev_info; -+extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; -+ -+/* io.c */ -+int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); -+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, -+ int dtype); -+int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf); -+int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, -+ int lnum, int offs); -+int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, -+ int lnum, int offs); -+int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, -+ int offs, int dtype); -+int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, -+ int offs, int quiet); -+void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); -+void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); -+int ubifs_io_init(struct ubifs_info *c); -+void ubifs_pad(const struct ubifs_info *c, void *buf, int pad); -+int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf); -+int ubifs_bg_wbufs_sync(struct ubifs_info *c); -+void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum); -+int ubifs_sync_wbufs_by_inodes(struct ubifs_info *c, -+ struct inode * const *inodes, int count); -+ -+/* scan.c */ -+struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, -+ int offs, void *sbuf); -+void ubifs_scan_destroy(struct ubifs_scan_leb *sleb); -+int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum, -+ int offs, int quiet); -+struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum, -+ int offs, void *sbuf); -+void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ int lnum, int offs); -+int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb, -+ void *buf, int offs); -+void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, -+ void *buf); -+ -+/* log.c */ -+void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud); -+void ubifs_create_buds_lists(struct ubifs_info *c); -+int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs); -+struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum); -+struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum); -+int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum); -+int ubifs_log_end_commit(struct ubifs_info *c, int new_ltail_lnum); -+int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum); -+int ubifs_consolidate_log(struct ubifs_info *c); -+ -+/* journal.c */ -+int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, -+ const struct qstr *nm, const struct inode *inode, -+ int deletion, int sync, int xent); -+int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, -+ const union ubifs_key *key, const void *buf, int len); -+int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, -+ int last_reference, int sync); -+int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, -+ const struct dentry *old_dentry, -+ const struct inode *new_dir, -+ const struct dentry *new_dentry, int sync); -+int ubifs_jnl_truncate(struct ubifs_info *c, ino_t inum, -+ loff_t old_size, loff_t new_size); -+int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, -+ const struct inode *inode, const struct qstr *nm, -+ int sync); -+int ubifs_jnl_write_2_inodes(struct ubifs_info *c, const struct inode *inode1, -+ const struct inode *inode2, int sync); -+ -+/* budget.c */ -+int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req); -+void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req); -+int ubifs_budget_inode_op(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req); -+void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req); -+void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req); -+int ubifs_budget_ino_cleaning(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req); -+void ubifs_release_ino_clean(struct ubifs_info *c, struct inode *inode, -+ struct ubifs_budget_req *req); -+long long ubifs_budg_get_free_space(struct ubifs_info *c); -+int ubifs_calc_min_idx_lebs(struct ubifs_info *c); -+void ubifs_convert_page_budget(struct ubifs_info *c); -+void ubifs_release_new_page_budget(struct ubifs_info *c); -+long long ubifs_calc_available(const struct ubifs_info *c); -+ -+/* find.c */ -+int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *free, -+ int squeeze); -+int ubifs_find_free_leb_for_idx(struct ubifs_info *c); -+int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, -+ int min_space, int pick_free); -+int ubifs_find_dirty_idx_leb(struct ubifs_info *c); -+int ubifs_save_dirty_idx_lnums(struct ubifs_info *c); -+ -+/* tnc.c */ -+int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, -+ void *node); -+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, -+ void *node, int *lnum, int *offs); -+int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, -+ void *node, const struct qstr *nm); -+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, -+ int offs, int len); -+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, -+ int old_lnum, int old_offs, int lnum, int offs, int len); -+int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, -+ int lnum, int offs, int len, const struct qstr *nm); -+int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key); -+int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, -+ const struct qstr *nm); -+int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, -+ union ubifs_key *to_key); -+int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum); -+struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, -+ union ubifs_key *key, -+ const struct qstr *nm); -+void ubifs_tnc_close(struct ubifs_info *c); -+int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs, int is_idx); -+int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs); -+/* Shared by tnc.c for tnc_commit.c */ -+void destroy_old_idx(struct ubifs_info *c); -+int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level, -+ int lnum, int offs); -+int insert_old_idx_znode(struct ubifs_info *c, struct ubifs_znode *znode); -+ -+/* tnc_misc.c */ -+struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr, -+ struct ubifs_znode *znode); -+int ubifs_search_zbranch(const struct ubifs_info *c, -+ const struct ubifs_znode *znode, -+ const union ubifs_key *key, int *n); -+struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode); -+struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode); -+long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr); -+ -+/* tnc_commit.c */ -+int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot); -+int ubifs_tnc_end_commit(struct ubifs_info *c); -+ -+/* shrinker.c */ -+int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask); -+ -+/* commit.c */ -+int ubifs_bg_thread(void *info); -+void ubifs_commit_required(struct ubifs_info *c); -+void ubifs_request_bg_commit(struct ubifs_info *c); -+int ubifs_run_commit(struct ubifs_info *c); -+void ubifs_recovery_commit(struct ubifs_info *c); -+int ubifs_gc_should_commit(struct ubifs_info *c); -+void ubifs_wait_for_commit(struct ubifs_info *c); -+ -+/* master.c */ -+int ubifs_read_master(struct ubifs_info *c); -+int ubifs_write_master(struct ubifs_info *c); -+ -+/* sb.c */ -+int ubifs_read_superblock(struct ubifs_info *c); -+struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); -+int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); -+ -+/* replay.c */ -+int ubifs_validate_entry(struct ubifs_info *c, -+ const struct ubifs_dent_node *dent); -+int ubifs_replay_journal(struct ubifs_info *c); -+ -+/* gc.c */ -+int ubifs_garbage_collect(struct ubifs_info *c, int anyway); -+int ubifs_gc_start_commit(struct ubifs_info *c); -+int ubifs_gc_end_commit(struct ubifs_info *c); -+void ubifs_destroy_idx_gc(struct ubifs_info *c); -+int ubifs_get_idx_gc_leb(struct ubifs_info *c); -+int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp); -+ -+/* orphan.c */ -+int ubifs_add_orphan(struct ubifs_info *c, ino_t inum); -+void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum); -+int ubifs_orphan_start_commit(struct ubifs_info *c); -+int ubifs_orphan_end_commit(struct ubifs_info *c); -+int ubifs_mount_orphans(struct ubifs_info *c, int unclean); -+ -+/* lpt.c */ -+int ubifs_calc_lpt_geom(struct ubifs_info *c); -+int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, -+ int *lpt_lebs, int *big_lpt); -+int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr); -+struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum); -+struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum); -+int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum, -+ ubifs_lpt_scan_callback scan_cb, void *data); -+ -+/* Shared by lpt.c for lpt_commit.c */ -+void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave); -+void ubifs_pack_ltab(struct ubifs_info *c, void *buf, -+ struct ubifs_lpt_lprops *ltab); -+void ubifs_pack_pnode(struct ubifs_info *c, void *buf, -+ struct ubifs_pnode *pnode); -+void ubifs_pack_nnode(struct ubifs_info *c, void *buf, -+ struct ubifs_nnode *nnode); -+struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip); -+struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c, -+ struct ubifs_nnode *parent, int iip); -+int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip); -+void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty); -+void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode); -+uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits); -+struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght); -+ -+/* lpt_commit.c */ -+int ubifs_lpt_start_commit(struct ubifs_info *c); -+int ubifs_lpt_end_commit(struct ubifs_info *c); -+int ubifs_lpt_post_commit(struct ubifs_info *c); -+void ubifs_lpt_free(struct ubifs_info *c, int wr_only); -+ -+/* lprops.c */ -+void ubifs_get_lprops(struct ubifs_info *c); -+const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, -+ const struct ubifs_lprops *lp, -+ int free, int dirty, int flags, -+ int idx_gc_cnt); -+void ubifs_release_lprops(struct ubifs_info *c); -+void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *stats); -+void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, -+ int cat); -+void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops, -+ struct ubifs_lprops *new_lprops); -+void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops); -+int ubifs_categorize_lprops(const struct ubifs_info *c, -+ const struct ubifs_lprops *lprops); -+int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, -+ int flags_set, int flags_clean, int idx_gc_cnt); -+int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, -+ int flags_set, int flags_clean); -+int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp); -+const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c); -+const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c); -+const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c); -+const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c); -+ -+/* file.c */ -+int ubifs_fsync(struct file *file, struct dentry *dentry, int datasync); -+int ubifs_setattr(struct dentry *dentry, struct iattr *attr); -+ -+/* dir.c */ -+struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, -+ int mode); -+int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, -+ struct kstat *stat); -+ -+/* xattr.c */ -+int ubifs_setxattr(struct dentry *dentry, const char *name, -+ const void *value, size_t size, int flags); -+ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, -+ size_t size); -+ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); -+int ubifs_removexattr(struct dentry *dentry, const char *name); -+ -+/* super.c */ -+struct inode *ubifs_iget(struct super_block *sb, unsigned long inum); -+ -+/* recovery.c */ -+int ubifs_recover_master_node(struct ubifs_info *c); -+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c); -+struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, -+ int offs, void *sbuf, int grouped); -+struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, -+ int offs, void *sbuf); -+int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf); -+int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf); -+int ubifs_recover_gc_lnum(struct ubifs_info *c); -+int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, -+ int deletion, loff_t new_size); -+int ubifs_recover_size(struct ubifs_info *c); -+void ubifs_destroy_size_tree(struct ubifs_info *c); -+ -+/* ioctl.c */ -+long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -+void ubifs_set_inode_flags(struct inode *inode); -+#ifdef CONFIG_COMPAT -+long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -+#endif -+ -+/* compressor.c */ -+int __init ubifs_compressors_init(void); -+void __exit ubifs_compressors_exit(void); -+void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len, -+ int *compr_type); -+int ubifs_decompress(const void *buf, int len, void *out, int *out_len, -+ int compr_type); -+ -+#include "debug.h" -+#include "misc.h" -+#include "key.h" -+ -+#endif /* !__UBIFS_H__ */ -diff -urN linux-2.6.24.7.old/fs/ubifs/xattr.c linux-2.6.24.7/fs/ubifs/xattr.c ---- linux-2.6.24.7.old/fs/ubifs/xattr.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/fs/ubifs/xattr.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,582 @@ -+/* -+ * This file is part of UBIFS. -+ * -+ * Copyright (C) 2006-2008 Nokia Corporation. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License version 2 as published by -+ * the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software Foundation, Inc., 51 -+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * Authors: Artem Bityutskiy (Битюцкий Ðртём) -+ * Adrian Hunter -+ */ -+ -+/* -+ * This file implements UBIFS extended attributes support. -+ * -+ * Extended attributes are implemented as regular inodes with attached data, -+ * which limits extended attribute size to UBIFS block size (4KiB). Names of -+ * extended attributes are described by extended attribute entries (xentries), -+ * which are almost identical to directory entries, but have different key type. -+ * -+ * In other words, the situation with extended attributes is very similar to -+ * directories. Indeed, any inode (but of course not xattr inodes) may have a -+ * number of associated xentries, just like directory inodes have associated -+ * directory entries. Extended attribute entries store the name of the extended -+ * attribute, the host inode number, and the extended attribute inode number. -+ * Similarly, direntries store the name, the parent and the target inode -+ * numbers. Thus, most of the common UBIFS mechanisms may be re-used for -+ * extended attributes. -+ * -+ * The number of extended attributes is not limited, but there is Linux -+ * limitation on the maximum possible size of the list of all extended -+ * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure -+ * the sum of all extended attribute names of the inode does not exceed that -+ * limit. -+ * -+ * Extended attributes are synchronous, which means they are written to the -+ * flash media synchronously and there is no write-back for extended attribute -+ * inodes. The extended attribute values are not stored in compressed form on -+ * the media. -+ * -+ * Since extended attributes are represented by regular inodes, they are cached -+ * in the VFS inode cache. The xentries are cached in the LNC cache (see -+ * tnc.c). -+ * -+ * ACL support is not implemented. -+ */ -+ -+#include -+#include -+#include "ubifs.h" -+ -+/* How many bytes an extended attribute adds to the host inode */ -+#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8) -+ -+/* -+ * Extended attribute type constants. -+ * -+ * USER_XATTR: user extended attribute ("user.*") -+ * TRUSTED_XATTR: trusted extended attribute ("trusted.*) -+ * SECURITY_XATTR: security extended attribute ("security.*") -+ */ -+enum { -+ USER_XATTR, -+ TRUSTED_XATTR, -+ SECURITY_XATTR, -+}; -+ -+static struct inode_operations none_inode_operations; -+static struct address_space_operations none_address_operations; -+static struct file_operations none_file_operations; -+ -+/** -+ * create_xattr - create an extended attribute. -+ * @c: UBIFS file-system description object -+ * @host: host inode -+ * @nm: extended attribute name -+ * @value: extended attribute value -+ * @size: size of extended attribute value -+ * -+ * This is a helper function which creates an extended attribute of name @nm -+ * and value @value for inode @host. The host inode is also updated on flash -+ * because the ctime and extended attribute accounting data changes. This -+ * function returns zero in case of success and a negative error code in case -+ * of failure. -+ */ -+static int create_xattr(struct ubifs_info *c, struct inode *host, -+ const struct qstr *nm, const void *value, int size) -+{ -+ struct ubifs_inode *ui, *host_ui = ubifs_inode(host); -+ struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, -+ .new_ino_d = size }; -+ struct inode *inode; -+ int err; -+ -+ /* -+ * Linux limits the maximum size of the extended attribute names list -+ * to %XATTR_LIST_MAX. This means we should not allow creating more* -+ * extended attributes if the name list becomes larger. This limitation -+ * is artificial for UBIFS, though. -+ */ -+ if (host_ui->xattr_names + host_ui->xattr_cnt + -+ nm->len + 1 > XATTR_LIST_MAX) -+ return -ENOSPC; -+ -+ err = ubifs_budget_inode_op(c, host, &req); -+ if (err) -+ return err; -+ -+ inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO); -+ if (IS_ERR(inode)) { -+ err = PTR_ERR(inode); -+ goto out_budg; -+ } -+ -+ /* Re-define all operations to be "nothing" */ -+ inode->i_mapping->a_ops = &none_address_operations; -+ inode->i_op = &none_inode_operations; -+ inode->i_fop = &none_file_operations; -+ -+ inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA; -+ ui = ubifs_inode(inode); -+ ui->xattr = 1; -+ ui->data = kmalloc(size, GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_inode; -+ } -+ -+ memcpy(ui->data, value, size); -+ host->i_ctime = ubifs_current_time(host); -+ host_ui->xattr_cnt += 1; -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size += CALC_DENT_SIZE(nm->len); -+ host_ui->xattr_size += CALC_XATTR_BYTES(size); -+ spin_unlock(&host->i_lock); -+ host_ui->xattr_names += nm->len; -+ -+ /* -+ * We do not use i_size_write() because nobody can race with us as we -+ * are holding host @host->i_mutex - every xattr operation for this -+ * inode is serialized by it. -+ */ -+ inode->i_size = size; -+ ui->data_len = size; -+ -+ /* -+ * Note, it is important that 'ubifs_jnl_update()' writes the @host -+ * inode last, so when it gets synchronized and the write-buffer is -+ * flushed, the extended attribute is flushed as well. -+ */ -+ err = ubifs_jnl_update(c, host, nm, inode, 0, IS_DIRSYNC(host), 1); -+ if (err) -+ goto out_cancel; -+ -+ ubifs_release_ino_clean(c, host, &req); -+ insert_inode_hash(inode); -+ iput(inode); -+ return 0; -+ -+out_cancel: -+ host_ui->xattr_cnt -= 1; -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); -+ host_ui->xattr_size -= CALC_XATTR_BYTES(size); -+ spin_unlock(&host->i_lock); -+out_inode: -+ make_bad_inode(inode); -+ iput(inode); -+out_budg: -+ ubifs_cancel_ino_op(c, host, &req); -+ return err; -+} -+ -+/** -+ * change_xattr - change an extended attribute. -+ * @c: UBIFS file-system description object -+ * @host: host inode -+ * @inode: extended attribute inode -+ * @value: extended attribute value -+ * @size: size of extended attribute value -+ * -+ * This helper function changes the value of extended attribute @inode with new -+ * data from @value. Returns zero in case of success and a negative error code -+ * in case of failure. -+ */ -+static int change_xattr(struct ubifs_info *c, struct inode *host, -+ struct inode *inode, const void *value, int size) -+{ -+ struct ubifs_inode *host_ui = ubifs_inode(host); -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_budget_req req = { .dirtied_ino = 1, -+ .dirtied_ino_d = ui->data_len }; -+ int err; -+ -+ ubifs_assert(ui->data_len == inode->i_size); -+ -+ err = ubifs_budget_inode_op(c, host, &req); -+ if (err) -+ return err; -+ -+ host->i_ctime = ubifs_current_time(host); -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); -+ host_ui->xattr_size += CALC_XATTR_BYTES(size); -+ spin_unlock(&host->i_lock); -+ -+ kfree(ui->data); -+ ui->data = kmalloc(size, GFP_NOFS); -+ if (!ui->data) { -+ err = -ENOMEM; -+ goto out_budg; -+ } -+ -+ memcpy(ui->data, value, size); -+ inode->i_size = size; -+ ui->data_len = size; -+ -+ /* -+ * It is important to write the host inode after the xattr inode -+ * because if the host inode gets synchronized, then the extended -+ * attribute inode gets synchronized, because it goes before the host -+ * inode in the write-buffer. -+ */ -+ err = ubifs_jnl_write_2_inodes(c, inode, host, IS_DIRSYNC(host)); -+ if (err) -+ goto out_cancel; -+ -+ ubifs_release_ino_clean(c, host, &req); -+ return 0; -+ -+out_cancel: -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size -= CALC_XATTR_BYTES(size); -+ host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); -+ spin_unlock(&host->i_lock); -+ make_bad_inode(inode); -+out_budg: -+ ubifs_cancel_ino_op(c, host, &req); -+ return err; -+} -+ -+/** -+ * check_namespace - check extended attribute name-space. -+ * @nm: extended attribute name -+ * -+ * This function makes sure the extended attribute name belongs to one of the -+ * supported extended attribute name-spaces. Returns name-space index in case -+ * of success and a negative error code in case of failure. -+ */ -+static int check_namespace(const struct qstr *nm) -+{ -+ int type; -+ -+ if (nm->len > UBIFS_MAX_NLEN) -+ return -ENAMETOOLONG; -+ -+ if (!strncmp(nm->name, XATTR_TRUSTED_PREFIX, -+ XATTR_TRUSTED_PREFIX_LEN)) { -+ if (nm->name[sizeof(XATTR_TRUSTED_PREFIX) - 1] == '\0') -+ return -EINVAL; -+ type = TRUSTED_XATTR; -+ } else if (!strncmp(nm->name, XATTR_USER_PREFIX, -+ XATTR_USER_PREFIX_LEN)) { -+ if (nm->name[XATTR_USER_PREFIX_LEN] == '\0') -+ return -EINVAL; -+ type = USER_XATTR; -+ } else if (!strncmp(nm->name, XATTR_SECURITY_PREFIX, -+ XATTR_SECURITY_PREFIX_LEN)) { -+ if (nm->name[sizeof(XATTR_SECURITY_PREFIX) - 1] == '\0') -+ return -EINVAL; -+ type = SECURITY_XATTR; -+ } else -+ return -EOPNOTSUPP; -+ -+ return type; -+} -+ -+int ubifs_setxattr(struct dentry *dentry, const char *name, -+ const void *value, size_t size, int flags) -+{ -+ struct inode *inode, *host = dentry->d_inode; -+ struct ubifs_info *c = host->i_sb->s_fs_info; -+ struct qstr nm = { .name = name, .len = strlen(name) }; -+ struct ubifs_dent_node *xent; -+ union ubifs_key key; -+ int err, type; -+ -+ dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name, -+ host->i_ino, dentry->d_name.len, dentry->d_name.name, size); -+ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); -+ -+ if (size > UBIFS_MAX_INO_DATA) -+ return -ERANGE; -+ -+ type = check_namespace(&nm); -+ if (type < 0) -+ return type; -+ -+ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); -+ if (!xent) -+ return -ENOMEM; -+ -+ /* -+ * The extended attribute entries are stored in LNC, so multiple -+ * look-ups do not involve reading the flash. -+ */ -+ xent_key_init(c, &key, host->i_ino, &nm); -+ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); -+ if (err) { -+ if (err != -ENOENT) -+ goto out_free; -+ -+ if (flags & XATTR_REPLACE) -+ /* We are asked not to create the xattr */ -+ err = -ENODATA; -+ else -+ err = create_xattr(c, host, &nm, value, size); -+ goto out_free; -+ } -+ -+ if (flags & XATTR_CREATE) { -+ /* We are asked not to replace the xattr */ -+ err = -EEXIST; -+ goto out_free; -+ } -+ -+ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); -+ if (IS_ERR(inode)) { -+ ubifs_err("dead extended attribute entry, error %d", err); -+ ubifs_ro_mode(c, err); -+ err = PTR_ERR(inode); -+ goto out_free; -+ } -+ -+ err = change_xattr(c, host, inode, value, size); -+ iput(inode); -+ -+out_free: -+ kfree(xent); -+ return err; -+} -+ -+ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, -+ size_t size) -+{ -+ struct inode *inode, *host = dentry->d_inode; -+ struct ubifs_info *c = host->i_sb->s_fs_info; -+ struct qstr nm = { .name = name, .len = strlen(name) }; -+ struct ubifs_inode *ui; -+ struct ubifs_dent_node *xent; -+ union ubifs_key key; -+ int err; -+ -+ dbg_gen("xattr '%s', ino %lu ('%.*s'), buf size %zd", name, -+ host->i_ino, dentry->d_name.len, dentry->d_name.name, size); -+ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); -+ -+ err = check_namespace(&nm); -+ if (err < 0) -+ return err; -+ -+ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); -+ if (!xent) -+ return -ENOMEM; -+ -+ mutex_lock(&host->i_mutex); -+ xent_key_init(c, &key, host->i_ino, &nm); -+ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); -+ if (err) { -+ if (err == -ENOENT) -+ err = -ENODATA; -+ goto out_unlock; -+ } -+ -+ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); -+ if (IS_ERR(inode)) { -+ ubifs_err("dead extended attribute entry, error %d", err); -+ ubifs_ro_mode(c, err); -+ err = PTR_ERR(inode); -+ goto out_unlock; -+ } -+ -+ ui = ubifs_inode(inode); -+ ubifs_assert(inode->i_size == ui->data_len); -+ ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len); -+ -+ if (buf) { -+ /* If @buf is %NULL we are supposed to return the length */ -+ if (ui->data_len > size) { -+ dbg_err("buffer size %zd, xattr len %d", -+ size, ui->data_len); -+ err = -ERANGE; -+ goto out_iput; -+ } -+ -+ memcpy(buf, ui->data, ui->data_len); -+ } -+ err = ui->data_len; -+ -+out_iput: -+ iput(inode); -+out_unlock: -+ mutex_unlock(&host->i_mutex); -+ kfree(xent); -+ return err; -+} -+ -+ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) -+{ -+ struct inode *host = dentry->d_inode; -+ struct ubifs_info *c = host->i_sb->s_fs_info; -+ struct ubifs_inode *host_ui = ubifs_inode(host); -+ union ubifs_key key; -+ struct ubifs_dent_node *xent, *pxent = NULL; -+ int err, len, written = 0; -+ struct qstr nm = { .name = NULL }; -+ -+ dbg_gen("ino %lu ('%.*s'), buffer size %zd", host->i_ino, -+ dentry->d_name.len, dentry->d_name.name, size); -+ ubifs_assert(host_ui->xattr_cnt >= 0); -+ ubifs_assert(host_ui->xattr_size >= 0); -+ ubifs_assert(host_ui->xattr_names >= 0); -+ -+ len = host_ui->xattr_names + host_ui->xattr_cnt; -+ if (!buffer) -+ /* -+ * We should return the minimum buffer size which will fit a -+ * null-terminated list of all the extended attribute names. -+ */ -+ return len; -+ -+ if (len > size) -+ return -ERANGE; -+ -+ lowest_xent_key(c, &key, host->i_ino); -+ -+ mutex_lock(&host->i_mutex); -+ while (1) { -+ int type; -+ -+ xent = ubifs_tnc_next_ent(c, &key, &nm); -+ if (unlikely(IS_ERR(xent))) { -+ err = PTR_ERR(xent); -+ break; -+ } -+ -+ nm.name = xent->name; -+ nm.len = le16_to_cpu(xent->nlen); -+ -+ type = check_namespace(&nm); -+ if (unlikely(type < 0)) { -+ err = type; -+ break; -+ } -+ -+ /* Show trusted namespace only for "power" users */ -+ if (type != TRUSTED_XATTR || capable(CAP_SYS_ADMIN)) { -+ memcpy(buffer + written, nm.name, nm.len + 1); -+ written += nm.len + 1; -+ } -+ -+ kfree(pxent); -+ pxent = xent; -+ key_read(c, &xent->key, &key); -+ } -+ mutex_unlock(&host->i_mutex); -+ -+ kfree(pxent); -+ if (err != -ENOENT) { -+ ubifs_err("cannot find next direntry, error %d", err); -+ return err; -+ } -+ -+ ubifs_assert(written <= size); -+ return written; -+} -+ -+static int remove_xattr(struct ubifs_info *c, struct inode *host, -+ struct inode *inode, const struct qstr *nm) -+{ -+ struct ubifs_inode *host_ui = ubifs_inode(host); -+ struct ubifs_inode *ui = ubifs_inode(inode); -+ struct ubifs_budget_req req = { .dirtied_ino = 1, .mod_dent = 1 }; -+ int err; -+ -+ ubifs_assert(ui->data_len == inode->i_size); -+ -+ err = ubifs_budget_inode_op(c, host, &req); -+ if (err) -+ return err; -+ -+ host->i_ctime = ubifs_current_time(host); -+ host_ui->xattr_cnt -= 1; -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); -+ spin_unlock(&host->i_lock); -+ host_ui->xattr_names -= nm->len; -+ -+ err = ubifs_jnl_delete_xattr(c, host, inode, nm, IS_DIRSYNC(host)); -+ if (err) -+ goto out_cancel; -+ -+ ubifs_release_ino_clean(c, host, &req); -+ return 0; -+ -+out_cancel: -+ ubifs_cancel_ino_op(c, host, &req); -+ host_ui->xattr_cnt += 1; -+ spin_lock(&host->i_lock); -+ host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); -+ spin_unlock(&host->i_lock); -+ make_bad_inode(inode); -+ return err; -+} -+ -+int ubifs_removexattr(struct dentry *dentry, const char *name) -+{ -+ struct inode *inode, *host = dentry->d_inode; -+ struct ubifs_info *c = host->i_sb->s_fs_info; -+ struct qstr nm = { .name = name, .len = strlen(name) }; -+ struct ubifs_dent_node *xent; -+ union ubifs_key key; -+ int err; -+ -+ dbg_gen("xattr '%s', ino %lu ('%.*s')", name, -+ host->i_ino, dentry->d_name.len, dentry->d_name.name); -+ ubifs_assert(mutex_is_locked(&host->i_mutex)); -+ ubifs_assert(ubifs_inode(host)->xattr_cnt >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_size >= 0); -+ ubifs_assert(ubifs_inode(host)->xattr_names >= 0); -+ -+ err = check_namespace(&nm); -+ if (err < 0) -+ return err; -+ -+ xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); -+ if (!xent) -+ return -ENOMEM; -+ -+ xent_key_init(c, &key, host->i_ino, &nm); -+ err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); -+ if (err) { -+ if (err == -ENOENT) -+ err = -ENODATA; -+ goto out_free; -+ } -+ -+ inode = ubifs_iget(c->vfs_sb, le64_to_cpu(xent->inum)); -+ if (IS_ERR(inode)) { -+ ubifs_err("dead extended attribute node entry"); -+ ubifs_ro_mode(c, err); -+ err = PTR_ERR(inode); -+ goto out_free; -+ } -+ -+ ubifs_assert(inode->i_nlink == 1); -+ inode->i_nlink = 0; -+ err = remove_xattr(c, host, inode, &nm); -+ if (err) -+ inode->i_nlink = 1; -+ -+ /* If @i_nlink is 0, 'iput()' will delete the inode */ -+ iput(inode); -+ -+out_free: -+ kfree(xent); -+ return err; -+} -diff -urN linux-2.6.24.7.old/include/asm-mips/bootinfo.h linux-2.6.24.7/include/asm-mips/bootinfo.h ---- linux-2.6.24.7.old/include/asm-mips/bootinfo.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/asm-mips/bootinfo.h 2009-04-12 18:13:57.000000000 +0200 -@@ -198,6 +198,14 @@ - #define MACH_GROUP_BRCM 23 /* Broadcom */ - #define MACH_BCM47XX 1 /* Broadcom BCM47XX */ - -+/* -+ * Valid machtype for group INGENIC -+ */ -+#define MACH_INGENIC_JZ4730 0 /* JZ4730 SOC */ -+#define MACH_INGENIC_JZ4740 1 /* JZ4740 SOC */ -+#define MACH_INGENIC_JZ4750 2 /* JZ4750 SOC */ -+#define MACH_INGENIC_JZ4750D 3 /* JZ4750D SOC */ -+ - #define CL_SIZE COMMAND_LINE_SIZE - - const char *get_system_type(void); -diff -urN linux-2.6.24.7.old/include/asm-mips/cpu.h linux-2.6.24.7/include/asm-mips/cpu.h ---- linux-2.6.24.7.old/include/asm-mips/cpu.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/asm-mips/cpu.h 2009-04-12 18:13:57.000000000 +0200 -@@ -33,6 +33,7 @@ - #define PRID_COMP_TOSHIBA 0x070000 - #define PRID_COMP_LSI 0x080000 - #define PRID_COMP_LEXRA 0x0b0000 -+#define PRID_COMP_INGENIC 0xd00000 - - - /* -@@ -113,6 +114,12 @@ - #define PRID_IMP_BCM3302 0x9000 - - /* -+ * These are the PRID's for when 23:16 == PRID_COMP_INGENIC -+ */ -+ -+#define PRID_IMP_JZRISC 0x0200 -+ -+/* - * Definitions for 7:0 on legacy processors - */ - -@@ -203,6 +210,11 @@ - */ - CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2, - -+ /* -+ * Ingenic class processors -+ */ -+ CPU_JZRISC, CPU_XBURST, -+ - CPU_LAST - }; - -diff -urN linux-2.6.24.7.old/include/asm-mips/jzsoc.h linux-2.6.24.7/include/asm-mips/jzsoc.h ---- linux-2.6.24.7.old/include/asm-mips/jzsoc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/jzsoc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,49 @@ -+/* -+ * linux/include/asm-mips/jzsoc.h -+ * -+ * Ingenic's JZXXXX SoC common include. -+ * -+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZSOC_H__ -+#define __ASM_JZSOC_H__ -+ -+/* -+ * SoC include -+ */ -+ -+#ifdef CONFIG_SOC_JZ4730 -+#include -+#endif -+ -+#ifdef CONFIG_SOC_JZ4740 -+#include -+#endif -+ -+#ifdef CONFIG_SOC_JZ4750 -+#include -+#endif -+ -+#ifdef CONFIG_SOC_JZ4750D -+#include -+#endif -+ -+/* -+ * Generic I/O routines -+ */ -+#define readb(addr) (*(volatile unsigned char *)(addr)) -+#define readw(addr) (*(volatile unsigned short *)(addr)) -+#define readl(addr) (*(volatile unsigned int *)(addr)) -+ -+#define writeb(b,addr) ((*(volatile unsigned char *)(addr)) = (b)) -+#define writew(b,addr) ((*(volatile unsigned short *)(addr)) = (b)) -+#define writel(b,addr) ((*(volatile unsigned int *)(addr)) = (b)) -+ -+#endif /* __ASM_JZSOC_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-generic/irq.h linux-2.6.24.7/include/asm-mips/mach-generic/irq.h ---- linux-2.6.24.7.old/include/asm-mips/mach-generic/irq.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/asm-mips/mach-generic/irq.h 2009-04-12 18:13:57.000000000 +0200 -@@ -9,7 +9,7 @@ - #define __ASM_MACH_GENERIC_IRQ_H - - #ifndef NR_IRQS --#define NR_IRQS 128 -+#define NR_IRQS 256 - #endif - - #ifdef CONFIG_I8259 -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/board-pmp.h linux-2.6.24.7/include/asm-mips/mach-jz4730/board-pmp.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/board-pmp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/board-pmp.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,83 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/board-pmp.h -+ * -+ * JZ4730-based PMP board ver 2.x definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_PMP_H__ -+#define __ASM_JZ4730_PMP_H__ -+ -+/*====================================================================== -+ * EXTAL frequency -+ */ -+#define JZ_EXTAL 12000000 /* EXTAL: 12 MHz */ -+#define JZ_EXTAL2 32768 /* EXTAL2: 32.768 KHz */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_PW_I 97 -+#define GPIO_PW_O 66 -+#define GPIO_LED_EN 92 -+#define GPIO_DISP_OFF_N 93 -+#define GPIO_PWM0 94 -+#define GPIO_RTC_IRQ 96 -+#define GPIO_USB_CLK_EN 29 -+#define GPIO_CHARG_STAT 125 -+#define GPIO_TS_PENIRQ 98 -+#define GPIO_UDC_HOTPLUG 86 -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+#define MSC_WP_PIN 82 -+#define MSC_POWEREN_PIN 91 -+#define MSC_HOTPLUG_PIN 90 -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + MSC_HOTPLUG_PIN) -+ -+/* enable slot power */ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_input(MSC_WP_PIN); \ -+ __gpio_as_output(MSC_POWEREN_PIN); \ -+} while (0) -+ -+/* enable slot power */ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(MSC_POWEREN_PIN); \ -+} while (0) -+ -+/* disable slot power */ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(MSC_POWEREN_PIN); \ -+} while (0) -+ -+/* detect card insertion or not */ -+#define __msc_card_detected(slot) \ -+({ \ -+ int ret; \ -+ if (slot == 0) { \ -+ __gpio_mask_irq(MSC_HOTPLUG_IRQ); \ -+ __gpio_as_input(MSC_HOTPLUG_PIN); \ -+ ret = __gpio_get_pin(MSC_HOTPLUG_PIN); \ -+ __gpio_unmask_irq(MSC_HOTPLUG_IRQ); \ -+ } \ -+ else { \ -+ ret = 1; \ -+ } \ -+ ret = !ret; \ -+ ret; \ -+}) -+ -+#endif /* __ASM_JZ4730_PMP_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/clock.h linux-2.6.24.7/include/asm-mips/mach-jz4730/clock.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/clock.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/clock.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,184 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/clock.h -+ * -+ * JZ4730 clocks definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_CLOCK_H__ -+#define __ASM_JZ4730_CLOCK_H__ -+ -+#ifndef JZ_EXTAL -+#define JZ_EXTAL 3686400 -+#endif -+ -+#ifndef JZ_EXTAL2 -+#define JZ_EXTAL2 32768 -+#endif -+ -+/* -+ * JZ4730 clocks structure -+ */ -+typedef struct { -+ unsigned int iclk; /* CPU core clock */ -+ unsigned int sclk; /* AHB bus clock */ -+ unsigned int mclk; /* Memory bus clock */ -+ unsigned int pclk; /* APB bus clock */ -+ unsigned int devclk; /* Devcie clock to specific modules */ -+ unsigned int rtcclk; /* RTC module clock */ -+ unsigned int uartclk; /* UART module clock */ -+ unsigned int lcdclk; /* LCD module clock */ -+ unsigned int pixclk; /* LCD pixel clock */ -+ unsigned int usbclk; /* USB module clock */ -+ unsigned int i2sclk; /* I2S module clock */ -+ unsigned int mscclk; /* MMC/SD module clock */ -+} jz_clocks_t; -+ -+extern jz_clocks_t jz_clocks; -+ -+ -+static __inline__ unsigned int __cpm_get_pllout(void) -+{ -+ unsigned int nf, nr, no, pllout; -+ unsigned long plcr = REG_CPM_PLCR1; -+ unsigned long od[4] = {1, 2, 2, 4}; -+ if (plcr & CPM_PLCR1_PLL1EN) { -+ nf = (plcr & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT; -+ nr = (plcr & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT; -+ no = od[((plcr & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT)]; -+ pllout = (JZ_EXTAL) / ((nr+2) * no) * (nf+2); -+ } else -+ pllout = JZ_EXTAL; -+ return pllout; -+} -+ -+static __inline__ unsigned int __cpm_get_iclk(void) -+{ -+ unsigned int iclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned long cfcr = REG_CPM_CFCR; -+ unsigned long plcr = REG_CPM_PLCR1; -+ if (plcr & CPM_PLCR1_PLL1EN) -+ iclk = __cpm_get_pllout() / -+ div[(cfcr & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT]; -+ else -+ iclk = JZ_EXTAL; -+ return iclk; -+} -+ -+static __inline__ unsigned int __cpm_get_sclk(void) -+{ -+ unsigned int sclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned long cfcr = REG_CPM_CFCR; -+ unsigned long plcr = REG_CPM_PLCR1; -+ if (plcr & CPM_PLCR1_PLL1EN) -+ sclk = __cpm_get_pllout() / -+ div[(cfcr & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT]; -+ else -+ sclk = JZ_EXTAL; -+ return sclk; -+} -+ -+static __inline__ unsigned int __cpm_get_mclk(void) -+{ -+ unsigned int mclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned long cfcr = REG_CPM_CFCR; -+ unsigned long plcr = REG_CPM_PLCR1; -+ if (plcr & CPM_PLCR1_PLL1EN) -+ mclk = __cpm_get_pllout() / -+ div[(cfcr & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT]; -+ else -+ mclk = JZ_EXTAL; -+ return mclk; -+} -+ -+static __inline__ unsigned int __cpm_get_pclk(void) -+{ -+ unsigned int devclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned long cfcr = REG_CPM_CFCR; -+ unsigned long plcr = REG_CPM_PLCR1; -+ if (plcr & CPM_PLCR1_PLL1EN) -+ devclk = __cpm_get_pllout() / -+ div[(cfcr & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT]; -+ else -+ devclk = JZ_EXTAL; -+ return devclk; -+} -+ -+static __inline__ unsigned int __cpm_get_lcdclk(void) -+{ -+ unsigned int lcdclk; -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ unsigned long cfcr = REG_CPM_CFCR; -+ unsigned long plcr = REG_CPM_PLCR1; -+ if (plcr & CPM_PLCR1_PLL1EN) -+ lcdclk = __cpm_get_pllout() / -+ div[(cfcr & CPM_CFCR_LFR_MASK) >> CPM_CFCR_LFR_BIT]; -+ else -+ lcdclk = JZ_EXTAL; -+ return lcdclk; -+} -+ -+static __inline__ unsigned int __cpm_get_pixclk(void) -+{ -+ unsigned int pixclk; -+ unsigned long cfcr2 = REG_CPM_CFCR2; -+ pixclk = __cpm_get_pllout() / (cfcr2 + 1); -+ return pixclk; -+} -+ -+static __inline__ unsigned int __cpm_get_devclk(void) -+{ -+ return JZ_EXTAL; -+} -+ -+static __inline__ unsigned int __cpm_get_rtcclk(void) -+{ -+ return JZ_EXTAL2; -+} -+ -+static __inline__ unsigned int __cpm_get_uartclk(void) -+{ -+ return JZ_EXTAL; -+} -+ -+static __inline__ unsigned int __cpm_get_usbclk(void) -+{ -+ unsigned int usbclk; -+ unsigned long cfcr = REG_CPM_CFCR; -+ if (cfcr & CPM_CFCR_UCS) -+ usbclk = 48000000; -+ else -+ usbclk = __cpm_get_pllout() / -+ (((cfcr &CPM_CFCR_UFR_MASK) >> CPM_CFCR_UFR_BIT) + 1); -+ return usbclk; -+} -+ -+static __inline__ unsigned int __cpm_get_i2sclk(void) -+{ -+ unsigned int i2sclk; -+ unsigned long cfcr = REG_CPM_CFCR; -+ i2sclk = __cpm_get_pllout() / -+ ((cfcr & CPM_CFCR_I2S) ? 2: 1); -+ return i2sclk; -+} -+ -+static __inline__ unsigned int __cpm_get_mscclk(void) -+{ -+ if (REG_CPM_CFCR & CPM_CFCR_MSC) -+ return 24000000; -+ else -+ return 16000000; -+} -+ -+#endif /* __ASM_JZ4730_CLOCK_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/dma.h linux-2.6.24.7/include/asm-mips/mach-jz4730/dma.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/dma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/dma.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,272 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/dma.h -+ * -+ * JZ4730 DMA definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_DMA_H__ -+#define __ASM_JZ4730_DMA_H__ -+ -+#include -+#include /* need byte IO */ -+#include /* And spinlocks */ -+#include -+#include -+ -+#define DMA_UNIT_32 32 -+#define DMA_UNIT_16 16 -+ -+ -+/* block-mode EOP: high DREQ: high DACK: low*/ -+#define DMA_BLOCK_CONF \ -+ DMAC_DCCSR_TM | \ -+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \ -+ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS -+ -+/* single-mode EOP: high DREQ: high DACK: low */ -+#define DMA_SINGLE_CONF \ -+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN | \ -+ DMAC_DCCSR_ERDM_HLEVEL | DMAC_DCCSR_EACKS -+ -+#define DMA_8bit_RX_CONF \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_8bit_TX_CONF \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \ -+ DMAC_DCCSR_DS_8b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_16bit_RX_CONF \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_16bit_TX_CONF \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_16 | \ -+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_32bit_RX_CONF \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_32bit_TX_CONF \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_32b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_16BYTE_RX_CONF \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_8 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_16BYTE_TX_CONF \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_8 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_TX_CMD \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_RX_CMD \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_32 | DMAC_DCCSR_DWDH_32 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_16BIT_TX_CMD \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ -+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_16BIT_RX_CMD \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ -+ DMAC_DCCSR_DS_16b | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_RX_CMD \ -+ DMAC_DCCSR_DAM | \ -+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD \ -+ DMAC_DCCSR_SAM | \ -+ DMAC_DCCSR_SWDH_16 | DMAC_DCCSR_DWDH_16 | \ -+ DMAC_DCCSR_DS_16B | DMAC_DCCSR_RDIL_IGN -+ -+/* DMA Device ID's follow */ -+enum { -+ DMA_ID_UART0_TX = 0, -+ DMA_ID_UART0_RX, -+ DMA_ID_UART1_TX, -+ DMA_ID_UART1_RX, -+ DMA_ID_UART2_TX, -+ DMA_ID_UART2_RX, -+ DMA_ID_UART3_TX, -+ DMA_ID_UART3_RX, -+ DMA_ID_SSI_TX, -+ DMA_ID_SSI_RX, -+ DMA_ID_MSC_TX, -+ DMA_ID_MSC_RX, -+ DMA_ID_AIC_TX, -+ DMA_ID_AIC_RX, -+ DMA_ID_BLOCK, /* DREQ */ -+ DMA_ID_SINGLE, /* DREQ */ -+ DMA_ID_PCMCIA0_TX, -+ DMA_ID_PCMCIA0_RX, -+ DMA_ID_PCMCIA1_TX, -+ DMA_ID_PCMCIA2_RX, -+ DMA_ID_AUTO, -+ DMA_ID_RAW_SET, -+ NUM_DMA_DEV -+}; -+ -+/* dummy DCCSR bit, i386 style DMA macros compitable */ -+#define DMA_MODE_READ 0 /* I/O to memory, no autoinit, -+ * increment, single mode */ -+#define DMA_MODE_WRITE 1 /* memory to I/O, no autoinit, -+ * increment, single mode */ -+#define DMA_MODE_CASCADE 2 /* pass thru DREQ->HRQ, -+ * DACK<-HLDA only */ -+#define DMA_AUTOINIT 3 -+#define DMA_MODE_MASK 3 -+ -+struct jz_dma_chan { -+ int dev_id; /* this channel is allocated if >=0, -+ * free otherwise */ -+ unsigned int io; -+ const char *dev_str; -+ int irq; -+ void *irq_dev; -+ unsigned int fifo_addr; -+ unsigned int mode; -+ unsigned int source; -+}; -+ -+extern struct jz_dma_chan jz_dma_table[]; -+ -+extern int jz_request_dma(int dev_id, -+ const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id); -+extern void jz_free_dma(unsigned int dmanr); -+ -+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data); -+extern void dump_jz_dma_channel(unsigned int dmanr); -+ -+extern void enable_dma(unsigned int dmanr); -+extern void disable_dma(unsigned int dmanr); -+extern void set_dma_addr(unsigned int dmanr, unsigned int a); -+extern void set_dma_count(unsigned int dmanr, unsigned int count); -+extern void set_dma_mode(unsigned int dmanr, unsigned int mode); -+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern int get_dma_residue(unsigned int dmanr); -+ -+extern spinlock_t dma_spin_lock; -+ -+static __inline__ unsigned long claim_dma_lock(void) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&dma_spin_lock, flags); -+ return flags; -+} -+ -+static __inline__ void release_dma_lock(unsigned long flags) -+{ -+ spin_unlock_irqrestore(&dma_spin_lock, flags); -+} -+ -+/* Clear the 'DMA Pointer Flip Flop'. -+ * Write 0 for LSB/MSB, 1 for MSB/LSB access. -+ */ -+#define clear_dma_ff(channel) -+ -+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) -+{ -+ if (dmanr > NUM_DMA -+ || jz_dma_table[dmanr].dev_id < 0) -+ return NULL; -+ return &jz_dma_table[dmanr]; -+} -+ -+static __inline__ int dma_halted(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 1; -+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; -+} -+ -+static __inline__ unsigned int get_dma_mode(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ return chan->mode; -+} -+ -+static __inline__ void clear_dma_done(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+} -+ -+static __inline__ void clear_dma_halt(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); -+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR); -+} -+static __inline__ void clear_dma_flag(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HTR | DMAC_DMACR_AER); -+} -+ -+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -+{ -+} -+ -+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ unsigned long dccsr; -+ if (!chan) -+ return 0; -+ -+ dccsr = REG_DMAC_DCCSR(chan->io); -+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TC | DMAC_DCCSR_AR); -+} -+ -+static __inline__ int get_dma_done_irq(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return -1; -+ -+ return chan->irq; -+} -+ -+#endif /* __ASM_JZ4730_DMA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/jz4730.h linux-2.6.24.7/include/asm-mips/mach-jz4730/jz4730.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/jz4730.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/jz4730.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/jz4730.h -+ * -+ * JZ4730 common definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_H__ -+#define __ASM_JZ4730_H__ -+ -+#include -+#include -+#include -+#include -+ -+/*------------------------------------------------------------------ -+ * Platform definitions -+ */ -+#ifdef CONFIG_JZ4730_PMP -+#include -+#endif -+ -+/* Add other platform definition here ... */ -+ -+ -+/*------------------------------------------------------------------ -+ * Follows are related to platform definitions -+ */ -+ -+#include -+#include -+ -+#endif /* __ASM_JZ4730_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/misc.h linux-2.6.24.7/include/asm-mips/mach-jz4730/misc.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/misc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/misc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,28 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/misc.h -+ * -+ * JZ4730 miscillaneous definitions. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_MISC_H__ -+#define __ASM_JZ4730_MISC_H__ -+ -+/* -+ * I2C routines -+ */ -+ -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern void i2c_setclk(unsigned int i2cclk); -+extern int i2c_read(unsigned char, unsigned char *, unsigned char, int); -+extern int i2c_write(unsigned char, unsigned char *, unsigned char, int); -+ -+#endif /* __ASM_JZ4730_MISC_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/ops.h linux-2.6.24.7/include/asm-mips/mach-jz4730/ops.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/ops.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/ops.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2541 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/ops.h -+ * -+ * JZ4730 module operations definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * 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 __ASM_JZ4730_OPS_H__ -+#define __ASM_JZ4730_OPS_H__ -+ -+/*************************************************************************** -+ * MSC -+ ***************************************************************************/ -+ -+#define __msc_start_op() \ -+ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) -+ -+#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) -+#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) -+#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) -+#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) -+#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) -+#define __msc_get_nob() ( REG_MSC_NOB ) -+#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) -+#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) -+#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) -+#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) -+ -+#define __msc_set_cmdat_bus_width1() \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_bus_width4() \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) -+#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) -+#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) -+#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) -+ -+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ -+#define __msc_set_cmdat_res_format(r) \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ -+ REG_MSC_CMDAT |= (r); \ -+} while(0) -+ -+#define __msc_clear_cmdat() \ -+ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ -+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ -+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) -+ -+#define __msc_get_imask() ( REG_MSC_IMASK ) -+#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) -+#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) -+#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) -+#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) -+#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) -+#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) -+ -+/* n=0,1,2,3,4,5,6,7 */ -+#define __msc_set_clkrt(n) \ -+do { \ -+ REG_MSC_CLKRT = n; \ -+} while(0) -+ -+#define __msc_get_ireg() ( REG_MSC_IREG ) -+#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) -+#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) -+#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) -+#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) -+ -+#define __msc_get_stat() ( REG_MSC_STAT ) -+#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) -+#define __msc_stat_crc_err() \ -+ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) -+#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) -+#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) -+#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) -+#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) -+#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) -+ -+#define __msc_rd_resfifo() ( REG_MSC_RES ) -+#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) -+#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) -+ -+#define __msc_reset() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_RESET; \ -+ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ -+} while (0) -+ -+#define __msc_start_clk() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ -+} while (0) -+ -+#define __msc_stop_clk() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ -+} while (0) -+ -+#define MMC_CLK 19169200 -+#define SD_CLK 24576000 -+ -+/* msc_clk should little than pclk and little than clk retrieve from card */ -+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ -+do { \ -+ unsigned int rate, pclk, i; \ -+ pclk = dev_clk; \ -+ rate = type?SD_CLK:MMC_CLK; \ -+ if (msc_clk && msc_clk < pclk) \ -+ pclk = msc_clk; \ -+ i = 0; \ -+ while (pclk < rate) \ -+ { \ -+ i ++; \ -+ rate >>= 1; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+/* divide rate to little than or equal to 400kHz */ -+#define __msc_calc_slow_clk_divisor(type, lv) \ -+do { \ -+ unsigned int rate, i; \ -+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ -+ i = 0; \ -+ while (rate > 0) \ -+ { \ -+ rate >>= 1; \ -+ i ++; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+/*************************************************************************** -+ * RTC -+ ***************************************************************************/ -+ -+#define __rtc_start() ( REG_RTC_RCR |= RTC_RCR_START ) -+#define __rtc_stop() ( REG_RTC_RCR &= ~RTC_RCR_START ) -+ -+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) -+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) -+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) -+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) -+ -+#define __rtc_enable_1hz_irq() ( REG_RTC_RCR |= RTC_RCR_HZIE ) -+#define __rtc_disable_1hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_HZIE ) -+ -+#define __rtc_is_alarm_flag() ( REG_RTC_RCR & RTC_RCR_AF ) -+#define __rtc_is_1hz_flag() ( REG_RTC_RCR & RTC_RCR_HZ ) -+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) -+#define __rtc_clear_1hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_HZ ) -+ -+#define __rtc_set_second(s) ( REG_RTC_RSR = (s) ) -+#define __rtc_get_second() REG_RTC_RSR -+#define __rtc_set_alarm(s) ( REG_RTC_RSAR = (s) ) -+#define __rtc_get_alarm() REG_RTC_RSAR -+ -+#define __rtc_adjust_1hz(f32k) \ -+ ( REG_RTC_RGR = (REG_RTC_RGR & ~(RTC_REG_DIV_MASK | RTC_RGR_ADJ_MASK)) | f32k | 0 ) -+#define __rtc_lock_1hz() ( REG_RTC_RGR |= RTC_RGR_LOCK ) -+ -+ -+/*************************************************************************** -+ * FIR -+ ***************************************************************************/ -+ -+/* enable/disable fir unit */ -+#define __fir_enable() ( REG_FIR_CR1 |= FIR_CR1_FIRUE ) -+#define __fir_disable() ( REG_FIR_CR1 &= ~FIR_CR1_FIRUE ) -+ -+/* enable/disable address comparison */ -+#define __fir_enable_ac() ( REG_FIR_CR1 |= FIR_CR1_ACE ) -+#define __fir_disable_ac() ( REG_FIR_CR1 &= ~FIR_CR1_ACE ) -+ -+/* select frame end mode as underrun or normal */ -+#define __fir_set_eous() ( REG_FIR_CR1 |= FIR_CR1_EOUS ) -+#define __fir_clear_eous() ( REG_FIR_CR1 &= ~FIR_CR1_EOUS ) -+ -+/* enable/disable transmitter idle interrupt */ -+#define __fir_enable_tii() ( REG_FIR_CR1 |= FIR_CR1_TIIE ) -+#define __fir_disable_tii() ( REG_FIR_CR1 &= ~FIR_CR1_TIIE ) -+ -+/* enable/disable transmit FIFO service request interrupt */ -+#define __fir_enable_tfi() ( REG_FIR_CR1 |= FIR_CR1_TFIE ) -+#define __fir_disable_tfi() ( REG_FIR_CR1 &= ~FIR_CR1_TFIE ) -+ -+/* enable/disable receive FIFO service request interrupt */ -+#define __fir_enable_rfi() ( REG_FIR_CR1 |= FIR_CR1_RFIE ) -+#define __fir_disable_rfi() ( REG_FIR_CR1 &= ~FIR_CR1_RFIE ) -+ -+/* enable/disable tx function */ -+#define __fir_tx_enable() ( REG_FIR_CR1 |= FIR_CR1_TXE ) -+#define __fir_tx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_TXE ) -+ -+/* enable/disable rx function */ -+#define __fir_rx_enable() ( REG_FIR_CR1 |= FIR_CR1_RXE ) -+#define __fir_rx_disable() ( REG_FIR_CR1 &= ~FIR_CR1_RXE ) -+ -+ -+/* enable/disable serial infrared interaction pulse (SIP) */ -+#define __fir_enable_sip() ( REG_FIR_CR2 |= FIR_CR2_SIPE ) -+#define __fir_disable_sip() ( REG_FIR_CR2 &= ~FIR_CR2_SIPE ) -+ -+/* un-inverted CRC value is sent out */ -+#define __fir_enable_bcrc() ( REG_FIR_CR2 |= FIR_CR2_BCRC ) -+ -+/* inverted CRC value is sent out */ -+#define __fir_disable_bcrc() ( REG_FIR_CR2 &= ~FIR_CR2_BCRC ) -+ -+/* enable/disable Transmit Frame Length Register */ -+#define __fir_enable_tflr() ( REG_FIR_CR2 |= FIR_CR2_TFLRS ) -+#define __fir_disable_tflr() ( REG_FIR_CR2 &= ~FIR_CR2_TFLRS ) -+ -+/* Preamble is transmitted in idle state */ -+#define __fir_set_iss() ( REG_FIR_CR2 |= FIR_CR2_ISS ) -+ -+/* Abort symbol is transmitted in idle state */ -+#define __fir_clear_iss() ( REG_FIR_CR2 &= ~FIR_CR2_ISS ) -+ -+/* enable/disable loopback mode */ -+#define __fir_enable_loopback() ( REG_FIR_CR2 |= FIR_CR2_LMS ) -+#define __fir_disable_loopback() ( REG_FIR_CR2 &= ~FIR_CR2_LMS ) -+ -+/* select transmit pin polarity */ -+#define __fir_tpp_negative() ( REG_FIR_CR2 |= FIR_CR2_TPPS ) -+#define __fir_tpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_TPPS ) -+ -+/* select receive pin polarity */ -+#define __fir_rpp_negative() ( REG_FIR_CR2 |= FIR_CR2_RPPS ) -+#define __fir_rpp_positive() ( REG_FIR_CR2 &= ~FIR_CR2_RPPS ) -+ -+/* n=16,32,64,128 */ -+#define __fir_set_txfifo_trigger(n) \ -+do { \ -+ REG_FIR_CR2 &= ~FIR_CR2_TTRG_MASK; \ -+ REG_FIR_CR2 |= FIR_CR2_TTRG_##n; \ -+} while (0) -+ -+/* n=16,32,64,128 */ -+#define __fir_set_rxfifo_trigger(n) \ -+do { \ -+ REG_FIR_CR2 &= ~FIR_CR2_RTRG_MASK; \ -+ REG_FIR_CR2 |= FIR_CR2_RTRG_##n; \ -+} while (0) -+ -+ -+/* FIR status checking */ -+ -+#define __fir_test_rfw() ( REG_FIR_SR & FIR_SR_RFW ) -+#define __fir_test_rfa() ( REG_FIR_SR & FIR_SR_RFA ) -+#define __fir_test_tfrtl() ( REG_FIR_SR & FIR_SR_TFRTL ) -+#define __fir_test_rfrtl() ( REG_FIR_SR & FIR_SR_RFRTL ) -+#define __fir_test_urun() ( REG_FIR_SR & FIR_SR_URUN ) -+#define __fir_test_rfte() ( REG_FIR_SR & FIR_SR_RFTE ) -+#define __fir_test_orun() ( REG_FIR_SR & FIR_SR_ORUN ) -+#define __fir_test_crce() ( REG_FIR_SR & FIR_SR_CRCE ) -+#define __fir_test_fend() ( REG_FIR_SR & FIR_SR_FEND ) -+#define __fir_test_tff() ( REG_FIR_SR & FIR_SR_TFF ) -+#define __fir_test_rfe() ( REG_FIR_SR & FIR_SR_RFE ) -+#define __fir_test_tidle() ( REG_FIR_SR & FIR_SR_TIDLE ) -+#define __fir_test_rb() ( REG_FIR_SR & FIR_SR_RB ) -+ -+#define __fir_clear_status() \ -+do { \ -+ REG_FIR_SR |= FIR_SR_RFW | FIR_SR_RFA | FIR_SR_URUN; \ -+} while (0) -+ -+#define __fir_clear_rfw() ( REG_FIR_SR |= FIR_SR_RFW ) -+#define __fir_clear_rfa() ( REG_FIR_SR |= FIR_SR_RFA ) -+#define __fir_clear_urun() ( REG_FIR_SR |= FIR_SR_URUN ) -+ -+#define __fir_set_tflr(len) \ -+do { \ -+ REG_FIR_TFLR = len; \ -+} while (0) -+ -+#define __fir_set_addr(a) ( REG_FIR_AR = (a) ) -+ -+#define __fir_write_data(data) ( REG_FIR_TDR = data ) -+#define __fir_read_data(data) ( data = REG_FIR_RDR ) -+ -+/*************************************************************************** -+ * SCC -+ ***************************************************************************/ -+ -+#define __scc_enable(base) ( REG_SCC_CR(base) |= SCC_CR_SCCE ) -+#define __scc_disable(base) ( REG_SCC_CR(base) &= ~SCC_CR_SCCE ) -+ -+#define __scc_set_tx_mode(base) ( REG_SCC_CR(base) |= SCC_CR_TRS ) -+#define __scc_set_rx_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_TRS ) -+ -+#define __scc_enable_t2r(base) ( REG_SCC_CR(base) |= SCC_CR_T2R ) -+#define __scc_disable_t2r(base) ( REG_SCC_CR(base) &= ~SCC_CR_T2R ) -+ -+#define __scc_clk_as_devclk(base) \ -+do { \ -+ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \ -+ REG_SCC_CR(base) |= SCC_CR_FDIV_1; \ -+} while (0) -+ -+#define __scc_clk_as_half_devclk(base) \ -+do { \ -+ REG_SCC_CR(base) &= ~SCC_CR_FDIV_MASK; \ -+ REG_SCC_CR(base) |= SCC_CR_FDIV_2; \ -+} while (0) -+ -+/* n=1,4,8,14 */ -+#define __scc_set_fifo_trigger(base, n) \ -+do { \ -+ REG_SCC_CR(base) &= ~SCC_CR_TRIG_MASK; \ -+ REG_SCC_CR(base) |= SCC_CR_TRIG_##n; \ -+} while (0) -+ -+#define __scc_set_protocol(base, p) \ -+do { \ -+ if (p) \ -+ REG_SCC_CR(base) |= SCC_CR_TP; \ -+ else \ -+ REG_SCC_CR(base) &= ~SCC_CR_TP; \ -+} while (0) -+ -+#define __scc_flush_fifo(base) ( REG_SCC_CR(base) |= SCC_CR_FLUSH ) -+ -+#define __scc_set_invert_mode(base) ( REG_SCC_CR(base) |= SCC_CR_CONV ) -+#define __scc_set_direct_mode(base) ( REG_SCC_CR(base) &= ~SCC_CR_CONV ) -+ -+#define SCC_ERR_INTRS \ -+ ( SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE ) -+#define SCC_ALL_INTRS \ -+ ( SCC_CR_TXIE | SCC_CR_RXIE | SCC_CR_TENDIE | SCC_CR_RTOIE | \ -+ SCC_CR_ECIE | SCC_CR_EPIE | SCC_CR_RETIE | SCC_CR_EOIE ) -+ -+#define __scc_enable_err_intrs(base) ( REG_SCC_CR(base) |= SCC_ERR_INTRS ) -+#define __scc_disable_err_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ERR_INTRS ) -+ -+#define SCC_ALL_ERRORS \ -+ ( SCC_SR_ORER | SCC_SR_RTO | SCC_SR_PER | SCC_SR_RETR_3 | SCC_SR_ECNTO) -+ -+#define __scc_clear_errors(base) ( REG_SCC_SR(base) &= ~SCC_ALL_ERRORS ) -+ -+#define __scc_enable_all_intrs(base) ( REG_SCC_CR(base) |= SCC_ALL_INTRS ) -+#define __scc_disable_all_intrs(base) ( REG_SCC_CR(base) &= ~SCC_ALL_INTRS ) -+ -+#define __scc_enable_tx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_TXIE | SCC_CR_TENDIE ) -+#define __scc_disable_tx_intr(base) ( REG_SCC_CR(base) &= ~(SCC_CR_TXIE | SCC_CR_TENDIE) ) -+ -+#define __scc_enable_rx_intr(base) ( REG_SCC_CR(base) |= SCC_CR_RXIE) -+#define __scc_disable_rx_intr(base) ( REG_SCC_CR(base) &= ~SCC_CR_RXIE) -+ -+#define __scc_set_tsend(base) ( REG_SCC_CR(base) |= SCC_CR_TSEND ) -+#define __scc_clear_tsend(base) ( REG_SCC_CR(base) &= ~SCC_CR_TSEND ) -+ -+#define __scc_set_clockstop(base) ( REG_SCC_CR(base) |= SCC_CR_CLKSTP ) -+#define __scc_clear_clockstop(base) ( REG_SCC_CR(base) &= ~SCC_CR_CLKSTP ) -+ -+#define __scc_clockstop_low(base) \ -+do { \ -+ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \ -+ REG_SCC_CR(base) |= SCC_CR_PX_STOP_LOW; \ -+} while (0) -+ -+#define __scc_clockstop_high(base) \ -+do { \ -+ REG_SCC_CR(base) &= ~SCC_CR_PX_MASK; \ -+ REG_SCC_CR(base) |= SCC_CR_PX_STOP_HIGH; \ -+} while (0) -+ -+ -+/* SCC status checking */ -+#define __scc_check_transfer_status(base) ( REG_SCC_SR(base) & SCC_SR_TRANS ) -+#define __scc_check_rx_overrun_error(base) ( REG_SCC_SR(base) & SCC_SR_ORER ) -+#define __scc_check_rx_timeout(base) ( REG_SCC_SR(base) & SCC_SR_RTO ) -+#define __scc_check_parity_error(base) ( REG_SCC_SR(base) & SCC_SR_PER ) -+#define __scc_check_txfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_TFTG ) -+#define __scc_check_rxfifo_trigger(base) ( REG_SCC_SR(base) & SCC_SR_RFTG ) -+#define __scc_check_tx_end(base) ( REG_SCC_SR(base) & SCC_SR_TEND ) -+#define __scc_check_retx_3(base) ( REG_SCC_SR(base) & SCC_SR_RETR_3 ) -+#define __scc_check_ecnt_overflow(base) ( REG_SCC_SR(base) & SCC_SR_ECNTO ) -+ -+ -+/*************************************************************************** -+ * WDT -+ ***************************************************************************/ -+ -+#define __wdt_set_count(count) ( REG_WDT_WTCNT = (count) ) -+#define __wdt_start() ( REG_WDT_WTCSR |= WDT_WTCSR_START ) -+#define __wdt_stop() ( REG_WDT_WTCSR &= ~WDT_WTCSR_START ) -+ -+ -+/*************************************************************************** -+ * OST -+ ***************************************************************************/ -+ -+#define __ost_enable_all() ( REG_OST_TER |= 0x07 ) -+#define __ost_disable_all() ( REG_OST_TER &= ~0x07 ) -+#define __ost_enable_channel(n) ( REG_OST_TER |= (1 << (n)) ) -+#define __ost_disable_channel(n) ( REG_OST_TER &= ~(1 << (n)) ) -+#define __ost_set_reload(n, val) ( REG_OST_TRDR(n) = (val) ) -+#define __ost_set_count(n, val) ( REG_OST_TCNT(n) = (val) ) -+#define __ost_get_count(n) ( REG_OST_TCNT(n) ) -+#define __ost_set_clock(n, cs) \ -+do { \ -+ REG_OST_TCSR(n) &= ~OST_TCSR_CKS_MASK; \ -+ REG_OST_TCSR(n) |= cs; \ -+} while (0) -+#define __ost_set_mode(n, val) ( REG_OST_TCSR(n) = (val) ) -+#define __ost_enable_interrupt(n) ( REG_OST_TCSR(n) |= OST_TCSR_UIE ) -+#define __ost_disable_interrupt(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UIE ) -+#define __ost_uf_detected(n) ( REG_OST_TCSR(n) & OST_TCSR_UF ) -+#define __ost_clear_uf(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_UF ) -+#define __ost_is_busy(n) ( REG_OST_TCSR(n) & OST_TCSR_BUSY ) -+#define __ost_clear_busy(n) ( REG_OST_TCSR(n) &= ~OST_TCSR_BUSY ) -+ -+ -+/*************************************************************************** -+ * UART -+ ***************************************************************************/ -+ -+#define __uart_enable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) -+#define __uart_disable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) -+ -+#define __uart_enable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) -+#define __uart_disable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) -+ -+#define __uart_enable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) -+#define __uart_disable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) -+ -+#define __uart_enable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) -+#define __uart_disable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) -+ -+#define __uart_set_8n1(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) -+ -+#define __uart_set_baud(n, devclk, baud) \ -+ do { \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ -+ } while (0) -+ -+#define __uart_parity_error(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) -+ -+#define __uart_clear_errors(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) -+ -+#define __uart_transmit_fifo_empty(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) -+ -+#define __uart_transmit_end(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) -+ -+#define __uart_transmit_char(n, ch) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) -+ -+#define __uart_receive_fifo_full(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_ready(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_char(n) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) -+ -+#define __uart_disable_irda() \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) -+#define __uart_enable_irda() \ -+ /* Tx high pulse as 0, Rx low pulse as 0 */ \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) -+ -+ -+/*************************************************************************** -+ * INTC -+ ***************************************************************************/ -+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) -+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) -+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) -+ -+/*************************************************************************** -+ * CIM -+ ***************************************************************************/ -+ -+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) -+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) -+ -+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) -+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) -+ -+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) -+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) -+ -+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) -+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) -+ -+#define __cim_sample_data_at_pclk_falling_edge() \ -+ ( REG_CIM_CFG |= CIM_CFG_PCP ) -+#define __cim_sample_data_at_pclk_rising_edge() \ -+ ( REG_CIM_CFG &= ~CIM_CFG_PCP ) -+ -+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) -+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) -+ -+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) -+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) -+ -+/* n=0-7 */ -+#define __cim_set_data_packing_mode(n) \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ -+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ -+} while (0) -+ -+#define __cim_enable_ccir656_progressive_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ -+} while (0) -+ -+#define __cim_enable_ccir656_interlace_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ -+} while (0) -+ -+#define __cim_enable_gated_clock_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ -+} while (0) -+ -+#define __cim_enable_nongated_clock_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ -+} while (0) -+ -+/* sclk:system bus clock -+ * mclk: CIM master clock -+ */ -+#define __cim_set_master_clk(sclk, mclk) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ -+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ -+} while (0) -+ -+#define __cim_enable_sof_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) -+#define __cim_disable_sof_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) -+ -+#define __cim_enable_eof_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) -+#define __cim_disable_eof_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) -+ -+#define __cim_enable_stop_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) -+#define __cim_disable_stop_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) -+ -+#define __cim_enable_trig_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) -+#define __cim_disable_trig_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) -+ -+#define __cim_enable_rxfifo_overflow_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) -+#define __cim_disable_rxfifo_overflow_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) -+ -+/* n=1-16 */ -+#define __cim_set_frame_rate(n) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ -+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ -+} while (0) -+ -+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) -+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) -+ -+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) -+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) -+ -+/* n=4,8,12,16,20,24,28,32 */ -+#define __cim_set_rxfifo_trigger(n) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ -+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ -+} while (0) -+ -+#define __cim_clear_state() ( REG_CIM_STATE = 0 ) -+ -+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) -+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) -+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) -+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) -+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) -+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) -+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) -+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) -+ -+#define __cim_get_iid() ( REG_CIM_IID ) -+#define __cim_get_image_data() ( REG_CIM_RXFIFO ) -+#define __cim_get_dam_cmd() ( REG_CIM_CMD ) -+ -+#define __cim_set_da(a) ( REG_CIM_DA = (a) ) -+ -+/*************************************************************************** -+ * PWM -+ ***************************************************************************/ -+ -+/* n is the pwm channel (0,1,..) */ -+#define __pwm_enable_module(n) ( REG_PWM_CTR(n) |= PWM_CTR_EN ) -+#define __pwm_disable_module(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_EN ) -+#define __pwm_graceful_shutdown_mode(n) ( REG_PWM_CTR(n) &= ~PWM_CTR_SD ) -+#define __pwm_abrupt_shutdown_mode(n) ( REG_PWM_CTR(n) |= PWM_CTR_SD ) -+#define __pwm_set_full_duty(n) ( REG_PWM_DUT(n) |= PWM_DUT_FDUTY ) -+ -+#define __pwm_set_prescale(n, p) \ -+ ( REG_PWM_CTR(n) = ((REG_PWM_CTR(n) & ~PWM_CTR_PRESCALE_MASK) | (p) ) ) -+#define __pwm_set_period(n, p) \ -+ ( REG_PWM_PER(n) = ( (REG_PWM_PER(n) & ~PWM_PER_PERIOD_MASK) | (p) ) ) -+#define __pwm_set_duty(n, d) \ -+ ( REG_PWM_DUT(n) = ( (REG_PWM_DUT(n) & ~(PWM_DUT_FDUTY | PWM_DUT_DUTY_MASK)) | (d) ) ) -+ -+/*************************************************************************** -+ * EMC -+ ***************************************************************************/ -+ -+#define __emc_enable_split() ( REG_EMC_BCR = EMC_BCR_BRE ) -+#define __emc_disable_split() ( REG_EMC_BCR = 0 ) -+ -+#define __emc_smem_bus_width(n) /* 8, 16 or 32*/ \ -+ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BW_MASK) | \ -+ EMC_SMCR_BW_##n##BIT ) -+#define __emc_smem_byte_control() \ -+ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_BCM ) -+#define __emc_normal_smem() \ -+ ( REG_EMC_SMCR = (REG_EMC_SMCR & ~EMC_SMCR_SMT ) -+#define __emc_burst_smem() \ -+ ( REG_EMC_SMCR = (REG_EMC_SMCR | EMC_SMCR_SMT ) -+#define __emc_smem_burstlen(n) /* 4, 8, 16 or 32 */ \ -+ ( REG_EMC_SMCR = (REG_EMC_SMCR & EMC_SMCR_BL_MASK) | (EMC_SMCR_BL_##n ) -+ -+/*************************************************************************** -+ * GPIO -+ ***************************************************************************/ -+ -+/* p is the port number (0,1,2,3) -+ * o is the pin offset (0-31) inside the port -+ * n is the absolute number of a pin (0-124), regardless of the port -+ * m is the interrupt manner (low/high/falling/rising) -+ */ -+ -+#define __gpio_port_data(p) ( REG_GPIO_GPDR(p) ) -+ -+#define __gpio_port_as_output(p, o) \ -+do { \ -+ unsigned int tmp; \ -+ REG_GPIO_GPIER(p) &= ~(1 << (o)); \ -+ REG_GPIO_GPDIR(p) |= (1 << (o)); \ -+ if (o < 16) { \ -+ tmp = REG_GPIO_GPALR(p); \ -+ tmp &= ~(3 << ((o) << 1)); \ -+ REG_GPIO_GPALR(p) = tmp; \ -+ } else { \ -+ tmp = REG_GPIO_GPAUR(p); \ -+ tmp &= ~(3 << (((o) - 16)<< 1)); \ -+ REG_GPIO_GPAUR(p) = tmp; \ -+ } \ -+} while (0) -+ -+#define __gpio_port_as_input(p, o) \ -+do { \ -+ unsigned int tmp; \ -+ REG_GPIO_GPIER(p) &= ~(1 << (o)); \ -+ REG_GPIO_GPDIR(p) &= ~(1 << (o)); \ -+ if (o < 16) { \ -+ tmp = REG_GPIO_GPALR(p); \ -+ tmp &= ~(3 << ((o) << 1)); \ -+ REG_GPIO_GPALR(p) = tmp; \ -+ } else { \ -+ tmp = REG_GPIO_GPAUR(p); \ -+ tmp &= ~(3 << (((o) - 16)<< 1)); \ -+ REG_GPIO_GPAUR(p) = tmp; \ -+ } \ -+} while (0) -+ -+#define __gpio_as_output(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_output(p, o); \ -+} while (0) -+ -+#define __gpio_as_input(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_input(p, o); \ -+} while (0) -+ -+#define __gpio_set_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_data(p) |= (1 << o); \ -+} while (0) -+ -+#define __gpio_clear_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_data(p) &= ~(1 << o); \ -+} while (0) -+ -+static __inline__ unsigned int __gpio_get_pin(unsigned int n) -+{ -+ unsigned int p, o; -+ p = (n) / 32; -+ o = (n) % 32; -+ if (__gpio_port_data(p) & (1 << o)) -+ return 1; -+ else -+ return 0; -+} -+ -+#define __gpio_set_irq_detect_manner(p, o, m) \ -+do { \ -+ unsigned int tmp; \ -+ if (o < 16) { \ -+ tmp = REG_GPIO_GPIDLR(p); \ -+ tmp &= ~(3 << ((o) << 1)); \ -+ tmp |= ((m) << ((o) << 1)); \ -+ REG_GPIO_GPIDLR(p) = tmp; \ -+ } else { \ -+ tmp = REG_GPIO_GPIDUR(p); \ -+ tmp &= ~(3 << (((o)-16) << 1)); \ -+ tmp |= ((m) << (((o)-16) << 1)); \ -+ REG_GPIO_GPIDUR(p) = tmp; \ -+ } \ -+} while (0) -+ -+#define __gpio_port_as_irq(p, o, m) \ -+do { \ -+ __gpio_port_as_input(p, o); \ -+ __gpio_set_irq_detect_manner(p, o, m); \ -+} while (0) -+ -+#define __gpio_as_irq(n, m) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_irq(p, o, m); \ -+} while (0) -+ -+ -+#define __gpio_as_irq_high_level(n) __gpio_as_irq(n, GPIO_IRQ_HILEVEL) -+#define __gpio_as_irq_low_level(n) __gpio_as_irq(n, GPIO_IRQ_LOLEVEL) -+#define __gpio_as_irq_fall_edge(n) __gpio_as_irq(n, GPIO_IRQ_FALLEDG) -+#define __gpio_as_irq_rise_edge(n) __gpio_as_irq(n, GPIO_IRQ_RAISEDG) -+ -+ -+#define __gpio_mask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_GPIER(p) &= ~(1 << o); \ -+} while (0) -+ -+#define __gpio_unmask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_GPIER(p) |= (1 << o); \ -+} while (0) -+ -+#define __gpio_ack_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_GPFR(p) |= (1 << o); \ -+} while (0) -+ -+ -+static __inline__ unsigned int __gpio_get_irq(void) -+{ -+ unsigned int tmp, i; -+ -+ tmp = REG_GPIO_GPFR(3); -+ for (i=0; i<32; i++) -+ if (tmp & (1 << i)) -+ return 0x60 + i; -+ tmp = REG_GPIO_GPFR(2); -+ for (i=0; i<32; i++) -+ if (tmp & (1 << i)) -+ return 0x40 + i; -+ tmp = REG_GPIO_GPFR(1); -+ for (i=0; i<32; i++) -+ if (tmp & (1 << i)) -+ return 0x20 + i; -+ tmp = REG_GPIO_GPFR(0); -+ for (i=0; i<32; i++) -+ if (tmp & (1 << i)) -+ return i; -+ return 0; -+} -+ -+#define __gpio_group_irq(n) \ -+({ \ -+ register int tmp, i; \ -+ tmp = REG_GPIO_GPFR((n)); \ -+ for (i=31;i>=0;i--) \ -+ if (tmp & (1 << i)) \ -+ break; \ -+ i; \ -+}) -+ -+#define __gpio_enable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_GPPUR(p) |= (1 << o); \ -+} while (0) -+ -+#define __gpio_disable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_GPPUR(p) &= ~(1 << o); \ -+} while (0) -+ -+ -+/* Init the alternate function pins */ -+ -+ -+#define __gpio_as_ssi() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xFC00FFFF; \ -+ REG_GPIO_GPALR(2) |= 0x01550000; \ -+} while (0) -+ -+#define __gpio_as_uart3() \ -+do { \ -+ REG_GPIO_GPAUR(0) &= 0xFFFF0000; \ -+ REG_GPIO_GPAUR(0) |= 0x00005555; \ -+} while (0) -+ -+#define __gpio_as_uart2() \ -+do { \ -+ REG_GPIO_GPALR(3) &= 0x3FFFFFFF; \ -+ REG_GPIO_GPALR(3) |= 0x40000000; \ -+ REG_GPIO_GPAUR(3) &= 0xF3FFFFFF; \ -+ REG_GPIO_GPAUR(3) |= 0x04000000; \ -+} while (0) -+ -+#define __gpio_as_uart1() \ -+do { \ -+ REG_GPIO_GPAUR(0) &= 0xFFF0FFFF; \ -+ REG_GPIO_GPAUR(0) |= 0x00050000; \ -+} while (0) -+ -+#define __gpio_as_uart0() \ -+do { \ -+ REG_GPIO_GPAUR(3) &= 0x0FFFFFFF; \ -+ REG_GPIO_GPAUR(3) |= 0x50000000; \ -+} while (0) -+ -+ -+#define __gpio_as_scc0() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xFFFFFFCC; \ -+ REG_GPIO_GPALR(2) |= 0x00000011; \ -+} while (0) -+ -+#define __gpio_as_scc1() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xFFFFFF33; \ -+ REG_GPIO_GPALR(2) |= 0x00000044; \ -+} while (0) -+ -+#define __gpio_as_scc() \ -+do { \ -+ __gpio_as_scc0(); \ -+ __gpio_as_scc1(); \ -+} while (0) -+ -+#define __gpio_as_dma() \ -+do { \ -+ REG_GPIO_GPALR(0) &= 0x00FFFFFF; \ -+ REG_GPIO_GPALR(0) |= 0x55000000; \ -+ REG_GPIO_GPAUR(0) &= 0xFF0FFFFF; \ -+ REG_GPIO_GPAUR(0) |= 0x00500000; \ -+} while (0) -+ -+#define __gpio_as_msc() \ -+do { \ -+ REG_GPIO_GPALR(1) &= 0xFFFF000F; \ -+ REG_GPIO_GPALR(1) |= 0x00005550; \ -+} while (0) -+ -+#define __gpio_as_pcmcia() \ -+do { \ -+ REG_GPIO_GPAUR(2) &= 0xF000FFFF; \ -+ REG_GPIO_GPAUR(2) |= 0x05550000; \ -+} while (0) -+ -+#define __gpio_as_emc(csmask) \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0x3FFFFFFF; \ -+ REG_GPIO_GPALR(2) |= 0x40000000; \ -+ REG_GPIO_GPAUR(2) &= 0xFFFF0000; \ -+ REG_GPIO_GPAUR(2) |= 0x00005555; \ -+} while (0) -+ -+#define __gpio_as_lcd_slave() \ -+do { \ -+ REG_GPIO_GPALR(1) &= 0x0000FFFF; \ -+ REG_GPIO_GPALR(1) |= 0x55550000; \ -+ REG_GPIO_GPAUR(1) &= 0x00000000; \ -+ REG_GPIO_GPAUR(1) |= 0x55555555; \ -+} while (0) -+ -+#define __gpio_as_lcd_master() \ -+do { \ -+ REG_GPIO_GPALR(1) &= 0x0000FFFF; \ -+ REG_GPIO_GPALR(1) |= 0x55550000; \ -+ REG_GPIO_GPAUR(1) &= 0x00000000; \ -+ REG_GPIO_GPAUR(1) |= 0x556A5555; \ -+} while (0) -+ -+#define __gpio_as_usb() \ -+do { \ -+ REG_GPIO_GPAUR(0) &= 0x00FFFFFF; \ -+ REG_GPIO_GPAUR(0) |= 0x55000000; \ -+} while (0) -+ -+#define __gpio_as_ac97() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xC3FF03FF; \ -+ REG_GPIO_GPALR(2) |= 0x24005400; \ -+} while (0) -+ -+#define __gpio_as_i2s_slave() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \ -+ REG_GPIO_GPALR(2) |= 0x14005100; \ -+} while (0) -+ -+#define __gpio_as_i2s_master() \ -+do { \ -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; \ -+ REG_GPIO_GPALR(2) |= 0x28005100; \ -+} while (0) -+ -+#define __gpio_as_eth() \ -+do { \ -+ REG_GPIO_GPAUR(3) &= 0xFC000000; \ -+ REG_GPIO_GPAUR(3) |= 0x01555555; \ -+} while (0) -+ -+#define __gpio_as_pwm() \ -+do { \ -+ REG_GPIO_GPAUR(2) &= 0x0FFFFFFF; \ -+ REG_GPIO_GPAUR(2) |= 0x50000000; \ -+} while (0) -+ -+#define __gpio_as_ps2() \ -+do { \ -+ REG_GPIO_GPALR(1) &= 0xFFFFFFF0; \ -+ REG_GPIO_GPALR(1) |= 0x00000005; \ -+} while (0) -+ -+#define __gpio_as_uprt() \ -+do { \ -+ REG_GPIO_GPALR(1) &= 0x0000000F; \ -+ REG_GPIO_GPALR(1) |= 0x55555550; \ -+ REG_GPIO_GPALR(3) &= 0xC0000000; \ -+ REG_GPIO_GPALR(3) |= 0x15555555; \ -+} while (0) -+ -+#define __gpio_as_cim() \ -+do { \ -+ REG_GPIO_GPALR(0) &= 0xFF000000; \ -+ REG_GPIO_GPALR(0) |= 0x00555555; \ -+} while (0) -+ -+/*************************************************************************** -+ * HARB -+ ***************************************************************************/ -+ -+#define __harb_usb0_udc() \ -+do { \ -+ REG_HARB_HAPOR &= ~HARB_HAPOR_UCHSEL; \ -+} while (0) -+ -+#define __harb_usb0_uhc() \ -+do { \ -+ REG_HARB_HAPOR |= HARB_HAPOR_UCHSEL; \ -+} while (0) -+ -+#define __harb_set_priority(n) \ -+do { \ -+ REG_HARB_HAPOR = ((REG_HARB_HAPOR & ~HARB_HAPOR_PRIO_MASK) | n); \ -+} while (0) -+ -+/*************************************************************************** -+ * I2C -+ ***************************************************************************/ -+ -+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) -+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) -+ -+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) -+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) -+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) -+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) -+ -+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) -+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) -+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) -+ -+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) -+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) -+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) -+ -+#define __i2c_set_clk(dev_clk, i2c_clk) \ -+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) -+ -+#define __i2c_read() ( REG_I2C_DR ) -+#define __i2c_write(val) ( REG_I2C_DR = (val) ) -+ -+/*************************************************************************** -+ * UDC -+ ***************************************************************************/ -+ -+#define __udc_set_16bit_phy() ( REG_UDC_DevCFGR |= UDC_DevCFGR_PI ) -+#define __udc_set_8bit_phy() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_PI ) -+ -+#define __udc_enable_sync_frame() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SS ) -+#define __udc_disable_sync_frame() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SS ) -+ -+#define __udc_self_powered() ( REG_UDC_DevCFGR |= UDC_DevCFGR_SP ) -+#define __udc_bus_powered() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_SP ) -+ -+#define __udc_enable_remote_wakeup() ( REG_UDC_DevCFGR |= UDC_DevCFGR_RW ) -+#define __udc_disable_remote_wakeup() ( REG_UDC_DevCFGR &= ~UDC_DevCFGR_RW ) -+ -+#define __udc_set_speed_high() \ -+do { \ -+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ -+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_HS; \ -+} while (0) -+ -+#define __udc_set_speed_full() \ -+do { \ -+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ -+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_FS; \ -+} while (0) -+ -+#define __udc_set_speed_low() \ -+do { \ -+ REG_UDC_DevCFGR &= ~UDC_DevCFGR_SPD_MASK; \ -+ REG_UDC_DevCFGR |= UDC_DevCFGR_SPD_LS; \ -+} while (0) -+ -+ -+#define __udc_set_dma_mode() ( REG_UDC_DevCR |= UDC_DevCR_DM ) -+#define __udc_set_slave_mode() ( REG_UDC_DevCR &= ~UDC_DevCR_DM ) -+#define __udc_set_big_endian() ( REG_UDC_DevCR |= UDC_DevCR_BE ) -+#define __udc_set_little_endian() ( REG_UDC_DevCR &= ~UDC_DevCR_BE ) -+#define __udc_generate_resume() ( REG_UDC_DevCR |= UDC_DevCR_RES ) -+#define __udc_clear_resume() ( REG_UDC_DevCR &= ~UDC_DevCR_RES ) -+ -+ -+#define __udc_get_enumarated_speed() ( REG_UDC_DevSR & UDC_DevSR_ENUMSPD_MASK ) -+#define __udc_suspend_detected() ( REG_UDC_DevSR & UDC_DevSR_SUSP ) -+#define __udc_get_alternate_setting() ( (REG_UDC_DevSR & UDC_DevSR_ALT_MASK) >> UDC_DevSR_ALT_BIT ) -+#define __udc_get_interface_number() ( (REG_UDC_DevSR & UDC_DevSR_INTF_MASK) >> UDC_DevSR_INTF_BIT ) -+#define __udc_get_config_number() ( (REG_UDC_DevSR & UDC_DevSR_CFG_MASK) >> UDC_DevSR_CFG_BIT ) -+ -+ -+#define __udc_sof_detected(r) ( (r) & UDC_DevIntR_SOF ) -+#define __udc_usb_suspend_detected(r) ( (r) & UDC_DevIntR_US ) -+#define __udc_usb_reset_detected(r) ( (r) & UDC_DevIntR_UR ) -+#define __udc_set_interface_detected(r) ( (r) & UDC_DevIntR_SI ) -+#define __udc_set_config_detected(r) ( (r) & UDC_DevIntR_SC ) -+ -+#define __udc_clear_sof() ( REG_UDC_DevIntR |= UDC_DevIntR_SOF ) -+#define __udc_clear_usb_suspend() ( REG_UDC_DevIntR |= UDC_DevIntR_US ) -+#define __udc_clear_usb_reset() ( REG_UDC_DevIntR |= UDC_DevIntR_UR ) -+#define __udc_clear_set_interface() ( REG_UDC_DevIntR |= UDC_DevIntR_SI ) -+#define __udc_clear_set_config() ( REG_UDC_DevIntR |= UDC_DevIntR_SC ) -+ -+#define __udc_mask_sof() ( REG_UDC_DevIntMR |= UDC_DevIntR_SOF ) -+#define __udc_mask_usb_suspend() ( REG_UDC_DevIntMR |= UDC_DevIntR_US ) -+#define __udc_mask_usb_reset() ( REG_UDC_DevIntMR |= UDC_DevIntR_UR ) -+#define __udc_mask_set_interface() ( REG_UDC_DevIntMR |= UDC_DevIntR_SI ) -+#define __udc_mask_set_config() ( REG_UDC_DevIntMR |= UDC_DevIntR_SC ) -+#define __udc_mask_all_dev_intrs() \ -+ ( REG_UDC_DevIntMR = UDC_DevIntR_SOF | UDC_DevIntR_US | \ -+ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC ) -+ -+#define __udc_unmask_sof() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SOF ) -+#define __udc_unmask_usb_suspend() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_US ) -+#define __udc_unmask_usb_reset() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_UR ) -+#define __udc_unmask_set_interface() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SI ) -+#define __udc_unmask_set_config() ( REG_UDC_DevIntMR &= ~UDC_DevIntR_SC ) -+#if 0 -+#define __udc_unmask_all_dev_intrs() \ -+ ( REG_UDC_DevIntMR = ~(UDC_DevIntR_SOF | UDC_DevIntR_US | \ -+ UDC_DevIntR_UR | UDC_DevIntR_SI | UDC_DevIntR_SC) ) -+#else -+#define __udc_unmask_all_dev_intrs() \ -+ ( REG_UDC_DevIntMR = 0x00000000 ) -+#endif -+ -+ -+#define __udc_ep0out_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 0)) & 0x1 ) -+#define __udc_ep5out_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 5)) & 0x1 ) -+#define __udc_ep6out_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 6)) & 0x1 ) -+#define __udc_ep7out_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_OUTEP_MASK) >> (UDC_EPIntR_OUTEP_BIT + 7)) & 0x1 ) -+ -+#define __udc_ep0in_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 0)) & 0x1 ) -+#define __udc_ep1in_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 1)) & 0x1 ) -+#define __udc_ep2in_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 2)) & 0x1 ) -+#define __udc_ep3in_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 3)) & 0x1 ) -+#define __udc_ep4in_irq_detected(epintr) \ -+ ( (((epintr) & UDC_EPIntR_INEP_MASK) >> (UDC_EPIntR_INEP_BIT + 4)) & 0x1 ) -+ -+ -+#define __udc_mask_ep0out_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 0)) ) -+#define __udc_mask_ep5out_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 5)) ) -+#define __udc_mask_ep6out_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 6)) ) -+#define __udc_mask_ep7out_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_OUTEP_BIT + 7)) ) -+ -+#define __udc_unmask_ep0out_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 0)) ) -+#define __udc_unmask_ep5out_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 5)) ) -+#define __udc_unmask_ep6out_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 6)) ) -+#define __udc_unmask_ep7out_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_OUTEP_BIT + 7)) ) -+ -+#define __udc_mask_ep0in_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 0)) ) -+#define __udc_mask_ep1in_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 1)) ) -+#define __udc_mask_ep2in_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 2)) ) -+#define __udc_mask_ep3in_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 3)) ) -+#define __udc_mask_ep4in_irq() \ -+ ( REG_UDC_EPIntMR |= (1 << (UDC_EPIntMR_INEP_BIT + 4)) ) -+ -+#define __udc_unmask_ep0in_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 0)) ) -+#define __udc_unmask_ep1in_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 1)) ) -+#define __udc_unmask_ep2in_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 2)) ) -+#define __udc_unmask_ep3in_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 3)) ) -+#define __udc_unmask_ep4in_irq() \ -+ ( REG_UDC_EPIntMR &= ~(1 << (UDC_EPIntMR_INEP_BIT + 4)) ) -+ -+#define __udc_mask_all_ep_intrs() \ -+ ( REG_UDC_EPIntMR = 0xffffffff ) -+#define __udc_unmask_all_ep_intrs() \ -+ ( REG_UDC_EPIntMR = 0x00000000 ) -+ -+ -+/* ep0 only CTRL, ep1 only INTR, ep2/3/5/6 only BULK, ep4/7 only ISO */ -+#define __udc_config_endpoint_type() \ -+do { \ -+ REG_UDC_EP0InCR = (REG_UDC_EP0InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \ -+ REG_UDC_EP0OutCR = (REG_UDC_EP0OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_CTRL; \ -+ REG_UDC_EP1InCR = (REG_UDC_EP1InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_INTR; \ -+ REG_UDC_EP2InCR = (REG_UDC_EP2InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ -+ REG_UDC_EP3InCR = (REG_UDC_EP3InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ -+ REG_UDC_EP4InCR = (REG_UDC_EP4InCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \ -+ REG_UDC_EP5OutCR = (REG_UDC_EP5OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ -+ REG_UDC_EP6OutCR = (REG_UDC_EP6OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_BULK; \ -+ REG_UDC_EP7OutCR = (REG_UDC_EP7OutCR & ~UDC_EPCR_ET_MASK) | UDC_EPCR_ET_ISO; \ -+} while (0) -+ -+#define __udc_enable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR |= UDC_EPCR_SN ) -+#define __udc_enable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR |= UDC_EPCR_SN ) -+#define __udc_enable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR |= UDC_EPCR_SN ) -+#define __udc_enable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR |= UDC_EPCR_SN ) -+ -+#define __udc_disable_ep0out_snoop_mode() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_SN ) -+#define __udc_disable_ep5out_snoop_mode() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_SN ) -+#define __udc_disable_ep6out_snoop_mode() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_SN ) -+#define __udc_disable_ep7out_snoop_mode() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_SN ) -+ -+#define __udc_flush_ep0in_fifo() ( REG_UDC_EP0InCR |= UDC_EPCR_F ) -+#define __udc_flush_ep1in_fifo() ( REG_UDC_EP1InCR |= UDC_EPCR_F ) -+#define __udc_flush_ep2in_fifo() ( REG_UDC_EP2InCR |= UDC_EPCR_F ) -+#define __udc_flush_ep3in_fifo() ( REG_UDC_EP3InCR |= UDC_EPCR_F ) -+#define __udc_flush_ep4in_fifo() ( REG_UDC_EP4InCR |= UDC_EPCR_F ) -+ -+#define __udc_unflush_ep0in_fifo() ( REG_UDC_EP0InCR &= ~UDC_EPCR_F ) -+#define __udc_unflush_ep1in_fifo() ( REG_UDC_EP1InCR &= ~UDC_EPCR_F ) -+#define __udc_unflush_ep2in_fifo() ( REG_UDC_EP2InCR &= ~UDC_EPCR_F ) -+#define __udc_unflush_ep3in_fifo() ( REG_UDC_EP3InCR &= ~UDC_EPCR_F ) -+#define __udc_unflush_ep4in_fifo() ( REG_UDC_EP4InCR &= ~UDC_EPCR_F ) -+ -+#define __udc_enable_ep0in_stall() ( REG_UDC_EP0InCR |= UDC_EPCR_S ) -+#define __udc_enable_ep0out_stall() ( REG_UDC_EP0OutCR |= UDC_EPCR_S ) -+#define __udc_enable_ep1in_stall() ( REG_UDC_EP1InCR |= UDC_EPCR_S ) -+#define __udc_enable_ep2in_stall() ( REG_UDC_EP2InCR |= UDC_EPCR_S ) -+#define __udc_enable_ep3in_stall() ( REG_UDC_EP3InCR |= UDC_EPCR_S ) -+#define __udc_enable_ep4in_stall() ( REG_UDC_EP4InCR |= UDC_EPCR_S ) -+#define __udc_enable_ep5out_stall() ( REG_UDC_EP5OutCR |= UDC_EPCR_S ) -+#define __udc_enable_ep6out_stall() ( REG_UDC_EP6OutCR |= UDC_EPCR_S ) -+#define __udc_enable_ep7out_stall() ( REG_UDC_EP7OutCR |= UDC_EPCR_S ) -+ -+#define __udc_disable_ep0in_stall() ( REG_UDC_EP0InCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep0out_stall() ( REG_UDC_EP0OutCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep1in_stall() ( REG_UDC_EP1InCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep2in_stall() ( REG_UDC_EP2InCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep3in_stall() ( REG_UDC_EP3InCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep4in_stall() ( REG_UDC_EP4InCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep5out_stall() ( REG_UDC_EP5OutCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep6out_stall() ( REG_UDC_EP6OutCR &= ~UDC_EPCR_S ) -+#define __udc_disable_ep7out_stall() ( REG_UDC_EP7OutCR &= ~UDC_EPCR_S ) -+ -+ -+#define __udc_ep0out_packet_size() \ -+ ( (REG_UDC_EP0OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) -+#define __udc_ep5out_packet_size() \ -+ ( (REG_UDC_EP5OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) -+#define __udc_ep6out_packet_size() \ -+ ( (REG_UDC_EP6OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) -+#define __udc_ep7out_packet_size() \ -+ ( (REG_UDC_EP7OutSR & UDC_EPSR_RXPKTSIZE_MASK) >> UDC_EPSR_RXPKTSIZE_BIT ) -+ -+#define __udc_ep0in_received_intoken() ( (REG_UDC_EP0InSR & UDC_EPSR_IN) ) -+#define __udc_ep1in_received_intoken() ( (REG_UDC_EP1InSR & UDC_EPSR_IN) ) -+#define __udc_ep2in_received_intoken() ( (REG_UDC_EP2InSR & UDC_EPSR_IN) ) -+#define __udc_ep3in_received_intoken() ( (REG_UDC_EP3InSR & UDC_EPSR_IN) ) -+#define __udc_ep4in_received_intoken() ( (REG_UDC_EP4InSR & UDC_EPSR_IN) ) -+ -+#define __udc_ep0out_received_none() \ -+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) -+#define __udc_ep0out_received_data() \ -+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) -+#define __udc_ep0out_received_setup() \ -+ ( (REG_UDC_EP0OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) -+ -+#define __udc_ep5out_received_none() \ -+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) -+#define __udc_ep5out_received_data() \ -+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) -+#define __udc_ep5out_received_setup() \ -+ ( (REG_UDC_EP5OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) -+ -+#define __udc_ep6out_received_none() \ -+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) -+#define __udc_ep6out_received_data() \ -+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) -+#define __udc_ep6out_received_setup() \ -+ ( (REG_UDC_EP6OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) -+ -+#define __udc_ep7out_received_none() \ -+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_NONE ) -+#define __udc_ep7out_received_data() \ -+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVDATA ) -+#define __udc_ep7out_received_setup() \ -+ ( (REG_UDC_EP7OutSR & UDC_EPSR_OUT_MASK) == UDC_EPSR_OUT_RCVSETUP ) -+ -+/* ep7out ISO only */ -+#define __udc_ep7out_get_pid() \ -+ ( (REG_UDC_EP7OutSR & UDC_EPSR_PID_MASK) >> UDC_EPSR_PID_BIT ) -+ -+ -+#define __udc_ep0in_set_buffer_size(n) ( REG_UDC_EP0InBSR = (n) ) -+#define __udc_ep1in_set_buffer_size(n) ( REG_UDC_EP1InBSR = (n) ) -+#define __udc_ep2in_set_buffer_size(n) ( REG_UDC_EP2InBSR = (n) ) -+#define __udc_ep3in_set_buffer_size(n) ( REG_UDC_EP3InBSR = (n) ) -+#define __udc_ep4in_set_buffer_size(n) ( REG_UDC_EP4InBSR = (n) ) -+ -+#define __udc_ep0out_get_frame_number(n) ( UDC_EP0OutPFNR ) -+#define __udc_ep5out_get_frame_number(n) ( UDC_EP5OutPFNR ) -+#define __udc_ep6out_get_frame_number(n) ( UDC_EP6OutPFNR ) -+#define __udc_ep7out_get_frame_number(n) ( UDC_EP7OutPFNR ) -+ -+ -+#define __udc_ep0in_set_max_packet_size(n) ( REG_UDC_EP0InMPSR = (n) ) -+#define __udc_ep0out_set_max_packet_size(n) ( REG_UDC_EP0OutMPSR = (n) ) -+#define __udc_ep1in_set_max_packet_size(n) ( REG_UDC_EP1InMPSR = (n) ) -+#define __udc_ep2in_set_max_packet_size(n) ( REG_UDC_EP2InMPSR = (n) ) -+#define __udc_ep3in_set_max_packet_size(n) ( REG_UDC_EP3InMPSR = (n) ) -+#define __udc_ep4in_set_max_packet_size(n) ( REG_UDC_EP4InMPSR = (n) ) -+#define __udc_ep5out_set_max_packet_size(n) ( REG_UDC_EP5OutMPSR = (n) ) -+#define __udc_ep6out_set_max_packet_size(n) ( REG_UDC_EP6OutMPSR = (n) ) -+#define __udc_ep7out_set_max_packet_size(n) ( REG_UDC_EP7OutMPSR = (n) ) -+ -+/* set to 0xFFFF for UDC */ -+#define __udc_set_setup_command_address(n) ( REG_UDC_STCMAR = (n) ) -+ -+/* Init and configure EPxInfR(x=0,1,2,3,4,5,6,7) -+ * c: Configuration number to which this endpoint belongs -+ * i: Interface number to which this endpoint belongs -+ * a: Alternate setting to which this endpoint belongs -+ * p: max Packet size of this endpoint -+ */ -+ -+#define __udc_ep0info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP0InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP0InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP0InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP0InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP0InfR |= UDC_EPInfR_EPT_CTRL; \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP0InfR |= UDC_EPInfR_EPD_OUT; \ -+ REG_UDC_EP0InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP0InfR |= (0 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep1info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP1InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP1InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP1InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP1InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP1InfR |= UDC_EPInfR_EPT_INTR; \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP1InfR |= UDC_EPInfR_EPD_IN; \ -+ REG_UDC_EP1InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP1InfR |= (1 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep2info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP2InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP2InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP2InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP2InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP2InfR |= UDC_EPInfR_EPT_BULK; \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP2InfR |= UDC_EPInfR_EPD_IN; \ -+ REG_UDC_EP2InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP2InfR |= (2 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep3info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP3InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP3InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP3InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP3InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP3InfR |= UDC_EPInfR_EPT_BULK; \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP3InfR |= UDC_EPInfR_EPD_IN; \ -+ REG_UDC_EP3InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP3InfR |= (3 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep4info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP4InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP4InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP4InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP4InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP4InfR |= UDC_EPInfR_EPT_ISO; \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP4InfR |= UDC_EPInfR_EPD_IN; \ -+ REG_UDC_EP4InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP4InfR |= (4 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep5info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP5InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP5InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP5InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP5InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP5InfR |= UDC_EPInfR_EPT_BULK; \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP5InfR |= UDC_EPInfR_EPD_OUT; \ -+ REG_UDC_EP5InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP5InfR |= (5 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep6info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP6InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP6InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP6InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP6InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP6InfR |= UDC_EPInfR_EPT_BULK; \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP6InfR |= UDC_EPInfR_EPD_OUT; \ -+ REG_UDC_EP6InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP6InfR |= (6 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+#define __udc_ep7info_init(c,i,a,p) \ -+do { \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_MPS_MASK; \ -+ REG_UDC_EP7InfR |= ((p) << UDC_EPInfR_MPS_BIT); \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_ALTS_MASK; \ -+ REG_UDC_EP7InfR |= ((a) << UDC_EPInfR_ALTS_BIT); \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_IFN_MASK; \ -+ REG_UDC_EP7InfR |= ((i) << UDC_EPInfR_IFN_BIT); \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_CGN_MASK; \ -+ REG_UDC_EP7InfR |= ((c) << UDC_EPInfR_CGN_BIT); \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPT_MASK; \ -+ REG_UDC_EP7InfR |= UDC_EPInfR_EPT_ISO; \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPD; \ -+ REG_UDC_EP7InfR |= UDC_EPInfR_EPD_OUT; \ -+ REG_UDC_EP7InfR &= ~UDC_EPInfR_EPN_MASK; \ -+ REG_UDC_EP7InfR |= (7 << UDC_EPInfR_EPN_BIT); \ -+} while (0) -+ -+ -+/*************************************************************************** -+ * DMAC -+ ***************************************************************************/ -+ -+/* n is the DMA channel (0 - 7) */ -+ -+#define __dmac_enable_all_channels() \ -+ ( REG_DMAC_DMACR |= DMAC_DMACR_DME | DMAC_DMACR_PR_ROUNDROBIN ) -+#define __dmac_disable_all_channels() \ -+ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DME ) -+ -+/* p=0,1,2,3 */ -+#define __dmac_set_priority(p) \ -+do { \ -+ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ -+ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ -+} while (0) -+ -+#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HTR ) -+#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AER ) -+ -+#define __dmac_enable_channel(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_CHDE ) -+#define __dmac_disable_channel(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_CHDE ) -+#define __dmac_channel_enabled(n) \ -+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_CHDE ) -+ -+#define __dmac_channel_enable_irq(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TCIE ) -+#define __dmac_channel_disable_irq(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TCIE ) -+ -+#define __dmac_channel_transmit_halt_detected(n) \ -+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_HLT ) -+#define __dmac_channel_transmit_end_detected(n) \ -+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_TC ) -+#define __dmac_channel_address_error_detected(n) \ -+ ( REG_DMAC_DCCSR(n) & DMAC_DCCSR_AR ) -+ -+#define __dmac_channel_clear_transmit_halt(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) -+#define __dmac_channel_clear_transmit_end(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TC ) -+#define __dmac_channel_clear_address_error(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) -+ -+#define __dmac_channel_set_single_mode(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TM ) -+#define __dmac_channel_set_block_mode(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_TM ) -+ -+#define __dmac_channel_set_transfer_unit_32bit(n) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32b; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16bit(n) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16b; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_8bit(n) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_8b; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16byte(n) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_16B; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_32byte(n) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DS_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DS_32B; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_dest_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DWDH_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DWDH_##w; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_src_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \ -+ REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SWDH_##w; \ -+} while (0) -+ -+/* v=0-15 */ -+#define __dmac_channel_set_rdil(n,v) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_RDIL_MASK; \ -+ REG_DMAC_DCCSR(n) |= ((v) << DMAC_DCCSR_RDIL_BIT); \ -+} while (0) -+ -+#define __dmac_channel_dest_addr_fixed(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_DAM ) -+#define __dmac_channel_dest_addr_increment(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_DAM ) -+ -+#define __dmac_channel_src_addr_fixed(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SAM ) -+#define __dmac_channel_src_addr_increment(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_SAM ) -+ -+#define __dmac_channel_set_eop_high(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EOPM ) -+#define __dmac_channel_set_eop_low(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EOPM ) -+ -+#define __dmac_channel_set_erdm(n,m) \ -+do { \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_SWDH_MASK; \ -+ REG_DMAC_DCCSR(n) |= ((m) << DMAC_DCCSR_ERDM_BIT); \ -+} while (0) -+ -+#define __dmac_channel_set_eackm(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKM ) -+#define __dmac_channel_clear_eackm(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKM ) -+ -+#define __dmac_channel_set_eacks(n) \ -+ ( REG_DMAC_DCCSR(n) |= DMAC_DCCSR_EACKS ) -+#define __dmac_channel_clear_eacks(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_EACKS ) -+ -+ -+#define __dmac_channel_irq_detected(n) \ -+ ( REG_DMAC_DCCSR(n) & (DMAC_DCCSR_TC | DMAC_DCCSR_AR) ) -+ -+static __inline__ int __dmac_get_irq(void) -+{ -+ int i; -+ for (i=0;i> AIC_SR_TFL_BIT ) -+#define __aic_get_receive_count() \ -+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) -+ -+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) -+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) -+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) -+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) -+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) -+ -+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) -+ -+#define CODEC_READ_CMD (1 << 19) -+#define CODEC_WRITE_CMD (0 << 19) -+#define CODEC_REG_INDEX_BIT 12 -+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ -+#define CODEC_REG_DATA_BIT 4 -+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ -+ -+#define __ac97_out_rcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_wcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_data(value) \ -+do { \ -+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ -+} while (0) -+ -+#define __ac97_in_data() \ -+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) -+ -+#define __ac97_in_status_addr() \ -+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) -+ -+#define __i2s_set_sample_rate(i2sclk, sync) \ -+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) -+ -+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) -+#define __aic_read_rfifo() ( REG_AIC_DR ) -+ -+// -+// Define next ops for AC97 compatible -+// -+ -+#define AC97_ACSR AIC_ACSR -+ -+#define __ac97_enable() __aic_enable(); __aic_select_ac97() -+#define __ac97_disable() __aic_disable() -+#define __ac97_reset() __aic_reset() -+ -+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __ac97_enable_record() __aic_enable_record() -+#define __ac97_disable_record() __aic_disable_record() -+#define __ac97_enable_replay() __aic_enable_replay() -+#define __ac97_disable_replay() __aic_disable_replay() -+#define __ac97_enable_loopback() __aic_enable_loopback() -+#define __ac97_disable_loopback() __aic_disable_loopback() -+ -+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __ac97_enable_receive_dma() __aic_enable_receive_dma() -+#define __ac97_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __ac97_transmit_request() __aic_transmit_request() -+#define __ac97_receive_request() __aic_receive_request() -+#define __ac97_transmit_underrun() __aic_transmit_underrun() -+#define __ac97_receive_overrun() __aic_receive_overrun() -+ -+#define __ac97_clear_errors() __aic_clear_errors() -+ -+#define __ac97_get_transmit_resident() __aic_get_transmit_resident() -+#define __ac97_get_receive_count() __aic_get_receive_count() -+ -+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __ac97_enable_receive_intr() __aic_enable_receive_intr() -+#define __ac97_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __ac97_write_tfifo(v) __aic_write_tfifo(v) -+#define __ac97_read_rfifo() __aic_read_rfifo() -+ -+// -+// Define next ops for I2S compatible -+// -+ -+#define I2S_ACSR AIC_I2SSR -+ -+#define __i2s_enable() __aic_enable(); __aic_select_i2s() -+#define __i2s_disable() __aic_disable() -+#define __i2s_reset() __aic_reset() -+ -+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __i2s_enable_record() __aic_enable_record() -+#define __i2s_disable_record() __aic_disable_record() -+#define __i2s_enable_replay() __aic_enable_replay() -+#define __i2s_disable_replay() __aic_disable_replay() -+#define __i2s_enable_loopback() __aic_enable_loopback() -+#define __i2s_disable_loopback() __aic_disable_loopback() -+ -+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __i2s_enable_receive_dma() __aic_enable_receive_dma() -+#define __i2s_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __i2s_transmit_request() __aic_transmit_request() -+#define __i2s_receive_request() __aic_receive_request() -+#define __i2s_transmit_underrun() __aic_transmit_underrun() -+#define __i2s_receive_overrun() __aic_receive_overrun() -+ -+#define __i2s_clear_errors() __aic_clear_errors() -+ -+#define __i2s_get_transmit_resident() __aic_get_transmit_resident() -+#define __i2s_get_receive_count() __aic_get_receive_count() -+ -+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __i2s_enable_receive_intr() __aic_enable_receive_intr() -+#define __i2s_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __i2s_write_tfifo(v) __aic_write_tfifo(v) -+#define __i2s_read_rfifo() __aic_read_rfifo() -+ -+#define __i2s_reset_codec() \ -+ do { \ -+ __gpio_as_output(70); /* SDATA_OUT */ \ -+ __gpio_as_input(71); /* SDATA_IN */ \ -+ __gpio_as_output(78); /* SYNC */ \ -+ __gpio_as_output(69); /* RESET# */ \ -+ __gpio_clear_pin(70); \ -+ __gpio_clear_pin(71); \ -+ __gpio_clear_pin(78); \ -+ __gpio_clear_pin(69); \ -+ __gpio_as_i2s_master(); \ -+ } while (0) -+ -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+ -+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) -+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) -+ -+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) -+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) -+ -+/* n=1,2,4,8,16 */ -+#define __lcd_set_bpp(n) \ -+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) -+ -+/* n=4,8,16 */ -+#define __lcd_set_burst_length(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ -+} while (0) -+ -+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) -+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) -+ -+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) -+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) -+ -+/* n=2,4,16 */ -+#define __lcd_set_stn_frc(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ -+} while (0) -+ -+ -+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) -+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) -+ -+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) -+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) -+ -+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) -+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) -+ -+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) -+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) -+ -+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) -+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) -+ -+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) -+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) -+ -+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) -+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) -+ -+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) -+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) -+ -+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) -+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) -+ -+ -+/* LCD status register indication */ -+ -+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) -+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) -+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) -+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) -+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) -+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) -+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) -+ -+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) -+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) -+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) -+ -+#define __lcd_panel_white() ( REG_LCD_DEV |= LCD_DEV_WHITE ) -+#define __lcd_panel_black() ( REG_LCD_DEV &= ~LCD_DEV_WHITE ) -+ -+/* n=1,2,4,8 for single mono-STN -+ * n=4,8 for dual mono-STN -+ */ -+#define __lcd_set_panel_datawidth(n) \ -+do { \ -+ REG_LCD_DEV &= ~LCD_DEV_PDW_MASK; \ -+ REG_LCD_DEV |= LCD_DEV_PDW_n##; \ -+} while (0) -+ -+/* m=LCD_DEV_MODE_GENERUIC_TFT_xxx */ -+#define __lcd_set_panel_mode(m) \ -+do { \ -+ REG_LCD_DEV &= ~LCD_DEV_MODE_MASK; \ -+ REG_LCD_DEV |= (m); \ -+} while(0) -+ -+/* n = 0-255 */ -+#define __lcd_disable_ac_bias() ( REG_LCD_IO = 0xff ) -+#define __lcd_set_ac_bias(n) \ -+do { \ -+ REG_LCD_IO &= ~LCD_IO_ACB_MASK; \ -+ REG_LCD_IO |= ((n) << LCD_IO_ACB_BIT); \ -+} while(0) -+ -+#define __lcd_io_set_dir() ( REG_LCD_IO |= LCD_IO_DIR ) -+#define __lcd_io_clr_dir() ( REG_LCD_IO &= ~LCD_IO_DIR ) -+ -+#define __lcd_io_set_dep() ( REG_LCD_IO |= LCD_IO_DEP ) -+#define __lcd_io_clr_dep() ( REG_LCD_IO &= ~LCD_IO_DEP ) -+ -+#define __lcd_io_set_vsp() ( REG_LCD_IO |= LCD_IO_VSP ) -+#define __lcd_io_clr_vsp() ( REG_LCD_IO &= ~LCD_IO_VSP ) -+ -+#define __lcd_io_set_hsp() ( REG_LCD_IO |= LCD_IO_HSP ) -+#define __lcd_io_clr_hsp() ( REG_LCD_IO &= ~LCD_IO_HSP ) -+ -+#define __lcd_io_set_pcp() ( REG_LCD_IO |= LCD_IO_PCP ) -+#define __lcd_io_clr_pcp() ( REG_LCD_IO &= ~LCD_IO_PCP ) -+ -+#define __lcd_vsync_get_vps() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) -+ -+#define __lcd_vsync_get_vpe() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) -+#define __lcd_vsync_set_vpe(n) \ -+do { \ -+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ -+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hps() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) -+#define __lcd_hsync_set_hps(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hpe() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) -+#define __lcd_hsync_set_hpe(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_ht() \ -+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) -+#define __lcd_vat_set_ht(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_vt() \ -+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) -+#define __lcd_vat_set_vt(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hds() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) -+#define __lcd_dah_set_hds(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hde() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) -+#define __lcd_dah_set_hde(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vds() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) -+#define __lcd_dav_set_vds(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vde() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) -+#define __lcd_dav_set_vde(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ -+} while (0) -+ -+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) -+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) -+ -+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) -+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) -+ -+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) -+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) -+ -+#define __lcd_cmd0_get_len() \ -+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+#define __lcd_cmd1_get_len() \ -+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+ -+ -+ -+/*************************************************************************** -+ * DES -+ ***************************************************************************/ -+ -+ -+/*************************************************************************** -+ * CPM -+ ***************************************************************************/ -+#define __cpm_plcr1_fd() \ -+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1FD_MASK) >> CPM_PLCR1_PLL1FD_BIT) -+#define __cpm_plcr1_rd() \ -+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1RD_MASK) >> CPM_PLCR1_PLL1RD_BIT) -+#define __cpm_plcr1_od() \ -+ ((REG_CPM_PLCR1 & CPM_PLCR1_PLL1OD_MASK) >> CPM_PLCR1_PLL1OD_BIT) -+#define __cpm_cfcr_mfr() \ -+ ((REG_CPM_CFCR & CPM_CFCR_MFR_MASK) >> CPM_CFCR_MFR_BIT) -+#define __cpm_cfcr_pfr() \ -+ ((REG_CPM_CFCR & CPM_CFCR_PFR_MASK) >> CPM_CFCR_PFR_BIT) -+#define __cpm_cfcr_sfr() \ -+ ((REG_CPM_CFCR & CPM_CFCR_SFR_MASK) >> CPM_CFCR_SFR_BIT) -+#define __cpm_cfcr_ifr() \ -+ ((REG_CPM_CFCR & CPM_CFCR_IFR_MASK) >> CPM_CFCR_IFR_BIT) -+ -+static __inline__ unsigned int __cpm_divisor_encode(unsigned int n) -+{ -+ unsigned int encode[10] = {1,2,3,4,6,8,12,16,24,32}; -+ int i; -+ for (i=0;i<10;i++) -+ if (n < encode[i]) -+ break; -+ return i; -+} -+ -+#define __cpm_set_mclk_div(n) \ -+do { \ -+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_MFR_MASK) | \ -+ ((n) << (CPM_CFCR_MFR_BIT)); \ -+} while (0) -+ -+#define __cpm_set_pclk_div(n) \ -+do { \ -+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_PFR_MASK) | \ -+ ((n) << (CPM_CFCR_PFR_BIT)); \ -+} while (0) -+ -+#define __cpm_set_sclk_div(n) \ -+do { \ -+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_SFR_MASK) | \ -+ ((n) << (CPM_CFCR_SFR_BIT)); \ -+} while (0) -+ -+#define __cpm_set_iclk_div(n) \ -+do { \ -+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_IFR_MASK) | \ -+ ((n) << (CPM_CFCR_IFR_BIT)); \ -+} while (0) -+ -+#define __cpm_set_lcdclk_div(n) \ -+do { \ -+ REG_CPM_CFCR = (REG_CPM_CFCR & ~CPM_CFCR_LFR_MASK) | \ -+ ((n) << (CPM_CFCR_LFR_BIT)); \ -+} while (0) -+ -+#define __cpm_enable_cko1() (REG_CPM_CFCR |= CPM_CFCR_CKOEN1) -+#define __cpm_enable_cko2() (REG_CPM_CFCR |= CPM_CFCR_CKOEN2) -+#define __cpm_disable_cko1() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN1) -+#define __cpm_disable_cko2() (REG_CPM_CFCR &= ~CPM_CFCR_CKOEN2) -+ -+#define __cpm_select_msc_clk(type) \ -+do { \ -+ if (type == 0) \ -+ REG_CPM_CFCR &= ~CPM_CFCR_MSC; \ -+ else \ -+ REG_CPM_CFCR |= CPM_CFCR_MSC; \ -+ REG_CPM_CFCR |= CPM_CFCR_UPE; \ -+} while(0) -+ -+#define __cpm_idle_mode() \ -+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ -+ CPM_LPCR_LPM_IDLE) -+#define __cpm_sleep_mode() \ -+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ -+ CPM_LPCR_LPM_SLEEP) -+#define __cpm_hibernate_mode() \ -+ (REG_CPM_LPCR = (REG_CPM_LPCR & ~CPM_LPCR_LPM_MASK) | \ -+ CPM_LPCR_LPM_HIBERNATE) -+ -+#define __cpm_start_uart0() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART0)) -+#define __cpm_start_uart1() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART1)) -+#define __cpm_start_uart2() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART2)) -+#define __cpm_start_uart3() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UART3)) -+#define __cpm_start_ost() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_OST)) -+#define __cpm_start_dmac() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_DMAC)) -+#define __cpm_start_uhc() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UHC)) -+#define __cpm_start_lcd() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_LCD)) -+#define __cpm_start_i2c() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_I2C)) -+#define __cpm_start_aic_pclk() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICPCLK)) -+#define __cpm_start_aic_bitclk() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_AICBCLK)) -+#define __cpm_start_pwm0() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM0)) -+#define __cpm_start_pwm1() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_PWM1)) -+#define __cpm_start_ssi() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SSI)) -+#define __cpm_start_msc() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_MSC)) -+#define __cpm_start_scc() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_SCC)) -+#define __cpm_start_eth() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_ETH)) -+#define __cpm_start_kbc() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_KBC)) -+#define __cpm_start_cim() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_CIM)) -+#define __cpm_start_udc() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UDC)) -+#define __cpm_start_uprt() \ -+ (REG_CPM_MSCR &= ~(1 << CPM_MSCR_MSTP_UPRT)) -+#define __cpm_start_all() (REG_CPM_MSCR = 0) -+ -+#define __cpm_stop_uart0() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART0)) -+#define __cpm_stop_uart1() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART1)) -+#define __cpm_stop_uart2() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART2)) -+#define __cpm_stop_uart3() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UART3)) -+#define __cpm_stop_ost() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_OST)) -+#define __cpm_stop_dmac() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_DMAC)) -+#define __cpm_stop_uhc() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UHC)) -+#define __cpm_stop_lcd() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_LCD)) -+#define __cpm_stop_i2c() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_I2C)) -+#define __cpm_stop_aic_pclk() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICPCLK)) -+#define __cpm_stop_aic_bitclk() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_AICBCLK)) -+#define __cpm_stop_pwm0() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM0)) -+#define __cpm_stop_pwm1() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_PWM1)) -+#define __cpm_stop_ssi() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SSI)) -+#define __cpm_stop_msc() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_MSC)) -+#define __cpm_stop_scc() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_SCC)) -+#define __cpm_stop_eth() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_ETH)) -+#define __cpm_stop_kbc() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_KBC)) -+#define __cpm_stop_cim() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_CIM)) -+#define __cpm_stop_udc() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UDC)) -+#define __cpm_stop_uprt() \ -+ (REG_CPM_MSCR |= (1 << CPM_MSCR_MSTP_UPRT)) -+#define __cpm_stop_all() (REG_CPM_MSCR = 0xffffffff) -+ -+#define __cpm_set_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ if (p == 0) \ -+ REG_CPM_GSR0 |= (1 << o); \ -+ else if (p == 1) \ -+ REG_CPM_GSR1 |= (1 << o); \ -+ else if (p == 2) \ -+ REG_CPM_GSR2 |= (1 << o); \ -+ else if (p == 3) \ -+ REG_CPM_GSR3 |= (1 << o); \ -+} while (0) -+ -+#define __cpm_clear_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ if (p == 0) \ -+ REG_CPM_GSR0 &= ~(1 << o); \ -+ else if (p == 1) \ -+ REG_CPM_GSR1 &= ~(1 << o); \ -+ else if (p == 2) \ -+ REG_CPM_GSR2 &= ~(1 << o); \ -+ else if (p == 3) \ -+ REG_CPM_GSR3 &= ~(1 << o); \ -+} while (0) -+ -+ -+/*************************************************************************** -+ * SSI -+ ***************************************************************************/ -+ -+#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) -+#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) -+#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) -+ -+#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) -+ -+#define __ssi_select_ce2() \ -+do { \ -+ REG_SSI_CR0 |= SSI_CR0_FSEL; \ -+ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_select_gpc() \ -+do { \ -+ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ -+ REG_SSI_CR1 |= SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_enable_tx_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) -+ -+#define __ssi_disable_tx_intr() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) -+ -+#define __ssi_enable_rx_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) -+ -+#define __ssi_disable_rx_intr() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) -+ -+#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) -+#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) -+ -+#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) -+#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) -+ -+#define __ssi_finish_receive() \ -+ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_disable_recvfinish() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) -+#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) -+ -+#define __ssi_flush_fifo() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) -+ -+#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) -+ -+#define __ssi_spi_format() \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ -+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ -+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ -+} while (0) -+ -+/* TI's SSP format, must clear SSI_CR1.UNFIN */ -+#define __ssi_ssp_format() \ -+do { \ -+ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ -+} while (0) -+ -+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ -+#define __ssi_microwire_format() \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ -+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ -+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ -+ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ -+} while (0) -+ -+/* CE# level (FRMHL), CE# in interval time (ITFRM), -+ clock phase and polarity (PHA POL), -+ interval time (SSIITR), interval characters/frame (SSIICR) */ -+ -+ /* frmhl,endian,mcom,flen,pha,pol MASK */ -+#define SSICR1_MISC_MASK \ -+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ -+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ -+ -+#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ -+do { \ -+ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ -+ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ -+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ -+ ((pha) << 1) | (pol); \ -+} while(0) -+ -+/* Transfer with MSB or LSB first */ -+#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) -+#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) -+ -+#define __ssi_set_frame_length(n) \ -+ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) -+ -+/* n = 1 - 16 */ -+#define __ssi_set_microwire_command_length(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) -+ -+/* Set the clock phase for SPI */ -+#define __ssi_set_spi_clock_phase(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1) << 1 ))) -+ -+/* Set the clock polarity for SPI */ -+#define __ssi_set_spi_clock_polarity(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | ((n&0x1) << 0 ))) -+ -+/* n = 1,4,8,14 */ -+#define __ssi_set_tx_trigger(n) \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_TTRG_##n; \ -+} while (0) -+ -+/* n = 1,4,8,14 */ -+#define __ssi_set_rx_trigger(n) \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_RTRG_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_RTRG_##n; \ -+} while (0) -+ -+#define __ssi_get_txfifo_count() \ -+ ( (REG_SSI_SR & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT ) -+ -+#define __ssi_get_rxfifo_count() \ -+ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) -+ -+#define __ssi_clear_errors() \ -+ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) -+ -+#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) -+#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) -+ -+#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) -+#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) -+#define __ssi_rxfifo_noempty() ( REG_SSI_SR & SSI_SR_RFHF ) -+#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF ) -+#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE ) -+#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR ) -+#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER ) -+ -+#define __ssi_set_clk(dev_clk, ssi_clk) \ -+ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) -+ -+#define __ssi_receive_data() REG_SSI_DR -+#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) -+ -+#endif /* __ASM_JZ4730_OPS_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/regs.h linux-2.6.24.7/include/asm-mips/mach-jz4730/regs.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/regs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/regs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2550 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/regs.h -+ * -+ * JZ4730 registers definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * 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 __ASM_JZ4730_REGS_H__ -+#define __ASM_JZ4730_REGS_H__ -+ -+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY) -+#define REG8(addr) (addr) -+#define REG16(addr) (addr) -+#define REG32(addr) (addr) -+#else -+#define REG8(addr) *((volatile unsigned char *)(addr)) -+#define REG16(addr) *((volatile unsigned short *)(addr)) -+#define REG32(addr) *((volatile unsigned int *)(addr)) -+#endif -+ -+#define HARB_BASE 0xB3000000 -+#define EMC_BASE 0xB3010000 -+#define DMAC_BASE 0xB3020000 -+#define UHC_BASE 0xB3030000 -+#define UDC_BASE 0xB3040000 -+#define LCD_BASE 0xB3050000 -+#define CIM_BASE 0xB3060000 -+#define ETH_BASE 0xB3100000 -+#define NBM_BASE 0xB3F00000 -+ -+#define CPM_BASE 0xB0000000 -+#define INTC_BASE 0xB0001000 -+#define OST_BASE 0xB0002000 -+#define RTC_BASE 0xB0003000 -+#define WDT_BASE 0xB0004000 -+#define GPIO_BASE 0xB0010000 -+#define AIC_BASE 0xB0020000 -+#define MSC_BASE 0xB0021000 -+#define UART0_BASE 0xB0030000 -+#define UART1_BASE 0xB0031000 -+#define UART2_BASE 0xB0032000 -+#define UART3_BASE 0xB0033000 -+#define FIR_BASE 0xB0040000 -+#define SCC_BASE 0xB0041000 -+#define SCC0_BASE 0xB0041000 -+#define I2C_BASE 0xB0042000 -+#define SSI_BASE 0xB0043000 -+#define SCC1_BASE 0xB0044000 -+#define PWM0_BASE 0xB0050000 -+#define PWM1_BASE 0xB0051000 -+#define DES_BASE 0xB0060000 -+#define UPRT_BASE 0xB0061000 -+#define KBC_BASE 0xB0062000 -+ -+ -+ -+ -+/************************************************************************* -+ * MSC -+ *************************************************************************/ -+#define MSC_STRPCL (MSC_BASE + 0x000) -+#define MSC_STAT (MSC_BASE + 0x004) -+#define MSC_CLKRT (MSC_BASE + 0x008) -+#define MSC_CMDAT (MSC_BASE + 0x00C) -+#define MSC_RESTO (MSC_BASE + 0x010) -+#define MSC_RDTO (MSC_BASE + 0x014) -+#define MSC_BLKLEN (MSC_BASE + 0x018) -+#define MSC_NOB (MSC_BASE + 0x01C) -+#define MSC_SNOB (MSC_BASE + 0x020) -+#define MSC_IMASK (MSC_BASE + 0x024) -+#define MSC_IREG (MSC_BASE + 0x028) -+#define MSC_CMD (MSC_BASE + 0x02C) -+#define MSC_ARG (MSC_BASE + 0x030) -+#define MSC_RES (MSC_BASE + 0x034) -+#define MSC_RXFIFO (MSC_BASE + 0x038) -+#define MSC_TXFIFO (MSC_BASE + 0x03C) -+ -+#define REG_MSC_STRPCL REG16(MSC_STRPCL) -+#define REG_MSC_STAT REG32(MSC_STAT) -+#define REG_MSC_CLKRT REG16(MSC_CLKRT) -+#define REG_MSC_CMDAT REG32(MSC_CMDAT) -+#define REG_MSC_RESTO REG16(MSC_RESTO) -+#define REG_MSC_RDTO REG16(MSC_RDTO) -+#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) -+#define REG_MSC_NOB REG16(MSC_NOB) -+#define REG_MSC_SNOB REG16(MSC_SNOB) -+#define REG_MSC_IMASK REG16(MSC_IMASK) -+#define REG_MSC_IREG REG16(MSC_IREG) -+#define REG_MSC_CMD REG8(MSC_CMD) -+#define REG_MSC_ARG REG32(MSC_ARG) -+#define REG_MSC_RES REG16(MSC_RES) -+#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) -+#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) -+ -+/* MSC Clock and Control Register (MSC_STRPCL) */ -+ -+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) -+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) -+#define MSC_STRPCL_START_READWAIT (1 << 5) -+#define MSC_STRPCL_STOP_READWAIT (1 << 4) -+#define MSC_STRPCL_RESET (1 << 3) -+#define MSC_STRPCL_START_OP (1 << 2) -+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 -+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) -+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ -+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ -+ -+/* MSC Status Register (MSC_STAT) */ -+ -+#define MSC_STAT_IS_RESETTING (1 << 15) -+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) -+#define MSC_STAT_PRG_DONE (1 << 13) -+#define MSC_STAT_DATA_TRAN_DONE (1 << 12) -+#define MSC_STAT_END_CMD_RES (1 << 11) -+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) -+#define MSC_STAT_IS_READWAIT (1 << 9) -+#define MSC_STAT_CLK_EN (1 << 8) -+#define MSC_STAT_DATA_FIFO_FULL (1 << 7) -+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) -+#define MSC_STAT_CRC_RES_ERR (1 << 5) -+#define MSC_STAT_CRC_READ_ERROR (1 << 4) -+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 -+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) -+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ -+#define MSC_STAT_TIME_OUT_RES (1 << 1) -+#define MSC_STAT_TIME_OUT_READ (1 << 0) -+ -+/* MSC Bus Clock Control Register (MSC_CLKRT) */ -+ -+#define MSC_CLKRT_CLK_RATE_BIT 0 -+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) -+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ -+ -+/* MSC Command Sequence Control Register (MSC_CMDAT) */ -+ -+#define MSC_CMDAT_IO_ABORT (1 << 11) -+#define MSC_CMDAT_BUS_WIDTH_BIT 9 -+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ -+ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) -+#define MSC_CMDAT_DMA_EN (1 << 8) -+#define MSC_CMDAT_INIT (1 << 7) -+#define MSC_CMDAT_BUSY (1 << 6) -+#define MSC_CMDAT_STREAM_BLOCK (1 << 5) -+#define MSC_CMDAT_WRITE (1 << 4) -+#define MSC_CMDAT_READ (0 << 4) -+#define MSC_CMDAT_DATA_EN (1 << 3) -+#define MSC_CMDAT_RESPONSE_BIT 0 -+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) -+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ -+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ -+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ -+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ -+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ -+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ -+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ -+ -+#define CMDAT_DMA_EN (1 << 8) -+#define CMDAT_INIT (1 << 7) -+#define CMDAT_BUSY (1 << 6) -+#define CMDAT_STREAM (1 << 5) -+#define CMDAT_WRITE (1 << 4) -+#define CMDAT_DATA_EN (1 << 3) -+ -+/* MSC Interrupts Mask Register (MSC_IMASK) */ -+ -+#define MSC_IMASK_SDIO (1 << 7) -+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IMASK_END_CMD_RES (1 << 2) -+#define MSC_IMASK_PRG_DONE (1 << 1) -+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) -+ -+ -+/* MSC Interrupts Status Register (MSC_IREG) */ -+ -+#define MSC_IREG_SDIO (1 << 7) -+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IREG_END_CMD_RES (1 << 2) -+#define MSC_IREG_PRG_DONE (1 << 1) -+#define MSC_IREG_DATA_TRAN_DONE (1 << 0) -+ -+ -+ -+ -+/************************************************************************* -+ * RTC -+ *************************************************************************/ -+#define RTC_RCR (RTC_BASE + 0x00) -+#define RTC_RSR (RTC_BASE + 0x04) -+#define RTC_RSAR (RTC_BASE + 0x08) -+#define RTC_RGR (RTC_BASE + 0x0c) -+ -+#define REG_RTC_RCR REG32(RTC_RCR) -+#define REG_RTC_RSR REG32(RTC_RSR) -+#define REG_RTC_RSAR REG32(RTC_RSAR) -+#define REG_RTC_RGR REG32(RTC_RGR) -+ -+#define RTC_RCR_HZ (1 << 6) -+#define RTC_RCR_HZIE (1 << 5) -+#define RTC_RCR_AF (1 << 4) -+#define RTC_RCR_AIE (1 << 3) -+#define RTC_RCR_AE (1 << 2) -+#define RTC_RCR_START (1 << 0) -+ -+#define RTC_RGR_LOCK (1 << 31) -+#define RTC_RGR_ADJ_BIT 16 -+#define RTC_RGR_ADJ_MASK (0x3ff << RTC_RGR_ADJ_BIT) -+#define RTC_RGR_DIV_BIT 0 -+#define RTC_REG_DIV_MASK (0xff << RTC_RGR_DIV_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * FIR -+ *************************************************************************/ -+#define FIR_TDR (FIR_BASE + 0x000) -+#define FIR_RDR (FIR_BASE + 0x004) -+#define FIR_TFLR (FIR_BASE + 0x008) -+#define FIR_AR (FIR_BASE + 0x00C) -+#define FIR_CR1 (FIR_BASE + 0x010) -+#define FIR_CR2 (FIR_BASE + 0x014) -+#define FIR_SR (FIR_BASE + 0x018) -+ -+#define REG_FIR_TDR REG8(FIR_TDR) -+#define REG_FIR_RDR REG8(FIR_RDR) -+#define REG_FIR_TFLR REG16(FIR_TFLR) -+#define REG_FIR_AR REG8(FIR_AR) -+#define REG_FIR_CR1 REG8(FIR_CR1) -+#define REG_FIR_CR2 REG16(FIR_CR2) -+#define REG_FIR_SR REG16(FIR_SR) -+ -+/* FIR Control Register 1 (FIR_CR1) */ -+ -+#define FIR_CR1_FIRUE (1 << 7) -+#define FIR_CR1_ACE (1 << 6) -+#define FIR_CR1_EOUS (1 << 5) -+#define FIR_CR1_TIIE (1 << 4) -+#define FIR_CR1_TFIE (1 << 3) -+#define FIR_CR1_RFIE (1 << 2) -+#define FIR_CR1_TXE (1 << 1) -+#define FIR_CR1_RXE (1 << 0) -+ -+/* FIR Control Register 2 (FIR_CR2) */ -+ -+#define FIR_CR2_SIPE (1 << 10) -+#define FIR_CR2_BCRC (1 << 9) -+#define FIR_CR2_TFLRS (1 << 8) -+#define FIR_CR2_ISS (1 << 7) -+#define FIR_CR2_LMS (1 << 6) -+#define FIR_CR2_TPPS (1 << 5) -+#define FIR_CR2_RPPS (1 << 4) -+#define FIR_CR2_TTRG_BIT 2 -+#define FIR_CR2_TTRG_MASK (0x3 << FIR_CR2_TTRG_BIT) -+ #define FIR_CR2_TTRG_16 (0 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 16 */ -+ #define FIR_CR2_TTRG_32 (1 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 32 */ -+ #define FIR_CR2_TTRG_64 (2 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 64 */ -+ #define FIR_CR2_TTRG_128 (3 << FIR_CR2_TTRG_BIT) /* Transmit Trigger Level is 128 */ -+#define FIR_CR2_RTRG_BIT 0 -+#define FIR_CR2_RTRG_MASK (0x3 << FIR_CR2_RTRG_BIT) -+ #define FIR_CR2_RTRG_16 (0 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 16 */ -+ #define FIR_CR2_RTRG_32 (1 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 32 */ -+ #define FIR_CR2_RTRG_64 (2 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 64 */ -+ #define FIR_CR2_RTRG_128 (3 << FIR_CR2_RTRG_BIT) /* Receive Trigger Level is 128 */ -+ -+/* FIR Status Register (FIR_SR) */ -+ -+#define FIR_SR_RFW (1 << 12) -+#define FIR_SR_RFA (1 << 11) -+#define FIR_SR_TFRTL (1 << 10) -+#define FIR_SR_RFRTL (1 << 9) -+#define FIR_SR_URUN (1 << 8) -+#define FIR_SR_RFTE (1 << 7) -+#define FIR_SR_ORUN (1 << 6) -+#define FIR_SR_CRCE (1 << 5) -+#define FIR_SR_FEND (1 << 4) -+#define FIR_SR_TFF (1 << 3) -+#define FIR_SR_RFE (1 << 2) -+#define FIR_SR_TIDLE (1 << 1) -+#define FIR_SR_RB (1 << 0) -+ -+ -+ -+ -+/************************************************************************* -+ * SCC -+ *************************************************************************/ -+#define SCC_DR(base) ((base) + 0x000) -+#define SCC_FDR(base) ((base) + 0x004) -+#define SCC_CR(base) ((base) + 0x008) -+#define SCC1_CR(base) ((base) + 0x008) -+#define SCC_SR(base) ((base) + 0x00C) -+#define SCC_TFR(base) ((base) + 0x010) -+#define SCC_EGTR(base) ((base) + 0x014) -+#define SCC_ECR(base) ((base) + 0x018) -+#define SCC_RTOR(base) ((base) + 0x01C) -+ -+#define REG_SCC_DR(base) REG8(SCC_DR(base)) -+#define REG_SCC_FDR(base) REG8(SCC_FDR(base)) -+#define REG_SCC_CR(base) REG32(SCC_CR(base)) -+#define REG_SCC1_CR(base) REG32(SCC1_CR(base)) -+#define REG_SCC_SR(base) REG16(SCC_SR(base)) -+#define REG_SCC_TFR(base) REG16(SCC_TFR(base)) -+#define REG_SCC_EGTR(base) REG8(SCC_EGTR(base)) -+#define REG_SCC_ECR(base) REG32(SCC_ECR(base)) -+#define REG_SCC_RTOR(base) REG8(SCC_RTOR(base)) -+ -+/* SCC FIFO Data Count Register (SCC_FDR) */ -+ -+#define SCC_FDR_EMPTY 0x00 -+#define SCC_FDR_FULL 0x10 -+ -+/* SCC Control Register (SCC_CR) */ -+ -+#define SCC_CR_SCCE (1 << 31) -+#define SCC_CR_TRS (1 << 30) -+#define SCC_CR_T2R (1 << 29) -+#define SCC_CR_FDIV_BIT 24 -+#define SCC_CR_FDIV_MASK (0x3 << SCC_CR_FDIV_BIT) -+ #define SCC_CR_FDIV_1 (0 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is the same as device clock */ -+ #define SCC_CR_FDIV_2 (1 << SCC_CR_FDIV_BIT) /* SCC_CLK frequency is half of device clock */ -+#define SCC_CR_FLUSH (1 << 23) -+#define SCC_CR_TRIG_BIT 16 -+#define SCC_CR_TRIG_MASK (0x3 << SCC_CR_TRIG_BIT) -+ #define SCC_CR_TRIG_1 (0 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 1 */ -+ #define SCC_CR_TRIG_4 (1 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 4 */ -+ #define SCC_CR_TRIG_8 (2 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 8 */ -+ #define SCC_CR_TRIG_14 (3 << SCC_CR_TRIG_BIT) /* Receive/Transmit-FIFO Trigger is 14 */ -+#define SCC_CR_TP (1 << 15) -+#define SCC_CR_CONV (1 << 14) -+#define SCC_CR_TXIE (1 << 13) -+#define SCC_CR_RXIE (1 << 12) -+#define SCC_CR_TENDIE (1 << 11) -+#define SCC_CR_RTOIE (1 << 10) -+#define SCC_CR_ECIE (1 << 9) -+#define SCC_CR_EPIE (1 << 8) -+#define SCC_CR_RETIE (1 << 7) -+#define SCC_CR_EOIE (1 << 6) -+#define SCC_CR_TSEND (1 << 3) -+#define SCC_CR_PX_BIT 1 -+#define SCC_CR_PX_MASK (0x3 << SCC_CR_PX_BIT) -+ #define SCC_CR_PX_NOT_SUPPORT (0 << SCC_CR_PX_BIT) /* SCC does not support clock stop */ -+ #define SCC_CR_PX_STOP_LOW (1 << SCC_CR_PX_BIT) /* SCC_CLK stops at state low */ -+ #define SCC_CR_PX_STOP_HIGH (2 << SCC_CR_PX_BIT) /* SCC_CLK stops at state high */ -+#define SCC_CR_CLKSTP (1 << 0) -+ -+/* SCC Status Register (SCC_SR) */ -+ -+#define SCC_SR_TRANS (1 << 15) -+#define SCC_SR_ORER (1 << 12) -+#define SCC_SR_RTO (1 << 11) -+#define SCC_SR_PER (1 << 10) -+#define SCC_SR_TFTG (1 << 9) -+#define SCC_SR_RFTG (1 << 8) -+#define SCC_SR_TEND (1 << 7) -+#define SCC_SR_RETR_3 (1 << 4) -+#define SCC_SR_ECNTO (1 << 0) -+ -+ -+ -+ -+/************************************************************************* -+ * ETH -+ *************************************************************************/ -+#define ETH_BMR (ETH_BASE + 0x1000) -+#define ETH_TPDR (ETH_BASE + 0x1004) -+#define ETH_RPDR (ETH_BASE + 0x1008) -+#define ETH_RAR (ETH_BASE + 0x100C) -+#define ETH_TAR (ETH_BASE + 0x1010) -+#define ETH_SR (ETH_BASE + 0x1014) -+#define ETH_CR (ETH_BASE + 0x1018) -+#define ETH_IER (ETH_BASE + 0x101C) -+#define ETH_MFCR (ETH_BASE + 0x1020) -+#define ETH_CTAR (ETH_BASE + 0x1050) -+#define ETH_CRAR (ETH_BASE + 0x1054) -+#define ETH_MCR (ETH_BASE + 0x0000) -+#define ETH_MAHR (ETH_BASE + 0x0004) -+#define ETH_MALR (ETH_BASE + 0x0008) -+#define ETH_HTHR (ETH_BASE + 0x000C) -+#define ETH_HTLR (ETH_BASE + 0x0010) -+#define ETH_MIAR (ETH_BASE + 0x0014) -+#define ETH_MIDR (ETH_BASE + 0x0018) -+#define ETH_FCR (ETH_BASE + 0x001C) -+#define ETH_VTR1 (ETH_BASE + 0x0020) -+#define ETH_VTR2 (ETH_BASE + 0x0024) -+#define ETH_WKFR (ETH_BASE + 0x0028) -+#define ETH_PMTR (ETH_BASE + 0x002C) -+ -+#define REG_ETH_BMR REG32(ETH_BMR) -+#define REG_ETH_TPDR REG32(ETH_TPDR) -+#define REG_ETH_RPDR REG32(ETH_RPDR) -+#define REG_ETH_RAR REG32(ETH_RAR) -+#define REG_ETH_TAR REG32(ETH_TAR) -+#define REG_ETH_SR REG32(ETH_SR) -+#define REG_ETH_CR REG32(ETH_CR) -+#define REG_ETH_IER REG32(ETH_IER) -+#define REG_ETH_MFCR REG32(ETH_MFCR) -+#define REG_ETH_CTAR REG32(ETH_CTAR) -+#define REG_ETH_CRAR REG32(ETH_CRAR) -+#define REG_ETH_MCR REG32(ETH_MCR) -+#define REG_ETH_MAHR REG32(ETH_MAHR) -+#define REG_ETH_MALR REG32(ETH_MALR) -+#define REG_ETH_HTHR REG32(ETH_HTHR) -+#define REG_ETH_HTLR REG32(ETH_HTLR) -+#define REG_ETH_MIAR REG32(ETH_MIAR) -+#define REG_ETH_MIDR REG32(ETH_MIDR) -+#define REG_ETH_FCR REG32(ETH_FCR) -+#define REG_ETH_VTR1 REG32(ETH_VTR1) -+#define REG_ETH_VTR2 REG32(ETH_VTR2) -+#define REG_ETH_WKFR REG32(ETH_WKFR) -+#define REG_ETH_PMTR REG32(ETH_PMTR) -+ -+/* Bus Mode Register (ETH_BMR) */ -+ -+#define ETH_BMR_DBO (1 << 20) -+#define ETH_BMR_PBL_BIT 8 -+#define ETH_BMR_PBL_MASK (0x3f << ETH_BMR_PBL_BIT) -+ #define ETH_BMR_PBL_1 (0x1 << ETH_BMR_PBL_BIT) -+ #define ETH_BMR_PBL_4 (0x4 << ETH_BMR_PBL_BIT) -+#define ETH_BMR_BLE (1 << 7) -+#define ETH_BMR_DSL_BIT 2 -+#define ETH_BMR_DSL_MASK (0x1f << ETH_BMR_DSL_BIT) -+ #define ETH_BMR_DSL_0 (0x0 << ETH_BMR_DSL_BIT) -+ #define ETH_BMR_DSL_1 (0x1 << ETH_BMR_DSL_BIT) -+ #define ETH_BMR_DSL_2 (0x2 << ETH_BMR_DSL_BIT) -+ #define ETH_BMR_DSL_4 (0x4 << ETH_BMR_DSL_BIT) -+ #define ETH_BMR_DSL_8 (0x8 << ETH_BMR_DSL_BIT) -+#define ETH_BMR_SWR (1 << 0) -+ -+/* DMA Status Register (ETH_SR) */ -+ -+#define ETH_SR_EB_BIT 23 -+#define ETH_SR_EB_MASK (0x7 << ETH_SR_EB_BIT) -+ #define ETH_SR_EB_TX_ABORT (0x1 << ETH_SR_EB_BIT) -+ #define ETH_SR_EB_RX_ABORT (0x2 << ETH_SR_EB_BIT) -+#define ETH_SR_TS_BIT 20 -+#define ETH_SR_TS_MASK (0x7 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_STOP (0x0 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_FTD (0x1 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_WEOT (0x2 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_QDAT (0x3 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_SUSPEND (0x6 << ETH_SR_TS_BIT) -+ #define ETH_SR_TS_CTD (0x7 << ETH_SR_TS_BIT) -+#define ETH_SR_RS_BIT 17 -+#define ETH_SR_RS_MASK (0x7 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_STOP (0x0 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_FRD (0x1 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_CEOR (0x2 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_WRP (0x3 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_SUSPEND (0x4 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_CRD (0x5 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_FCF (0x6 << ETH_SR_RS_BIT) -+ #define ETH_SR_RS_QRF (0x7 << ETH_SR_RS_BIT) -+#define ETH_SR_NIS (1 << 16) -+#define ETH_SR_AIS (1 << 15) -+#define ETH_SR_ERI (1 << 14) -+#define ETH_SR_FBE (1 << 13) -+#define ETH_SR_ETI (1 << 10) -+#define ETH_SR_RWT (1 << 9) -+#define ETH_SR_RPS (1 << 8) -+#define ETH_SR_RU (1 << 7) -+#define ETH_SR_RI (1 << 6) -+#define ETH_SR_UNF (1 << 5) -+#define ETH_SR_TJT (1 << 3) -+#define ETH_SR_TU (1 << 2) -+#define ETH_SR_TPS (1 << 1) -+#define ETH_SR_TI (1 << 0) -+ -+/* Control (Operation Mode) Register (ETH_CR) */ -+ -+#define ETH_CR_TTM (1 << 22) -+#define ETH_CR_SF (1 << 21) -+#define ETH_CR_TR_BIT 14 -+#define ETH_CR_TR_MASK (0x3 << ETH_CR_TR_BIT) -+#define ETH_CR_ST (1 << 13) -+#define ETH_CR_OSF (1 << 2) -+#define ETH_CR_SR (1 << 1) -+ -+/* Interrupt Enable Register (ETH_IER) */ -+ -+#define ETH_IER_NI (1 << 16) -+#define ETH_IER_AI (1 << 15) -+#define ETH_IER_ERE (1 << 14) -+#define ETH_IER_FBE (1 << 13) -+#define ETH_IER_ET (1 << 10) -+#define ETH_IER_RWE (1 << 9) -+#define ETH_IER_RS (1 << 8) -+#define ETH_IER_RU (1 << 7) -+#define ETH_IER_RI (1 << 6) -+#define ETH_IER_UN (1 << 5) -+#define ETH_IER_TJ (1 << 3) -+#define ETH_IER_TU (1 << 2) -+#define ETH_IER_TS (1 << 1) -+#define ETH_IER_TI (1 << 0) -+ -+/* Missed Frame and Buffer Overflow Counter Register (ETH_MFCR) */ -+ -+#define ETH_MFCR_OVERFLOW_BIT 17 -+#define ETH_MFCR_OVERFLOW_MASK (0x7ff << ETH_MFCR_OVERFLOW_BIT) -+#define ETH_MFCR_MFC_BIT 0 -+#define ETH_MFCR_MFC_MASK (0xffff << ETH_MFCR_MFC_BIT) -+ -+/* MAC Control Register (ETH_MCR) */ -+ -+#define ETH_MCR_RA (1 << 31) -+#define ETH_MCR_HBD (1 << 28) -+#define ETH_MCR_PS (1 << 27) -+#define ETH_MCR_DRO (1 << 23) -+#define ETH_MCR_OM_BIT 21 -+#define ETH_MCR_OM_MASK (0x3 << ETH_MCR_OM_BIT) -+ #define ETH_MCR_OM_NORMAL (0x0 << ETH_MCR_OM_BIT) -+ #define ETH_MCR_OM_INTERNAL (0x1 << ETH_MCR_OM_BIT) -+ #define ETH_MCR_OM_EXTERNAL (0x2 << ETH_MCR_OM_BIT) -+#define ETH_MCR_F (1 << 20) -+#define ETH_MCR_PM (1 << 19) -+#define ETH_MCR_PR (1 << 18) -+#define ETH_MCR_IF (1 << 17) -+#define ETH_MCR_PB (1 << 16) -+#define ETH_MCR_HO (1 << 15) -+#define ETH_MCR_HP (1 << 13) -+#define ETH_MCR_LCC (1 << 12) -+#define ETH_MCR_DBF (1 << 11) -+#define ETH_MCR_DTRY (1 << 10) -+#define ETH_MCR_ASTP (1 << 8) -+#define ETH_MCR_BOLMT_BIT 6 -+#define ETH_MCR_BOLMT_MASK (0x3 << ETH_MCR_BOLMT_BIT) -+ #define ETH_MCR_BOLMT_10 (0 << ETH_MCR_BOLMT_BIT) -+ #define ETH_MCR_BOLMT_8 (1 << ETH_MCR_BOLMT_BIT) -+ #define ETH_MCR_BOLMT_4 (2 << ETH_MCR_BOLMT_BIT) -+ #define ETH_MCR_BOLMT_1 (3 << ETH_MCR_BOLMT_BIT) -+#define ETH_MCR_DC (1 << 5) -+#define ETH_MCR_TE (1 << 3) -+#define ETH_MCR_RE (1 << 2) -+ -+/* MII Address Register (ETH_MIAR) */ -+ -+#define ETH_MIAR_PHY_ADDR_BIT 11 -+#define ETH_MIAR_PHY_ADDR_MASK (0x1f << ETH_MIAR_PHY_ADDR_BIT) -+#define ETH_MIAR_MII_REG_BIT 6 -+#define ETH_MIAR_MII_REG_MASK (0x1f << ETH_MIAR_MII_REG_BIT) -+#define ETH_MIAR_MII_WRITE (1 << 1) -+#define ETH_MIAR_MII_BUSY (1 << 0) -+ -+/* Flow Control Register (ETH_FCR) */ -+ -+#define ETH_FCR_PAUSE_TIME_BIT 16 -+#define ETH_FCR_PAUSE_TIME_MASK (0xffff << ETH_FCR_PAUSE_TIME_BIT) -+#define ETH_FCR_PCF (1 << 2) -+#define ETH_FCR_FCE (1 << 1) -+#define ETH_FCR_BUSY (1 << 0) -+ -+/* PMT Control and Status Register (ETH_PMTR) */ -+ -+#define ETH_PMTR_GU (1 << 9) -+#define ETH_PMTR_RF (1 << 6) -+#define ETH_PMTR_MF (1 << 5) -+#define ETH_PMTR_RWK (1 << 2) -+#define ETH_PMTR_MPK (1 << 1) -+ -+/* Receive Descriptor 0 (ETH_RD0) Bits */ -+ -+#define ETH_RD0_OWN (1 << 31) -+#define ETH_RD0_FF (1 << 30) -+#define ETH_RD0_FL_BIT 16 -+#define ETH_RD0_FL_MASK (0x3fff << ETH_RD0_FL_BIT) -+#define ETH_RD0_ES (1 << 15) -+#define ETH_RD0_DE (1 << 14) -+#define ETH_RD0_LE (1 << 12) -+#define ETH_RD0_RF (1 << 11) -+#define ETH_RD0_MF (1 << 10) -+#define ETH_RD0_FD (1 << 9) -+#define ETH_RD0_LD (1 << 8) -+#define ETH_RD0_TL (1 << 7) -+#define ETH_RD0_CS (1 << 6) -+#define ETH_RD0_FT (1 << 5) -+#define ETH_RD0_WT (1 << 4) -+#define ETH_RD0_ME (1 << 3) -+#define ETH_RD0_DB (1 << 2) -+#define ETH_RD0_CE (1 << 1) -+ -+/* Receive Descriptor 1 (ETH_RD1) Bits */ -+ -+#define ETH_RD1_RER (1 << 25) -+#define ETH_RD1_RCH (1 << 24) -+#define ETH_RD1_RBS2_BIT 11 -+#define ETH_RD1_RBS2_MASK (0x7ff << ETH_RD1_RBS2_BIT) -+#define ETH_RD1_RBS1_BIT 0 -+#define ETH_RD1_RBS1_MASK (0x7ff << ETH_RD1_RBS1_BIT) -+ -+/* Transmit Descriptor 0 (ETH_TD0) Bits */ -+ -+#define ETH_TD0_OWN (1 << 31) -+#define ETH_TD0_FA (1 << 15) -+#define ETH_TD0_LOC (1 << 11) -+#define ETH_TD0_NC (1 << 10) -+#define ETH_TD0_LC (1 << 9) -+#define ETH_TD0_EC (1 << 8) -+#define ETH_TD0_HBF (1 << 7) -+#define ETH_TD0_CC_BIT 3 -+#define ETH_TD0_CC_MASK (0xf << ETH_TD0_CC_BIT) -+#define ETH_TD0_ED (1 << 2) -+#define ETH_TD0_UF (1 << 1) -+#define ETH_TD0_DF (1 << 0) -+ -+/* Transmit Descriptor 1 (ETH_TD1) Bits */ -+ -+#define ETH_TD1_IC (1 << 31) -+#define ETH_TD1_LS (1 << 30) -+#define ETH_TD1_FS (1 << 29) -+#define ETH_TD1_AC (1 << 26) -+#define ETH_TD1_TER (1 << 25) -+#define ETH_TD1_TCH (1 << 24) -+#define ETH_TD1_DPD (1 << 23) -+#define ETH_TD1_TBS2_BIT 11 -+#define ETH_TD1_TBS2_MASK (0x7ff << ETH_TD1_TBS2_BIT) -+#define ETH_TD1_TBS1_BIT 0 -+#define ETH_TD1_TBS1_MASK (0x7ff << ETH_TD1_TBS1_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * WDT -+ *************************************************************************/ -+#define WDT_WTCSR (WDT_BASE + 0x00) -+#define WDT_WTCNT (WDT_BASE + 0x04) -+ -+#define REG_WDT_WTCSR REG8(WDT_WTCSR) -+#define REG_WDT_WTCNT REG32(WDT_WTCNT) -+ -+#define WDT_WTCSR_START (1 << 4) -+ -+ -+ -+ -+/************************************************************************* -+ * OST -+ *************************************************************************/ -+#define OST_TER (OST_BASE + 0x00) -+#define OST_TRDR(n) (OST_BASE + 0x10 + ((n) * 0x20)) -+#define OST_TCNT(n) (OST_BASE + 0x14 + ((n) * 0x20)) -+#define OST_TCSR(n) (OST_BASE + 0x18 + ((n) * 0x20)) -+#define OST_TCRB(n) (OST_BASE + 0x1c + ((n) * 0x20)) -+ -+#define REG_OST_TER REG8(OST_TER) -+#define REG_OST_TRDR(n) REG32(OST_TRDR((n))) -+#define REG_OST_TCNT(n) REG32(OST_TCNT((n))) -+#define REG_OST_TCSR(n) REG16(OST_TCSR((n))) -+#define REG_OST_TCRB(n) REG32(OST_TCRB((n))) -+ -+#define OST_TCSR_BUSY (1 << 7) -+#define OST_TCSR_UF (1 << 6) -+#define OST_TCSR_UIE (1 << 5) -+#define OST_TCSR_CKS_BIT 0 -+#define OST_TCSR_CKS_MASK (0x07 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_PCLK_4 (0 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_PCLK_16 (1 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_PCLK_64 (2 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_PCLK_256 (3 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_RTCCLK (4 << OST_TCSR_CKS_BIT) -+ #define OST_TCSR_CKS_EXTAL (5 << OST_TCSR_CKS_BIT) -+ -+#define OST_TCSR0 OST_TCSR(0) -+#define OST_TCSR1 OST_TCSR(1) -+#define OST_TCSR2 OST_TCSR(2) -+#define OST_TRDR0 OST_TRDR(0) -+#define OST_TRDR1 OST_TRDR(1) -+#define OST_TRDR2 OST_TRDR(2) -+#define OST_TCNT0 OST_TCNT(0) -+#define OST_TCNT1 OST_TCNT(1) -+#define OST_TCNT2 OST_TCNT(2) -+#define OST_TCRB0 OST_TCRB(0) -+#define OST_TCRB1 OST_TCRB(1) -+#define OST_TCRB2 OST_TCRB(2) -+ -+/************************************************************************* -+ * UART -+ *************************************************************************/ -+ -+#define IRDA_BASE UART0_BASE -+#define UART_BASE UART0_BASE -+#define UART_OFF 0x1000 -+ -+/* register offset */ -+#define OFF_RDR (0x00) /* R 8b H'xx */ -+#define OFF_TDR (0x00) /* W 8b H'xx */ -+#define OFF_DLLR (0x00) /* RW 8b H'00 */ -+#define OFF_DLHR (0x04) /* RW 8b H'00 */ -+#define OFF_IER (0x04) /* RW 8b H'00 */ -+#define OFF_ISR (0x08) /* R 8b H'01 */ -+#define OFF_FCR (0x08) /* W 8b H'00 */ -+#define OFF_LCR (0x0C) /* RW 8b H'00 */ -+#define OFF_MCR (0x10) /* RW 8b H'00 */ -+#define OFF_LSR (0x14) /* R 8b H'00 */ -+#define OFF_MSR (0x18) /* R 8b H'00 */ -+#define OFF_SPR (0x1C) /* RW 8b H'00 */ -+#define OFF_MCR (0x10) /* RW 8b H'00 */ -+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ -+ -+/* register address */ -+#define UART0_RDR (UART0_BASE + OFF_RDR) -+#define UART0_TDR (UART0_BASE + OFF_TDR) -+#define UART0_DLLR (UART0_BASE + OFF_DLLR) -+#define UART0_DLHR (UART0_BASE + OFF_DLHR) -+#define UART0_IER (UART0_BASE + OFF_IER) -+#define UART0_ISR (UART0_BASE + OFF_ISR) -+#define UART0_FCR (UART0_BASE + OFF_FCR) -+#define UART0_LCR (UART0_BASE + OFF_LCR) -+#define UART0_MCR (UART0_BASE + OFF_MCR) -+#define UART0_LSR (UART0_BASE + OFF_LSR) -+#define UART0_MSR (UART0_BASE + OFF_MSR) -+#define UART0_SPR (UART0_BASE + OFF_SPR) -+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) -+ -+#define UART1_RDR (UART1_BASE + OFF_RDR) -+#define UART1_TDR (UART1_BASE + OFF_TDR) -+#define UART1_DLLR (UART1_BASE + OFF_DLLR) -+#define UART1_DLHR (UART1_BASE + OFF_DLHR) -+#define UART1_IER (UART1_BASE + OFF_IER) -+#define UART1_ISR (UART1_BASE + OFF_ISR) -+#define UART1_FCR (UART1_BASE + OFF_FCR) -+#define UART1_LCR (UART1_BASE + OFF_LCR) -+#define UART1_MCR (UART1_BASE + OFF_MCR) -+#define UART1_LSR (UART1_BASE + OFF_LSR) -+#define UART1_MSR (UART1_BASE + OFF_MSR) -+#define UART1_SPR (UART1_BASE + OFF_SPR) -+#define UART1_SIRCR (UART1_BASE + OFF_SIRCR) -+ -+#define UART2_RDR (UART2_BASE + OFF_RDR) -+#define UART2_TDR (UART2_BASE + OFF_TDR) -+#define UART2_DLLR (UART2_BASE + OFF_DLLR) -+#define UART2_DLHR (UART2_BASE + OFF_DLHR) -+#define UART2_IER (UART2_BASE + OFF_IER) -+#define UART2_ISR (UART2_BASE + OFF_ISR) -+#define UART2_FCR (UART2_BASE + OFF_FCR) -+#define UART2_LCR (UART2_BASE + OFF_LCR) -+#define UART2_MCR (UART2_BASE + OFF_MCR) -+#define UART2_LSR (UART2_BASE + OFF_LSR) -+#define UART2_MSR (UART2_BASE + OFF_MSR) -+#define UART2_SPR (UART2_BASE + OFF_SPR) -+#define UART2_SIRCR (UART2_BASE + OFF_SIRCR) -+ -+#define UART3_RDR (UART3_BASE + OFF_RDR) -+#define UART3_TDR (UART3_BASE + OFF_TDR) -+#define UART3_DLLR (UART3_BASE + OFF_DLLR) -+#define UART3_DLHR (UART3_BASE + OFF_DLHR) -+#define UART3_IER (UART3_BASE + OFF_IER) -+#define UART3_ISR (UART3_BASE + OFF_ISR) -+#define UART3_FCR (UART3_BASE + OFF_FCR) -+#define UART3_LCR (UART3_BASE + OFF_LCR) -+#define UART3_MCR (UART3_BASE + OFF_MCR) -+#define UART3_LSR (UART3_BASE + OFF_LSR) -+#define UART3_MSR (UART3_BASE + OFF_MSR) -+#define UART3_SPR (UART3_BASE + OFF_SPR) -+#define UART3_SIRCR (UART3_BASE + OFF_SIRCR) -+ -+/* -+ * Define macros for UARTIER -+ * UART Interrupt Enable Register -+ */ -+#define UARTIER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */ -+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */ -+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ -+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ -+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ -+ -+/* -+ * Define macros for UARTISR -+ * UART Interrupt Status Register -+ */ -+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ -+#define UARTISR_IID (7 << 1) /* Source of Interrupt */ -+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ -+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ -+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ -+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ -+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ -+#define UARTISR_FFMS_NO_FIFO (0 << 6) -+#define UARTISR_FFMS_FIFO_MODE (3 << 6) -+ -+/* -+ * Define macros for UARTFCR -+ * UART FIFO Control Register -+ */ -+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ -+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ -+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ -+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ -+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ -+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ -+#define UARTFCR_RTRG_1 (0 << 6) -+#define UARTFCR_RTRG_4 (1 << 6) -+#define UARTFCR_RTRG_8 (2 << 6) -+#define UARTFCR_RTRG_15 (3 << 6) -+ -+/* -+ * Define macros for UARTLCR -+ * UART Line Control Register -+ */ -+#define UARTLCR_WLEN (3 << 0) /* word length */ -+#define UARTLCR_WLEN_5 (0 << 0) -+#define UARTLCR_WLEN_6 (1 << 0) -+#define UARTLCR_WLEN_7 (2 << 0) -+#define UARTLCR_WLEN_8 (3 << 0) -+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 -+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ -+#define UARTLCR_PE (1 << 3) /* 0: parity disable */ -+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ -+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ -+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ -+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ -+ -+/* -+ * Define macros for UARTLSR -+ * UART Line Status Register -+ */ -+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ -+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ -+#define UARTLSR_PER (1 << 2) /* 0: no parity error */ -+#define UARTLSR_FER (1 << 3) /* 0; no framing error */ -+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ -+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ -+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ -+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ -+ -+/* -+ * Define macros for UARTMCR -+ * UART Modem Control Register -+ */ -+#define UARTMCR_DTR (1 << 0) /* 0: DTR_ ouput high */ -+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high */ -+#define UARTMCR_OUT1 (1 << 2) /* 0: UARTMSR.RI is set to 0 and RI_ input high */ -+#define UARTMCR_OUT2 (1 << 3) /* 0: UARTMSR.DCD is set to 0 and DCD_ input high */ -+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ -+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ -+ -+/* -+ * Define macros for UARTMSR -+ * UART Modem Status Register -+ */ -+#define UARTMSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UARTMSR */ -+#define UARTMSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UARTMSR */ -+#define UARTMSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UARTMSR */ -+#define UARTMSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UARTMSR */ -+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ -+#define UARTMSR_DSR (1 << 5) /* 0: DSR_ pin is high */ -+#define UARTMSR_RI (1 << 6) /* 0: RI_ pin is high */ -+#define UARTMSR_DCD (1 << 7) /* 0: DCD_ pin is high */ -+ -+/* -+ * Define macros for SIRCR -+ * Slow IrDA Control Register -+ */ -+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */ -+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */ -+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length -+ 1: 0 pulse width is 1.6us for 115.2Kbps */ -+#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ -+#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ -+ -+ -+ -+/************************************************************************* -+ * INTC -+ *************************************************************************/ -+#define INTC_ISR (INTC_BASE + 0x00) -+#define INTC_IMR (INTC_BASE + 0x04) -+#define INTC_IMSR (INTC_BASE + 0x08) -+#define INTC_IMCR (INTC_BASE + 0x0c) -+#define INTC_IPR (INTC_BASE + 0x10) -+ -+#define REG_INTC_ISR REG32(INTC_ISR) -+#define REG_INTC_IMR REG32(INTC_IMR) -+#define REG_INTC_IMSR REG32(INTC_IMSR) -+#define REG_INTC_IMCR REG32(INTC_IMCR) -+#define REG_INTC_IPR REG32(INTC_IPR) -+ -+#define IRQ_I2C 1 -+#define IRQ_PS2 2 -+#define IRQ_UPRT 3 -+#define IRQ_CORE 4 -+#define IRQ_UART3 6 -+#define IRQ_UART2 7 -+#define IRQ_UART1 8 -+#define IRQ_UART0 9 -+#define IRQ_SCC1 10 -+#define IRQ_SCC0 11 -+#define IRQ_UDC 12 -+#define IRQ_UHC 13 -+#define IRQ_MSC 14 -+#define IRQ_RTC 15 -+#define IRQ_FIR 16 -+#define IRQ_SSI 17 -+#define IRQ_CIM 18 -+#define IRQ_ETH 19 -+#define IRQ_AIC 20 -+#define IRQ_DMAC 21 -+#define IRQ_OST2 22 -+#define IRQ_OST1 23 -+#define IRQ_OST0 24 -+#define IRQ_GPIO3 25 -+#define IRQ_GPIO2 26 -+#define IRQ_GPIO1 27 -+#define IRQ_GPIO0 28 -+#define IRQ_LCD 30 -+ -+ -+ -+ -+/************************************************************************* -+ * CIM -+ *************************************************************************/ -+#define CIM_CFG (CIM_BASE + 0x0000) -+#define CIM_CTRL (CIM_BASE + 0x0004) -+#define CIM_STATE (CIM_BASE + 0x0008) -+#define CIM_IID (CIM_BASE + 0x000C) -+#define CIM_RXFIFO (CIM_BASE + 0x0010) -+#define CIM_DA (CIM_BASE + 0x0020) -+#define CIM_FA (CIM_BASE + 0x0024) -+#define CIM_FID (CIM_BASE + 0x0028) -+#define CIM_CMD (CIM_BASE + 0x002C) -+ -+#define REG_CIM_CFG REG32(CIM_CFG) -+#define REG_CIM_CTRL REG32(CIM_CTRL) -+#define REG_CIM_STATE REG32(CIM_STATE) -+#define REG_CIM_IID REG32(CIM_IID) -+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) -+#define REG_CIM_DA REG32(CIM_DA) -+#define REG_CIM_FA REG32(CIM_FA) -+#define REG_CIM_FID REG32(CIM_FID) -+#define REG_CIM_CMD REG32(CIM_CMD) -+ -+/* CIM Configuration Register (CIM_CFG) */ -+ -+#define CIM_CFG_INV_DAT (1 << 15) -+#define CIM_CFG_VSP (1 << 14) -+#define CIM_CFG_HSP (1 << 13) -+#define CIM_CFG_PCP (1 << 12) -+#define CIM_CFG_DUMMY_ZERO (1 << 9) -+#define CIM_CFG_EXT_VSYNC (1 << 8) -+#define CIM_CFG_PACK_BIT 4 -+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) -+#define CIM_CFG_DSM_BIT 0 -+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) -+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ -+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ -+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ -+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ -+ -+/* CIM Control Register (CIM_CTRL) */ -+ -+#define CIM_CTRL_MCLKDIV_BIT 24 -+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) -+#define CIM_CTRL_FRC_BIT 16 -+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) -+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ -+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ -+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ -+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ -+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ -+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ -+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ -+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ -+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ -+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ -+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ -+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ -+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ -+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ -+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ -+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ -+#define CIM_CTRL_VDDM (1 << 13) -+#define CIM_CTRL_DMA_SOFM (1 << 12) -+#define CIM_CTRL_DMA_EOFM (1 << 11) -+#define CIM_CTRL_DMA_STOPM (1 << 10) -+#define CIM_CTRL_RXF_TRIGM (1 << 9) -+#define CIM_CTRL_RXF_OFM (1 << 8) -+#define CIM_CTRL_RXF_TRIG_BIT 4 -+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) -+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ -+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ -+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ -+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ -+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ -+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ -+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ -+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ -+#define CIM_CTRL_DMA_EN (1 << 2) -+#define CIM_CTRL_RXF_RST (1 << 1) -+#define CIM_CTRL_ENA (1 << 0) -+ -+/* CIM State Register (CIM_STATE) */ -+ -+#define CIM_STATE_DMA_SOF (1 << 6) -+#define CIM_STATE_DMA_EOF (1 << 5) -+#define CIM_STATE_DMA_STOP (1 << 4) -+#define CIM_STATE_RXF_OF (1 << 3) -+#define CIM_STATE_RXF_TRIG (1 << 2) -+#define CIM_STATE_RXF_EMPTY (1 << 1) -+#define CIM_STATE_VDD (1 << 0) -+ -+/* CIM DMA Command Register (CIM_CMD) */ -+ -+#define CIM_CMD_SOFINT (1 << 31) -+#define CIM_CMD_EOFINT (1 << 30) -+#define CIM_CMD_STOP (1 << 28) -+#define CIM_CMD_LEN_BIT 0 -+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * PWM -+ *************************************************************************/ -+#define PWM_CTR(n) (PWM##n##_BASE + 0x000) -+#define PWM_PER(n) (PWM##n##_BASE + 0x004) -+#define PWM_DUT(n) (PWM##n##_BASE + 0x008) -+ -+#define REG_PWM_CTR(n) REG8(PWM_CTR(n)) -+#define REG_PWM_PER(n) REG16(PWM_PER(n)) -+#define REG_PWM_DUT(n) REG16(PWM_DUT(n)) -+ -+/* PWM Control Register (PWM_CTR) */ -+ -+#define PWM_CTR_EN (1 << 7) -+#define PWM_CTR_SD (1 << 6) -+#define PWM_CTR_PRESCALE_BIT 0 -+#define PWM_CTR_PRESCALE_MASK (0x3f << PWM_CTR_PRESCALE_BIT) -+ -+/* PWM Period Register (PWM_PER) */ -+ -+#define PWM_PER_PERIOD_BIT 0 -+#define PWM_PER_PERIOD_MASK (0x3ff << PWM_PER_PERIOD_BIT) -+ -+/* PWM Duty Register (PWM_DUT) */ -+ -+#define PWM_DUT_FDUTY (1 << 10) -+#define PWM_DUT_DUTY_BIT 0 -+#define PWM_DUT_DUTY_MASK (0x3ff << PWM_DUT_DUTY_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * EMC -+ *************************************************************************/ -+#define EMC_BCR (EMC_BASE + 0x00) -+#define EMC_SMCR0 (EMC_BASE + 0x10) -+#define EMC_SMCR1 (EMC_BASE + 0x14) -+#define EMC_SMCR2 (EMC_BASE + 0x18) -+#define EMC_SMCR3 (EMC_BASE + 0x1c) -+#define EMC_SMCR4 (EMC_BASE + 0x20) -+#define EMC_SMCR5 (EMC_BASE + 0x24) -+#define EMC_SMCR6 (EMC_BASE + 0x28) -+#define EMC_SMCR7 (EMC_BASE + 0x2c) -+#define EMC_SACR0 (EMC_BASE + 0x30) -+#define EMC_SACR1 (EMC_BASE + 0x34) -+#define EMC_SACR2 (EMC_BASE + 0x38) -+#define EMC_SACR3 (EMC_BASE + 0x3c) -+#define EMC_SACR4 (EMC_BASE + 0x40) -+#define EMC_SACR5 (EMC_BASE + 0x44) -+#define EMC_SACR6 (EMC_BASE + 0x48) -+#define EMC_SACR7 (EMC_BASE + 0x4c) -+#define EMC_NFCSR (EMC_BASE + 0x50) -+#define EMC_NFECC (EMC_BASE + 0x54) -+#define EMC_PCCR1 (EMC_BASE + 0x60) -+#define EMC_PCCR2 (EMC_BASE + 0x64) -+#define EMC_PCCR3 (EMC_BASE + 0x68) -+#define EMC_PCCR4 (EMC_BASE + 0x6c) -+#define EMC_DMCR (EMC_BASE + 0x80) -+#define EMC_RTCSR (EMC_BASE + 0x84) -+#define EMC_RTCNT (EMC_BASE + 0x88) -+#define EMC_RTCOR (EMC_BASE + 0x8c) -+#define EMC_DMAR1 (EMC_BASE + 0x90) -+#define EMC_DMAR2 (EMC_BASE + 0x94) -+#define EMC_DMAR3 (EMC_BASE + 0x98) -+#define EMC_DMAR4 (EMC_BASE + 0x9c) -+ -+#define EMC_SDMR0 (EMC_BASE + 0xa000) -+#define EMC_SDMR1 (EMC_BASE + 0xb000) -+#define EMC_SDMR2 (EMC_BASE + 0xc000) -+#define EMC_SDMR3 (EMC_BASE + 0xd000) -+ -+#define REG_EMC_BCR REG32(EMC_BCR) -+#define REG_EMC_SMCR0 REG32(EMC_SMCR0) -+#define REG_EMC_SMCR1 REG32(EMC_SMCR1) -+#define REG_EMC_SMCR2 REG32(EMC_SMCR2) -+#define REG_EMC_SMCR3 REG32(EMC_SMCR3) -+#define REG_EMC_SMCR4 REG32(EMC_SMCR4) -+#define REG_EMC_SMCR5 REG32(EMC_SMCR5) -+#define REG_EMC_SMCR6 REG32(EMC_SMCR6) -+#define REG_EMC_SMCR7 REG32(EMC_SMCR7) -+#define REG_EMC_SACR0 REG32(EMC_SACR0) -+#define REG_EMC_SACR1 REG32(EMC_SACR1) -+#define REG_EMC_SACR2 REG32(EMC_SACR2) -+#define REG_EMC_SACR3 REG32(EMC_SACR3) -+#define REG_EMC_SACR4 REG32(EMC_SACR4) -+#define REG_EMC_SACR5 REG32(EMC_SACR5) -+#define REG_EMC_SACR6 REG32(EMC_SACR6) -+#define REG_EMC_SACR7 REG32(EMC_SACR7) -+#define REG_EMC_NFCSR REG32(EMC_NFCSR) -+#define REG_EMC_NFECC REG32(EMC_NFECC) -+#define REG_EMC_DMCR REG32(EMC_DMCR) -+#define REG_EMC_RTCSR REG16(EMC_RTCSR) -+#define REG_EMC_RTCNT REG16(EMC_RTCNT) -+#define REG_EMC_RTCOR REG16(EMC_RTCOR) -+#define REG_EMC_DMAR1 REG32(EMC_DMAR1) -+#define REG_EMC_DMAR2 REG32(EMC_DMAR2) -+#define REG_EMC_DMAR3 REG32(EMC_DMAR3) -+#define REG_EMC_DMAR4 REG32(EMC_DMAR4) -+#define REG_EMC_PCCR1 REG32(EMC_PCCR1) -+#define REG_EMC_PCCR2 REG32(EMC_PCCR2) -+#define REG_EMC_PCCR3 REG32(EMC_PCCR3) -+#define REG_EMC_PCCR4 REG32(EMC_PCCR4) -+ -+ -+#define EMC_BCR_BRE (1 << 1) -+ -+#define EMC_SMCR_STRV_BIT 24 -+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) -+#define EMC_SMCR_TAW_BIT 20 -+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) -+#define EMC_SMCR_TBP_BIT 16 -+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) -+#define EMC_SMCR_TAH_BIT 12 -+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) -+#define EMC_SMCR_TAS_BIT 8 -+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) -+#define EMC_SMCR_BW_BIT 6 -+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) -+#define EMC_SMCR_BCM (1 << 3) -+#define EMC_SMCR_BL_BIT 1 -+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) -+#define EMC_SMCR_SMT (1 << 0) -+ -+#define EMC_SACR_BASE_BIT 8 -+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) -+#define EMC_SACR_MASK_BIT 0 -+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) -+ -+#define EMC_NFCSR_RB (1 << 7) -+#define EMC_NFCSR_BOOT_SEL_BIT 4 -+#define EMC_NFCSR_BOOT_SEL_MASK (0x07 << EMC_NFCSR_BOOT_SEL_BIT) -+#define EMC_NFCSR_ERST (1 << 3) -+#define EMC_NFCSR_ECCE (1 << 2) -+#define EMC_NFCSR_FCE (1 << 1) -+#define EMC_NFCSR_NFE (1 << 0) -+ -+#define EMC_NFECC_ECC2_BIT 16 -+#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) -+#define EMC_NFECC_ECC1_BIT 8 -+#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) -+#define EMC_NFECC_ECC0_BIT 0 -+#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) -+ -+#define EMC_DMCR_BW_BIT 31 -+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) -+#define EMC_DMCR_CA_BIT 26 -+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) -+#define EMC_DMCR_RMODE (1 << 25) -+#define EMC_DMCR_RFSH (1 << 24) -+#define EMC_DMCR_MRSET (1 << 23) -+#define EMC_DMCR_RA_BIT 20 -+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) -+#define EMC_DMCR_BA_BIT 19 -+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) -+#define EMC_DMCR_PDM (1 << 18) -+#define EMC_DMCR_EPIN (1 << 17) -+#define EMC_DMCR_TRAS_BIT 13 -+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) -+#define EMC_DMCR_RCD_BIT 11 -+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) -+#define EMC_DMCR_TPC_BIT 8 -+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) -+#define EMC_DMCR_TRWL_BIT 5 -+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) -+#define EMC_DMCR_TRC_BIT 2 -+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) -+#define EMC_DMCR_TCL_BIT 0 -+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) -+ -+#define EMC_RTCSR_CMF (1 << 7) -+#define EMC_RTCSR_CKS_BIT 0 -+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) -+ -+#define EMC_DMAR_BASE_BIT 8 -+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) -+#define EMC_DMAR_MASK_BIT 0 -+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) -+ -+#define EMC_SDMR_BM (1 << 9) -+#define EMC_SDMR_OM_BIT 7 -+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) -+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) -+#define EMC_SDMR_CAS_BIT 4 -+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) -+#define EMC_SDMR_BT_BIT 3 -+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) -+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) -+ #define EMC_SDMR_BT_INTR (1 << EMC_SDMR_BT_BIT) -+#define EMC_SDMR_BL_BIT 0 -+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) -+ -+#define EMC_SDMR_CAS2_16BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS2_32BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+#define EMC_SDMR_CAS3_16BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS3_32BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+ -+#define EMC_PCCR12_AMW (1 << 31) -+#define EMC_PCCR12_AMAS_BIT 28 -+#define EMC_PCCR12_AMAS_MASK (0x07 << EMC_PCCR12_AMAS_BIT) -+#define EMC_PCCR12_AMAH_BIT 24 -+#define EMC_PCCR12_AMAH_MASK (0x07 << EMC_PCCR12_AMAH_BIT) -+#define EMC_PCCR12_AMPW_BIT 20 -+#define EMC_PCCR12_AMPW_MASK (0x0f << EMC_PCCR12_AMPW_BIT) -+#define EMC_PCCR12_AMRT_BIT 16 -+#define EMC_PCCR12_AMRT_MASK (0x0f << EMC_PCCR12_AMRT_BIT) -+#define EMC_PCCR12_CMW (1 << 15) -+#define EMC_PCCR12_CMAS_BIT 12 -+#define EMC_PCCR12_CMAS_MASK (0x07 << EMC_PCCR12_CMAS_BIT) -+#define EMC_PCCR12_CMAH_BIT 8 -+#define EMC_PCCR12_CMAH_MASK (0x07 << EMC_PCCR12_CMAH_BIT) -+#define EMC_PCCR12_CMPW_BIT 4 -+#define EMC_PCCR12_CMPW_MASK (0x0f << EMC_PCCR12_CMPW_BIT) -+#define EMC_PCCR12_CMRT_BIT 0 -+#define EMC_PCCR12_CMRT_MASK (0x07 << EMC_PCCR12_CMRT_BIT) -+ -+#define EMC_PCCR34_DRS_BIT 16 -+#define EMC_PCCR34_DRS_MASK (0x03 << EMC_PCCR34_DRS_BIT) -+ #define EMC_PCCR34_DRS_SPKR (1 << EMC_PCCR34_DRS_BIT) -+ #define EMC_PCCR34_DRS_IOIS16 (2 << EMC_PCCR34_DRS_BIT) -+ #define EMC_PCCR34_DRS_INPACK (3 << EMC_PCCR34_DRS_BIT) -+#define EMC_PCCR34_IOIS16 (1 << 15) -+#define EMC_PCCR34_IOW (1 << 14) -+#define EMC_PCCR34_TCB_BIT 12 -+#define EMC_PCCR34_TCB_MASK (0x03 << EMC_PCCR34_TCB_BIT) -+#define EMC_PCCR34_IORT_BIT 8 -+#define EMC_PCCR34_IORT_MASK (0x07 << EMC_PCCR34_IORT_BIT) -+#define EMC_PCCR34_IOAE_BIT 6 -+#define EMC_PCCR34_IOAE_MASK (0x03 << EMC_PCCR34_IOAE_BIT) -+ #define EMC_PCCR34_IOAE_NONE (0 << EMC_PCCR34_IOAE_BIT) -+ #define EMC_PCCR34_IOAE_1 (1 << EMC_PCCR34_IOAE_BIT) -+ #define EMC_PCCR34_IOAE_2 (2 << EMC_PCCR34_IOAE_BIT) -+ #define EMC_PCCR34_IOAE_5 (3 << EMC_PCCR34_IOAE_BIT) -+#define EMC_PCCR34_IOAH_BIT 4 -+#define EMC_PCCR34_IOAH_MASK (0x03 << EMC_PCCR34_IOAH_BIT) -+ #define EMC_PCCR34_IOAH_NONE (0 << EMC_PCCR34_IOAH_BIT) -+ #define EMC_PCCR34_IOAH_1 (1 << EMC_PCCR34_IOAH_BIT) -+ #define EMC_PCCR34_IOAH_2 (2 << EMC_PCCR34_IOAH_BIT) -+ #define EMC_PCCR34_IOAH_5 (3 << EMC_PCCR34_IOAH_BIT) -+#define EMC_PCCR34_IOPW_BIT 0 -+#define EMC_PCCR34_IOPW_MASK (0x0f << EMC_PCCR34_IOPW_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * GPIO -+ *************************************************************************/ -+#define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30)) -+#define GPIO_GPDIR(n) (GPIO_BASE + (0x04 + (n)*0x30)) -+#define GPIO_GPODR(n) (GPIO_BASE + (0x08 + (n)*0x30)) -+#define GPIO_GPPUR(n) (GPIO_BASE + (0x0c + (n)*0x30)) -+#define GPIO_GPALR(n) (GPIO_BASE + (0x10 + (n)*0x30)) -+#define GPIO_GPAUR(n) (GPIO_BASE + (0x14 + (n)*0x30)) -+#define GPIO_GPIDLR(n) (GPIO_BASE + (0x18 + (n)*0x30)) -+#define GPIO_GPIDUR(n) (GPIO_BASE + (0x1c + (n)*0x30)) -+#define GPIO_GPIER(n) (GPIO_BASE + (0x20 + (n)*0x30)) -+#define GPIO_GPIMR(n) (GPIO_BASE + (0x24 + (n)*0x30)) -+#define GPIO_GPFR(n) (GPIO_BASE + (0x28 + (n)*0x30)) -+ -+#define REG_GPIO_GPDR(n) REG32(GPIO_GPDR((n))) -+#define REG_GPIO_GPDIR(n) REG32(GPIO_GPDIR((n))) -+#define REG_GPIO_GPODR(n) REG32(GPIO_GPODR((n))) -+#define REG_GPIO_GPPUR(n) REG32(GPIO_GPPUR((n))) -+#define REG_GPIO_GPALR(n) REG32(GPIO_GPALR((n))) -+#define REG_GPIO_GPAUR(n) REG32(GPIO_GPAUR((n))) -+#define REG_GPIO_GPIDLR(n) REG32(GPIO_GPIDLR((n))) -+#define REG_GPIO_GPIDUR(n) REG32(GPIO_GPIDUR((n))) -+#define REG_GPIO_GPIER(n) REG32(GPIO_GPIER((n))) -+#define REG_GPIO_GPIMR(n) REG32(GPIO_GPIMR((n))) -+#define REG_GPIO_GPFR(n) REG32(GPIO_GPFR((n))) -+ -+#define GPIO_IRQ_LOLEVEL 0 -+#define GPIO_IRQ_HILEVEL 1 -+#define GPIO_IRQ_FALLEDG 2 -+#define GPIO_IRQ_RAISEDG 3 -+ -+#define IRQ_GPIO_0 48 -+#define NUM_GPIO 128 -+ -+#define GPIO_GPDR0 GPIO_GPDR(0) -+#define GPIO_GPDR1 GPIO_GPDR(1) -+#define GPIO_GPDR2 GPIO_GPDR(2) -+#define GPIO_GPDR3 GPIO_GPDR(3) -+#define GPIO_GPDIR0 GPIO_GPDIR(0) -+#define GPIO_GPDIR1 GPIO_GPDIR(1) -+#define GPIO_GPDIR2 GPIO_GPDIR(2) -+#define GPIO_GPDIR3 GPIO_GPDIR(3) -+#define GPIO_GPODR0 GPIO_GPODR(0) -+#define GPIO_GPODR1 GPIO_GPODR(1) -+#define GPIO_GPODR2 GPIO_GPODR(2) -+#define GPIO_GPODR3 GPIO_GPODR(3) -+#define GPIO_GPPUR0 GPIO_GPPUR(0) -+#define GPIO_GPPUR1 GPIO_GPPUR(1) -+#define GPIO_GPPUR2 GPIO_GPPUR(2) -+#define GPIO_GPPUR3 GPIO_GPPUR(3) -+#define GPIO_GPALR0 GPIO_GPALR(0) -+#define GPIO_GPALR1 GPIO_GPALR(1) -+#define GPIO_GPALR2 GPIO_GPALR(2) -+#define GPIO_GPALR3 GPIO_GPALR(3) -+#define GPIO_GPAUR0 GPIO_GPAUR(0) -+#define GPIO_GPAUR1 GPIO_GPAUR(1) -+#define GPIO_GPAUR2 GPIO_GPAUR(2) -+#define GPIO_GPAUR3 GPIO_GPAUR(3) -+#define GPIO_GPIDLR0 GPIO_GPIDLR(0) -+#define GPIO_GPIDLR1 GPIO_GPIDLR(1) -+#define GPIO_GPIDLR2 GPIO_GPIDLR(2) -+#define GPIO_GPIDLR3 GPIO_GPIDLR(3) -+#define GPIO_GPIDUR0 GPIO_GPIDUR(0) -+#define GPIO_GPIDUR1 GPIO_GPIDUR(1) -+#define GPIO_GPIDUR2 GPIO_GPIDUR(2) -+#define GPIO_GPIDUR3 GPIO_GPIDUR(3) -+#define GPIO_GPIER0 GPIO_GPIER(0) -+#define GPIO_GPIER1 GPIO_GPIER(1) -+#define GPIO_GPIER2 GPIO_GPIER(2) -+#define GPIO_GPIER3 GPIO_GPIER(3) -+#define GPIO_GPIMR0 GPIO_GPIMR(0) -+#define GPIO_GPIMR1 GPIO_GPIMR(1) -+#define GPIO_GPIMR2 GPIO_GPIMR(2) -+#define GPIO_GPIMR3 GPIO_GPIMR(3) -+#define GPIO_GPFR0 GPIO_GPFR(0) -+#define GPIO_GPFR1 GPIO_GPFR(1) -+#define GPIO_GPFR2 GPIO_GPFR(2) -+#define GPIO_GPFR3 GPIO_GPFR(3) -+ -+ -+/************************************************************************* -+ * HARB -+ *************************************************************************/ -+#define HARB_HAPOR (HARB_BASE + 0x000) -+#define HARB_HMCTR (HARB_BASE + 0x010) -+#define HARB_HME8H (HARB_BASE + 0x014) -+#define HARB_HMCR1 (HARB_BASE + 0x018) -+#define HARB_HMER2 (HARB_BASE + 0x01C) -+#define HARB_HMER3 (HARB_BASE + 0x020) -+#define HARB_HMLTR (HARB_BASE + 0x024) -+ -+#define REG_HARB_HAPOR REG32(HARB_HAPOR) -+#define REG_HARB_HMCTR REG32(HARB_HMCTR) -+#define REG_HARB_HME8H REG32(HARB_HME8H) -+#define REG_HARB_HMCR1 REG32(HARB_HMCR1) -+#define REG_HARB_HMER2 REG32(HARB_HMER2) -+#define REG_HARB_HMER3 REG32(HARB_HMER3) -+#define REG_HARB_HMLTR REG32(HARB_HMLTR) -+ -+/* HARB Priority Order Register (HARB_HAPOR) */ -+ -+#define HARB_HAPOR_UCHSEL (1 << 7) -+#define HARB_HAPOR_PRIO_BIT 0 -+#define HARB_HAPOR_PRIO_MASK (0xf << HARB_HAPOR_PRIO_BIT) -+ -+/* AHB Monitor Control Register (HARB_HMCTR) */ -+ -+#define HARB_HMCTR_HET3_BIT 20 -+#define HARB_HMCTR_HET3_MASK (0xf << HARB_HMCTR_HET3_BIT) -+#define HARB_HMCTR_HMS3_BIT 16 -+#define HARB_HMCTR_HMS3_MASK (0xf << HARB_HMCTR_HMS3_BIT) -+#define HARB_HMCTR_HET2_BIT 12 -+#define HARB_HMCTR_HET2_MASK (0xf << HARB_HMCTR_HET2_BIT) -+#define HARB_HMCTR_HMS2_BIT 8 -+#define HARB_HMCTR_HMS2_MASK (0xf << HARB_HMCTR_HMS2_BIT) -+#define HARB_HMCTR_HOVF3 (1 << 7) -+#define HARB_HMCTR_HOVF2 (1 << 6) -+#define HARB_HMCTR_HOVF1 (1 << 5) -+#define HARB_HMCTR_HRST (1 << 4) -+#define HARB_HMCTR_HEE3 (1 << 2) -+#define HARB_HMCTR_HEE2 (1 << 1) -+#define HARB_HMCTR_HEE1 (1 << 0) -+ -+/* AHB Monitor Event 8bits High Register (HARB_HME8H) */ -+ -+#define HARB_HME8H_HC8H1_BIT 16 -+#define HARB_HME8H_HC8H1_MASK (0xff << HARB_HME8H_HC8H1_BIT) -+#define HARB_HME8H_HC8H2_BIT 8 -+#define HARB_HME8H_HC8H2_MASK (0xff << HARB_HME8H_HC8H2_BIT) -+#define HARB_HME8H_HC8H3_BIT 0 -+#define HARB_HME8H_HC8H3_MASK (0xff << HARB_HME8H_HC8H3_BIT) -+ -+/* AHB Monitor Latency Register (HARB_HMLTR) */ -+ -+#define HARB_HMLTR_HLT2_BIT 16 -+#define HARB_HMLTR_HLT2_MASK (0xffff << HARB_HMLTR_HLT2_BIT) -+#define HARB_HMLTR_HLT3_BIT 0 -+#define HARB_HMLTR_HLT3_MASK (0xffff << HARB_HMLTR_HLT3_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * I2C -+ *************************************************************************/ -+#define I2C_DR (I2C_BASE + 0x000) -+#define I2C_CR (I2C_BASE + 0x004) -+#define I2C_SR (I2C_BASE + 0x008) -+#define I2C_GR (I2C_BASE + 0x00C) -+ -+#define REG_I2C_DR REG8(I2C_DR) -+#define REG_I2C_CR REG8(I2C_CR) -+#define REG_I2C_SR REG8(I2C_SR) -+#define REG_I2C_GR REG16(I2C_GR) -+ -+/* I2C Control Register (I2C_CR) */ -+ -+#define I2C_CR_IEN (1 << 4) -+#define I2C_CR_STA (1 << 3) -+#define I2C_CR_STO (1 << 2) -+#define I2C_CR_AC (1 << 1) -+#define I2C_CR_I2CE (1 << 0) -+ -+/* I2C Status Register (I2C_SR) */ -+ -+#define I2C_SR_STX (1 << 4) -+#define I2C_SR_BUSY (1 << 3) -+#define I2C_SR_TEND (1 << 2) -+#define I2C_SR_DRF (1 << 1) -+#define I2C_SR_ACKF (1 << 0) -+ -+ -+ -+ -+/************************************************************************* -+ * UDC -+ *************************************************************************/ -+#define UDC_EP0InCR (UDC_BASE + 0x00) -+#define UDC_EP0InSR (UDC_BASE + 0x04) -+#define UDC_EP0InBSR (UDC_BASE + 0x08) -+#define UDC_EP0InMPSR (UDC_BASE + 0x0c) -+#define UDC_EP0InDesR (UDC_BASE + 0x14) -+#define UDC_EP1InCR (UDC_BASE + 0x20) -+#define UDC_EP1InSR (UDC_BASE + 0x24) -+#define UDC_EP1InBSR (UDC_BASE + 0x28) -+#define UDC_EP1InMPSR (UDC_BASE + 0x2c) -+#define UDC_EP1InDesR (UDC_BASE + 0x34) -+#define UDC_EP2InCR (UDC_BASE + 0x40) -+#define UDC_EP2InSR (UDC_BASE + 0x44) -+#define UDC_EP2InBSR (UDC_BASE + 0x48) -+#define UDC_EP2InMPSR (UDC_BASE + 0x4c) -+#define UDC_EP2InDesR (UDC_BASE + 0x54) -+#define UDC_EP3InCR (UDC_BASE + 0x60) -+#define UDC_EP3InSR (UDC_BASE + 0x64) -+#define UDC_EP3InBSR (UDC_BASE + 0x68) -+#define UDC_EP3InMPSR (UDC_BASE + 0x6c) -+#define UDC_EP3InDesR (UDC_BASE + 0x74) -+#define UDC_EP4InCR (UDC_BASE + 0x80) -+#define UDC_EP4InSR (UDC_BASE + 0x84) -+#define UDC_EP4InBSR (UDC_BASE + 0x88) -+#define UDC_EP4InMPSR (UDC_BASE + 0x8c) -+#define UDC_EP4InDesR (UDC_BASE + 0x94) -+ -+#define UDC_EP0OutCR (UDC_BASE + 0x200) -+#define UDC_EP0OutSR (UDC_BASE + 0x204) -+#define UDC_EP0OutPFNR (UDC_BASE + 0x208) -+#define UDC_EP0OutMPSR (UDC_BASE + 0x20c) -+#define UDC_EP0OutSBPR (UDC_BASE + 0x210) -+#define UDC_EP0OutDesR (UDC_BASE + 0x214) -+#define UDC_EP5OutCR (UDC_BASE + 0x2a0) -+#define UDC_EP5OutSR (UDC_BASE + 0x2a4) -+#define UDC_EP5OutPFNR (UDC_BASE + 0x2a8) -+#define UDC_EP5OutMPSR (UDC_BASE + 0x2ac) -+#define UDC_EP5OutDesR (UDC_BASE + 0x2b4) -+#define UDC_EP6OutCR (UDC_BASE + 0x2c0) -+#define UDC_EP6OutSR (UDC_BASE + 0x2c4) -+#define UDC_EP6OutPFNR (UDC_BASE + 0x2c8) -+#define UDC_EP6OutMPSR (UDC_BASE + 0x2cc) -+#define UDC_EP6OutDesR (UDC_BASE + 0x2d4) -+#define UDC_EP7OutCR (UDC_BASE + 0x2e0) -+#define UDC_EP7OutSR (UDC_BASE + 0x2e4) -+#define UDC_EP7OutPFNR (UDC_BASE + 0x2e8) -+#define UDC_EP7OutMPSR (UDC_BASE + 0x2ec) -+#define UDC_EP7OutDesR (UDC_BASE + 0x2f4) -+ -+#define UDC_DevCFGR (UDC_BASE + 0x400) -+#define UDC_DevCR (UDC_BASE + 0x404) -+#define UDC_DevSR (UDC_BASE + 0x408) -+#define UDC_DevIntR (UDC_BASE + 0x40c) -+#define UDC_DevIntMR (UDC_BASE + 0x410) -+#define UDC_EPIntR (UDC_BASE + 0x414) -+#define UDC_EPIntMR (UDC_BASE + 0x418) -+ -+#define UDC_STCMAR (UDC_BASE + 0x500) -+#define UDC_EP0InfR (UDC_BASE + 0x504) -+#define UDC_EP1InfR (UDC_BASE + 0x508) -+#define UDC_EP2InfR (UDC_BASE + 0x50c) -+#define UDC_EP3InfR (UDC_BASE + 0x510) -+#define UDC_EP4InfR (UDC_BASE + 0x514) -+#define UDC_EP5InfR (UDC_BASE + 0x518) -+#define UDC_EP6InfR (UDC_BASE + 0x51c) -+#define UDC_EP7InfR (UDC_BASE + 0x520) -+ -+#define UDC_TXCONFIRM (UDC_BASE + 0x41C) -+#define UDC_TXZLP (UDC_BASE + 0x420) -+#define UDC_RXCONFIRM (UDC_BASE + 0x41C) -+ -+#define UDC_RXFIFO (UDC_BASE + 0x800) -+#define UDC_TXFIFOEP0 (UDC_BASE + 0x840) -+ -+#define REG_UDC_EP0InCR REG32(UDC_EP0InCR) -+#define REG_UDC_EP0InSR REG32(UDC_EP0InSR) -+#define REG_UDC_EP0InBSR REG32(UDC_EP0InBSR) -+#define REG_UDC_EP0InMPSR REG32(UDC_EP0InMPSR) -+#define REG_UDC_EP0InDesR REG32(UDC_EP0InDesR) -+#define REG_UDC_EP1InCR REG32(UDC_EP1InCR) -+#define REG_UDC_EP1InSR REG32(UDC_EP1InSR) -+#define REG_UDC_EP1InBSR REG32(UDC_EP1InBSR) -+#define REG_UDC_EP1InMPSR REG32(UDC_EP1InMPSR) -+#define REG_UDC_EP1InDesR REG32(UDC_EP1InDesR) -+#define REG_UDC_EP2InCR REG32(UDC_EP2InCR) -+#define REG_UDC_EP2InSR REG32(UDC_EP2InSR) -+#define REG_UDC_EP2InBSR REG32(UDC_EP2InBSR) -+#define REG_UDC_EP2InMPSR REG32(UDC_EP2InMPSR) -+#define REG_UDC_EP2InDesR REG32(UDC_EP2InDesR) -+#define REG_UDC_EP3InCR REG32(UDC_EP3InCR) -+#define REG_UDC_EP3InSR REG32(UDC_EP3InSR) -+#define REG_UDC_EP3InBSR REG32(UDC_EP3InBSR) -+#define REG_UDC_EP3InMPSR REG32(UDC_EP3InMPSR) -+#define REG_UDC_EP3InDesR REG32(UDC_EP3InDesR) -+#define REG_UDC_EP4InCR REG32(UDC_EP4InCR) -+#define REG_UDC_EP4InSR REG32(UDC_EP4InSR) -+#define REG_UDC_EP4InBSR REG32(UDC_EP4InBSR) -+#define REG_UDC_EP4InMPSR REG32(UDC_EP4InMPSR) -+#define REG_UDC_EP4InDesR REG32(UDC_EP4InDesR) -+ -+#define REG_UDC_EP0OutCR REG32(UDC_EP0OutCR) -+#define REG_UDC_EP0OutSR REG32(UDC_EP0OutSR) -+#define REG_UDC_EP0OutPFNR REG32(UDC_EP0OutPFNR) -+#define REG_UDC_EP0OutMPSR REG32(UDC_EP0OutMPSR) -+#define REG_UDC_EP0OutSBPR REG32(UDC_EP0OutSBPR) -+#define REG_UDC_EP0OutDesR REG32(UDC_EP0OutDesR) -+#define REG_UDC_EP5OutCR REG32(UDC_EP5OutCR) -+#define REG_UDC_EP5OutSR REG32(UDC_EP5OutSR) -+#define REG_UDC_EP5OutPFNR REG32(UDC_EP5OutPFNR) -+#define REG_UDC_EP5OutMPSR REG32(UDC_EP5OutMPSR) -+#define REG_UDC_EP5OutDesR REG32(UDC_EP5OutDesR) -+#define REG_UDC_EP6OutCR REG32(UDC_EP6OutCR) -+#define REG_UDC_EP6OutSR REG32(UDC_EP6OutSR) -+#define REG_UDC_EP6OutPFNR REG32(UDC_EP6OutPFNR) -+#define REG_UDC_EP6OutMPSR REG32(UDC_EP6OutMPSR) -+#define REG_UDC_EP6OutDesR REG32(UDC_EP6OutDesR) -+#define REG_UDC_EP7OutCR REG32(UDC_EP7OutCR) -+#define REG_UDC_EP7OutSR REG32(UDC_EP7OutSR) -+#define REG_UDC_EP7OutPFNR REG32(UDC_EP7OutPFNR) -+#define REG_UDC_EP7OutMPSR REG32(UDC_EP7OutMPSR) -+#define REG_UDC_EP7OutDesR REG32(UDC_EP7OutDesR) -+ -+#define REG_UDC_DevCFGR REG32(UDC_DevCFGR) -+#define REG_UDC_DevCR REG32(UDC_DevCR) -+#define REG_UDC_DevSR REG32(UDC_DevSR) -+#define REG_UDC_DevIntR REG32(UDC_DevIntR) -+#define REG_UDC_DevIntMR REG32(UDC_DevIntMR) -+#define REG_UDC_EPIntR REG32(UDC_EPIntR) -+#define REG_UDC_EPIntMR REG32(UDC_EPIntMR) -+ -+#define REG_UDC_STCMAR REG32(UDC_STCMAR) -+#define REG_UDC_EP0InfR REG32(UDC_EP0InfR) -+#define REG_UDC_EP1InfR REG32(UDC_EP1InfR) -+#define REG_UDC_EP2InfR REG32(UDC_EP2InfR) -+#define REG_UDC_EP3InfR REG32(UDC_EP3InfR) -+#define REG_UDC_EP4InfR REG32(UDC_EP4InfR) -+#define REG_UDC_EP5InfR REG32(UDC_EP5InfR) -+#define REG_UDC_EP6InfR REG32(UDC_EP6InfR) -+#define REG_UDC_EP7InfR REG32(UDC_EP7InfR) -+ -+#define UDC_DevCFGR_PI (1 << 5) -+#define UDC_DevCFGR_SS (1 << 4) -+#define UDC_DevCFGR_SP (1 << 3) -+#define UDC_DevCFGR_RW (1 << 2) -+#define UDC_DevCFGR_SPD_BIT 0 -+#define UDC_DevCFGR_SPD_MASK (0x03 << UDC_DevCFGR_SPD_BIT) -+ #define UDC_DevCFGR_SPD_HS (0 << UDC_DevCFGR_SPD_BIT) -+ #define UDC_DevCFGR_SPD_LS (2 << UDC_DevCFGR_SPD_BIT) -+ #define UDC_DevCFGR_SPD_FS (3 << UDC_DevCFGR_SPD_BIT) -+ -+#define UDC_DevCR_DM (1 << 9) -+#define UDC_DevCR_BE (1 << 5) -+#define UDC_DevCR_RES (1 << 0) -+ -+#define UDC_DevSR_ENUMSPD_BIT 13 -+#define UDC_DevSR_ENUMSPD_MASK (0x03 << UDC_DevSR_ENUMSPD_BIT) -+ #define UDC_DevSR_ENUMSPD_HS (0 << UDC_DevSR_ENUMSPD_BIT) -+ #define UDC_DevSR_ENUMSPD_LS (2 << UDC_DevSR_ENUMSPD_BIT) -+ #define UDC_DevSR_ENUMSPD_FS (3 << UDC_DevSR_ENUMSPD_BIT) -+#define UDC_DevSR_SUSP (1 << 12) -+#define UDC_DevSR_ALT_BIT 8 -+#define UDC_DevSR_ALT_MASK (0x0f << UDC_DevSR_ALT_BIT) -+#define UDC_DevSR_INTF_BIT 4 -+#define UDC_DevSR_INTF_MASK (0x0f << UDC_DevSR_INTF_BIT) -+#define UDC_DevSR_CFG_BIT 0 -+#define UDC_DevSR_CFG_MASK (0x0f << UDC_DevSR_CFG_BIT) -+ -+#define UDC_DevIntR_ENUM (1 << 6) -+#define UDC_DevIntR_SOF (1 << 5) -+#define UDC_DevIntR_US (1 << 4) -+#define UDC_DevIntR_UR (1 << 3) -+#define UDC_DevIntR_SI (1 << 1) -+#define UDC_DevIntR_SC (1 << 0) -+ -+#define UDC_EPIntR_OUTEP_BIT 16 -+#define UDC_EPIntR_OUTEP_MASK (0xffff << UDC_EPIntR_OUTEP_BIT) -+#define UDC_EPIntR_OUTEP0 0x00010000 -+#define UDC_EPIntR_OUTEP5 0x00200000 -+#define UDC_EPIntR_OUTEP6 0x00400000 -+#define UDC_EPIntR_OUTEP7 0x00800000 -+#define UDC_EPIntR_INEP_BIT 0 -+#define UDC_EPIntR_INEP_MASK (0xffff << UDC_EPIntR_INEP_BIT) -+#define UDC_EPIntR_INEP0 0x00000001 -+#define UDC_EPIntR_INEP1 0x00000002 -+#define UDC_EPIntR_INEP2 0x00000004 -+#define UDC_EPIntR_INEP3 0x00000008 -+#define UDC_EPIntR_INEP4 0x00000010 -+ -+ -+#define UDC_EPIntMR_OUTEP_BIT 16 -+#define UDC_EPIntMR_OUTEP_MASK (0xffff << UDC_EPIntMR_OUTEP_BIT) -+#define UDC_EPIntMR_INEP_BIT 0 -+#define UDC_EPIntMR_INEP_MASK (0xffff << UDC_EPIntMR_INEP_BIT) -+ -+#define UDC_EPCR_ET_BIT 4 -+#define UDC_EPCR_ET_MASK (0x03 << UDC_EPCR_ET_BIT) -+ #define UDC_EPCR_ET_CTRL (0 << UDC_EPCR_ET_BIT) -+ #define UDC_EPCR_ET_ISO (1 << UDC_EPCR_ET_BIT) -+ #define UDC_EPCR_ET_BULK (2 << UDC_EPCR_ET_BIT) -+ #define UDC_EPCR_ET_INTR (3 << UDC_EPCR_ET_BIT) -+#define UDC_EPCR_SN (1 << 2) -+#define UDC_EPCR_F (1 << 1) -+#define UDC_EPCR_S (1 << 0) -+ -+#define UDC_EPSR_RXPKTSIZE_BIT 11 -+#define UDC_EPSR_RXPKTSIZE_MASK (0x7ff << UDC_EPSR_RXPKTSIZE_BIT) -+#define UDC_EPSR_IN (1 << 6) -+#define UDC_EPSR_OUT_BIT 4 -+#define UDC_EPSR_OUT_MASK (0x03 << UDC_EPSR_OUT_BIT) -+ #define UDC_EPSR_OUT_NONE (0 << UDC_EPSR_OUT_BIT) -+ #define UDC_EPSR_OUT_RCVDATA (1 << UDC_EPSR_OUT_BIT) -+ #define UDC_EPSR_OUT_RCVSETUP (2 << UDC_EPSR_OUT_BIT) -+#define UDC_EPSR_PID_BIT 0 -+#define UDC_EPSR_PID_MASK (0x0f << UDC_EPSR_PID_BIT) -+ -+#define UDC_EPInfR_MPS_BIT 19 -+#define UDC_EPInfR_MPS_MASK (0x3ff << UDC_EPInfR_MPS_BIT) -+#define UDC_EPInfR_ALTS_BIT 15 -+#define UDC_EPInfR_ALTS_MASK (0x0f << UDC_EPInfR_ALTS_BIT) -+#define UDC_EPInfR_IFN_BIT 11 -+#define UDC_EPInfR_IFN_MASK (0x0f << UDC_EPInfR_IFN_BIT) -+#define UDC_EPInfR_CGN_BIT 7 -+#define UDC_EPInfR_CGN_MASK (0x0f << UDC_EPInfR_CGN_BIT) -+#define UDC_EPInfR_EPT_BIT 5 -+#define UDC_EPInfR_EPT_MASK (0x03 << UDC_EPInfR_EPT_BIT) -+ #define UDC_EPInfR_EPT_CTRL (0 << UDC_EPInfR_EPT_BIT) -+ #define UDC_EPInfR_EPT_ISO (1 << UDC_EPInfR_EPT_BIT) -+ #define UDC_EPInfR_EPT_BULK (2 << UDC_EPInfR_EPT_BIT) -+ #define UDC_EPInfR_EPT_INTR (3 << UDC_EPInfR_EPT_BIT) -+#define UDC_EPInfR_EPD (1 << 4) -+ #define UDC_EPInfR_EPD_OUT (0 << 4) -+ #define UDC_EPInfR_EPD_IN (1 << 4) -+ -+#define UDC_EPInfR_EPN_BIT 0 -+#define UDC_EPInfR_EPN_MASK (0xf << UDC_EPInfR_EPN_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * DMAC -+ *************************************************************************/ -+#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) -+#define DMAC_DDAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) -+#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) -+#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) -+#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) -+#define DMAC_DMAIPR (DMAC_BASE + 0xf8) -+#define DMAC_DMACR (DMAC_BASE + 0xfc) -+ -+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) -+#define REG_DMAC_DDAR(n) REG32(DMAC_DDAR((n))) -+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) -+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) -+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) -+#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) -+#define REG_DMAC_DMACR REG32(DMAC_DMACR) -+ -+#define DMAC_DRSR_RS_BIT 0 -+#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_EXTREXTR (0 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_PCMCIAOUT (4 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_PCMCIAIN (5 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_DESOUT (10 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_DESIN (11 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART3OUT (14 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART3IN (15 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART2OUT (16 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART2IN (17 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART1OUT (18 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART1IN (19 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_OST2 (28 << DMAC_DRSR_RS_BIT) -+ -+#define DMAC_DCCSR_EACKS (1 << 31) -+#define DMAC_DCCSR_EACKM (1 << 30) -+#define DMAC_DCCSR_ERDM_BIT 28 -+#define DMAC_DCCSR_ERDM_MASK (0x03 << DMAC_DCCSR_ERDM_BIT) -+ #define DMAC_DCCSR_ERDM_LLEVEL (0 << DMAC_DCCSR_ERDM_BIT) -+ #define DMAC_DCCSR_ERDM_FEDGE (1 << DMAC_DCCSR_ERDM_BIT) -+ #define DMAC_DCCSR_ERDM_HLEVEL (2 << DMAC_DCCSR_ERDM_BIT) -+ #define DMAC_DCCSR_ERDM_REDGE (3 << DMAC_DCCSR_ERDM_BIT) -+#define DMAC_DCCSR_EOPM (1 << 27) -+#define DMAC_DCCSR_SAM (1 << 23) -+#define DMAC_DCCSR_DAM (1 << 22) -+#define DMAC_DCCSR_RDIL_BIT 16 -+#define DMAC_DCCSR_RDIL_MASK (0x0f << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_IGN (0 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_2 (1 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_4 (2 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_8 (3 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_12 (4 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_16 (5 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_20 (6 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_24 (7 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_28 (8 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_32 (9 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_48 (10 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_60 (11 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_64 (12 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_124 (13 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_128 (14 << DMAC_DCCSR_RDIL_BIT) -+ #define DMAC_DCCSR_RDIL_200 (15 << DMAC_DCCSR_RDIL_BIT) -+#define DMAC_DCCSR_SWDH_BIT 14 -+#define DMAC_DCCSR_SWDH_MASK (0x03 << DMAC_DCCSR_SWDH_BIT) -+ #define DMAC_DCCSR_SWDH_32 (0 << DMAC_DCCSR_SWDH_BIT) -+ #define DMAC_DCCSR_SWDH_8 (1 << DMAC_DCCSR_SWDH_BIT) -+ #define DMAC_DCCSR_SWDH_16 (2 << DMAC_DCCSR_SWDH_BIT) -+#define DMAC_DCCSR_DWDH_BIT 12 -+#define DMAC_DCCSR_DWDH_MASK (0x03 << DMAC_DCCSR_DWDH_BIT) -+ #define DMAC_DCCSR_DWDH_32 (0 << DMAC_DCCSR_DWDH_BIT) -+ #define DMAC_DCCSR_DWDH_8 (1 << DMAC_DCCSR_DWDH_BIT) -+ #define DMAC_DCCSR_DWDH_16 (2 << DMAC_DCCSR_DWDH_BIT) -+#define DMAC_DCCSR_DS_BIT 8 -+#define DMAC_DCCSR_DS_MASK (0x07 << DMAC_DCCSR_DS_BIT) -+ #define DMAC_DCCSR_DS_32b (0 << DMAC_DCCSR_DS_BIT) -+ #define DMAC_DCCSR_DS_8b (1 << DMAC_DCCSR_DS_BIT) -+ #define DMAC_DCCSR_DS_16b (2 << DMAC_DCCSR_DS_BIT) -+ #define DMAC_DCCSR_DS_16B (3 << DMAC_DCCSR_DS_BIT) -+ #define DMAC_DCCSR_DS_32B (4 << DMAC_DCCSR_DS_BIT) -+#define DMAC_DCCSR_TM (1 << 7) -+#define DMAC_DCCSR_AR (1 << 4) -+#define DMAC_DCCSR_TC (1 << 3) -+#define DMAC_DCCSR_HLT (1 << 2) -+#define DMAC_DCCSR_TCIE (1 << 1) -+#define DMAC_DCCSR_CHDE (1 << 0) -+ -+#define DMAC_DMAIPR_CINT_BIT 8 -+#define DMAC_DMAIPR_CINT_MASK (0xff << DMAC_DMAIPR_CINT_BIT) -+ -+#define DMAC_DMACR_PR_BIT 8 -+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_01234567 (0 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_02314675 (1 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_20136457 (2 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_ROUNDROBIN (3 << DMAC_DMACR_PR_BIT) -+#define DMAC_DMACR_HTR (1 << 3) -+#define DMAC_DMACR_AER (1 << 2) -+#define DMAC_DMACR_DME (1 << 0) -+ -+#define IRQ_DMA_0 32 -+#define NUM_DMA 6 -+ -+#define DMAC_DSAR0 DMAC_DSAR(0) -+#define DMAC_DDAR0 DMAC_DDAR(0) -+#define DMAC_DTCR0 DMAC_DTCR(0) -+#define DMAC_DRSR0 DMAC_DRSR(0) -+#define DMAC_DCCSR0 DMAC_DCCSR(0) -+ -+#define DMAC_DSAR1 DMAC_DSAR(1) -+#define DMAC_DDAR1 DMAC_DDAR(1) -+#define DMAC_DTCR1 DMAC_DTCR(1) -+#define DMAC_DRSR1 DMAC_DRSR(1) -+#define DMAC_DCCSR1 DMAC_DCCSR(1) -+ -+#define DMAC_DSAR2 DMAC_DSAR(2) -+#define DMAC_DDAR2 DMAC_DDAR(2) -+#define DMAC_DTCR2 DMAC_DTCR(2) -+#define DMAC_DRSR2 DMAC_DRSR(2) -+#define DMAC_DCCSR2 DMAC_DCCSR(2) -+ -+#define DMAC_DSAR3 DMAC_DSAR(3) -+#define DMAC_DDAR3 DMAC_DDAR(3) -+#define DMAC_DTCR3 DMAC_DTCR(3) -+#define DMAC_DRSR3 DMAC_DRSR(3) -+#define DMAC_DCCSR3 DMAC_DCCSR(3) -+ -+#define DMAC_DSAR4 DMAC_DSAR(4) -+#define DMAC_DDAR4 DMAC_DDAR(4) -+#define DMAC_DTCR4 DMAC_DTCR(4) -+#define DMAC_DRSR4 DMAC_DRSR(4) -+#define DMAC_DCCSR4 DMAC_DCCSR(4) -+ -+#define DMAC_DSAR5 DMAC_DSAR(5) -+#define DMAC_DDAR5 DMAC_DDAR(5) -+#define DMAC_DTCR5 DMAC_DTCR(5) -+#define DMAC_DRSR5 DMAC_DRSR(5) -+#define DMAC_DCCSR5 DMAC_DCCSR(5) -+ -+#define DMAC_DSAR6 DMAC_DSAR(6) -+#define DMAC_DDAR6 DMAC_DDAR(6) -+#define DMAC_DTCR6 DMAC_DTCR(6) -+#define DMAC_DRSR6 DMAC_DRSR(6) -+#define DMAC_DCCSR6 DMAC_DCCSR(6) -+ -+#define DMAC_DSAR7 DMAC_DSAR(7) -+#define DMAC_DDAR7 DMAC_DDAR(7) -+#define DMAC_DTCR7 DMAC_DTCR(7) -+#define DMAC_DRSR7 DMAC_DRSR(7) -+#define DMAC_DCCSR7 DMAC_DCCSR(7) -+ -+ -+ -+/************************************************************************* -+ * AIC -+ *************************************************************************/ -+#define AIC_FR (AIC_BASE + 0x000) -+#define AIC_CR (AIC_BASE + 0x004) -+#define AIC_ACCR1 (AIC_BASE + 0x008) -+#define AIC_ACCR2 (AIC_BASE + 0x00C) -+#define AIC_I2SCR (AIC_BASE + 0x010) -+#define AIC_SR (AIC_BASE + 0x014) -+#define AIC_ACSR (AIC_BASE + 0x018) -+#define AIC_I2SSR (AIC_BASE + 0x01C) -+#define AIC_ACCAR (AIC_BASE + 0x020) -+#define AIC_ACCDR (AIC_BASE + 0x024) -+#define AIC_ACSAR (AIC_BASE + 0x028) -+#define AIC_ACSDR (AIC_BASE + 0x02C) -+#define AIC_I2SDIV (AIC_BASE + 0x030) -+#define AIC_DR (AIC_BASE + 0x034) -+ -+#define REG_AIC_FR REG32(AIC_FR) -+#define REG_AIC_CR REG32(AIC_CR) -+#define REG_AIC_ACCR1 REG32(AIC_ACCR1) -+#define REG_AIC_ACCR2 REG32(AIC_ACCR2) -+#define REG_AIC_I2SCR REG32(AIC_I2SCR) -+#define REG_AIC_SR REG32(AIC_SR) -+#define REG_AIC_ACSR REG32(AIC_ACSR) -+#define REG_AIC_I2SSR REG32(AIC_I2SSR) -+#define REG_AIC_ACCAR REG32(AIC_ACCAR) -+#define REG_AIC_ACCDR REG32(AIC_ACCDR) -+#define REG_AIC_ACSAR REG32(AIC_ACSAR) -+#define REG_AIC_ACSDR REG32(AIC_ACSDR) -+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) -+#define REG_AIC_DR REG32(AIC_DR) -+ -+/* AIC Controller Configuration Register (AIC_FR) */ -+ -+#define AIC_FR_RFTH_BIT 12 -+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) -+#define AIC_FR_TFTH_BIT 8 -+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) -+#define AIC_FR_AUSEL (1 << 4) -+#define AIC_FR_RST (1 << 3) -+#define AIC_FR_BCKD (1 << 2) -+#define AIC_FR_SYNCD (1 << 1) -+#define AIC_FR_ENB (1 << 0) -+ -+/* AIC Controller Common Control Register (AIC_CR) */ -+ -+#define AIC_CR_RDMS (1 << 15) -+#define AIC_CR_TDMS (1 << 14) -+#define AIC_CR_FLUSH (1 << 8) -+#define AIC_CR_EROR (1 << 6) -+#define AIC_CR_ETUR (1 << 5) -+#define AIC_CR_ERFS (1 << 4) -+#define AIC_CR_ETFS (1 << 3) -+#define AIC_CR_ENLBF (1 << 2) -+#define AIC_CR_ERPL (1 << 1) -+#define AIC_CR_EREC (1 << 0) -+ -+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ -+ -+#define AIC_ACCR1_RS_BIT 16 -+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) -+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit */ -+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit */ -+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit */ -+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit */ -+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit */ -+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit */ -+#define AIC_ACCR1_XS_BIT 0 -+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) -+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit */ -+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit */ -+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit */ -+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit */ -+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit */ -+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit */ -+ -+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ -+ -+#define AIC_ACCR2_ERSTO (1 << 18) -+#define AIC_ACCR2_ESADR (1 << 17) -+#define AIC_ACCR2_ECADT (1 << 16) -+#define AIC_ACCR2_OASS_BIT 8 -+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) -+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_IASS_BIT 6 -+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) -+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_SO (1 << 3) -+#define AIC_ACCR2_SR (1 << 2) -+#define AIC_ACCR2_SS (1 << 1) -+#define AIC_ACCR2_SA (1 << 0) -+ -+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ -+ -+#define AIC_I2SCR_STPBK (1 << 12) -+#define AIC_I2SCR_WL_BIT 1 -+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) -+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ -+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ -+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ -+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ -+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ -+#define AIC_I2SCR_AMSL (1 << 0) -+ -+/* AIC Controller FIFO Status Register (AIC_SR) */ -+ -+#define AIC_SR_RFL_BIT 24 -+#define AIC_SR_RFL_MASK (0x1f << AIC_SR_RFL_BIT) -+#define AIC_SR_TFL_BIT 8 -+#define AIC_SR_TFL_MASK (0x1f << AIC_SR_TFL_BIT) -+#define AIC_SR_ROR (1 << 6) -+#define AIC_SR_TUR (1 << 5) -+#define AIC_SR_RFS (1 << 4) -+#define AIC_SR_TFS (1 << 3) -+ -+/* AIC Controller AC-link Status Register (AIC_ACSR) */ -+ -+#define AIC_ACSR_CRDY (1 << 20) -+#define AIC_ACSR_CLPM (1 << 19) -+#define AIC_ACSR_RSTO (1 << 18) -+#define AIC_ACSR_SADR (1 << 17) -+#define AIC_ACSR_CADT (1 << 16) -+ -+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ -+ -+#define AIC_I2SSR_BSY (1 << 2) -+ -+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ -+ -+#define AIC_ACCAR_CAR_BIT 0 -+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) -+ -+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ -+ -+#define AIC_ACCDR_CDR_BIT 0 -+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) -+ -+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ -+ -+#define AIC_ACSAR_SAR_BIT 0 -+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) -+ -+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ -+ -+#define AIC_ACSDR_SDR_BIT 0 -+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) -+ -+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ -+ -+#define AIC_I2SDIV_DIV_BIT 0 -+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) -+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ -+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ -+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ -+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ -+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ -+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ -+ -+ -+ -+ -+/************************************************************************* -+ * LCD -+ *************************************************************************/ -+#define LCD_CFG (LCD_BASE + 0x00) -+#define LCD_VSYNC (LCD_BASE + 0x04) -+#define LCD_HSYNC (LCD_BASE + 0x08) -+#define LCD_VAT (LCD_BASE + 0x0c) -+#define LCD_DAH (LCD_BASE + 0x10) -+#define LCD_DAV (LCD_BASE + 0x14) -+#define LCD_PS (LCD_BASE + 0x18) -+#define LCD_CLS (LCD_BASE + 0x1c) -+#define LCD_SPL (LCD_BASE + 0x20) -+#define LCD_REV (LCD_BASE + 0x24) -+#define LCD_CTRL (LCD_BASE + 0x30) -+#define LCD_STATE (LCD_BASE + 0x34) -+#define LCD_IID (LCD_BASE + 0x38) -+#define LCD_DA0 (LCD_BASE + 0x40) -+#define LCD_SA0 (LCD_BASE + 0x44) -+#define LCD_FID0 (LCD_BASE + 0x48) -+#define LCD_CMD0 (LCD_BASE + 0x4c) -+#define LCD_DA1 (LCD_BASE + 0x50) -+#define LCD_SA1 (LCD_BASE + 0x54) -+#define LCD_FID1 (LCD_BASE + 0x58) -+#define LCD_CMD1 (LCD_BASE + 0x5c) -+ -+#define REG_LCD_CFG REG32(LCD_CFG) -+#define REG_LCD_VSYNC REG32(LCD_VSYNC) -+#define REG_LCD_HSYNC REG32(LCD_HSYNC) -+#define REG_LCD_VAT REG32(LCD_VAT) -+#define REG_LCD_DAH REG32(LCD_DAH) -+#define REG_LCD_DAV REG32(LCD_DAV) -+#define REG_LCD_PS REG32(LCD_PS) -+#define REG_LCD_CLS REG32(LCD_CLS) -+#define REG_LCD_SPL REG32(LCD_SPL) -+#define REG_LCD_REV REG32(LCD_REV) -+#define REG_LCD_CTRL REG32(LCD_CTRL) -+#define REG_LCD_STATE REG32(LCD_STATE) -+#define REG_LCD_IID REG32(LCD_IID) -+#define REG_LCD_DA0 REG32(LCD_DA0) -+#define REG_LCD_SA0 REG32(LCD_SA0) -+#define REG_LCD_FID0 REG32(LCD_FID0) -+#define REG_LCD_CMD0 REG32(LCD_CMD0) -+#define REG_LCD_DA1 REG32(LCD_DA1) -+#define REG_LCD_SA1 REG32(LCD_SA1) -+#define REG_LCD_FID1 REG32(LCD_FID1) -+#define REG_LCD_CMD1 REG32(LCD_CMD1) -+ -+#define LCD_CFG_PDW_BIT 4 -+#define LCD_CFG_PDW_MASK (0x03 << LCD_DEV_PDW_BIT) -+ #define LCD_CFG_PDW_1 (0 << LCD_DEV_PDW_BIT) -+ #define LCD_CFG_PDW_2 (1 << LCD_DEV_PDW_BIT) -+ #define LCD_CFG_PDW_4 (2 << LCD_DEV_PDW_BIT) -+ #define LCD_CFG_PDW_8 (3 << LCD_DEV_PDW_BIT) -+#define LCD_CFG_MODE_BIT 0 -+#define LCD_CFG_MODE_MASK (0x0f << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_DEV_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_DEV_MODE_BIT) -+ -+#define LCD_VSYNC_VPS_BIT 16 -+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) -+#define LCD_VSYNC_VPE_BIT 0 -+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) -+ -+#define LCD_HSYNC_HPS_BIT 16 -+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) -+#define LCD_HSYNC_HPE_BIT 0 -+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) -+ -+#define LCD_VAT_HT_BIT 16 -+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) -+#define LCD_VAT_VT_BIT 0 -+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) -+ -+#define LCD_DAH_HDS_BIT 16 -+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) -+#define LCD_DAH_HDE_BIT 0 -+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) -+ -+#define LCD_DAV_VDS_BIT 16 -+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) -+#define LCD_DAV_VDE_BIT 0 -+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) -+ -+#define LCD_CTRL_BST_BIT 28 -+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) -+#define LCD_CTRL_RGB555 (1 << 27) -+#define LCD_CTRL_OFUP (1 << 26) -+#define LCD_CTRL_FRC_BIT 24 -+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) -+#define LCD_CTRL_PDD_BIT 16 -+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) -+#define LCD_CTRL_EOFM (1 << 13) -+#define LCD_CTRL_SOFM (1 << 12) -+#define LCD_CTRL_OFUM (1 << 11) -+#define LCD_CTRL_IFUM0 (1 << 10) -+#define LCD_CTRL_IFUM1 (1 << 9) -+#define LCD_CTRL_LDDM (1 << 8) -+#define LCD_CTRL_QDM (1 << 7) -+#define LCD_CTRL_BEDN (1 << 6) -+#define LCD_CTRL_PEDN (1 << 5) -+#define LCD_CTRL_DIS (1 << 4) -+#define LCD_CTRL_ENA (1 << 3) -+#define LCD_CTRL_BPP_BIT 0 -+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) -+ -+#define LCD_STATE_QD (1 << 7) -+#define LCD_STATE_EOF (1 << 5) -+#define LCD_STATE_SOF (1 << 4) -+#define LCD_STATE_OFU (1 << 3) -+#define LCD_STATE_IFU0 (1 << 2) -+#define LCD_STATE_IFU1 (1 << 1) -+#define LCD_STATE_LDD (1 << 0) -+ -+#define LCD_CMD_SOFINT (1 << 31) -+#define LCD_CMD_EOFINT (1 << 30) -+#define LCD_CMD_PAL (1 << 28) -+#define LCD_CMD_LEN_BIT 0 -+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * DES -+ *************************************************************************/ -+#define DES_CR1 (DES_BASE + 0x000) -+#define DES_CR2 (DES_BASE + 0x004) -+#define DES_SR (DES_BASE + 0x008) -+#define DES_K1L (DES_BASE + 0x010) -+#define DES_K1R (DES_BASE + 0x014) -+#define DES_K2L (DES_BASE + 0x018) -+#define DES_K2R (DES_BASE + 0x01C) -+#define DES_K3L (DES_BASE + 0x020) -+#define DES_K3R (DES_BASE + 0x024) -+#define DES_IVL (DES_BASE + 0x028) -+#define DES_IVR (DES_BASE + 0x02C) -+#define DES_DIN (DES_BASE + 0x030) -+#define DES_DOUT (DES_BASE + 0x034) -+ -+#define REG_DES_CR1 REG32(DES_CR1) -+#define REG_DES_CR2 REG32(DES_CR2) -+#define REG_DES_SR REG32(DES_SR) -+#define REG_DES_K1L REG32(DES_K1L) -+#define REG_DES_K1R REG32(DES_K1R) -+#define REG_DES_K2L REG32(DES_K2L) -+#define REG_DES_K2R REG32(DES_K2R) -+#define REG_DES_K3L REG32(DES_K3L) -+#define REG_DES_K3R REG32(DES_K3R) -+#define REG_DES_IVL REG32(DES_IVL) -+#define REG_DES_IVR REG32(DES_IVR) -+#define REG_DES_DIN REG32(DES_DIN) -+#define REG_DES_DOUT REG32(DES_DOUT) -+ -+/* DES Control Register 1 (DES_CR1) */ -+ -+#define DES_CR1_EN (1 << 0) -+ -+/* DES Control Register 2 (DES_CR2) */ -+ -+#define DES_CR2_ENDEC (1 << 3) -+#define DES_CR2_MODE (1 << 2) -+#define DES_CR2_ALG (1 << 1) -+#define DES_CR2_DMAE (1 << 0) -+ -+/* DES State Register (DES_SR) */ -+ -+#define DES_SR_IN_FULL (1 << 5) -+#define DES_SR_IN_LHF (1 << 4) -+#define DES_SR_IN_EMPTY (1 << 3) -+#define DES_SR_OUT_FULL (1 << 2) -+#define DES_SR_OUT_GHF (1 << 1) -+#define DES_SR_OUT_EMPTY (1 << 0) -+ -+ -+ -+ -+/************************************************************************* -+ * CPM -+ *************************************************************************/ -+#define CPM_CFCR (CPM_BASE+0x00) -+#define CPM_PLCR1 (CPM_BASE+0x10) -+#define CPM_OCR (CPM_BASE+0x1c) -+#define CPM_CFCR2 (CPM_BASE+0x60) -+#define CPM_LPCR (CPM_BASE+0x04) -+#define CPM_RSTR (CPM_BASE+0x08) -+#define CPM_MSCR (CPM_BASE+0x20) -+#define CPM_SCR (CPM_BASE+0x24) -+#define CPM_WRER (CPM_BASE+0x28) -+#define CPM_WFER (CPM_BASE+0x2c) -+#define CPM_WER (CPM_BASE+0x30) -+#define CPM_WSR (CPM_BASE+0x34) -+#define CPM_GSR0 (CPM_BASE+0x38) -+#define CPM_GSR1 (CPM_BASE+0x3c) -+#define CPM_GSR2 (CPM_BASE+0x40) -+#define CPM_SPR (CPM_BASE+0x44) -+#define CPM_GSR3 (CPM_BASE+0x48) -+ -+#define REG_CPM_CFCR REG32(CPM_CFCR) -+#define REG_CPM_PLCR1 REG32(CPM_PLCR1) -+#define REG_CPM_OCR REG32(CPM_OCR) -+#define REG_CPM_CFCR2 REG32(CPM_CFCR2) -+#define REG_CPM_LPCR REG32(CPM_LPCR) -+#define REG_CPM_RSTR REG32(CPM_RSTR) -+#define REG_CPM_MSCR REG32(CPM_MSCR) -+#define REG_CPM_SCR REG32(CPM_SCR) -+#define REG_CPM_WRER REG32(CPM_WRER) -+#define REG_CPM_WFER REG32(CPM_WFER) -+#define REG_CPM_WER REG32(CPM_WER) -+#define REG_CPM_WSR REG32(CPM_WSR) -+#define REG_CPM_GSR0 REG32(CPM_GSR0) -+#define REG_CPM_GSR1 REG32(CPM_GSR1) -+#define REG_CPM_GSR2 REG32(CPM_GSR2) -+#define REG_CPM_SPR REG32(CPM_SPR) -+#define REG_CPM_GSR3 REG32(CPM_GSR3) -+ -+#define CPM_CFCR_SSI (1 << 31) -+#define CPM_CFCR_LCD (1 << 30) -+#define CPM_CFCR_I2S (1 << 29) -+#define CPM_CFCR_UCS (1 << 28) -+#define CPM_CFCR_UFR_BIT 25 -+#define CPM_CFCR_UFR_MASK (0x07 << CPM_CFCR_UFR_BIT) -+#define CPM_CFCR_MSC (1 << 24) -+#define CPM_CFCR_CKOEN2 (1 << 23) -+#define CPM_CFCR_CKOEN1 (1 << 22) -+#define CPM_CFCR_UPE (1 << 20) -+#define CPM_CFCR_MFR_BIT 16 -+#define CPM_CFCR_MFR_MASK (0x0f << CPM_CFCR_MFR_BIT) -+#define CPM_CFCR_LFR_BIT 12 -+#define CPM_CFCR_LFR_MASK (0x0f << CPM_CFCR_LFR_BIT) -+#define CPM_CFCR_PFR_BIT 8 -+#define CPM_CFCR_PFR_MASK (0x0f << CPM_CFCR_PFR_BIT) -+#define CPM_CFCR_SFR_BIT 4 -+#define CPM_CFCR_SFR_MASK (0x0f << CPM_CFCR_SFR_BIT) -+#define CPM_CFCR_IFR_BIT 0 -+#define CPM_CFCR_IFR_MASK (0x0f << CPM_CFCR_IFR_BIT) -+ -+#define CPM_PLCR1_PLL1FD_BIT 23 -+#define CPM_PLCR1_PLL1FD_MASK (0x1ff << CPM_PLCR1_PLL1FD_BIT) -+#define CPM_PLCR1_PLL1RD_BIT 18 -+#define CPM_PLCR1_PLL1RD_MASK (0x1f << CPM_PLCR1_PLL1RD_BIT) -+#define CPM_PLCR1_PLL1OD_BIT 16 -+#define CPM_PLCR1_PLL1OD_MASK (0x03 << CPM_PLCR1_PLL1OD_BIT) -+#define CPM_PLCR1_PLL1S (1 << 10) -+#define CPM_PLCR1_PLL1BP (1 << 9) -+#define CPM_PLCR1_PLL1EN (1 << 8) -+#define CPM_PLCR1_PLL1ST_BIT 0 -+#define CPM_PLCR1_PLL1ST_MASK (0xff << CPM_PLCR1_PLL1ST_BIT) -+ -+#define CPM_OCR_O1ST_BIT 16 -+#define CPM_OCR_O1ST_MASK (0xff << CPM_OCR_O1ST_BIT) -+#define CPM_OCR_EXT_RTC_CLK (1<<8) -+#define CPM_OCR_SUSPEND_PHY1 (1<<7) -+#define CPM_OCR_SUSPEND_PHY0 (1<<6) -+ -+#define CPM_CFCR2_PXFR_BIT 0 -+#define CPM_CFCR2_PXFR_MASK (0x1ff << CPM_CFCR2_PXFR_BIT) -+ -+#define CPM_LPCR_DUTY_BIT 3 -+#define CPM_LPCR_DUTY_MASK (0x1f << CPM_LPCR_DUTY_BIT) -+#define CPM_LPCR_DOZE (1 << 2) -+#define CPM_LPCR_LPM_BIT 0 -+#define CPM_LPCR_LPM_MASK (0x03 << CPM_LPCR_LPM_BIT) -+ #define CPM_LPCR_LPM_IDLE (0 << CPM_LPCR_LPM_BIT) -+ #define CPM_LPCR_LPM_SLEEP (1 << CPM_LPCR_LPM_BIT) -+ #define CPM_LPCR_LPM_HIBERNATE (2 << CPM_LPCR_LPM_BIT) -+ -+#define CPM_RSTR_SR (1 << 2) -+#define CPM_RSTR_WR (1 << 1) -+#define CPM_RSTR_HR (1 << 0) -+ -+#define CPM_MSCR_MSTP_BIT 0 -+#define CPM_MSCR_MSTP_MASK (0x1ffffff << CPM_MSCR_MSTP_BIT) -+ #define CPM_MSCR_MSTP_UART0 0 -+ #define CPM_MSCR_MSTP_UART1 1 -+ #define CPM_MSCR_MSTP_UART2 2 -+ #define CPM_MSCR_MSTP_OST 3 -+ #define CPM_MSCR_MSTP_DMAC 5 -+ #define CPM_MSCR_MSTP_UHC 6 -+ #define CPM_MSCR_MSTP_LCD 7 -+ #define CPM_MSCR_MSTP_I2C 8 -+ #define CPM_MSCR_MSTP_AICPCLK 9 -+ #define CPM_MSCR_MSTP_PWM0 10 -+ #define CPM_MSCR_MSTP_PWM1 11 -+ #define CPM_MSCR_MSTP_SSI 12 -+ #define CPM_MSCR_MSTP_MSC 13 -+ #define CPM_MSCR_MSTP_SCC 14 -+ #define CPM_MSCR_MSTP_AICBCLK 18 -+ #define CPM_MSCR_MSTP_UART3 20 -+ #define CPM_MSCR_MSTP_ETH 21 -+ #define CPM_MSCR_MSTP_KBC 22 -+ #define CPM_MSCR_MSTP_CIM 23 -+ #define CPM_MSCR_MSTP_UDC 24 -+ #define CPM_MSCR_MSTP_UPRT 25 -+ -+#define CPM_SCR_O1SE (1 << 4) -+#define CPM_SCR_HGP (1 << 3) -+#define CPM_SCR_HZP (1 << 2) -+#define CPM_SCR_HZM (1 << 1) -+ -+#define CPM_WRER_RE_BIT 0 -+#define CPM_WRER_RE_MASK (0xffff << CPM_WRER_RE_BIT) -+ -+#define CPM_WFER_FE_BIT 0 -+#define CPM_WFER_FE_MASK (0xffff << CPM_WFER_FE_BIT) -+ -+#define CPM_WER_WERTC (1 << 31) -+#define CPM_WER_WEETH (1 << 30) -+#define CPM_WER_WE_BIT 0 -+#define CPM_WER_WE_MASK (0xffff << CPM_WER_WE_BIT) -+ -+#define CPM_WSR_WSRTC (1 << 31) -+#define CPM_WSR_WSETH (1 << 30) -+#define CPM_WSR_WS_BIT 0 -+#define CPM_WSR_WS_MASK (0xffff << CPM_WSR_WS_BIT) -+ -+ -+ -+ -+/************************************************************************* -+ * SSI -+ *************************************************************************/ -+#define SSI_DR (SSI_BASE + 0x000) -+#define SSI_CR0 (SSI_BASE + 0x004) -+#define SSI_CR1 (SSI_BASE + 0x008) -+#define SSI_SR (SSI_BASE + 0x00C) -+#define SSI_ITR (SSI_BASE + 0x010) -+#define SSI_ICR (SSI_BASE + 0x014) -+#define SSI_GR (SSI_BASE + 0x018) -+ -+#define REG_SSI_DR REG32(SSI_DR) -+#define REG_SSI_CR0 REG16(SSI_CR0) -+#define REG_SSI_CR1 REG32(SSI_CR1) -+#define REG_SSI_SR REG32(SSI_SR) -+#define REG_SSI_ITR REG16(SSI_ITR) -+#define REG_SSI_ICR REG8(SSI_ICR) -+#define REG_SSI_GR REG16(SSI_GR) -+ -+/* SSI Data Register (SSI_DR) */ -+ -+#define SSI_DR_GPC_BIT 0 -+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) -+ -+/* SSI Control Register 0 (SSI_CR0) */ -+ -+#define SSI_CR0_SSIE (1 << 15) -+#define SSI_CR0_TIE (1 << 14) -+#define SSI_CR0_RIE (1 << 13) -+#define SSI_CR0_TEIE (1 << 12) -+#define SSI_CR0_REIE (1 << 11) -+#define SSI_CR0_LOOP (1 << 10) -+#define SSI_CR0_RFINE (1 << 9) -+#define SSI_CR0_RFINC (1 << 8) -+#define SSI_CR0_FSEL (1 << 6) -+#define SSI_CR0_TFLUSH (1 << 2) -+#define SSI_CR0_RFLUSH (1 << 1) -+#define SSI_CR0_DISREV (1 << 0) -+ -+/* SSI Control Register 1 (SSI_CR1) */ -+ -+#define SSI_CR1_FRMHL_BIT 30 -+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) -+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ -+#define SSI_CR1_TFVCK_BIT 28 -+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) -+#define SSI_CR1_TCKFI_BIT 26 -+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) -+#define SSI_CR1_LFST (1 << 25) -+#define SSI_CR1_ITFRM (1 << 24) -+#define SSI_CR1_UNFIN (1 << 23) -+#define SSI_CR1_MULTS (1 << 22) -+#define SSI_CR1_FMAT_BIT 20 -+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) -+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ -+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ -+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ -+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ -+#define SSI_CR1_MCOM_BIT 12 -+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) -+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ -+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ -+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ -+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ -+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ -+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ -+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ -+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ -+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ -+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ -+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ -+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ -+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ -+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ -+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ -+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ -+#define SSI_CR1_TTRG_BIT 10 -+#define SSI_CR1_TTRG_MASK (0x3 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT)/* Less than or equal to 1 */ -+ #define SSI_CR1_TTRG_4 (1 << SSI_CR1_TTRG_BIT) /* Less than or equal to 4 */ -+ #define SSI_CR1_TTRG_8 (2 << SSI_CR1_TTRG_BIT) /* Less than or equal to 8 */ -+ #define SSI_CR1_TTRG_14 (3 << SSI_CR1_TTRG_BIT) /* Less than or equal to 14 */ -+#define SSI_CR1_RTRG_BIT 8 -+#define SSI_CR1_RTRG_MASK (0x3 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) /* More than or equal to 1 */ -+ #define SSI_CR1_RTRG_4 (1 << SSI_CR1_RTRG_BIT) /* More than or equal to 4 */ -+ #define SSI_CR1_RTRG_8 (2 << SSI_CR1_RTRG_BIT) /* More than or equal to 8 */ -+ #define SSI_CR1_RTRG_14 (3 << SSI_CR1_RTRG_BIT) /* More than or equal to 14 */ -+#define SSI_CR1_FLEN_BIT 4 -+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) -+#define SSI_CR1_PHA (1 << 1) -+#define SSI_CR1_POL (1 << 0) -+ -+/* SSI Status Register (SSI_SR) */ -+ -+#define SSI_SR_TFIFONUM_BIT 13 -+#define SSI_SR_TFIFONUM_MASK (0x1f << SSI_SR_TFIFONUM_BIT) -+#define SSI_SR_RFIFONUM_BIT 8 -+#define SSI_SR_RFIFONUM_MASK (0x1f << SSI_SR_RFIFONUM_BIT) -+#define SSI_SR_END (1 << 7) -+#define SSI_SR_BUSY (1 << 6) -+#define SSI_SR_TFF (1 << 5) -+#define SSI_SR_RFE (1 << 4) -+#define SSI_SR_TFHE (1 << 3) -+#define SSI_SR_RFHF (1 << 2) -+#define SSI_SR_UNDR (1 << 1) -+#define SSI_SR_OVER (1 << 0) -+ -+/* SSI Interval Time Control Register (SSI_ITR) */ -+ -+#define SSI_ITR_CNTCLK (1 << 15) -+#define SSI_ITR_IVLTM_BIT 0 -+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) -+ -+#endif /* __ASM_JZ4730_REGS_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/serial.h linux-2.6.24.7/include/asm-mips/mach-jz4730/serial.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/serial.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/serial.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * linux/include/asm-mips/mach-jz4730/serial.h -+ * -+ * JZ4730 serial port definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4730_SERIAL_H__ -+#define __ASM_JZ4730_SERIAL_H__ -+ -+#define JZ_BASE_BAUD (JZ_EXTAL/16) -+#define JZ_SERIAL_PORT_DEFNS \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART1, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART1_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART2, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART2_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART3, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART3_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, -+ -+#endif /* __ASM_JZ4730_SERIAL_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4730/war.h linux-2.6.24.7/include/asm-mips/mach-jz4730/war.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4730/war.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4730/war.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle -+ */ -+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H -+#define __ASM_MIPS_MACH_JZ4740_WAR_H -+ -+#define R4600_V1_INDEX_ICACHEOP_WAR 0 -+#define R4600_V1_HIT_CACHEOP_WAR 0 -+#define R4600_V2_HIT_CACHEOP_WAR 0 -+#define R5432_CP0_INTERRUPT_WAR 0 -+#define BCM1250_M3_WAR 0 -+#define SIBYTE_1956_WAR 0 -+#define MIPS4K_ICACHE_REFILL_WAR 0 -+#define MIPS_CACHE_SYNC_WAR 0 -+#define TX49XX_ICACHE_INDEX_INV_WAR 0 -+#define RM9000_CDEX_SMP_WAR 0 -+#define ICACHE_REFILLS_WORKAROUND_WAR 0 -+#define R10000_LLSC_WAR 0 -+#define MIPS34K_MISSED_ITLB_WAR 0 -+ -+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-dipper.h linux-2.6.24.7/include/asm-mips/mach-jz4740/board-dipper.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-dipper.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/board-dipper.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,69 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/board-dipper.h -+ * -+ * JZ4725-based (16bit) Dipper board ver 1.x definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4725_DIPPER_H__ -+#define __ASM_JZ4725_DIPPER_H__ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+/*====================================================================== -+ * GPIO JZ4725 -+ */ -+#define GPIO_SD_VCC_EN_N 85 /* GPC21 */ -+#define GPIO_SD_CD_N 91 /* GPC27 */ -+#define GPIO_SD_WP 112 /* GPD16 */ -+#define GPIO_USB_DETE 124 /* GPD28 */ -+#define GPIO_DC_DETE_N 103 /* GPD7 */ -+#define GPIO_CHARG_STAT_N 86 /* GPC22 */ -+#define GPIO_DISP_OFF_N 118 /* GPD22 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_WP_PIN GPIO_SD_WP -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4740_DIPPER_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-leo.h linux-2.6.24.7/include/asm-mips/mach-jz4740/board-leo.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-leo.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/board-leo.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+#ifndef __ASM_JZ4740_LEO_H__ -+#define __ASM_JZ4740_LEO_H__ -+ -+/* -+ * Define your board specific codes here !!! -+ */ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_DISP_OFF_N 100 -+#define GPIO_SD_VCC_EN_N 119 -+#define GPIO_SD_CD_N 120 -+#define GPIO_SD_WP 111 -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_WP_PIN GPIO_SD_WP -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+ if (__gpio_get_pin(GPIO_SD_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4740_BOARD_LEO_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-lyra.h linux-2.6.24.7/include/asm-mips/mach-jz4740/board-lyra.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-lyra.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/board-lyra.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/board-lyra.h -+ * -+ * JZ4740-based LYRA board ver 2.x definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_LYRA_H__ -+#define __ASM_JZ4740_LYRA_H__ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ -+#define GPIO_SD_CD_N 110 /* GPD14 */ -+#define GPIO_SD_WP 112 /* GPD16 */ -+#define GPIO_USB_DETE 102 /* GPD6 */ -+#define GPIO_DC_DETE_N 103 /* GPD7 */ -+#define GPIO_CHARG_STAT_N 111 /* GPD15 */ -+#define GPIO_DISP_OFF_N 118 /* GPD22 */ -+#define GPIO_LED_EN 124 /* GPD28 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_WP_PIN GPIO_SD_WP -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (!(__gpio_get_pin(GPIO_SD_CD_N))) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4740_LYRA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-pavo.h linux-2.6.24.7/include/asm-mips/mach-jz4740/board-pavo.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-pavo.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/board-pavo.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,70 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/board-pavo.h -+ * -+ * JZ4730-based PAVO board ver 2.x definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_PAVO_H__ -+#define __ASM_JZ4740_PAVO_H__ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ -+#define GPIO_SD_CD_N 110 /* GPD14 */ -+#define GPIO_SD_WP 112 /* GPD16 */ -+#define GPIO_USB_DETE 102 /* GPD6 */ -+#define GPIO_DC_DETE_N 103 /* GPD7 */ -+#define GPIO_CHARG_STAT_N 111 /* GPD15 */ -+#define GPIO_DISP_OFF_N 118 /* GPD22 */ -+#define GPIO_LED_EN 124 /* GPD28 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_WP_PIN GPIO_SD_WP -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4740_PAVO_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-virgo.h linux-2.6.24.7/include/asm-mips/mach-jz4740/board-virgo.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/board-virgo.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/board-virgo.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,67 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/board-virgo.h -+ * -+ * JZ4720-based VIRGO board ver 1.x definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4720_VIRGO_H__ -+#define __ASM_JZ4720_VIRGO_H__ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+/*====================================================================== -+ * GPIO VIRGO(JZ4720) -+ */ -+#define GPIO_SD_VCC_EN_N 115 /* GPD19 */ -+#define GPIO_SD_CD_N 116 /* GPD20 */ -+#define GPIO_USB_DETE 114 /* GPD18 */ -+#define GPIO_DC_DETE_N 120 /* GPD24 */ -+#define GPIO_DISP_OFF_N 118 /* GPD22 */ -+#define GPIO_LED_EN 117 /* GPD21 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4720_VIRGO_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/clock.h linux-2.6.24.7/include/asm-mips/mach-jz4740/clock.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/clock.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/clock.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,173 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/clock.h -+ * -+ * JZ4740 clocks definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_CLOCK_H__ -+#define __ASM_JZ4740_CLOCK_H__ -+ -+#ifndef JZ_EXTAL -+//#define JZ_EXTAL 3686400 /* 3.6864 MHz */ -+#define JZ_EXTAL 12000000 /* 3.6864 MHz */ -+#endif -+#ifndef JZ_EXTAL2 -+#define JZ_EXTAL2 32768 /* 32.768 KHz */ -+#endif -+ -+/* -+ * JZ4740 clocks structure -+ */ -+typedef struct { -+ unsigned int cclk; /* CPU clock */ -+ unsigned int hclk; /* System bus clock */ -+ unsigned int pclk; /* Peripheral bus clock */ -+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ -+ unsigned int lcdclk; /* LCDC module clock */ -+ unsigned int pixclk; /* LCD pixel clock */ -+ unsigned int i2sclk; /* AIC module clock */ -+ unsigned int usbclk; /* USB module clock */ -+ unsigned int mscclk; /* MSC module clock */ -+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+} jz_clocks_t; -+ -+extern jz_clocks_t jz_clocks; -+ -+ -+/* PLL output frequency */ -+static __inline__ unsigned int __cpm_get_pllout(void) -+{ -+ unsigned long m, n, no, pllout; -+ unsigned long cppcr = REG_CPM_CPPCR; -+ unsigned long od[4] = {1, 2, 2, 4}; -+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { -+ m = __cpm_get_pllm() + 2; -+ n = __cpm_get_plln() + 2; -+ no = od[__cpm_get_pllod()]; -+ pllout = ((JZ_EXTAL) / (n * no)) * m; -+ } else -+ pllout = JZ_EXTAL; -+ return pllout; -+} -+ -+/* PLL output frequency for MSC/I2S/LCD/USB */ -+static __inline__ unsigned int __cpm_get_pllout2(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) -+ return __cpm_get_pllout(); -+ else -+ return __cpm_get_pllout()/2; -+} -+ -+/* CPU core clock */ -+static __inline__ unsigned int __cpm_get_cclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; -+} -+ -+/* AHB system bus clock */ -+static __inline__ unsigned int __cpm_get_hclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; -+} -+ -+/* Memory bus clock */ -+static __inline__ unsigned int __cpm_get_mclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; -+} -+ -+/* APB peripheral bus clock */ -+static __inline__ unsigned int __cpm_get_pclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; -+} -+ -+/* LCDC module clock */ -+static __inline__ unsigned int __cpm_get_lcdclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); -+} -+ -+/* LCD pixel clock */ -+static __inline__ unsigned int __cpm_get_pixclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); -+} -+ -+/* I2S clock */ -+static __inline__ unsigned int __cpm_get_i2sclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { -+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* USB clock */ -+static __inline__ unsigned int __cpm_get_usbclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { -+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* MSC clock */ -+static __inline__ unsigned int __cpm_get_mscclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1); -+} -+ -+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+static __inline__ unsigned int __cpm_get_extalclk(void) -+{ -+ return JZ_EXTAL; -+} -+ -+/* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+static __inline__ unsigned int __cpm_get_rtcclk(void) -+{ -+ return JZ_EXTAL2; -+} -+ -+/* -+ * Output 24MHz for SD and 16MHz for MMC. -+ */ -+static inline void __cpm_select_msc_clk(int sd) -+{ -+ unsigned int pllout2 = __cpm_get_pllout2(); -+ unsigned int div = 0; -+ -+ if (sd) { -+ div = pllout2 / 24000000; -+ } -+ else { -+ div = pllout2 / 16000000; -+ } -+ -+ REG_CPM_MSCCDR = div - 1; -+} -+ -+#endif /* __ASM_JZ4740_CLOCK_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/dma.h linux-2.6.24.7/include/asm-mips/mach-jz4740/dma.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/dma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/dma.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,265 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/dma.h -+ * -+ * JZ4740 DMA definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_DMA_H__ -+#define __ASM_JZ4740_DMA_H__ -+ -+#include -+#include /* need byte IO */ -+#include /* And spinlocks */ -+#include -+#include -+ -+/* -+ * Descriptor structure for JZ4740 DMA engine -+ * Note: this structure must always be aligned to a 16-bytes boundary. -+ */ -+ -+typedef struct { -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+ volatile u32 dsadr; /* DSAR value for the current transfer */ -+ volatile u32 dtadr; /* DTAR value for the current transfer */ -+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ -+} jz_dma_desc; -+ -+ -+/* DMA Device ID's follow */ -+enum { -+ DMA_ID_UART0_TX = 0, -+ DMA_ID_UART0_RX, -+ DMA_ID_SSI_TX, -+ DMA_ID_SSI_RX, -+ DMA_ID_AIC_TX, -+ DMA_ID_AIC_RX, -+ DMA_ID_MSC_TX, -+ DMA_ID_MSC_RX, -+ DMA_ID_TCU_OVERFLOW, -+ DMA_ID_AUTO, -+ DMA_ID_RAW_SET, -+ DMA_ID_MAX -+}; -+ -+/* DMA modes, simulated by sw */ -+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ -+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ -+#define DMA_AUTOINIT 0x2 -+#define DMA_MODE_MASK 0x3 -+ -+struct jz_dma_chan { -+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ -+ unsigned int io; /* DMA channel number */ -+ const char *dev_str; /* string describes the DMA channel */ -+ int irq; /* DMA irq number */ -+ void *irq_dev; /* DMA private device structure */ -+ unsigned int fifo_addr; /* physical fifo address of the requested device */ -+ unsigned int cntl; /* DMA controll */ -+ unsigned int mode; /* DMA configuration */ -+ unsigned int source; /* DMA request source */ -+}; -+ -+extern struct jz_dma_chan jz_dma_table[]; -+ -+ -+#define DMA_8BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_8BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+extern int jz_request_dma(int dev_id, -+ const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id); -+extern void jz_free_dma(unsigned int dmanr); -+ -+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data); -+extern void dump_jz_dma_channel(unsigned int dmanr); -+ -+extern void enable_dma(unsigned int dmanr); -+extern void disable_dma(unsigned int dmanr); -+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); -+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); -+extern void set_dma_mode(unsigned int dmanr, unsigned int mode); -+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern unsigned int get_dma_residue(unsigned int dmanr); -+ -+extern spinlock_t dma_spin_lock; -+ -+static __inline__ unsigned long claim_dma_lock(void) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&dma_spin_lock, flags); -+ return flags; -+} -+ -+static __inline__ void release_dma_lock(unsigned long flags) -+{ -+ spin_unlock_irqrestore(&dma_spin_lock, flags); -+} -+ -+/* Clear the 'DMA Pointer Flip Flop'. -+ * Write 0 for LSB/MSB, 1 for MSB/LSB access. -+ */ -+#define clear_dma_ff(channel) -+ -+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) -+{ -+ if (dmanr > MAX_DMA_NUM -+ || jz_dma_table[dmanr].dev_id < 0) -+ return NULL; -+ return &jz_dma_table[dmanr]; -+} -+ -+static __inline__ int dma_halted(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 1; -+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; -+} -+ -+static __inline__ unsigned int get_dma_mode(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ return chan->mode; -+} -+ -+static __inline__ void clear_dma_done(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ void clear_dma_halt(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); -+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT); -+} -+ -+static __inline__ void clear_dma_flag(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); -+} -+ -+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -+{ -+} -+ -+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) -+{ -+ unsigned long dccsr; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ dccsr = REG_DMAC_DCCSR(chan->io); -+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ int get_dma_done_irq(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return -1; -+ return chan->irq; -+} -+ -+#endif /* __ASM_JZ4740_DMA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/jz4740.h linux-2.6.24.7/include/asm-mips/mach-jz4740/jz4740.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/jz4740.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/jz4740.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/jz4740.h -+ * -+ * JZ4740 common definition. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_H__ -+#define __ASM_JZ4740_H__ -+ -+#include -+#include -+#include -+#include -+ -+/*------------------------------------------------------------------ -+ * Platform definitions -+ */ -+#ifdef CONFIG_JZ4740_PAVO -+#include -+#endif -+ -+#ifdef CONFIG_JZ4740_LEO -+#include -+#endif -+ -+#ifdef CONFIG_JZ4740_LYRA -+#include -+#endif -+ -+#ifdef CONFIG_JZ4725_DIPPER -+#include -+#endif -+ -+#ifdef CONFIG_JZ4720_VIRGO -+#include -+#endif -+ -+/* Add other platform definition here ... */ -+ -+ -+/*------------------------------------------------------------------ -+ * Follows are related to platform definitions -+ */ -+ -+#include -+#include -+ -+#endif /* __ASM_JZ4740_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/misc.h linux-2.6.24.7/include/asm-mips/mach-jz4740/misc.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/misc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/misc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,43 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/misc.h -+ * -+ * Ingenic's JZ4740 common include. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4740_MISC_H__ -+#define __ASM_JZ4740_MISC_H__ -+ -+/*========================================================== -+ * I2C -+ *===========================================================*/ -+ -+#define I2C_EEPROM_DEV 0xA /* b'1010 */ -+#define I2C_RTC_DEV 0xD /* b'1101 */ -+#define DIMM0_SPD_ADDR 0 -+#define DIMM1_SPD_ADDR 1 -+#define DIMM2_SPD_ADDR 2 -+#define DIMM3_SPD_ADDR 3 -+#define JZ_HCI_ADDR 7 -+ -+#define DIMM_SPD_LEN 128 -+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ -+#define I2C_RTC_LEN 16 -+#define HCI_MAC_OFFSET 64 -+ -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern void i2c_setclk(unsigned int i2cclk); -+extern int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+extern int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+ -+#endif /* __ASM_JZ4740_MISC_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/ops.h linux-2.6.24.7/include/asm-mips/mach-jz4740/ops.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/ops.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/ops.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2224 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/ops.h -+ * -+ * Ingenic's JZ4740 common include. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef __JZ4740_OPS_H__ -+#define __JZ4740_OPS_H__ -+ -+/* -+ * Definition of Module Operations -+ */ -+ -+/*************************************************************************** -+ * GPIO -+ ***************************************************************************/ -+ -+//------------------------------------------------------ -+// GPIO Pins Description -+// -+// PORT 0: -+// -+// PIN/BIT N FUNC0 FUNC1 -+// 0 D0 - -+// 1 D1 - -+// 2 D2 - -+// 3 D3 - -+// 4 D4 - -+// 5 D5 - -+// 6 D6 - -+// 7 D7 - -+// 8 D8 - -+// 9 D9 - -+// 10 D10 - -+// 11 D11 - -+// 12 D12 - -+// 13 D13 - -+// 14 D14 - -+// 15 D15 - -+// 16 D16 - -+// 17 D17 - -+// 18 D18 - -+// 19 D19 - -+// 20 D20 - -+// 21 D21 - -+// 22 D22 - -+// 23 D23 - -+// 24 D24 - -+// 25 D25 - -+// 26 D26 - -+// 27 D27 - -+// 28 D28 - -+// 29 D29 - -+// 30 D30 - -+// 31 D31 - -+// -+//------------------------------------------------------ -+// PORT 1: -+// -+// PIN/BIT N FUNC0 FUNC1 -+// 0 A0 - -+// 1 A1 - -+// 2 A2 - -+// 3 A3 - -+// 4 A4 - -+// 5 A5 - -+// 6 A6 - -+// 7 A7 - -+// 8 A8 - -+// 9 A9 - -+// 10 A10 - -+// 11 A11 - -+// 12 A12 - -+// 13 A13 - -+// 14 A14 - -+// 15 A15/CL - -+// 16 A16/AL - -+// 17 LCD_CLS A21 -+// 18 LCD_SPL A22 -+// 19 DCS# - -+// 20 RAS# - -+// 21 CAS# - -+// 22 RDWE#/BUFD# - -+// 23 CKE - -+// 24 CKO - -+// 25 CS1# - -+// 26 CS2# - -+// 27 CS3# - -+// 28 CS4# - -+// 29 RD# - -+// 30 WR# - -+// 31 WE0# - -+// -+// Note: PIN15&16 are CL&AL when connecting to NAND flash. -+//------------------------------------------------------ -+// PORT 2: -+// -+// PIN/BIT N FUNC0 FUNC1 -+// 0 LCD_D0 - -+// 1 LCD_D1 - -+// 2 LCD_D2 - -+// 3 LCD_D3 - -+// 4 LCD_D4 - -+// 5 LCD_D5 - -+// 6 LCD_D6 - -+// 7 LCD_D7 - -+// 8 LCD_D8 - -+// 9 LCD_D9 - -+// 10 LCD_D10 - -+// 11 LCD_D11 - -+// 12 LCD_D12 - -+// 13 LCD_D13 - -+// 14 LCD_D14 - -+// 15 LCD_D15 - -+// 16 LCD_D16 - -+// 17 LCD_D17 - -+// 18 LCD_PCLK - -+// 19 LCD_HSYNC - -+// 20 LCD_VSYNC - -+// 21 LCD_DE - -+// 22 LCD_PS A19 -+// 23 LCD_REV A20 -+// 24 WE1# - -+// 25 WE2# - -+// 26 WE3# - -+// 27 WAIT# - -+// 28 FRE# - -+// 29 FWE# - -+// 30(NOTE:FRB#) - - -+// 31 - - -+// -+// NOTE(1): PIN30 is used for FRB# when connecting to NAND flash. -+//------------------------------------------------------ -+// PORT 3: -+// -+// PIN/BIT N FUNC0 FUNC1 -+// 0 CIM_D0 - -+// 1 CIM_D1 - -+// 2 CIM_D2 - -+// 3 CIM_D3 - -+// 4 CIM_D4 - -+// 5 CIM_D5 - -+// 6 CIM_D6 - -+// 7 CIM_D7 - -+// 8 MSC_CMD - -+// 9 MSC_CLK - -+// 10 MSC_D0 - -+// 11 MSC_D1 - -+// 12 MSC_D2 - -+// 13 MSC_D3 - -+// 14 CIM_MCLK - -+// 15 CIM_PCLK - -+// 16 CIM_VSYNC - -+// 17 CIM_HSYNC - -+// 18 SSI_CLK SCLK_RSTN -+// 19 SSI_CE0# BIT_CLK(AIC) -+// 20 SSI_DT SDATA_OUT(AIC) -+// 21 SSI_DR SDATA_IN(AIC) -+// 22 SSI_CE1#&GPC SYNC(AIC) -+// 23 PWM0 I2C_SDA -+// 24 PWM1 I2C_SCK -+// 25 PWM2 UART0_TxD -+// 26 PWM3 UART0_RxD -+// 27 PWM4 A17 -+// 28 PWM5 A18 -+// 29 - - -+// 30 PWM6 UART0_CTS/UART1_RxD -+// 31 PWM7 UART0_RTS/UART1_TxD -+// -+////////////////////////////////////////////////////////// -+ -+/* -+ * p is the port number (0,1,2,3) -+ * o is the pin offset (0-31) inside the port -+ * n is the absolute number of a pin (0-127), regardless of the port -+ */ -+ -+//------------------------------------------- -+// Function Pins Mode -+ -+#define __gpio_as_func0(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXSELC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_func1(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+} while (0) -+ -+/* -+ * D0 ~ D31, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, -+ * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# -+ */ -+#define __gpio_as_sdram_32bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0xffffffff; \ -+ REG_GPIO_PXSELC(0) = 0xffffffff; \ -+ REG_GPIO_PXPES(0) = 0xffffffff; \ -+ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ -+ REG_GPIO_PXSELC(1) = 0x81f9ffff; \ -+ REG_GPIO_PXPES(1) = 0x81f9ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x07000000; \ -+ REG_GPIO_PXSELC(2) = 0x07000000; \ -+ REG_GPIO_PXPES(2) = 0x07000000; \ -+} while (0) -+ -+/* -+ * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, -+ * RDWE#, CKO#, WE0#, WE1# -+ */ -+#define __gpio_as_sdram_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0x5442bfaa; \ -+ REG_GPIO_PXSELC(0) = 0x5442bfaa; \ -+ REG_GPIO_PXPES(0) = 0x5442bfaa; \ -+ REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ -+ REG_GPIO_PXSELC(1) = 0x81f9ffff; \ -+ REG_GPIO_PXPES(1) = 0x81f9ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x01000000; \ -+ REG_GPIO_PXSELC(2) = 0x01000000; \ -+ REG_GPIO_PXPES(2) = 0x01000000; \ -+} while (0) -+ -+/* -+ * CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# -+ */ -+#define __gpio_as_nand() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0x02018000; \ -+ REG_GPIO_PXSELC(1) = 0x02018000; \ -+ REG_GPIO_PXPES(1) = 0x02018000; \ -+ REG_GPIO_PXFUNS(2) = 0x30000000; \ -+ REG_GPIO_PXSELC(2) = 0x30000000; \ -+ REG_GPIO_PXPES(2) = 0x30000000; \ -+ REG_GPIO_PXFUNC(2) = 0x40000000; \ -+ REG_GPIO_PXSELC(2) = 0x40000000; \ -+ REG_GPIO_PXDIRC(2) = 0x40000000; \ -+ REG_GPIO_PXPES(2) = 0x40000000; \ -+ REG_GPIO_PXFUNS(1) = 0x00400000; \ -+ REG_GPIO_PXSELC(1) = 0x00400000; \ -+} while (0) -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 -+ */ -+#define __gpio_as_nor_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0x000000ff; \ -+ REG_GPIO_PXSELC(0) = 0x000000ff; \ -+ REG_GPIO_PXPES(0) = 0x000000ff; \ -+ REG_GPIO_PXFUNS(1) = 0x7041ffff; \ -+ REG_GPIO_PXSELC(1) = 0x7041ffff; \ -+ REG_GPIO_PXPES(1) = 0x7041ffff; \ -+ REG_GPIO_PXFUNS(1) = 0x00060000; \ -+ REG_GPIO_PXSELS(1) = 0x00060000; \ -+ REG_GPIO_PXPES(1) = 0x00060000; \ -+ REG_GPIO_PXFUNS(2) = 0x08000000; \ -+ REG_GPIO_PXSELC(2) = 0x08000000; \ -+ REG_GPIO_PXPES(2) = 0x08000000; \ -+ REG_GPIO_PXFUNS(2) = 0x00c00000; \ -+ REG_GPIO_PXSELS(2) = 0x00c00000; \ -+ REG_GPIO_PXPES(2) = 0x00c00000; \ -+ REG_GPIO_PXFUNS(3) = 0x18000000; \ -+ REG_GPIO_PXSELS(3) = 0x18000000; \ -+ REG_GPIO_PXPES(3) = 0x18000000; \ -+} while (0) -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 -+ */ -+#define __gpio_as_nor_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ -+ REG_GPIO_PXSELC(0) = 0x0000ffff; \ -+ REG_GPIO_PXPES(0) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(1) = 0x7041ffff; \ -+ REG_GPIO_PXSELC(1) = 0x7041ffff; \ -+ REG_GPIO_PXPES(1) = 0x7041ffff; \ -+ REG_GPIO_PXFUNS(1) = 0x00060000; \ -+ REG_GPIO_PXSELS(1) = 0x00060000; \ -+ REG_GPIO_PXPES(1) = 0x00060000; \ -+ REG_GPIO_PXFUNS(2) = 0x08000000; \ -+ REG_GPIO_PXSELC(2) = 0x08000000; \ -+ REG_GPIO_PXPES(2) = 0x08000000; \ -+ REG_GPIO_PXFUNS(2) = 0x00c00000; \ -+ REG_GPIO_PXSELS(2) = 0x00c00000; \ -+ REG_GPIO_PXPES(2) = 0x00c00000; \ -+ REG_GPIO_PXFUNS(3) = 0x18000000; \ -+ REG_GPIO_PXSELS(3) = 0x18000000; \ -+ REG_GPIO_PXPES(3) = 0x18000000; \ -+} while (0) -+ -+/* -+ * UART0_TxD, UART_RxD0 -+ */ -+#define __gpio_as_uart0() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x06000000; \ -+ REG_GPIO_PXSELS(3) = 0x06000000; \ -+ REG_GPIO_PXPES(3) = 0x06000000; \ -+} while (0) -+ -+/* -+ * UART0_CTS, UART0_RTS -+ */ -+#define __gpio_as_ctsrts() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0xc0000000; \ -+ REG_GPIO_PXSELS(3) = 0xc0000000; \ -+ REG_GPIO_PXTRGC(3) = 0xc0000000; \ -+ REG_GPIO_PXPES(3) = 0xc0000000; \ -+} while (0) -+ -+/* -+ * UART1_TxD, UART1_RxD1 -+ */ -+#define __gpio_as_uart1() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0xc0000000; \ -+ REG_GPIO_PXSELC(3) = 0xc0000000; \ -+ REG_GPIO_PXTRGS(3) = 0xc0000000; \ -+ REG_GPIO_PXPES(3) = 0xc0000000; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x003cffff; \ -+ REG_GPIO_PXSELC(2) = 0x003cffff; \ -+ REG_GPIO_PXPES(2) = 0x003cffff; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_18bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x003fffff; \ -+ REG_GPIO_PXSELC(2) = 0x003fffff; \ -+ REG_GPIO_PXPES(2) = 0x003fffff; \ -+} while (0) -+ -+/* -+ * LCD_PS, LCD_REV, LCD_CLS, LCD_SPL -+ */ -+#define __gpio_as_lcd_special() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0x00060000; \ -+ REG_GPIO_PXSELC(1) = 0x00060000; \ -+ REG_GPIO_PXPES(1) = 0x00060000; \ -+ REG_GPIO_PXFUNS(2) = 0x00c00000; \ -+ REG_GPIO_PXSELC(2) = 0x00c00000; \ -+ REG_GPIO_PXPES(2) = 0x00c00000; \ -+} while (0) -+ -+/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ -+#define __gpio_as_slcd_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x001800ff; \ -+ REG_GPIO_PXSELC(2) = 0x001800ff; \ -+} while (0) -+ -+/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ -+#define __gpio_as_slcd_9bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x001801ff; \ -+ REG_GPIO_PXSELC(2) = 0x001801ff; \ -+} while (0) -+ -+/* LCD_D0~LCD_D15, SLCD_RS, SLCD_CS */ -+#define __gpio_as_slcd_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x0018ffff; \ -+ REG_GPIO_PXSELC(2) = 0x0018ffff; \ -+} while (0) -+ -+/* LCD_D0~LCD_D17, SLCD_RS, SLCD_CS */ -+#define __gpio_as_slcd_18bit() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x001bffff; \ -+ REG_GPIO_PXSELC(2) = 0x001bffff; \ -+} while (0) -+ -+/* -+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC -+ */ -+#define __gpio_as_cim() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x0003c0ff; \ -+ REG_GPIO_PXSELC(3) = 0x0003c0ff; \ -+ REG_GPIO_PXPES(3) = 0x0003c0ff; \ -+} while (0) -+ -+/* -+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET -+ */ -+#define __gpio_as_aic() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x007c0000; \ -+ REG_GPIO_PXSELS(3) = 0x007c0000; \ -+ REG_GPIO_PXPES(3) = 0x007c0000; \ -+} while (0) -+ -+/* -+ * MSC_CMD, MSC_CLK, MSC_D0 ~ MSC_D3 -+ */ -+#define __gpio_as_msc() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x00003f00; \ -+ REG_GPIO_PXSELC(3) = 0x00003f00; \ -+ REG_GPIO_PXPES(3) = 0x00003f00; \ -+} while (0) -+ -+/* -+ * SSI_CS0, SSI_CLK, SSI_DT, SSI_DR -+ */ -+#define __gpio_as_ssi() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003c0000; \ -+ REG_GPIO_PXSELC(3) = 0x003c0000; \ -+ REG_GPIO_PXPES(3) = 0x003c0000; \ -+} while (0) -+ -+/* -+ * I2C_SCK, I2C_SDA -+ */ -+#define __gpio_as_i2c() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x01800000; \ -+ REG_GPIO_PXSELS(3) = 0x01800000; \ -+ REG_GPIO_PXPES(3) = 0x01800000; \ -+} while (0) -+ -+/* -+ * PWM0 -+ */ -+#define __gpio_as_pwm0() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x00800000; \ -+ REG_GPIO_PXSELC(3) = 0x00800000; \ -+ REG_GPIO_PXPES(3) = 0x00800000; \ -+} while (0) -+ -+/* -+ * PWM1 -+ */ -+#define __gpio_as_pwm1() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x01000000; \ -+ REG_GPIO_PXSELC(3) = 0x01000000; \ -+ REG_GPIO_PXPES(3) = 0x01000000; \ -+} while (0) -+ -+/* -+ * PWM2 -+ */ -+#define __gpio_as_pwm2() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x02000000; \ -+ REG_GPIO_PXSELC(3) = 0x02000000; \ -+ REG_GPIO_PXPES(3) = 0x02000000; \ -+} while (0) -+ -+/* -+ * PWM3 -+ */ -+#define __gpio_as_pwm3() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x04000000; \ -+ REG_GPIO_PXSELC(3) = 0x04000000; \ -+ REG_GPIO_PXPES(3) = 0x04000000; \ -+} while (0) -+ -+/* -+ * PWM4 -+ */ -+#define __gpio_as_pwm4() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x08000000; \ -+ REG_GPIO_PXSELC(3) = 0x08000000; \ -+ REG_GPIO_PXPES(3) = 0x08000000; \ -+} while (0) -+ -+/* -+ * PWM5 -+ */ -+#define __gpio_as_pwm5() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x10000000; \ -+ REG_GPIO_PXSELC(3) = 0x10000000; \ -+ REG_GPIO_PXPES(3) = 0x10000000; \ -+} while (0) -+ -+/* -+ * PWM6 -+ */ -+#define __gpio_as_pwm6() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x40000000; \ -+ REG_GPIO_PXSELC(3) = 0x40000000; \ -+ REG_GPIO_PXPES(3) = 0x40000000; \ -+} while (0) -+ -+/* -+ * PWM7 -+ */ -+#define __gpio_as_pwm7() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x80000000; \ -+ REG_GPIO_PXSELC(3) = 0x80000000; \ -+ REG_GPIO_PXPES(3) = 0x80000000; \ -+} while (0) -+ -+/* -+ * n = 0 ~ 7 -+ */ -+#define __gpio_as_pwm(n) __gpio_as_pwm##n() -+ -+//------------------------------------------- -+// GPIO or Interrupt Mode -+ -+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) -+ -+#define __gpio_port_as_output(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRS(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_port_as_input(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRC(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_as_output(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_output(p, o); \ -+} while (0) -+ -+#define __gpio_as_input(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_input(p, o); \ -+} while (0) -+ -+#define __gpio_set_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_clear_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_pin(n) \ -+({ \ -+ unsigned int p, o, v; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ if (__gpio_get_port(p) & (1 << o)) \ -+ v = 1; \ -+ else \ -+ v = 0; \ -+ v; \ -+}) -+ -+#define __gpio_as_irq_high_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_low_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_rise_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_fall_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_mask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_unmask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_ack_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_irq() \ -+({ \ -+ unsigned int p, i, tmp, v = 0; \ -+ for (p = 3; p >= 0; p--) { \ -+ tmp = REG_GPIO_PXFLG(p); \ -+ for (i = 0; i < 32; i++) \ -+ if (tmp & (1 << i)) \ -+ v = (32*p + i); \ -+ } \ -+ v; \ -+}) -+ -+#define __gpio_group_irq(n) \ -+({ \ -+ register int tmp, i; \ -+ tmp = REG_GPIO_PXFLG((n)); \ -+ for (i=31;i>=0;i--) \ -+ if (tmp & (1 << i)) \ -+ break; \ -+ i; \ -+}) -+ -+#define __gpio_enable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPEC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_disable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPES(p) = (1 << o); \ -+} while (0) -+ -+ -+/*************************************************************************** -+ * CPM -+ ***************************************************************************/ -+#define __cpm_get_pllm() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) -+#define __cpm_get_plln() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) -+#define __cpm_get_pllod() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) -+ -+#define __cpm_get_cdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) -+#define __cpm_get_hdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) -+#define __cpm_get_pdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) -+#define __cpm_get_mdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) -+#define __cpm_get_ldiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) -+#define __cpm_get_udiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) -+#define __cpm_get_i2sdiv() \ -+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) -+#define __cpm_get_pixdiv() \ -+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) -+#define __cpm_get_mscdiv() \ -+ ((REG_CPM_MSCCDR & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) -+#define __cpm_get_uhcdiv() \ -+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) -+#define __cpm_get_ssidiv() \ -+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) -+ -+#define __cpm_set_cdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) -+#define __cpm_set_hdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) -+#define __cpm_set_pdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) -+#define __cpm_set_mdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) -+#define __cpm_set_ldiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) -+#define __cpm_set_udiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) -+#define __cpm_set_i2sdiv(v) \ -+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) -+#define __cpm_set_pixdiv(v) \ -+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) -+#define __cpm_set_mscdiv(v) \ -+ (REG_CPM_MSCCDR = (REG_CPM_MSCCDR & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) -+#define __cpm_set_uhcdiv(v) \ -+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) -+#define __cpm_ssiclk_select_exclk() \ -+ (REG_CPM_SSICDR &= ~CPM_SSICDR_SCS) -+#define __cpm_ssiclk_select_pllout() \ -+ (REG_CPM_SSICDR |= CPM_SSICDR_SCS) -+#define __cpm_set_ssidiv(v) \ -+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) -+ -+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) -+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) -+#define __cpm_enable_cko() (REG_CPM_CPCCR |= CPM_CPCCR_CLKOEN) -+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) -+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) -+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) -+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) -+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) -+ -+#define __cpm_pll_is_on() (REG_CPM_CPPCR & CPM_CPPCR_PLLS) -+#define __cpm_pll_bypass() (REG_CPM_CPPCR |= CPM_CPPCR_PLLBP) -+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) -+ -+#define __cpm_get_cclk_doze_duty() \ -+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) -+#define __cpm_set_cclk_doze_duty(v) \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) -+ -+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) -+#define __cpm_idle_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) -+#define __cpm_sleep_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) -+ -+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x7fff) -+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) -+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) -+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) -+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) -+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) -+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) -+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) -+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) -+#define __cpm_stop_msc() (REG_CPM_CLKGR |= CPM_CLKGR_MSC) -+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) -+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) -+#define __cpm_stop_ssi() (REG_CPM_CLKGR |= CPM_CLKGR_SSI) -+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) -+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) -+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) -+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) -+ -+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) -+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) -+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) -+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) -+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) -+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) -+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) -+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) -+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) -+#define __cpm_start_msc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC) -+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) -+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) -+#define __cpm_start_ssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI) -+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) -+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) -+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) -+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) -+ -+#define __cpm_get_o1st() \ -+ ((REG_CPM_SCR & CPM_SCR_O1ST_MASK) >> CPM_SCR_O1ST_BIT) -+#define __cpm_set_o1st(v) \ -+ (REG_CPM_SCR = (REG_CPM_SCR & ~CPM_SCR_O1ST_MASK) | ((v) << (CPM_SCR_O1ST_BIT))) -+#define __cpm_suspend_usbphy() (REG_CPM_SCR |= CPM_SCR_USBPHY_SUSPEND) -+#define __cpm_enable_osc_in_sleep() (REG_CPM_SCR |= CPM_SCR_OSC_ENABLE) -+ -+ -+/*************************************************************************** -+ * TCU -+ ***************************************************************************/ -+// where 'n' is the TCU channel -+#define __tcu_select_extalclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) -+#define __tcu_select_rtcclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) -+#define __tcu_select_pclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) -+ -+#define __tcu_select_clk_div1(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) -+#define __tcu_select_clk_div4(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) -+#define __tcu_select_clk_div16(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) -+#define __tcu_select_clk_div64(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) -+#define __tcu_select_clk_div256(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) -+#define __tcu_select_clk_div1024(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) -+ -+#define __tcu_enable_pwm_output(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN ) -+#define __tcu_disable_pwm_output(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN ) -+ -+#define __tcu_init_pwm_output_high(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH ) -+#define __tcu_init_pwm_output_low(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH ) -+ -+#define __tcu_set_pwm_output_shutdown_graceful(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD ) -+#define __tcu_set_pwm_output_shutdown_abrupt(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD ) -+ -+#define __tcu_start_counter(n) ( REG_TCU_TESR |= (1 << (n)) ) -+#define __tcu_stop_counter(n) ( REG_TCU_TECR |= (1 << (n)) ) -+ -+#define __tcu_half_match_flag(n) ( REG_TCU_TFR & (1 << ((n) + 16)) ) -+#define __tcu_full_match_flag(n) ( REG_TCU_TFR & (1 << (n)) ) -+#define __tcu_set_half_match_flag(n) ( REG_TCU_TFSR = (1 << ((n) + 16)) ) -+#define __tcu_set_full_match_flag(n) ( REG_TCU_TFSR = (1 << (n)) ) -+#define __tcu_clear_half_match_flag(n) ( REG_TCU_TFCR = (1 << ((n) + 16)) ) -+#define __tcu_clear_full_match_flag(n) ( REG_TCU_TFCR = (1 << (n)) ) -+#define __tcu_mask_half_match_irq(n) ( REG_TCU_TMSR = (1 << ((n) + 16)) ) -+#define __tcu_mask_full_match_irq(n) ( REG_TCU_TMSR = (1 << (n)) ) -+#define __tcu_unmask_half_match_irq(n) ( REG_TCU_TMCR = (1 << ((n) + 16)) ) -+#define __tcu_unmask_full_match_irq(n) ( REG_TCU_TMCR = (1 << (n)) ) -+ -+#define __tcu_wdt_clock_stopped() ( REG_TCU_TSR & TCU_TSSR_WDTSC ) -+#define __tcu_timer_clock_stopped(n) ( REG_TCU_TSR & (1 << (n)) ) -+ -+#define __tcu_start_wdt_clock() ( REG_TCU_TSCR = TCU_TSSR_WDTSC ) -+#define __tcu_start_timer_clock(n) ( REG_TCU_TSCR = (1 << (n)) ) -+ -+#define __tcu_stop_wdt_clock() ( REG_TCU_TSSR = TCU_TSSR_WDTSC ) -+#define __tcu_stop_timer_clock(n) ( REG_TCU_TSSR = (1 << (n)) ) -+ -+#define __tcu_get_count(n) ( REG_TCU_TCNT((n)) ) -+#define __tcu_set_count(n,v) ( REG_TCU_TCNT((n)) = (v) ) -+#define __tcu_set_full_data(n,v) ( REG_TCU_TDFR((n)) = (v) ) -+#define __tcu_set_half_data(n,v) ( REG_TCU_TDHR((n)) = (v) ) -+ -+ -+/*************************************************************************** -+ * WDT -+ ***************************************************************************/ -+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) -+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) -+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) -+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) -+ -+#define __wdt_select_extalclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) -+#define __wdt_select_rtcclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) -+#define __wdt_select_pclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) -+ -+#define __wdt_select_clk_div1() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) -+#define __wdt_select_clk_div4() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) -+#define __wdt_select_clk_div16() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) -+#define __wdt_select_clk_div64() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) -+#define __wdt_select_clk_div256() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) -+#define __wdt_select_clk_div1024() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) -+ -+ -+/*************************************************************************** -+ * UART -+ ***************************************************************************/ -+ -+#define __uart_enable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) -+#define __uart_disable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) -+ -+#define __uart_enable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) -+#define __uart_disable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) -+ -+#define __uart_enable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) -+#define __uart_disable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) -+ -+#define __uart_enable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) -+#define __uart_disable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) -+ -+#define __uart_set_8n1(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) -+ -+#define __uart_set_baud(n, devclk, baud) \ -+ do { \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ -+ } while (0) -+ -+#define __uart_parity_error(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) -+ -+#define __uart_clear_errors(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) -+ -+#define __uart_transmit_fifo_empty(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) -+ -+#define __uart_transmit_end(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) -+ -+#define __uart_transmit_char(n, ch) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) -+ -+#define __uart_receive_fifo_full(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_ready(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_char(n) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) -+ -+#define __uart_disable_irda() \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) -+#define __uart_enable_irda() \ -+ /* Tx high pulse as 0, Rx low pulse as 0 */ \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) -+ -+ -+/*************************************************************************** -+ * DMAC -+ ***************************************************************************/ -+ -+/* n is the DMA channel (0 - 5) */ -+ -+#define __dmac_enable_module() \ -+ ( REG_DMAC_DMACR |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_RR ) -+#define __dmac_disable_module() \ -+ ( REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE ) -+ -+/* p=0,1,2,3 */ -+#define __dmac_set_priority(p) \ -+do { \ -+ REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ -+ REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ -+} while (0) -+ -+#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HLT ) -+#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AR ) -+ -+#define __dmac_enable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) -+#define __dmac_disable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) -+ -+#define __dmac_enable_channel(n) \ -+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN ) -+#define __dmac_disable_channel(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN ) -+#define __dmac_channel_enabled(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) -+ -+#define __dmac_channel_enable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) -+#define __dmac_channel_disable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) -+ -+#define __dmac_channel_transmit_halt_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) -+#define __dmac_channel_transmit_end_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) -+#define __dmac_channel_address_error_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) -+#define __dmac_channel_count_terminated_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) -+#define __dmac_channel_descriptor_invalid_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_clear_transmit_halt(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) -+#define __dmac_channel_clear_transmit_end(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) -+#define __dmac_channel_clear_address_error(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) -+#define __dmac_channel_clear_count_terminated(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) -+#define __dmac_channel_clear_descriptor_invalid(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_set_single_mode(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TM ) -+#define __dmac_channel_set_block_mode(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TM ) -+ -+#define __dmac_channel_set_transfer_unit_32bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_8bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_32byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_dest_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_src_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ -+} while (0) -+ -+/* v=0-15 */ -+#define __dmac_channel_set_rdil(n,v) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ -+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ -+} while (0) -+ -+#define __dmac_channel_dest_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) -+#define __dmac_channel_dest_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) -+ -+#define __dmac_channel_src_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) -+#define __dmac_channel_src_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) -+ -+#define __dmac_channel_set_doorbell(n) \ -+ ( REG_DMAC_DMADBSR = (1 << (n)) ) -+ -+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR & (1 << (n)) ) -+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR &= ~(1 << (n)) ) -+ -+static __inline__ int __dmac_get_irq(void) -+{ -+ int i; -+ for (i = 0; i < MAX_DMA_NUM; i++) -+ if (__dmac_channel_irq_detected(i)) -+ return i; -+ return -1; -+} -+ -+ -+/*************************************************************************** -+ * AIC (AC'97 & I2S Controller) -+ ***************************************************************************/ -+ -+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) -+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) -+ -+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) -+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) -+ -+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) -+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) -+ -+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) -+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) -+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) -+ -+#define __aic_reset() \ -+do { \ -+ REG_AIC_FR |= AIC_FR_RST; \ -+} while(0) -+ -+ -+#define __aic_set_transmit_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ -+} while(0) -+ -+#define __aic_set_receive_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ -+} while(0) -+ -+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) -+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) -+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) -+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) -+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) -+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) -+ -+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) -+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) -+ -+#define __aic_enable_transmit_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_disable_transmit_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_enable_receive_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) -+#define __aic_disable_receive_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) -+ -+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) -+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) -+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) -+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) -+ -+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) -+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) -+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) -+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) -+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) -+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) -+ -+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 -+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 -+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 -+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 -+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 -+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 -+ -+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 -+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 -+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 -+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 -+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 -+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 -+ -+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) -+#define __ac97_set_xs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ -+} while(0) -+#define __ac97_set_xs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ -+} while(0) -+ -+/* In fact, only stereo is support now. */ -+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) -+#define __ac97_set_rs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ -+} while(0) -+#define __ac97_set_rs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ -+} while(0) -+ -+#define __ac97_warm_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ -+ } while (0) -+ -+#define __ac97_cold_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ -+ } while (0) -+ -+/* n=8,16,18,20 */ -+#define __ac97_set_iass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) -+#define __ac97_set_oass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) -+ -+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) -+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) -+ -+/* n=8,16,18,20,24 */ -+/*#define __i2s_set_sample_size(n) \ -+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ -+ -+#define __i2s_set_oss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) -+#define __i2s_set_iss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) -+ -+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) -+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) -+ -+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) -+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) -+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) -+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) -+ -+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) -+ -+#define __aic_get_transmit_resident() \ -+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) -+#define __aic_get_receive_count() \ -+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) -+ -+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) -+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) -+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) -+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) -+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) -+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) -+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) -+ -+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) -+ -+#define CODEC_READ_CMD (1 << 19) -+#define CODEC_WRITE_CMD (0 << 19) -+#define CODEC_REG_INDEX_BIT 12 -+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ -+#define CODEC_REG_DATA_BIT 4 -+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ -+ -+#define __ac97_out_rcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_wcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_data(value) \ -+do { \ -+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ -+} while (0) -+ -+#define __ac97_in_data() \ -+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) -+ -+#define __ac97_in_status_addr() \ -+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) -+ -+#define __i2s_set_sample_rate(i2sclk, sync) \ -+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) -+ -+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) -+#define __aic_read_rfifo() ( REG_AIC_DR ) -+ -+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) -+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) -+ -+// -+// Define next ops for AC97 compatible -+// -+ -+#define AC97_ACSR AIC_ACSR -+ -+#define __ac97_enable() __aic_enable(); __aic_select_ac97() -+#define __ac97_disable() __aic_disable() -+#define __ac97_reset() __aic_reset() -+ -+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __ac97_enable_record() __aic_enable_record() -+#define __ac97_disable_record() __aic_disable_record() -+#define __ac97_enable_replay() __aic_enable_replay() -+#define __ac97_disable_replay() __aic_disable_replay() -+#define __ac97_enable_loopback() __aic_enable_loopback() -+#define __ac97_disable_loopback() __aic_disable_loopback() -+ -+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __ac97_enable_receive_dma() __aic_enable_receive_dma() -+#define __ac97_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __ac97_transmit_request() __aic_transmit_request() -+#define __ac97_receive_request() __aic_receive_request() -+#define __ac97_transmit_underrun() __aic_transmit_underrun() -+#define __ac97_receive_overrun() __aic_receive_overrun() -+ -+#define __ac97_clear_errors() __aic_clear_errors() -+ -+#define __ac97_get_transmit_resident() __aic_get_transmit_resident() -+#define __ac97_get_receive_count() __aic_get_receive_count() -+ -+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __ac97_enable_receive_intr() __aic_enable_receive_intr() -+#define __ac97_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __ac97_write_tfifo(v) __aic_write_tfifo(v) -+#define __ac97_read_rfifo() __aic_read_rfifo() -+ -+// -+// Define next ops for I2S compatible -+// -+ -+#define I2S_ACSR AIC_I2SSR -+ -+#define __i2s_enable() __aic_enable(); __aic_select_i2s() -+#define __i2s_disable() __aic_disable() -+#define __i2s_reset() __aic_reset() -+ -+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __i2s_enable_record() __aic_enable_record() -+#define __i2s_disable_record() __aic_disable_record() -+#define __i2s_enable_replay() __aic_enable_replay() -+#define __i2s_disable_replay() __aic_disable_replay() -+#define __i2s_enable_loopback() __aic_enable_loopback() -+#define __i2s_disable_loopback() __aic_disable_loopback() -+ -+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __i2s_enable_receive_dma() __aic_enable_receive_dma() -+#define __i2s_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __i2s_transmit_request() __aic_transmit_request() -+#define __i2s_receive_request() __aic_receive_request() -+#define __i2s_transmit_underrun() __aic_transmit_underrun() -+#define __i2s_receive_overrun() __aic_receive_overrun() -+ -+#define __i2s_clear_errors() __aic_clear_errors() -+ -+#define __i2s_get_transmit_resident() __aic_get_transmit_resident() -+#define __i2s_get_receive_count() __aic_get_receive_count() -+ -+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __i2s_enable_receive_intr() __aic_enable_receive_intr() -+#define __i2s_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __i2s_write_tfifo(v) __aic_write_tfifo(v) -+#define __i2s_read_rfifo() __aic_read_rfifo() -+ -+#define __i2s_reset_codec() \ -+ do { \ -+ } while (0) -+ -+ -+/*************************************************************************** -+ * ICDC -+ ***************************************************************************/ -+#define __i2s_internal_codec() __aic_internal_codec() -+#define __i2s_external_codec() __aic_external_codec() -+ -+/*************************************************************************** -+ * INTC -+ ***************************************************************************/ -+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) -+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) -+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) -+ -+ -+/*************************************************************************** -+ * I2C -+ ***************************************************************************/ -+ -+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) -+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) -+ -+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) -+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) -+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) -+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) -+ -+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) -+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) -+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) -+ -+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) -+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) -+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) -+ -+#define __i2c_set_clk(dev_clk, i2c_clk) \ -+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) -+ -+#define __i2c_read() ( REG_I2C_DR ) -+#define __i2c_write(val) ( REG_I2C_DR = (val) ) -+ -+ -+/*************************************************************************** -+ * MSC -+ ***************************************************************************/ -+ -+#define __msc_start_op() \ -+ ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) -+ -+#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) -+#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) -+#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) -+#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) -+#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) -+#define __msc_get_nob() ( REG_MSC_NOB ) -+#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) -+#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) -+#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) -+#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) -+ -+#define __msc_set_cmdat_bus_width1() \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_bus_width4() \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) -+#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) -+#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) -+#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) -+ -+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ -+#define __msc_set_cmdat_res_format(r) \ -+do { \ -+ REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ -+ REG_MSC_CMDAT |= (r); \ -+} while(0) -+ -+#define __msc_clear_cmdat() \ -+ REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ -+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ -+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) -+ -+#define __msc_get_imask() ( REG_MSC_IMASK ) -+#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) -+#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) -+#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) -+#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) -+#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) -+#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) -+ -+/* n=0,1,2,3,4,5,6,7 */ -+#define __msc_set_clkrt(n) \ -+do { \ -+ REG_MSC_CLKRT = n; \ -+} while(0) -+ -+#define __msc_get_ireg() ( REG_MSC_IREG ) -+#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) -+#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) -+#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) -+#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) -+ -+#define __msc_get_stat() ( REG_MSC_STAT ) -+#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) -+#define __msc_stat_crc_err() \ -+ ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) -+#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) -+#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) -+#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) -+#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) -+#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) -+ -+#define __msc_rd_resfifo() ( REG_MSC_RES ) -+#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) -+#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) -+ -+#define __msc_reset() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_RESET; \ -+ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ -+} while (0) -+ -+#define __msc_start_clk() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ -+} while (0) -+ -+#define __msc_stop_clk() \ -+do { \ -+ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ -+} while (0) -+ -+#define MMC_CLK 19169200 -+#define SD_CLK 24576000 -+ -+/* msc_clk should little than pclk and little than clk retrieve from card */ -+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ -+do { \ -+ unsigned int rate, pclk, i; \ -+ pclk = dev_clk; \ -+ rate = type?SD_CLK:MMC_CLK; \ -+ if (msc_clk && msc_clk < pclk) \ -+ pclk = msc_clk; \ -+ i = 0; \ -+ while (pclk < rate) \ -+ { \ -+ i ++; \ -+ rate >>= 1; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+/* divide rate to little than or equal to 400kHz */ -+#define __msc_calc_slow_clk_divisor(type, lv) \ -+do { \ -+ unsigned int rate, i; \ -+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ -+ i = 0; \ -+ while (rate > 0) \ -+ { \ -+ rate >>= 1; \ -+ i ++; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+ -+/*************************************************************************** -+ * SSI -+ ***************************************************************************/ -+ -+#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) -+#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) -+#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) -+ -+#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) -+ -+#define __ssi_select_ce2() \ -+do { \ -+ REG_SSI_CR0 |= SSI_CR0_FSEL; \ -+ REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_select_gpc() \ -+do { \ -+ REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ -+ REG_SSI_CR1 |= SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_enable_tx_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) -+ -+#define __ssi_disable_tx_intr() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) -+ -+#define __ssi_enable_rx_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) -+ -+#define __ssi_disable_rx_intr() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) -+ -+#define __ssi_enable_txfifo_half_empty_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TIE ) -+#define __ssi_disable_txfifo_half_empty_intr() \ -+ ( REG_SSI_CR0 &= ~SSI_CR0_TIE ) -+#define __ssi_enable_tx_error_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TEIE ) -+#define __ssi_disable_tx_error_intr() \ -+ ( REG_SSI_CR0 &= ~SSI_CR0_TEIE ) -+ -+#define __ssi_enable_rxfifo_half_full_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_RIE ) -+#define __ssi_disable_rxfifo_half_full_intr() \ -+ ( REG_SSI_CR0 &= ~SSI_CR0_RIE ) -+#define __ssi_enable_rx_error_intr() \ -+ ( REG_SSI_CR0 |= SSI_CR0_REIE ) -+#define __ssi_disable_rx_error_intr() \ -+ ( REG_SSI_CR0 &= ~SSI_CR0_REIE ) -+ -+#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) -+#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) -+ -+#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) -+#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) -+ -+#define __ssi_finish_receive() \ -+ ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_disable_recvfinish() \ -+ ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) -+#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) -+ -+#define __ssi_flush_fifo() \ -+ ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) -+ -+#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) -+#define __ssi_wait_transmit() ( REG_SSI_CR1 |= SSI_CR1_UNFIN ) -+ -+#define __ssi_spi_format() \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ -+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ -+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ -+} while (0) -+ -+/* TI's SSP format, must clear SSI_CR1.UNFIN */ -+#define __ssi_ssp_format() \ -+do { \ -+ REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ -+} while (0) -+ -+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ -+#define __ssi_microwire_format() \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ -+ REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ -+ REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ -+ REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ -+} while (0) -+ -+/* CE# level (FRMHL), CE# in interval time (ITFRM), -+ clock phase and polarity (PHA POL), -+ interval time (SSIITR), interval characters/frame (SSIICR) */ -+ -+ /* frmhl,endian,mcom,flen,pha,pol MASK */ -+#define SSICR1_MISC_MASK \ -+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ -+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ -+ -+#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ -+do { \ -+ REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ -+ REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ -+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ -+ ((pha) << 1) | (pol); \ -+} while(0) -+ -+/* Transfer with MSB or LSB first */ -+#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) -+#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) -+ -+#define __ssi_set_frame_length(n) \ -+ REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) -+ -+/* n = 1 - 16 */ -+#define __ssi_set_microwire_command_length(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) -+ -+/* Set the clock phase for SPI */ -+#define __ssi_set_spi_clock_phase(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1)<< 1))) -+ -+/* Set the clock polarity for SPI */ -+#define __ssi_set_spi_clock_polarity(n) \ -+ ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | (n&0x1)) ) -+ -+/* n = ix8 */ -+#define __ssi_set_tx_trigger(n) \ -+do { \ -+ REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ -+ REG_SSI_CR1 |= (n/8)<> SSI_SR_TFIFONUM_BIT ) -+ -+#define __ssi_get_rxfifo_count() \ -+ ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) -+ -+#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) -+#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) -+ -+#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) -+#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) -+#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF ) -+#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE ) -+#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR ) -+#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER ) -+#define __ssi_clear_underrun() ( REG_SSI_SR = ~SSI_SR_UNDR ) -+#define __ssi_clear_overrun() ( REG_SSI_SR = ~SSI_SR_OVER ) -+#define __ssi_clear_errors() \ -+ ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) -+ -+ -+#define __ssi_set_clk(dev_clk, ssi_clk) \ -+ ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) -+ -+#define __ssi_receive_data() REG_SSI_DR -+#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) -+ -+ -+/*************************************************************************** -+ * CIM -+ ***************************************************************************/ -+ -+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) -+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) -+ -+#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) -+#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) -+ -+#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) -+#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) -+ -+#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) -+#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) -+ -+#define __cim_sample_data_at_pclk_falling_edge() \ -+ ( REG_CIM_CFG |= CIM_CFG_PCP ) -+#define __cim_sample_data_at_pclk_rising_edge() \ -+ ( REG_CIM_CFG &= ~CIM_CFG_PCP ) -+ -+#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) -+#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) -+ -+#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) -+#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) -+ -+/* n=0-7 */ -+#define __cim_set_data_packing_mode(n) \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ -+ REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ -+} while (0) -+ -+#define __cim_enable_ccir656_progressive_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ -+} while (0) -+ -+#define __cim_enable_ccir656_interlace_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ -+} while (0) -+ -+#define __cim_enable_gated_clock_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ -+} while (0) -+ -+#define __cim_enable_nongated_clock_mode() \ -+do { \ -+ REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ -+ REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ -+} while (0) -+ -+/* sclk:system bus clock -+ * mclk: CIM master clock -+ */ -+#define __cim_set_master_clk(sclk, mclk) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ -+ REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ -+} while (0) -+ -+#define __cim_enable_sof_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) -+#define __cim_disable_sof_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) -+ -+#define __cim_enable_eof_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) -+#define __cim_disable_eof_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) -+ -+#define __cim_enable_stop_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) -+#define __cim_disable_stop_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) -+ -+#define __cim_enable_trig_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) -+#define __cim_disable_trig_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) -+ -+#define __cim_enable_rxfifo_overflow_intr() \ -+ ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) -+#define __cim_disable_rxfifo_overflow_intr() \ -+ ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) -+ -+/* n=1-16 */ -+#define __cim_set_frame_rate(n) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ -+ REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ -+} while (0) -+ -+#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) -+#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) -+ -+#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) -+#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) -+ -+/* n=4,8,12,16,20,24,28,32 */ -+#define __cim_set_rxfifo_trigger(n) \ -+do { \ -+ REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ -+ REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ -+} while (0) -+ -+#define __cim_clear_state() ( REG_CIM_STATE = 0 ) -+ -+#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) -+#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) -+#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) -+#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) -+#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) -+#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) -+#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) -+#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) -+ -+#define __cim_get_iid() ( REG_CIM_IID ) -+#define __cim_get_image_data() ( REG_CIM_RXFIFO ) -+#define __cim_get_dam_cmd() ( REG_CIM_CMD ) -+ -+#define __cim_set_da(a) ( REG_CIM_DA = (a) ) -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= (1<> LCD_VSYNC_VPS_BIT ) -+ -+#define __lcd_vsync_get_vpe() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) -+#define __lcd_vsync_set_vpe(n) \ -+do { \ -+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ -+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hps() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) -+#define __lcd_hsync_set_hps(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hpe() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) -+#define __lcd_hsync_set_hpe(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_ht() \ -+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) -+#define __lcd_vat_set_ht(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_vt() \ -+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) -+#define __lcd_vat_set_vt(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hds() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) -+#define __lcd_dah_set_hds(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hde() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) -+#define __lcd_dah_set_hde(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vds() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) -+#define __lcd_dav_set_vds(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vde() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) -+#define __lcd_dav_set_vde(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ -+} while (0) -+ -+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) -+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) -+ -+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) -+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) -+ -+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) -+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) -+ -+#define __lcd_cmd0_get_len() \ -+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+#define __lcd_cmd1_get_len() \ -+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+ -+/******************************************************* -+ * SMART LCD -+ *******************************************************/ -+ -+#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) -+#define __slcd_dma_disable() \ -+do {\ -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ -+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ -+} while(0) -+ -+/******************************************************* -+ * SMART LCD -+ *******************************************************/ -+ -+#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) -+#define __slcd_dma_disable() \ -+do {\ -+ while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ -+ REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ -+} while(0) -+ -+/*************************************************************************** -+ * RTC ops -+ ***************************************************************************/ -+ -+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) -+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) -+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) -+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) -+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) -+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) -+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) -+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) -+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) -+ -+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) -+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) -+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) -+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) -+ -+#define __rtc_get_second() ( REG_RTC_RSR ) -+#define __rtc_set_second(v) ( REG_RTC_RSR = v ) -+ -+#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) -+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) -+ -+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) -+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) -+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) -+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) -+#define __rtc_set_adjc_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) -+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) -+#define __rtc_set_nc1Hz_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) -+ -+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) -+ -+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) -+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) -+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) -+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) -+ -+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) -+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) -+ -+#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) -+#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) -+#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) -+#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) -+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) -+ -+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) -+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) -+ -+ -+ -+#endif /* __JZ4740_OPS_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/regs.h linux-2.6.24.7/include/asm-mips/mach-jz4740/regs.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/regs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/regs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2392 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/regs.h -+ * -+ * Ingenic's JZ4740 common include. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __JZ4740_REGS_H__ -+#define __JZ4740_REGS_H__ -+ -+#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY) -+#define REG8(addr) (addr) -+#define REG16(addr) (addr) -+#define REG32(addr) (addr) -+#else -+#define REG8(addr) *((volatile unsigned char *)(addr)) -+#define REG16(addr) *((volatile unsigned short *)(addr)) -+#define REG32(addr) *((volatile unsigned int *)(addr)) -+#endif -+ -+/* -+ * Define the module base addresses -+ */ -+#define CPM_BASE 0xB0000000 -+#define INTC_BASE 0xB0001000 -+#define TCU_BASE 0xB0002000 -+#define WDT_BASE 0xB0002000 -+#define RTC_BASE 0xB0003000 -+#define GPIO_BASE 0xB0010000 -+#define AIC_BASE 0xB0020000 -+#define ICDC_BASE 0xB0020000 -+#define MSC_BASE 0xB0021000 -+#define UART0_BASE 0xB0030000 -+#define UART1_BASE 0xB0031000 -+#define I2C_BASE 0xB0042000 -+#define SSI_BASE 0xB0043000 -+#define SADC_BASE 0xB0070000 -+#define EMC_BASE 0xB3010000 -+#define DMAC_BASE 0xB3020000 -+#define UHC_BASE 0xB3030000 -+#define UDC_BASE 0xB3040000 -+#define LCD_BASE 0xB3050000 -+#define SLCD_BASE 0xB3050000 -+#define CIM_BASE 0xB3060000 -+#define IPU_BASE 0xB3080000 -+#define ETH_BASE 0xB3100000 -+ -+ -+/************************************************************************* -+ * INTC (Interrupt Controller) -+ *************************************************************************/ -+#define INTC_ISR (INTC_BASE + 0x00) -+#define INTC_IMR (INTC_BASE + 0x04) -+#define INTC_IMSR (INTC_BASE + 0x08) -+#define INTC_IMCR (INTC_BASE + 0x0c) -+#define INTC_IPR (INTC_BASE + 0x10) -+ -+#define REG_INTC_ISR REG32(INTC_ISR) -+#define REG_INTC_IMR REG32(INTC_IMR) -+#define REG_INTC_IMSR REG32(INTC_IMSR) -+#define REG_INTC_IMCR REG32(INTC_IMCR) -+#define REG_INTC_IPR REG32(INTC_IPR) -+ -+// 1st-level interrupts -+#define IRQ_I2C 1 -+#define IRQ_UHC 3 -+#define IRQ_UART1 8 -+#define IRQ_UART0 9 -+#define IRQ_SADC 12 -+#define IRQ_MSC 14 -+#define IRQ_RTC 15 -+#define IRQ_SSI 16 -+#define IRQ_CIM 17 -+#define IRQ_AIC 18 -+#define IRQ_ETH 19 -+#define IRQ_DMAC 20 -+#define IRQ_TCU2 21 -+#define IRQ_TCU1 22 -+#define IRQ_TCU0 23 -+#define IRQ_UDC 24 -+#define IRQ_GPIO3 25 -+#define IRQ_GPIO2 26 -+#define IRQ_GPIO1 27 -+#define IRQ_GPIO0 28 -+#define IRQ_IPU 29 -+#define IRQ_LCD 30 -+ -+// 2nd-level interrupts -+#define IRQ_DMA_0 32 /* 32 to 37 for DMAC channel 0 to 5 */ -+#define IRQ_GPIO_0 48 /* 48 to 175 for GPIO pin 0 to 127 */ -+ -+#define NUM_DMA 6 -+#define NUM_GPIO 128 -+/************************************************************************* -+ * RTC -+ *************************************************************************/ -+#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */ -+#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */ -+#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */ -+#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */ -+ -+#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */ -+#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */ -+#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */ -+#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */ -+#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */ -+#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */ -+ -+#define REG_RTC_RCR REG32(RTC_RCR) -+#define REG_RTC_RSR REG32(RTC_RSR) -+#define REG_RTC_RSAR REG32(RTC_RSAR) -+#define REG_RTC_RGR REG32(RTC_RGR) -+#define REG_RTC_HCR REG32(RTC_HCR) -+#define REG_RTC_HWFCR REG32(RTC_HWFCR) -+#define REG_RTC_HRCR REG32(RTC_HRCR) -+#define REG_RTC_HWCR REG32(RTC_HWCR) -+#define REG_RTC_HWRSR REG32(RTC_HWRSR) -+#define REG_RTC_HSPR REG32(RTC_HSPR) -+ -+/* RTC Control Register */ -+#define RTC_RCR_WRDY_BIT 7 -+#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */ -+#define RTC_RCR_1HZ_BIT 6 -+#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */ -+#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */ -+#define RTC_RCR_AF_BIT 4 -+#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */ -+#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */ -+#define RTC_RCR_AE (1 << 2) /* Alarm Enable */ -+#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */ -+ -+/* RTC Regulator Register */ -+#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */ -+#define RTC_RGR_ADJC_BIT 16 -+#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT) -+#define RTC_RGR_NC1HZ_BIT 0 -+#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT) -+ -+/* Hibernate Control Register */ -+#define RTC_HCR_PD (1 << 0) /* Power Down */ -+ -+/* Hibernate Wakeup Filter Counter Register */ -+#define RTC_HWFCR_BIT 5 -+#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) -+ -+/* Hibernate Reset Counter Register */ -+#define RTC_HRCR_BIT 5 -+#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) -+ -+/* Hibernate Wakeup Control Register */ -+#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ -+ -+/* Hibernate Wakeup Status Register */ -+#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ -+#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ -+#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ -+#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ -+ -+ -+/************************************************************************* -+ * CPM (Clock reset and Power control Management) -+ *************************************************************************/ -+#define CPM_CPCCR (CPM_BASE+0x00) -+#define CPM_CPPCR (CPM_BASE+0x10) -+#define CPM_I2SCDR (CPM_BASE+0x60) -+#define CPM_LPCDR (CPM_BASE+0x64) -+#define CPM_MSCCDR (CPM_BASE+0x68) -+#define CPM_UHCCDR (CPM_BASE+0x6C) -+#define CPM_SSICDR (CPM_BASE+0x74) -+ -+#define CPM_LCR (CPM_BASE+0x04) -+#define CPM_CLKGR (CPM_BASE+0x20) -+#define CPM_SCR (CPM_BASE+0x24) -+ -+#define CPM_HCR (CPM_BASE+0x30) -+#define CPM_HWFCR (CPM_BASE+0x34) -+#define CPM_HRCR (CPM_BASE+0x38) -+#define CPM_HWCR (CPM_BASE+0x3c) -+#define CPM_HWSR (CPM_BASE+0x40) -+#define CPM_HSPR (CPM_BASE+0x44) -+ -+#define CPM_RSR (CPM_BASE+0x08) -+ -+ -+#define REG_CPM_CPCCR REG32(CPM_CPCCR) -+#define REG_CPM_CPPCR REG32(CPM_CPPCR) -+#define REG_CPM_I2SCDR REG32(CPM_I2SCDR) -+#define REG_CPM_LPCDR REG32(CPM_LPCDR) -+#define REG_CPM_MSCCDR REG32(CPM_MSCCDR) -+#define REG_CPM_UHCCDR REG32(CPM_UHCCDR) -+#define REG_CPM_SSICDR REG32(CPM_SSICDR) -+ -+#define REG_CPM_LCR REG32(CPM_LCR) -+#define REG_CPM_CLKGR REG32(CPM_CLKGR) -+#define REG_CPM_SCR REG32(CPM_SCR) -+#define REG_CPM_HCR REG32(CPM_HCR) -+#define REG_CPM_HWFCR REG32(CPM_HWFCR) -+#define REG_CPM_HRCR REG32(CPM_HRCR) -+#define REG_CPM_HWCR REG32(CPM_HWCR) -+#define REG_CPM_HWSR REG32(CPM_HWSR) -+#define REG_CPM_HSPR REG32(CPM_HSPR) -+ -+#define REG_CPM_RSR REG32(CPM_RSR) -+ -+ -+/* Clock Control Register */ -+#define CPM_CPCCR_I2CS (1 << 31) -+#define CPM_CPCCR_CLKOEN (1 << 30) -+#define CPM_CPCCR_UCS (1 << 29) -+#define CPM_CPCCR_UDIV_BIT 23 -+#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT) -+#define CPM_CPCCR_CE (1 << 22) -+#define CPM_CPCCR_PCS (1 << 21) -+#define CPM_CPCCR_LDIV_BIT 16 -+#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT) -+#define CPM_CPCCR_MDIV_BIT 12 -+#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT) -+#define CPM_CPCCR_PDIV_BIT 8 -+#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT) -+#define CPM_CPCCR_HDIV_BIT 4 -+#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT) -+#define CPM_CPCCR_CDIV_BIT 0 -+#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT) -+ -+/* I2S Clock Divider Register */ -+#define CPM_I2SCDR_I2SDIV_BIT 0 -+#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT) -+ -+/* LCD Pixel Clock Divider Register */ -+#define CPM_LPCDR_PIXDIV_BIT 0 -+#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT) -+ -+/* MSC Clock Divider Register */ -+#define CPM_MSCCDR_MSCDIV_BIT 0 -+#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT) -+ -+/* UHC Clock Divider Register */ -+#define CPM_UHCCDR_UHCDIV_BIT 0 -+#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT) -+ -+/* SSI Clock Divider Register */ -+#define CPM_SSICDR_SCS (1<<31) /* SSI clock source selection, 0:EXCLK, 1: PLL */ -+#define CPM_SSICDR_SSIDIV_BIT 0 -+#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT) -+ -+/* PLL Control Register */ -+#define CPM_CPPCR_PLLM_BIT 23 -+#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT) -+#define CPM_CPPCR_PLLN_BIT 18 -+#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT) -+#define CPM_CPPCR_PLLOD_BIT 16 -+#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT) -+#define CPM_CPPCR_PLLS (1 << 10) -+#define CPM_CPPCR_PLLBP (1 << 9) -+#define CPM_CPPCR_PLLEN (1 << 8) -+#define CPM_CPPCR_PLLST_BIT 0 -+#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT) -+ -+/* Low Power Control Register */ -+#define CPM_LCR_DOZE_DUTY_BIT 3 -+#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT) -+#define CPM_LCR_DOZE_ON (1 << 2) -+#define CPM_LCR_LPM_BIT 0 -+#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT) -+ #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT) -+ #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT) -+ -+/* Clock Gate Register */ -+#define CPM_CLKGR_UART1 (1 << 15) -+#define CPM_CLKGR_UHC (1 << 14) -+#define CPM_CLKGR_IPU (1 << 13) -+#define CPM_CLKGR_DMAC (1 << 12) -+#define CPM_CLKGR_UDC (1 << 11) -+#define CPM_CLKGR_LCD (1 << 10) -+#define CPM_CLKGR_CIM (1 << 9) -+#define CPM_CLKGR_SADC (1 << 8) -+#define CPM_CLKGR_MSC (1 << 7) -+#define CPM_CLKGR_AIC1 (1 << 6) -+#define CPM_CLKGR_AIC2 (1 << 5) -+#define CPM_CLKGR_SSI (1 << 4) -+#define CPM_CLKGR_I2C (1 << 3) -+#define CPM_CLKGR_RTC (1 << 2) -+#define CPM_CLKGR_TCU (1 << 1) -+#define CPM_CLKGR_UART0 (1 << 0) -+ -+/* Sleep Control Register */ -+#define CPM_SCR_O1ST_BIT 8 -+#define CPM_SCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT) -+#define CPM_SCR_USBPHY_ENABLE (1 << 6) -+#define CPM_SCR_OSC_ENABLE (1 << 4) -+ -+/* Hibernate Control Register */ -+#define CPM_HCR_PD (1 << 0) -+ -+/* Wakeup Filter Counter Register in Hibernate Mode */ -+#define CPM_HWFCR_TIME_BIT 0 -+#define CPM_HWFCR_TIME_MASK (0x3ff << CPM_HWFCR_TIME_BIT) -+ -+/* Reset Counter Register in Hibernate Mode */ -+#define CPM_HRCR_TIME_BIT 0 -+#define CPM_HRCR_TIME_MASK (0x7f << CPM_HRCR_TIME_BIT) -+ -+/* Wakeup Control Register in Hibernate Mode */ -+#define CPM_HWCR_WLE_LOW (0 << 2) -+#define CPM_HWCR_WLE_HIGH (1 << 2) -+#define CPM_HWCR_PIN_WAKEUP (1 << 1) -+#define CPM_HWCR_RTC_WAKEUP (1 << 0) -+ -+/* Wakeup Status Register in Hibernate Mode */ -+#define CPM_HWSR_WSR_PIN (1 << 1) -+#define CPM_HWSR_WSR_RTC (1 << 0) -+ -+/* Reset Status Register */ -+#define CPM_RSR_HR (1 << 2) -+#define CPM_RSR_WR (1 << 1) -+#define CPM_RSR_PR (1 << 0) -+ -+ -+/************************************************************************* -+ * TCU (Timer Counter Unit) -+ *************************************************************************/ -+#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */ -+#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */ -+#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */ -+#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */ -+#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */ -+#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */ -+#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */ -+#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */ -+#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */ -+#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */ -+#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */ -+#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */ -+#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */ -+#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */ -+#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */ -+#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */ -+#define TCU_TDFR1 (TCU_BASE + 0x50) -+#define TCU_TDHR1 (TCU_BASE + 0x54) -+#define TCU_TCNT1 (TCU_BASE + 0x58) -+#define TCU_TCSR1 (TCU_BASE + 0x5C) -+#define TCU_TDFR2 (TCU_BASE + 0x60) -+#define TCU_TDHR2 (TCU_BASE + 0x64) -+#define TCU_TCNT2 (TCU_BASE + 0x68) -+#define TCU_TCSR2 (TCU_BASE + 0x6C) -+#define TCU_TDFR3 (TCU_BASE + 0x70) -+#define TCU_TDHR3 (TCU_BASE + 0x74) -+#define TCU_TCNT3 (TCU_BASE + 0x78) -+#define TCU_TCSR3 (TCU_BASE + 0x7C) -+#define TCU_TDFR4 (TCU_BASE + 0x80) -+#define TCU_TDHR4 (TCU_BASE + 0x84) -+#define TCU_TCNT4 (TCU_BASE + 0x88) -+#define TCU_TCSR4 (TCU_BASE + 0x8C) -+#define TCU_TDFR5 (TCU_BASE + 0x90) -+#define TCU_TDHR5 (TCU_BASE + 0x94) -+#define TCU_TCNT5 (TCU_BASE + 0x98) -+#define TCU_TCSR5 (TCU_BASE + 0x9C) -+ -+#define REG_TCU_TSR REG32(TCU_TSR) -+#define REG_TCU_TSSR REG32(TCU_TSSR) -+#define REG_TCU_TSCR REG32(TCU_TSCR) -+#define REG_TCU_TER REG8(TCU_TER) -+#define REG_TCU_TESR REG8(TCU_TESR) -+#define REG_TCU_TECR REG8(TCU_TECR) -+#define REG_TCU_TFR REG32(TCU_TFR) -+#define REG_TCU_TFSR REG32(TCU_TFSR) -+#define REG_TCU_TFCR REG32(TCU_TFCR) -+#define REG_TCU_TMR REG32(TCU_TMR) -+#define REG_TCU_TMSR REG32(TCU_TMSR) -+#define REG_TCU_TMCR REG32(TCU_TMCR) -+#define REG_TCU_TDFR0 REG16(TCU_TDFR0) -+#define REG_TCU_TDHR0 REG16(TCU_TDHR0) -+#define REG_TCU_TCNT0 REG16(TCU_TCNT0) -+#define REG_TCU_TCSR0 REG16(TCU_TCSR0) -+#define REG_TCU_TDFR1 REG16(TCU_TDFR1) -+#define REG_TCU_TDHR1 REG16(TCU_TDHR1) -+#define REG_TCU_TCNT1 REG16(TCU_TCNT1) -+#define REG_TCU_TCSR1 REG16(TCU_TCSR1) -+#define REG_TCU_TDFR2 REG16(TCU_TDFR2) -+#define REG_TCU_TDHR2 REG16(TCU_TDHR2) -+#define REG_TCU_TCNT2 REG16(TCU_TCNT2) -+#define REG_TCU_TCSR2 REG16(TCU_TCSR2) -+#define REG_TCU_TDFR3 REG16(TCU_TDFR3) -+#define REG_TCU_TDHR3 REG16(TCU_TDHR3) -+#define REG_TCU_TCNT3 REG16(TCU_TCNT3) -+#define REG_TCU_TCSR3 REG16(TCU_TCSR3) -+#define REG_TCU_TDFR4 REG16(TCU_TDFR4) -+#define REG_TCU_TDHR4 REG16(TCU_TDHR4) -+#define REG_TCU_TCNT4 REG16(TCU_TCNT4) -+#define REG_TCU_TCSR4 REG16(TCU_TCSR4) -+ -+// n = 0,1,2,3,4,5 -+#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */ -+#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */ -+#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */ -+#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */ -+ -+#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n))) -+#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n))) -+#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n))) -+#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n))) -+ -+// Register definitions -+#define TCU_TCSR_PWM_SD (1 << 9) -+#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) -+#define TCU_TCSR_PWM_EN (1 << 7) -+#define TCU_TCSR_PRESCALE_BIT 3 -+#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT) -+ #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT) -+#define TCU_TCSR_EXT_EN (1 << 2) -+#define TCU_TCSR_RTC_EN (1 << 1) -+#define TCU_TCSR_PCK_EN (1 << 0) -+ -+#define TCU_TER_TCEN5 (1 << 5) -+#define TCU_TER_TCEN4 (1 << 4) -+#define TCU_TER_TCEN3 (1 << 3) -+#define TCU_TER_TCEN2 (1 << 2) -+#define TCU_TER_TCEN1 (1 << 1) -+#define TCU_TER_TCEN0 (1 << 0) -+ -+#define TCU_TESR_TCST5 (1 << 5) -+#define TCU_TESR_TCST4 (1 << 4) -+#define TCU_TESR_TCST3 (1 << 3) -+#define TCU_TESR_TCST2 (1 << 2) -+#define TCU_TESR_TCST1 (1 << 1) -+#define TCU_TESR_TCST0 (1 << 0) -+ -+#define TCU_TECR_TCCL5 (1 << 5) -+#define TCU_TECR_TCCL4 (1 << 4) -+#define TCU_TECR_TCCL3 (1 << 3) -+#define TCU_TECR_TCCL2 (1 << 2) -+#define TCU_TECR_TCCL1 (1 << 1) -+#define TCU_TECR_TCCL0 (1 << 0) -+ -+#define TCU_TFR_HFLAG5 (1 << 21) -+#define TCU_TFR_HFLAG4 (1 << 20) -+#define TCU_TFR_HFLAG3 (1 << 19) -+#define TCU_TFR_HFLAG2 (1 << 18) -+#define TCU_TFR_HFLAG1 (1 << 17) -+#define TCU_TFR_HFLAG0 (1 << 16) -+#define TCU_TFR_FFLAG5 (1 << 5) -+#define TCU_TFR_FFLAG4 (1 << 4) -+#define TCU_TFR_FFLAG3 (1 << 3) -+#define TCU_TFR_FFLAG2 (1 << 2) -+#define TCU_TFR_FFLAG1 (1 << 1) -+#define TCU_TFR_FFLAG0 (1 << 0) -+ -+#define TCU_TFSR_HFLAG5 (1 << 21) -+#define TCU_TFSR_HFLAG4 (1 << 20) -+#define TCU_TFSR_HFLAG3 (1 << 19) -+#define TCU_TFSR_HFLAG2 (1 << 18) -+#define TCU_TFSR_HFLAG1 (1 << 17) -+#define TCU_TFSR_HFLAG0 (1 << 16) -+#define TCU_TFSR_FFLAG5 (1 << 5) -+#define TCU_TFSR_FFLAG4 (1 << 4) -+#define TCU_TFSR_FFLAG3 (1 << 3) -+#define TCU_TFSR_FFLAG2 (1 << 2) -+#define TCU_TFSR_FFLAG1 (1 << 1) -+#define TCU_TFSR_FFLAG0 (1 << 0) -+ -+#define TCU_TFCR_HFLAG5 (1 << 21) -+#define TCU_TFCR_HFLAG4 (1 << 20) -+#define TCU_TFCR_HFLAG3 (1 << 19) -+#define TCU_TFCR_HFLAG2 (1 << 18) -+#define TCU_TFCR_HFLAG1 (1 << 17) -+#define TCU_TFCR_HFLAG0 (1 << 16) -+#define TCU_TFCR_FFLAG5 (1 << 5) -+#define TCU_TFCR_FFLAG4 (1 << 4) -+#define TCU_TFCR_FFLAG3 (1 << 3) -+#define TCU_TFCR_FFLAG2 (1 << 2) -+#define TCU_TFCR_FFLAG1 (1 << 1) -+#define TCU_TFCR_FFLAG0 (1 << 0) -+ -+#define TCU_TMR_HMASK5 (1 << 21) -+#define TCU_TMR_HMASK4 (1 << 20) -+#define TCU_TMR_HMASK3 (1 << 19) -+#define TCU_TMR_HMASK2 (1 << 18) -+#define TCU_TMR_HMASK1 (1 << 17) -+#define TCU_TMR_HMASK0 (1 << 16) -+#define TCU_TMR_FMASK5 (1 << 5) -+#define TCU_TMR_FMASK4 (1 << 4) -+#define TCU_TMR_FMASK3 (1 << 3) -+#define TCU_TMR_FMASK2 (1 << 2) -+#define TCU_TMR_FMASK1 (1 << 1) -+#define TCU_TMR_FMASK0 (1 << 0) -+ -+#define TCU_TMSR_HMST5 (1 << 21) -+#define TCU_TMSR_HMST4 (1 << 20) -+#define TCU_TMSR_HMST3 (1 << 19) -+#define TCU_TMSR_HMST2 (1 << 18) -+#define TCU_TMSR_HMST1 (1 << 17) -+#define TCU_TMSR_HMST0 (1 << 16) -+#define TCU_TMSR_FMST5 (1 << 5) -+#define TCU_TMSR_FMST4 (1 << 4) -+#define TCU_TMSR_FMST3 (1 << 3) -+#define TCU_TMSR_FMST2 (1 << 2) -+#define TCU_TMSR_FMST1 (1 << 1) -+#define TCU_TMSR_FMST0 (1 << 0) -+ -+#define TCU_TMCR_HMCL5 (1 << 21) -+#define TCU_TMCR_HMCL4 (1 << 20) -+#define TCU_TMCR_HMCL3 (1 << 19) -+#define TCU_TMCR_HMCL2 (1 << 18) -+#define TCU_TMCR_HMCL1 (1 << 17) -+#define TCU_TMCR_HMCL0 (1 << 16) -+#define TCU_TMCR_FMCL5 (1 << 5) -+#define TCU_TMCR_FMCL4 (1 << 4) -+#define TCU_TMCR_FMCL3 (1 << 3) -+#define TCU_TMCR_FMCL2 (1 << 2) -+#define TCU_TMCR_FMCL1 (1 << 1) -+#define TCU_TMCR_FMCL0 (1 << 0) -+ -+#define TCU_TSR_WDTS (1 << 16) -+#define TCU_TSR_STOP5 (1 << 5) -+#define TCU_TSR_STOP4 (1 << 4) -+#define TCU_TSR_STOP3 (1 << 3) -+#define TCU_TSR_STOP2 (1 << 2) -+#define TCU_TSR_STOP1 (1 << 1) -+#define TCU_TSR_STOP0 (1 << 0) -+ -+#define TCU_TSSR_WDTSS (1 << 16) -+#define TCU_TSSR_STPS5 (1 << 5) -+#define TCU_TSSR_STPS4 (1 << 4) -+#define TCU_TSSR_STPS3 (1 << 3) -+#define TCU_TSSR_STPS2 (1 << 2) -+#define TCU_TSSR_STPS1 (1 << 1) -+#define TCU_TSSR_STPS0 (1 << 0) -+ -+#define TCU_TSSR_WDTSC (1 << 16) -+#define TCU_TSSR_STPC5 (1 << 5) -+#define TCU_TSSR_STPC4 (1 << 4) -+#define TCU_TSSR_STPC3 (1 << 3) -+#define TCU_TSSR_STPC2 (1 << 2) -+#define TCU_TSSR_STPC1 (1 << 1) -+#define TCU_TSSR_STPC0 (1 << 0) -+ -+ -+/************************************************************************* -+ * WDT (WatchDog Timer) -+ *************************************************************************/ -+#define WDT_TDR (WDT_BASE + 0x00) -+#define WDT_TCER (WDT_BASE + 0x04) -+#define WDT_TCNT (WDT_BASE + 0x08) -+#define WDT_TCSR (WDT_BASE + 0x0C) -+ -+#define REG_WDT_TDR REG16(WDT_TDR) -+#define REG_WDT_TCER REG8(WDT_TCER) -+#define REG_WDT_TCNT REG16(WDT_TCNT) -+#define REG_WDT_TCSR REG16(WDT_TCSR) -+ -+// Register definition -+#define WDT_TCSR_PRESCALE_BIT 3 -+#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT) -+ #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT) -+#define WDT_TCSR_EXT_EN (1 << 2) -+#define WDT_TCSR_RTC_EN (1 << 1) -+#define WDT_TCSR_PCK_EN (1 << 0) -+ -+#define WDT_TCER_TCEN (1 << 0) -+ -+ -+/************************************************************************* -+ * DMAC (DMA Controller) -+ *************************************************************************/ -+ -+#define MAX_DMA_NUM 6 /* max 6 channels */ -+ -+#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) /* DMA source address */ -+#define DMAC_DTAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) /* DMA target address */ -+#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) /* DMA transfer count */ -+#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) /* DMA request source */ -+#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */ -+#define DMAC_DCMD(n) (DMAC_BASE + (0x14 + (n) * 0x20)) /* DMA command */ -+#define DMAC_DDA(n) (DMAC_BASE + (0x18 + (n) * 0x20)) /* DMA descriptor address */ -+#define DMAC_DMACR (DMAC_BASE + 0x0300) /* DMA control register */ -+#define DMAC_DMAIPR (DMAC_BASE + 0x0304) /* DMA interrupt pending */ -+#define DMAC_DMADBR (DMAC_BASE + 0x0308) /* DMA doorbell */ -+#define DMAC_DMADBSR (DMAC_BASE + 0x030C) /* DMA doorbell set */ -+ -+// channel 0 -+#define DMAC_DSAR0 DMAC_DSAR(0) -+#define DMAC_DTAR0 DMAC_DTAR(0) -+#define DMAC_DTCR0 DMAC_DTCR(0) -+#define DMAC_DRSR0 DMAC_DRSR(0) -+#define DMAC_DCCSR0 DMAC_DCCSR(0) -+#define DMAC_DCMD0 DMAC_DCMD(0) -+#define DMAC_DDA0 DMAC_DDA(0) -+ -+// channel 1 -+#define DMAC_DSAR1 DMAC_DSAR(1) -+#define DMAC_DTAR1 DMAC_DTAR(1) -+#define DMAC_DTCR1 DMAC_DTCR(1) -+#define DMAC_DRSR1 DMAC_DRSR(1) -+#define DMAC_DCCSR1 DMAC_DCCSR(1) -+#define DMAC_DCMD1 DMAC_DCMD(1) -+#define DMAC_DDA1 DMAC_DDA(1) -+ -+// channel 2 -+#define DMAC_DSAR2 DMAC_DSAR(2) -+#define DMAC_DTAR2 DMAC_DTAR(2) -+#define DMAC_DTCR2 DMAC_DTCR(2) -+#define DMAC_DRSR2 DMAC_DRSR(2) -+#define DMAC_DCCSR2 DMAC_DCCSR(2) -+#define DMAC_DCMD2 DMAC_DCMD(2) -+#define DMAC_DDA2 DMAC_DDA(2) -+ -+// channel 3 -+#define DMAC_DSAR3 DMAC_DSAR(3) -+#define DMAC_DTAR3 DMAC_DTAR(3) -+#define DMAC_DTCR3 DMAC_DTCR(3) -+#define DMAC_DRSR3 DMAC_DRSR(3) -+#define DMAC_DCCSR3 DMAC_DCCSR(3) -+#define DMAC_DCMD3 DMAC_DCMD(3) -+#define DMAC_DDA3 DMAC_DDA(3) -+ -+// channel 4 -+#define DMAC_DSAR4 DMAC_DSAR(4) -+#define DMAC_DTAR4 DMAC_DTAR(4) -+#define DMAC_DTCR4 DMAC_DTCR(4) -+#define DMAC_DRSR4 DMAC_DRSR(4) -+#define DMAC_DCCSR4 DMAC_DCCSR(4) -+#define DMAC_DCMD4 DMAC_DCMD(4) -+#define DMAC_DDA4 DMAC_DDA(4) -+ -+// channel 5 -+#define DMAC_DSAR5 DMAC_DSAR(5) -+#define DMAC_DTAR5 DMAC_DTAR(5) -+#define DMAC_DTCR5 DMAC_DTCR(5) -+#define DMAC_DRSR5 DMAC_DRSR(5) -+#define DMAC_DCCSR5 DMAC_DCCSR(5) -+#define DMAC_DCMD5 DMAC_DCMD(5) -+#define DMAC_DDA5 DMAC_DDA(5) -+ -+#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) -+#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n))) -+#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) -+#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) -+#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) -+#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n))) -+#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n))) -+#define REG_DMAC_DMACR REG32(DMAC_DMACR) -+#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) -+#define REG_DMAC_DMADBR REG32(DMAC_DMADBR) -+#define REG_DMAC_DMADBSR REG32(DMAC_DMADBSR) -+ -+// DMA request source register -+#define DMAC_DRSR_RS_BIT 0 -+#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT) -+ #define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT) -+ -+// DMA channel control/status register -+#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */ -+#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */ -+#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT) -+#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */ -+#define DMAC_DCCSR_AR (1 << 4) /* address error */ -+#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */ -+#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */ -+#define DMAC_DCCSR_CT (1 << 1) /* count terminated */ -+#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */ -+ -+// DMA channel command register -+#define DMAC_DCMD_SAI (1 << 23) /* source address increment */ -+#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */ -+#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */ -+#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT) -+ #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT) -+#define DMAC_DCMD_SWDH_BIT 14 /* source port width */ -+#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT) -+ #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT) -+ #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT) -+ #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT) -+#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */ -+#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT) -+ #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT) -+ #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT) -+ #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT) -+#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */ -+#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT) -+ #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT) -+ #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT) -+ #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT) -+ #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT) -+ #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT) -+#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */ -+#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */ -+#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */ -+#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */ -+#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */ -+#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */ -+ -+// DMA descriptor address register -+#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */ -+#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT) -+#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */ -+#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT) -+ -+// DMA control register -+#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */ -+#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT) -+ #define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */ -+#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */ -+#define DMAC_DMACR_AR (1 << 2) /* address error flag */ -+#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */ -+ -+// DMA doorbell register -+#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */ -+#define DMAC_DMADBR_DB4 (1 << 5) /* doorbell for channel 4 */ -+#define DMAC_DMADBR_DB3 (1 << 5) /* doorbell for channel 3 */ -+#define DMAC_DMADBR_DB2 (1 << 5) /* doorbell for channel 2 */ -+#define DMAC_DMADBR_DB1 (1 << 5) /* doorbell for channel 1 */ -+#define DMAC_DMADBR_DB0 (1 << 5) /* doorbell for channel 0 */ -+ -+// DMA doorbell set register -+#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */ -+#define DMAC_DMADBSR_DBS4 (1 << 5) /* enable doorbell for channel 4 */ -+#define DMAC_DMADBSR_DBS3 (1 << 5) /* enable doorbell for channel 3 */ -+#define DMAC_DMADBSR_DBS2 (1 << 5) /* enable doorbell for channel 2 */ -+#define DMAC_DMADBSR_DBS1 (1 << 5) /* enable doorbell for channel 1 */ -+#define DMAC_DMADBSR_DBS0 (1 << 5) /* enable doorbell for channel 0 */ -+ -+// DMA interrupt pending register -+#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */ -+#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */ -+#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */ -+#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */ -+#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */ -+#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */ -+ -+ -+/************************************************************************* -+ * GPIO (General-Purpose I/O Ports) -+ *************************************************************************/ -+#define MAX_GPIO_NUM 128 -+ -+//n = 0,1,2,3 -+#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */ -+#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */ -+#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */ -+#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */ -+#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */ -+#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */ -+#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */ -+#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */ -+#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */ -+#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */ -+#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */ -+#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */ -+#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */ -+#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */ -+#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */ -+#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */ -+#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */ -+#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */ -+#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */ -+#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */ -+#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */ -+#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */ -+#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */ -+#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */ -+ -+#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */ -+#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */ -+#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n))) -+#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n))) -+#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */ -+#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n))) -+#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n))) -+#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */ -+#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n))) -+#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n))) -+#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */ -+#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n))) -+#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n))) -+#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/ -+#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n))) -+#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n))) -+#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */ -+#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n))) -+#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n))) -+#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */ -+#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n))) -+#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n))) -+#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */ -+#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */ -+ -+ -+/************************************************************************* -+ * UART -+ *************************************************************************/ -+ -+#define IRDA_BASE UART0_BASE -+#define UART_BASE UART0_BASE -+#define UART_OFF 0x1000 -+ -+/* Register Offset */ -+#define OFF_RDR (0x00) /* R 8b H'xx */ -+#define OFF_TDR (0x00) /* W 8b H'xx */ -+#define OFF_DLLR (0x00) /* RW 8b H'00 */ -+#define OFF_DLHR (0x04) /* RW 8b H'00 */ -+#define OFF_IER (0x04) /* RW 8b H'00 */ -+#define OFF_ISR (0x08) /* R 8b H'01 */ -+#define OFF_FCR (0x08) /* W 8b H'00 */ -+#define OFF_LCR (0x0C) /* RW 8b H'00 */ -+#define OFF_MCR (0x10) /* RW 8b H'00 */ -+#define OFF_LSR (0x14) /* R 8b H'00 */ -+#define OFF_MSR (0x18) /* R 8b H'00 */ -+#define OFF_SPR (0x1C) /* RW 8b H'00 */ -+#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ -+#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */ -+#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */ -+ -+/* Register Address */ -+#define UART0_RDR (UART0_BASE + OFF_RDR) -+#define UART0_TDR (UART0_BASE + OFF_TDR) -+#define UART0_DLLR (UART0_BASE + OFF_DLLR) -+#define UART0_DLHR (UART0_BASE + OFF_DLHR) -+#define UART0_IER (UART0_BASE + OFF_IER) -+#define UART0_ISR (UART0_BASE + OFF_ISR) -+#define UART0_FCR (UART0_BASE + OFF_FCR) -+#define UART0_LCR (UART0_BASE + OFF_LCR) -+#define UART0_MCR (UART0_BASE + OFF_MCR) -+#define UART0_LSR (UART0_BASE + OFF_LSR) -+#define UART0_MSR (UART0_BASE + OFF_MSR) -+#define UART0_SPR (UART0_BASE + OFF_SPR) -+#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) -+#define UART0_UMR (UART0_BASE + OFF_UMR) -+#define UART0_UACR (UART0_BASE + OFF_UACR) -+ -+/* -+ * Define macros for UARTIER -+ * UART Interrupt Enable Register -+ */ -+#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */ -+#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */ -+#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ -+#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ -+#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ -+ -+/* -+ * Define macros for UARTISR -+ * UART Interrupt Status Register -+ */ -+#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ -+#define UARTISR_IID (7 << 1) /* Source of Interrupt */ -+#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ -+#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ -+#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ -+#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ -+#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */ -+#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ -+#define UARTISR_FFMS_NO_FIFO (0 << 6) -+#define UARTISR_FFMS_FIFO_MODE (3 << 6) -+ -+/* -+ * Define macros for UARTFCR -+ * UART FIFO Control Register -+ */ -+#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ -+#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ -+#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ -+#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ -+#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ -+#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ -+#define UARTFCR_RTRG_1 (0 << 6) -+#define UARTFCR_RTRG_4 (1 << 6) -+#define UARTFCR_RTRG_8 (2 << 6) -+#define UARTFCR_RTRG_15 (3 << 6) -+ -+/* -+ * Define macros for UARTLCR -+ * UART Line Control Register -+ */ -+#define UARTLCR_WLEN (3 << 0) /* word length */ -+#define UARTLCR_WLEN_5 (0 << 0) -+#define UARTLCR_WLEN_6 (1 << 0) -+#define UARTLCR_WLEN_7 (2 << 0) -+#define UARTLCR_WLEN_8 (3 << 0) -+#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 -+ 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ -+#define UARTLCR_STOP1 (0 << 2) -+#define UARTLCR_STOP2 (1 << 2) -+#define UARTLCR_PE (1 << 3) /* 0: parity disable */ -+#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ -+#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ -+#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ -+#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ -+ -+/* -+ * Define macros for UARTLSR -+ * UART Line Status Register -+ */ -+#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ -+#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ -+#define UARTLSR_PER (1 << 2) /* 0: no parity error */ -+#define UARTLSR_FER (1 << 3) /* 0; no framing error */ -+#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ -+#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ -+#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ -+#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ -+ -+/* -+ * Define macros for UARTMCR -+ * UART Modem Control Register -+ */ -+#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */ -+#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ -+#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ -+ -+/* -+ * Define macros for UARTMSR -+ * UART Modem Status Register -+ */ -+#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */ -+#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ -+ -+/* -+ * Define macros for SIRCR -+ * Slow IrDA Control Register -+ */ -+#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */ -+#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */ -+#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length -+ 1: 0 pulse width is 1.6us for 115.2Kbps */ -+#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ -+#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ -+ -+ -+/************************************************************************* -+ * AIC (AC97/I2S Controller) -+ *************************************************************************/ -+#define AIC_FR (AIC_BASE + 0x000) -+#define AIC_CR (AIC_BASE + 0x004) -+#define AIC_ACCR1 (AIC_BASE + 0x008) -+#define AIC_ACCR2 (AIC_BASE + 0x00C) -+#define AIC_I2SCR (AIC_BASE + 0x010) -+#define AIC_SR (AIC_BASE + 0x014) -+#define AIC_ACSR (AIC_BASE + 0x018) -+#define AIC_I2SSR (AIC_BASE + 0x01C) -+#define AIC_ACCAR (AIC_BASE + 0x020) -+#define AIC_ACCDR (AIC_BASE + 0x024) -+#define AIC_ACSAR (AIC_BASE + 0x028) -+#define AIC_ACSDR (AIC_BASE + 0x02C) -+#define AIC_I2SDIV (AIC_BASE + 0x030) -+#define AIC_DR (AIC_BASE + 0x034) -+ -+#define REG_AIC_FR REG32(AIC_FR) -+#define REG_AIC_CR REG32(AIC_CR) -+#define REG_AIC_ACCR1 REG32(AIC_ACCR1) -+#define REG_AIC_ACCR2 REG32(AIC_ACCR2) -+#define REG_AIC_I2SCR REG32(AIC_I2SCR) -+#define REG_AIC_SR REG32(AIC_SR) -+#define REG_AIC_ACSR REG32(AIC_ACSR) -+#define REG_AIC_I2SSR REG32(AIC_I2SSR) -+#define REG_AIC_ACCAR REG32(AIC_ACCAR) -+#define REG_AIC_ACCDR REG32(AIC_ACCDR) -+#define REG_AIC_ACSAR REG32(AIC_ACSAR) -+#define REG_AIC_ACSDR REG32(AIC_ACSDR) -+#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) -+#define REG_AIC_DR REG32(AIC_DR) -+ -+/* AIC Controller Configuration Register (AIC_FR) */ -+ -+#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */ -+#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) -+#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */ -+#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) -+#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */ -+#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */ -+#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */ -+#define AIC_FR_RST (1 << 3) /* AIC registers reset */ -+#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */ -+#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */ -+#define AIC_FR_ENB (1 << 0) /* AIC enable bit */ -+ -+/* AIC Controller Common Control Register (AIC_CR) */ -+ -+#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */ -+#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT) -+ #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT) -+ #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT) -+ #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT) -+ #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT) -+ #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT) -+#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */ -+#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT) -+ #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT) -+ #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT) -+ #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT) -+ #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT) -+ #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT) -+#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */ -+#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */ -+#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */ -+#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */ -+#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */ -+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ -+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ -+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ -+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ -+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ -+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ -+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ -+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ -+ -+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ -+ -+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ -+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) -+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ -+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ -+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) -+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ -+ -+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ -+ -+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ -+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ -+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ -+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) -+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) -+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ -+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ -+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ -+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ -+ -+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ -+ -+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) -+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ -+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ -+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ -+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ -+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ -+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ -+ -+/* AIC Controller FIFO Status Register (AIC_SR) */ -+ -+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ -+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) -+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ -+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) -+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ -+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ -+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ -+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ -+ -+/* AIC Controller AC-link Status Register (AIC_ACSR) */ -+ -+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ -+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ -+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ -+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ -+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ -+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ -+ -+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ -+ -+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ -+ -+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ -+ -+#define AIC_ACCAR_CAR_BIT 0 -+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) -+ -+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ -+ -+#define AIC_ACCDR_CDR_BIT 0 -+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) -+ -+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ -+ -+#define AIC_ACSAR_SAR_BIT 0 -+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) -+ -+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ -+ -+#define AIC_ACSDR_SDR_BIT 0 -+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) -+ -+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ -+ -+#define AIC_I2SDIV_DIV_BIT 0 -+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) -+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ -+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ -+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ -+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ -+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ -+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ -+ -+ -+/************************************************************************* -+ * ICDC (Internal CODEC) -+ *************************************************************************/ -+#define ICDC_CR (ICDC_BASE + 0x0400) /* ICDC Control Register */ -+#define ICDC_APWAIT (ICDC_BASE + 0x0404) /* Anti-Pop WAIT Stage Timing Control Register */ -+#define ICDC_APPRE (ICDC_BASE + 0x0408) /* Anti-Pop HPEN-PRE Stage Timing Control Register */ -+#define ICDC_APHPEN (ICDC_BASE + 0x040C) /* Anti-Pop HPEN Stage Timing Control Register */ -+#define ICDC_APSR (ICDC_BASE + 0x0410) /* Anti-Pop Status Register */ -+#define ICDC_CDCCR1 (ICDC_BASE + 0x0080) -+#define ICDC_CDCCR2 (ICDC_BASE + 0x0084) -+ -+#define REG_ICDC_CR REG32(ICDC_CR) -+#define REG_ICDC_APWAIT REG32(ICDC_APWAIT) -+#define REG_ICDC_APPRE REG32(ICDC_APPRE) -+#define REG_ICDC_APHPEN REG32(ICDC_APHPEN) -+#define REG_ICDC_APSR REG32(ICDC_APSR) -+#define REG_ICDC_CDCCR1 REG32(ICDC_CDCCR1) -+#define REG_ICDC_CDCCR2 REG32(ICDC_CDCCR2) -+ -+/* ICDC Control Register */ -+#define ICDC_CR_LINVOL_BIT 24 /* LINE Input Volume Gain: GAIN=LINVOL*1.5-34.5 */ -+#define ICDC_CR_LINVOL_MASK (0x1f << ICDC_CR_LINVOL_BIT) -+#define ICDC_CR_ASRATE_BIT 20 /* Audio Sample Rate */ -+#define ICDC_CR_ASRATE_MASK (0x0f << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_8000 (0x0 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_11025 (0x1 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_12000 (0x2 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_16000 (0x3 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_22050 (0x4 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_24000 (0x5 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_32000 (0x6 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_44100 (0x7 << ICDC_CR_ASRATE_BIT) -+ #define ICDC_CR_ASRATE_48000 (0x8 << ICDC_CR_ASRATE_BIT) -+#define ICDC_CR_MICBG_BIT 18 /* MIC Boost Gain */ -+#define ICDC_CR_MICBG_MASK (0x3 << ICDC_CR_MICBG_BIT) -+ #define ICDC_CR_MICBG_0DB (0x0 << ICDC_CR_MICBG_BIT) -+ #define ICDC_CR_MICBG_6DB (0x1 << ICDC_CR_MICBG_BIT) -+ #define ICDC_CR_MICBG_12DB (0x2 << ICDC_CR_MICBG_BIT) -+ #define ICDC_CR_MICBG_20DB (0x3 << ICDC_CR_MICBG_BIT) -+#define ICDC_CR_HPVOL_BIT 16 /* Headphone Volume Gain */ -+#define ICDC_CR_HPVOL_MASK (0x3 << ICDC_CR_HPVOL_BIT) -+ #define ICDC_CR_HPVOL_0DB (0x0 << ICDC_CR_HPVOL_BIT) -+ #define ICDC_CR_HPVOL_2DB (0x1 << ICDC_CR_HPVOL_BIT) -+ #define ICDC_CR_HPVOL_4DB (0x2 << ICDC_CR_HPVOL_BIT) -+ #define ICDC_CR_HPVOL_6DB (0x3 << ICDC_CR_HPVOL_BIT) -+#define ICDC_CR_ELINEIN (1 << 13) /* Enable LINE Input */ -+#define ICDC_CR_EMIC (1 << 12) /* Enable MIC Input */ -+#define ICDC_CR_SW1ON (1 << 11) /* Switch 1 in CODEC is on */ -+#define ICDC_CR_EADC (1 << 10) /* Enable ADC */ -+#define ICDC_CR_SW2ON (1 << 9) /* Switch 2 in CODEC is on */ -+#define ICDC_CR_EDAC (1 << 8) /* Enable DAC */ -+#define ICDC_CR_HPMUTE (1 << 5) /* Headphone Mute */ -+#define ICDC_CR_HPTON (1 << 4) /* Headphone Amplifier Trun On */ -+#define ICDC_CR_HPTOFF (1 << 3) /* Headphone Amplifier Trun Off */ -+#define ICDC_CR_TAAP (1 << 2) /* Turn Around of the Anti-Pop Procedure */ -+#define ICDC_CR_EAP (1 << 1) /* Enable Anti-Pop Procedure */ -+#define ICDC_CR_SUSPD (1 << 0) /* CODEC Suspend */ -+ -+/* Anti-Pop WAIT Stage Timing Control Register */ -+#define ICDC_APWAIT_WAITSN_BIT 0 -+#define ICDC_APWAIT_WAITSN_MASK (0x7ff << ICDC_APWAIT_WAITSN_BIT) -+ -+/* Anti-Pop HPEN-PRE Stage Timing Control Register */ -+#define ICDC_APPRE_PRESN_BIT 0 -+#define ICDC_APPRE_PRESN_MASK (0x1ff << ICDC_APPRE_PRESN_BIT) -+ -+/* Anti-Pop HPEN Stage Timing Control Register */ -+#define ICDC_APHPEN_HPENSN_BIT 0 -+#define ICDC_APHPEN_HPENSN_MASK (0x3fff << ICDC_APHPEN_HPENSN_BIT) -+ -+/* Anti-Pop Status Register */ -+#define ICDC_SR_HPST_BIT 14 /* Headphone Amplifier State */ -+#define ICDC_SR_HPST_MASK (0x7 << ICDC_SR_HPST_BIT) -+#define ICDC_SR_HPST_HP_OFF (0x0 << ICDC_SR_HPST_BIT) /* HP amplifier is off */ -+#define ICDC_SR_HPST_TON_WAIT (0x1 << ICDC_SR_HPST_BIT) /* wait state in turn-on */ -+ #define ICDC_SR_HPST_TON_PRE (0x2 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-on */ -+#define ICDC_SR_HPST_TON_HPEN (0x3 << ICDC_SR_HPST_BIT) /* HP enable state in turn-on */ -+ #define ICDC_SR_HPST_TOFF_HPEN (0x4 << ICDC_SR_HPST_BIT) /* HP enable state in turn-off */ -+ #define ICDC_SR_HPST_TOFF_PRE (0x5 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-off */ -+ #define ICDC_SR_HPST_TOFF_WAIT (0x6 << ICDC_SR_HPST_BIT) /* wait state in turn-off */ -+ #define ICDC_SR_HPST_HP_ON (0x7 << ICDC_SR_HPST_BIT) /* HP amplifier is on */ -+#define ICDC_SR_SNCNT_BIT 0 /* Sample Number Counter */ -+#define ICDC_SR_SNCNT_MASK (0x3fff << ICDC_SR_SNCNT_BIT) -+ -+ -+/************************************************************************* -+ * I2C -+ *************************************************************************/ -+#define I2C_DR (I2C_BASE + 0x000) -+#define I2C_CR (I2C_BASE + 0x004) -+#define I2C_SR (I2C_BASE + 0x008) -+#define I2C_GR (I2C_BASE + 0x00C) -+ -+#define REG_I2C_DR REG8(I2C_DR) -+#define REG_I2C_CR REG8(I2C_CR) -+#define REG_I2C_SR REG8(I2C_SR) -+#define REG_I2C_GR REG16(I2C_GR) -+ -+/* I2C Control Register (I2C_CR) */ -+ -+#define I2C_CR_IEN (1 << 4) -+#define I2C_CR_STA (1 << 3) -+#define I2C_CR_STO (1 << 2) -+#define I2C_CR_AC (1 << 1) -+#define I2C_CR_I2CE (1 << 0) -+ -+/* I2C Status Register (I2C_SR) */ -+ -+#define I2C_SR_STX (1 << 4) -+#define I2C_SR_BUSY (1 << 3) -+#define I2C_SR_TEND (1 << 2) -+#define I2C_SR_DRF (1 << 1) -+#define I2C_SR_ACKF (1 << 0) -+ -+ -+/************************************************************************* -+ * SSI -+ *************************************************************************/ -+#define SSI_DR (SSI_BASE + 0x000) -+#define SSI_CR0 (SSI_BASE + 0x004) -+#define SSI_CR1 (SSI_BASE + 0x008) -+#define SSI_SR (SSI_BASE + 0x00C) -+#define SSI_ITR (SSI_BASE + 0x010) -+#define SSI_ICR (SSI_BASE + 0x014) -+#define SSI_GR (SSI_BASE + 0x018) -+ -+#define REG_SSI_DR REG32(SSI_DR) -+#define REG_SSI_CR0 REG16(SSI_CR0) -+#define REG_SSI_CR1 REG32(SSI_CR1) -+#define REG_SSI_SR REG32(SSI_SR) -+#define REG_SSI_ITR REG16(SSI_ITR) -+#define REG_SSI_ICR REG8(SSI_ICR) -+#define REG_SSI_GR REG16(SSI_GR) -+ -+/* SSI Data Register (SSI_DR) */ -+ -+#define SSI_DR_GPC_BIT 0 -+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) -+ -+/* SSI Control Register 0 (SSI_CR0) */ -+ -+#define SSI_CR0_SSIE (1 << 15) -+#define SSI_CR0_TIE (1 << 14) -+#define SSI_CR0_RIE (1 << 13) -+#define SSI_CR0_TEIE (1 << 12) -+#define SSI_CR0_REIE (1 << 11) -+#define SSI_CR0_LOOP (1 << 10) -+#define SSI_CR0_RFINE (1 << 9) -+#define SSI_CR0_RFINC (1 << 8) -+#define SSI_CR0_FSEL (1 << 6) -+#define SSI_CR0_TFLUSH (1 << 2) -+#define SSI_CR0_RFLUSH (1 << 1) -+#define SSI_CR0_DISREV (1 << 0) -+ -+/* SSI Control Register 1 (SSI_CR1) */ -+ -+#define SSI_CR1_FRMHL_BIT 30 -+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) -+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ -+#define SSI_CR1_TFVCK_BIT 28 -+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) -+#define SSI_CR1_TCKFI_BIT 26 -+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) -+#define SSI_CR1_LFST (1 << 25) -+#define SSI_CR1_ITFRM (1 << 24) -+#define SSI_CR1_UNFIN (1 << 23) -+#define SSI_CR1_MULTS (1 << 22) -+#define SSI_CR1_FMAT_BIT 20 -+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) -+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ -+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ -+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ -+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ -+#define SSI_CR1_TTRG_BIT 16 -+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_8 (1 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_16 (2 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_24 (3 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_32 (4 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_40 (5 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_48 (6 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_56 (7 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_64 (8 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_72 (9 << SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_80 (10<< SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_88 (11<< SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_96 (12<< SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_104 (13<< SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_112 (14<< SSI_CR1_TTRG_BIT) -+ #define SSI_CR1_TTRG_120 (15<< SSI_CR1_TTRG_BIT) -+#define SSI_CR1_MCOM_BIT 12 -+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) -+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ -+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ -+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ -+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ -+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ -+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ -+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ -+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ -+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ -+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ -+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ -+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ -+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ -+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ -+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ -+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ -+#define SSI_CR1_RTRG_BIT 8 -+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_8 (1 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_16 (2 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_24 (3 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_32 (4 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_40 (5 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_48 (6 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_56 (7 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_64 (8 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_72 (9 << SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_80 (10<< SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_88 (11<< SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_96 (12<< SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_104 (13<< SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_112 (14<< SSI_CR1_RTRG_BIT) -+ #define SSI_CR1_RTRG_120 (15<< SSI_CR1_RTRG_BIT) -+#define SSI_CR1_FLEN_BIT 4 -+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) -+#define SSI_CR1_PHA (1 << 1) -+#define SSI_CR1_POL (1 << 0) -+ -+/* SSI Status Register (SSI_SR) */ -+ -+#define SSI_SR_TFIFONUM_BIT 16 -+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) -+#define SSI_SR_RFIFONUM_BIT 8 -+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) -+#define SSI_SR_END (1 << 7) -+#define SSI_SR_BUSY (1 << 6) -+#define SSI_SR_TFF (1 << 5) -+#define SSI_SR_RFE (1 << 4) -+#define SSI_SR_TFHE (1 << 3) -+#define SSI_SR_RFHF (1 << 2) -+#define SSI_SR_UNDR (1 << 1) -+#define SSI_SR_OVER (1 << 0) -+ -+/* SSI Interval Time Control Register (SSI_ITR) */ -+ -+#define SSI_ITR_CNTCLK (1 << 15) -+#define SSI_ITR_IVLTM_BIT 0 -+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) -+ -+ -+/************************************************************************* -+ * MSC -+ *************************************************************************/ -+#define MSC_STRPCL (MSC_BASE + 0x000) -+#define MSC_STAT (MSC_BASE + 0x004) -+#define MSC_CLKRT (MSC_BASE + 0x008) -+#define MSC_CMDAT (MSC_BASE + 0x00C) -+#define MSC_RESTO (MSC_BASE + 0x010) -+#define MSC_RDTO (MSC_BASE + 0x014) -+#define MSC_BLKLEN (MSC_BASE + 0x018) -+#define MSC_NOB (MSC_BASE + 0x01C) -+#define MSC_SNOB (MSC_BASE + 0x020) -+#define MSC_IMASK (MSC_BASE + 0x024) -+#define MSC_IREG (MSC_BASE + 0x028) -+#define MSC_CMD (MSC_BASE + 0x02C) -+#define MSC_ARG (MSC_BASE + 0x030) -+#define MSC_RES (MSC_BASE + 0x034) -+#define MSC_RXFIFO (MSC_BASE + 0x038) -+#define MSC_TXFIFO (MSC_BASE + 0x03C) -+ -+#define REG_MSC_STRPCL REG16(MSC_STRPCL) -+#define REG_MSC_STAT REG32(MSC_STAT) -+#define REG_MSC_CLKRT REG16(MSC_CLKRT) -+#define REG_MSC_CMDAT REG32(MSC_CMDAT) -+#define REG_MSC_RESTO REG16(MSC_RESTO) -+#define REG_MSC_RDTO REG16(MSC_RDTO) -+#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) -+#define REG_MSC_NOB REG16(MSC_NOB) -+#define REG_MSC_SNOB REG16(MSC_SNOB) -+#define REG_MSC_IMASK REG16(MSC_IMASK) -+#define REG_MSC_IREG REG16(MSC_IREG) -+#define REG_MSC_CMD REG8(MSC_CMD) -+#define REG_MSC_ARG REG32(MSC_ARG) -+#define REG_MSC_RES REG16(MSC_RES) -+#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) -+#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) -+ -+/* MSC Clock and Control Register (MSC_STRPCL) */ -+ -+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) -+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) -+#define MSC_STRPCL_START_READWAIT (1 << 5) -+#define MSC_STRPCL_STOP_READWAIT (1 << 4) -+#define MSC_STRPCL_RESET (1 << 3) -+#define MSC_STRPCL_START_OP (1 << 2) -+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 -+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) -+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ -+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ -+ -+/* MSC Status Register (MSC_STAT) */ -+ -+#define MSC_STAT_IS_RESETTING (1 << 15) -+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) -+#define MSC_STAT_PRG_DONE (1 << 13) -+#define MSC_STAT_DATA_TRAN_DONE (1 << 12) -+#define MSC_STAT_END_CMD_RES (1 << 11) -+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) -+#define MSC_STAT_IS_READWAIT (1 << 9) -+#define MSC_STAT_CLK_EN (1 << 8) -+#define MSC_STAT_DATA_FIFO_FULL (1 << 7) -+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) -+#define MSC_STAT_CRC_RES_ERR (1 << 5) -+#define MSC_STAT_CRC_READ_ERROR (1 << 4) -+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 -+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) -+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ -+#define MSC_STAT_TIME_OUT_RES (1 << 1) -+#define MSC_STAT_TIME_OUT_READ (1 << 0) -+ -+/* MSC Bus Clock Control Register (MSC_CLKRT) */ -+ -+#define MSC_CLKRT_CLK_RATE_BIT 0 -+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) -+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ -+ -+/* MSC Command Sequence Control Register (MSC_CMDAT) */ -+ -+#define MSC_CMDAT_IO_ABORT (1 << 11) -+#define MSC_CMDAT_BUS_WIDTH_BIT 9 -+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ -+ #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) -+#define MSC_CMDAT_DMA_EN (1 << 8) -+#define MSC_CMDAT_INIT (1 << 7) -+#define MSC_CMDAT_BUSY (1 << 6) -+#define MSC_CMDAT_STREAM_BLOCK (1 << 5) -+#define MSC_CMDAT_WRITE (1 << 4) -+#define MSC_CMDAT_READ (0 << 4) -+#define MSC_CMDAT_DATA_EN (1 << 3) -+#define MSC_CMDAT_RESPONSE_BIT 0 -+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) -+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ -+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ -+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ -+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ -+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ -+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ -+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ -+ -+#define CMDAT_DMA_EN (1 << 8) -+#define CMDAT_INIT (1 << 7) -+#define CMDAT_BUSY (1 << 6) -+#define CMDAT_STREAM (1 << 5) -+#define CMDAT_WRITE (1 << 4) -+#define CMDAT_DATA_EN (1 << 3) -+ -+/* MSC Interrupts Mask Register (MSC_IMASK) */ -+ -+#define MSC_IMASK_SDIO (1 << 7) -+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IMASK_END_CMD_RES (1 << 2) -+#define MSC_IMASK_PRG_DONE (1 << 1) -+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) -+ -+ -+/* MSC Interrupts Status Register (MSC_IREG) */ -+ -+#define MSC_IREG_SDIO (1 << 7) -+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IREG_END_CMD_RES (1 << 2) -+#define MSC_IREG_PRG_DONE (1 << 1) -+#define MSC_IREG_DATA_TRAN_DONE (1 << 0) -+ -+ -+/************************************************************************* -+ * EMC (External Memory Controller) -+ *************************************************************************/ -+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ -+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ -+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ -+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ -+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ -+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ -+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ -+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ -+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ -+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ -+ -+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ -+#define EMC_NFECR (EMC_BASE + 0x100) /* NAND Flash ECC Control Register */ -+#define EMC_NFECC (EMC_BASE + 0x104) /* NAND Flash ECC Data Register */ -+#define EMC_NFPAR0 (EMC_BASE + 0x108) /* NAND Flash RS Parity 0 Register */ -+#define EMC_NFPAR1 (EMC_BASE + 0x10c) /* NAND Flash RS Parity 1 Register */ -+#define EMC_NFPAR2 (EMC_BASE + 0x110) /* NAND Flash RS Parity 2 Register */ -+#define EMC_NFINTS (EMC_BASE + 0x114) /* NAND Flash Interrupt Status Register */ -+#define EMC_NFINTE (EMC_BASE + 0x118) /* NAND Flash Interrupt Enable Register */ -+#define EMC_NFERR0 (EMC_BASE + 0x11c) /* NAND Flash RS Error Report 0 Register */ -+#define EMC_NFERR1 (EMC_BASE + 0x120) /* NAND Flash RS Error Report 1 Register */ -+#define EMC_NFERR2 (EMC_BASE + 0x124) /* NAND Flash RS Error Report 2 Register */ -+#define EMC_NFERR3 (EMC_BASE + 0x128) /* NAND Flash RS Error Report 3 Register */ -+ -+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ -+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ -+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ -+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ -+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ -+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ -+ -+ -+#define REG_EMC_SMCR0 REG32(EMC_SMCR0) -+#define REG_EMC_SMCR1 REG32(EMC_SMCR1) -+#define REG_EMC_SMCR2 REG32(EMC_SMCR2) -+#define REG_EMC_SMCR3 REG32(EMC_SMCR3) -+#define REG_EMC_SMCR4 REG32(EMC_SMCR4) -+#define REG_EMC_SACR0 REG32(EMC_SACR0) -+#define REG_EMC_SACR1 REG32(EMC_SACR1) -+#define REG_EMC_SACR2 REG32(EMC_SACR2) -+#define REG_EMC_SACR3 REG32(EMC_SACR3) -+#define REG_EMC_SACR4 REG32(EMC_SACR4) -+ -+#define REG_EMC_NFCSR REG32(EMC_NFCSR) -+#define REG_EMC_NFECR REG32(EMC_NFECR) -+#define REG_EMC_NFECC REG32(EMC_NFECC) -+#define REG_EMC_NFPAR0 REG32(EMC_NFPAR0) -+#define REG_EMC_NFPAR1 REG32(EMC_NFPAR1) -+#define REG_EMC_NFPAR2 REG32(EMC_NFPAR2) -+#define REG_EMC_NFINTS REG32(EMC_NFINTS) -+#define REG_EMC_NFINTE REG32(EMC_NFINTE) -+#define REG_EMC_NFERR0 REG32(EMC_NFERR0) -+#define REG_EMC_NFERR1 REG32(EMC_NFERR1) -+#define REG_EMC_NFERR2 REG32(EMC_NFERR2) -+#define REG_EMC_NFERR3 REG32(EMC_NFERR3) -+ -+#define REG_EMC_DMCR REG32(EMC_DMCR) -+#define REG_EMC_RTCSR REG16(EMC_RTCSR) -+#define REG_EMC_RTCNT REG16(EMC_RTCNT) -+#define REG_EMC_RTCOR REG16(EMC_RTCOR) -+#define REG_EMC_DMAR0 REG32(EMC_DMAR0) -+ -+/* Static Memory Control Register */ -+#define EMC_SMCR_STRV_BIT 24 -+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) -+#define EMC_SMCR_TAW_BIT 20 -+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) -+#define EMC_SMCR_TBP_BIT 16 -+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) -+#define EMC_SMCR_TAH_BIT 12 -+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) -+#define EMC_SMCR_TAS_BIT 8 -+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) -+#define EMC_SMCR_BW_BIT 6 -+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) -+#define EMC_SMCR_BCM (1 << 3) -+#define EMC_SMCR_BL_BIT 1 -+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) -+#define EMC_SMCR_SMT (1 << 0) -+ -+/* Static Memory Bank Addr Config Reg */ -+#define EMC_SACR_BASE_BIT 8 -+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) -+#define EMC_SACR_MASK_BIT 0 -+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) -+ -+/* NAND Flash Control/Status Register */ -+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ -+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ -+#define EMC_NFCSR_NFCE3 (1 << 5) -+#define EMC_NFCSR_NFE3 (1 << 4) -+#define EMC_NFCSR_NFCE2 (1 << 3) -+#define EMC_NFCSR_NFE2 (1 << 2) -+#define EMC_NFCSR_NFCE1 (1 << 1) -+#define EMC_NFCSR_NFE1 (1 << 0) -+ -+/* NAND Flash ECC Control Register */ -+#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */ -+#define EMC_NFECR_RS_DECODING (0 << 3) /* RS is in decoding phase */ -+#define EMC_NFECR_RS_ENCODING (1 << 3) /* RS is in encoding phase */ -+#define EMC_NFECR_HAMMING (0 << 2) /* Select HAMMING Correction Algorithm */ -+#define EMC_NFECR_RS (1 << 2) /* Select RS Correction Algorithm */ -+#define EMC_NFECR_ERST (1 << 1) /* ECC Reset */ -+#define EMC_NFECR_ECCE (1 << 0) /* ECC Enable */ -+ -+/* NAND Flash ECC Data Register */ -+#define EMC_NFECC_ECC2_BIT 16 -+#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) -+#define EMC_NFECC_ECC1_BIT 8 -+#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) -+#define EMC_NFECC_ECC0_BIT 0 -+#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) -+ -+/* NAND Flash Interrupt Status Register */ -+#define EMC_NFINTS_ERRCNT_BIT 29 /* Error Count */ -+#define EMC_NFINTS_ERRCNT_MASK (0x7 << EMC_NFINTS_ERRCNT_BIT) -+#define EMC_NFINTS_PADF (1 << 4) /* Padding Finished */ -+#define EMC_NFINTS_DECF (1 << 3) /* Decoding Finished */ -+#define EMC_NFINTS_ENCF (1 << 2) /* Encoding Finished */ -+#define EMC_NFINTS_UNCOR (1 << 1) /* Uncorrectable Error Occurred */ -+#define EMC_NFINTS_ERR (1 << 0) /* Error Occurred */ -+ -+/* NAND Flash Interrupt Enable Register */ -+#define EMC_NFINTE_PADFE (1 << 4) /* Padding Finished Interrupt Enable */ -+#define EMC_NFINTE_DECFE (1 << 3) /* Decoding Finished Interrupt Enable */ -+#define EMC_NFINTE_ENCFE (1 << 2) /* Encoding Finished Interrupt Enable */ -+#define EMC_NFINTE_UNCORE (1 << 1) /* Uncorrectable Error Occurred Intr Enable */ -+#define EMC_NFINTE_ERRE (1 << 0) /* Error Occurred Interrupt */ -+ -+/* NAND Flash RS Error Report Register */ -+#define EMC_NFERR_INDEX_BIT 16 /* Error Symbol Index */ -+#define EMC_NFERR_INDEX_MASK (0x1ff << EMC_NFERR_INDEX_BIT) -+#define EMC_NFERR_MASK_BIT 0 /* Error Symbol Value */ -+#define EMC_NFERR_MASK_MASK (0x1ff << EMC_NFERR_MASK_BIT) -+ -+ -+/* DRAM Control Register */ -+#define EMC_DMCR_BW_BIT 31 -+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) -+#define EMC_DMCR_CA_BIT 26 -+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) -+#define EMC_DMCR_RMODE (1 << 25) -+#define EMC_DMCR_RFSH (1 << 24) -+#define EMC_DMCR_MRSET (1 << 23) -+#define EMC_DMCR_RA_BIT 20 -+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) -+#define EMC_DMCR_BA_BIT 19 -+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) -+#define EMC_DMCR_PDM (1 << 18) -+#define EMC_DMCR_EPIN (1 << 17) -+#define EMC_DMCR_TRAS_BIT 13 -+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) -+#define EMC_DMCR_RCD_BIT 11 -+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) -+#define EMC_DMCR_TPC_BIT 8 -+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) -+#define EMC_DMCR_TRWL_BIT 5 -+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) -+#define EMC_DMCR_TRC_BIT 2 -+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) -+#define EMC_DMCR_TCL_BIT 0 -+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) -+ -+/* Refresh Time Control/Status Register */ -+#define EMC_RTCSR_CMF (1 << 7) -+#define EMC_RTCSR_CKS_BIT 0 -+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) -+ -+/* SDRAM Bank Address Configuration Register */ -+#define EMC_DMAR_BASE_BIT 8 -+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) -+#define EMC_DMAR_MASK_BIT 0 -+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) -+ -+/* Mode Register of SDRAM bank 0 */ -+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ -+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ -+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) -+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) -+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ -+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) -+#define EMC_SDMR_BT_BIT 3 /* Burst Type */ -+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) -+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ -+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ -+#define EMC_SDMR_BL_BIT 0 /* Burst Length */ -+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) -+ -+#define EMC_SDMR_CAS2_16BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS2_32BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+#define EMC_SDMR_CAS3_16BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS3_32BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+ -+ -+/************************************************************************* -+ * CIM -+ *************************************************************************/ -+#define CIM_CFG (CIM_BASE + 0x0000) -+#define CIM_CTRL (CIM_BASE + 0x0004) -+#define CIM_STATE (CIM_BASE + 0x0008) -+#define CIM_IID (CIM_BASE + 0x000C) -+#define CIM_RXFIFO (CIM_BASE + 0x0010) -+#define CIM_DA (CIM_BASE + 0x0020) -+#define CIM_FA (CIM_BASE + 0x0024) -+#define CIM_FID (CIM_BASE + 0x0028) -+#define CIM_CMD (CIM_BASE + 0x002C) -+ -+#define REG_CIM_CFG REG32(CIM_CFG) -+#define REG_CIM_CTRL REG32(CIM_CTRL) -+#define REG_CIM_STATE REG32(CIM_STATE) -+#define REG_CIM_IID REG32(CIM_IID) -+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) -+#define REG_CIM_DA REG32(CIM_DA) -+#define REG_CIM_FA REG32(CIM_FA) -+#define REG_CIM_FID REG32(CIM_FID) -+#define REG_CIM_CMD REG32(CIM_CMD) -+ -+/* CIM Configuration Register (CIM_CFG) */ -+ -+#define CIM_CFG_INV_DAT (1 << 15) -+#define CIM_CFG_VSP (1 << 14) -+#define CIM_CFG_HSP (1 << 13) -+#define CIM_CFG_PCP (1 << 12) -+#define CIM_CFG_DUMMY_ZERO (1 << 9) -+#define CIM_CFG_EXT_VSYNC (1 << 8) -+#define CIM_CFG_PACK_BIT 4 -+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) -+#define CIM_CFG_DSM_BIT 0 -+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) -+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ -+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ -+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ -+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ -+ -+/* CIM Control Register (CIM_CTRL) */ -+ -+#define CIM_CTRL_MCLKDIV_BIT 24 -+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) -+#define CIM_CTRL_FRC_BIT 16 -+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) -+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ -+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ -+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ -+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ -+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ -+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ -+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ -+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ -+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ -+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ -+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ -+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ -+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ -+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ -+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ -+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ -+#define CIM_CTRL_VDDM (1 << 13) -+#define CIM_CTRL_DMA_SOFM (1 << 12) -+#define CIM_CTRL_DMA_EOFM (1 << 11) -+#define CIM_CTRL_DMA_STOPM (1 << 10) -+#define CIM_CTRL_RXF_TRIGM (1 << 9) -+#define CIM_CTRL_RXF_OFM (1 << 8) -+#define CIM_CTRL_RXF_TRIG_BIT 4 -+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) -+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ -+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ -+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ -+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ -+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ -+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ -+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ -+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ -+#define CIM_CTRL_DMA_EN (1 << 2) -+#define CIM_CTRL_RXF_RST (1 << 1) -+#define CIM_CTRL_ENA (1 << 0) -+ -+/* CIM State Register (CIM_STATE) */ -+ -+#define CIM_STATE_DMA_SOF (1 << 6) -+#define CIM_STATE_DMA_EOF (1 << 5) -+#define CIM_STATE_DMA_STOP (1 << 4) -+#define CIM_STATE_RXF_OF (1 << 3) -+#define CIM_STATE_RXF_TRIG (1 << 2) -+#define CIM_STATE_RXF_EMPTY (1 << 1) -+#define CIM_STATE_VDD (1 << 0) -+ -+/* CIM DMA Command Register (CIM_CMD) */ -+ -+#define CIM_CMD_SOFINT (1 << 31) -+#define CIM_CMD_EOFINT (1 << 30) -+#define CIM_CMD_STOP (1 << 28) -+#define CIM_CMD_LEN_BIT 0 -+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) -+ -+ -+/************************************************************************* -+ * SADC (Smart A/D Controller) -+ *************************************************************************/ -+ -+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ -+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ -+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ -+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ -+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ -+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ -+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ -+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ -+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ -+ -+#define REG_SADC_ENA REG8(SADC_ENA) -+#define REG_SADC_CFG REG32(SADC_CFG) -+#define REG_SADC_CTRL REG8(SADC_CTRL) -+#define REG_SADC_STATE REG8(SADC_STATE) -+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) -+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) -+#define REG_SADC_TSDAT REG32(SADC_TSDAT) -+#define REG_SADC_BATDAT REG16(SADC_BATDAT) -+#define REG_SADC_SADDAT REG16(SADC_SADDAT) -+ -+/* ADC Enable Register */ -+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ -+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ -+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ -+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ -+ -+/* ADC Configure Register */ -+#define SADC_CFG_EXIN (1 << 30) -+#define SADC_CFG_CLKOUT_NUM_BIT 16 -+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) -+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ -+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ -+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) -+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ -+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) -+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ -+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) -+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ -+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ -+#define SADC_CFG_CMD_BIT 0 /* ADC Command */ -+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) -+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ -+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ -+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ -+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ -+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ -+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ -+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ -+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ -+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ -+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ -+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ -+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ -+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ -+ -+/* ADC Control Register */ -+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ -+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ -+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ -+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ -+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ -+ -+/* ADC Status Register */ -+#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */ -+#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */ -+#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */ -+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ -+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ -+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ -+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ -+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ -+ -+/* ADC Touch Screen Data Register */ -+#define SADC_TSDAT_DATA0_BIT 0 -+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) -+#define SADC_TSDAT_TYPE0 (1 << 15) -+#define SADC_TSDAT_DATA1_BIT 16 -+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) -+#define SADC_TSDAT_TYPE1 (1 << 31) -+ -+ -+/************************************************************************* -+ * SLCD (Smart LCD Controller) -+ *************************************************************************/ -+ -+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ -+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ -+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ -+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ -+#define SLCD_FIFO (SLCD_BASE + 0xB0) /* SLCD FIFO Register */ -+ -+#define REG_SLCD_CFG REG32(SLCD_CFG) -+#define REG_SLCD_CTRL REG8(SLCD_CTRL) -+#define REG_SLCD_STATE REG8(SLCD_STATE) -+#define REG_SLCD_DATA REG32(SLCD_DATA) -+#define REG_SLCD_FIFO REG32(SLCD_FIFO) -+ -+/* SLCD Configure Register */ -+#define SLCD_CFG_BURST_BIT 14 -+#define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT) -+ #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT) -+ #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT) -+#define SLCD_CFG_DWIDTH_BIT 10 -+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_16BIT (0 << 8) -+#define SLCD_CFG_CWIDTH_8BIT (1 << 8) -+#define SLCD_CFG_CWIDTH_18BIT (2 << 8) -+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) -+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) -+#define SLCD_CFG_RS_CMD_LOW (0 << 3) -+#define SLCD_CFG_RS_CMD_HIGH (1 << 3) -+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) -+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) -+#define SLCD_CFG_TYPE_PARALLEL (0 << 0) -+#define SLCD_CFG_TYPE_SERIAL (1 << 0) -+ -+/* SLCD Control Register */ -+#define SLCD_CTRL_DMA_EN (1 << 0) -+ -+/* SLCD Status Register */ -+#define SLCD_STATE_BUSY (1 << 0) -+ -+/* SLCD Data Register */ -+#define SLCD_DATA_RS_DATA (0 << 31) -+#define SLCD_DATA_RS_COMMAND (1 << 31) -+ -+/* SLCD FIFO Register */ -+#define SLCD_FIFO_RS_DATA (0 << 31) -+#define SLCD_FIFO_RS_COMMAND (1 << 31) -+ -+ -+/************************************************************************* -+ * LCD (LCD Controller) -+ *************************************************************************/ -+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ -+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ -+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ -+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ -+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ -+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ -+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ -+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ -+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ -+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ -+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ -+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ -+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ -+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ -+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ -+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ -+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ -+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ -+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ -+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ -+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ -+ -+#define REG_LCD_CFG REG32(LCD_CFG) -+#define REG_LCD_VSYNC REG32(LCD_VSYNC) -+#define REG_LCD_HSYNC REG32(LCD_HSYNC) -+#define REG_LCD_VAT REG32(LCD_VAT) -+#define REG_LCD_DAH REG32(LCD_DAH) -+#define REG_LCD_DAV REG32(LCD_DAV) -+#define REG_LCD_PS REG32(LCD_PS) -+#define REG_LCD_CLS REG32(LCD_CLS) -+#define REG_LCD_SPL REG32(LCD_SPL) -+#define REG_LCD_REV REG32(LCD_REV) -+#define REG_LCD_CTRL REG32(LCD_CTRL) -+#define REG_LCD_STATE REG32(LCD_STATE) -+#define REG_LCD_IID REG32(LCD_IID) -+#define REG_LCD_DA0 REG32(LCD_DA0) -+#define REG_LCD_SA0 REG32(LCD_SA0) -+#define REG_LCD_FID0 REG32(LCD_FID0) -+#define REG_LCD_CMD0 REG32(LCD_CMD0) -+#define REG_LCD_DA1 REG32(LCD_DA1) -+#define REG_LCD_SA1 REG32(LCD_SA1) -+#define REG_LCD_FID1 REG32(LCD_FID1) -+#define REG_LCD_CMD1 REG32(LCD_CMD1) -+ -+/* LCD Configure Register */ -+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ -+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) -+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ -+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ -+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ -+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ -+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ -+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ -+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ -+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ -+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ -+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ -+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ -+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ -+#define LCD_CFG_HSP (1 << 11) /* HSYNC pority:0-active high,1-active low */ -+#define LCD_CFG_PCP (1 << 10) /* PCLK pority:0-rising,1-falling */ -+#define LCD_CFG_DEP (1 << 9) /* DE pority:0-active high,1-active low */ -+#define LCD_CFG_VSP (1 << 8) /* VSYNC pority:0-rising,1-falling */ -+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ -+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) -+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ -+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ -+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ -+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ -+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ -+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ -+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) -+ /* JZ47XX defines */ -+ #define LCD_CFG_MODE_SHARP_HR (1 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_CFG_MODE_BIT) -+ -+ -+ -+/* Vertical Synchronize Register */ -+#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */ -+#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) -+#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */ -+#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) -+ -+/* Horizontal Synchronize Register */ -+#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */ -+#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) -+#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */ -+#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) -+ -+/* Virtual Area Setting Register */ -+#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */ -+#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) -+#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */ -+#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) -+ -+/* Display Area Horizontal Start/End Point Register */ -+#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */ -+#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) -+#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */ -+#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) -+ -+/* Display Area Vertical Start/End Point Register */ -+#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */ -+#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) -+#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */ -+#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) -+ -+/* PS Signal Setting */ -+#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */ -+#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT) -+#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */ -+#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT) -+ -+/* CLS Signal Setting */ -+#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */ -+#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT) -+#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */ -+#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT) -+ -+/* SPL Signal Setting */ -+#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */ -+#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT) -+#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */ -+#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT) -+ -+/* REV Signal Setting */ -+#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */ -+#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT) -+ -+/* LCD Control Register */ -+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ -+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ -+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ -+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ -+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ -+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ -+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ -+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ -+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ -+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ -+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ -+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ -+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) -+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ -+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ -+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ -+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ -+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ -+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ -+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ -+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ -+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ -+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ -+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ -+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ -+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ -+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ -+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ -+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ -+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ -+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ -+ -+/* LCD Status Register */ -+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ -+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ -+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ -+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ -+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ -+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ -+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ -+ -+/* DMA Command Register */ -+#define LCD_CMD_SOFINT (1 << 31) -+#define LCD_CMD_EOFINT (1 << 30) -+#define LCD_CMD_PAL (1 << 28) -+#define LCD_CMD_LEN_BIT 0 -+#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) -+ -+ -+/************************************************************************* -+ * USB Device -+ *************************************************************************/ -+#define USB_BASE UDC_BASE -+ -+#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */ -+#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */ -+#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */ -+#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */ -+#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */ -+#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */ -+#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */ -+#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */ -+#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */ -+#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */ -+#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */ -+ -+#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */ -+#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */ -+#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */ -+#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */ -+#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */ -+#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */ -+#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */ -+#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */ -+ -+#define USB_FIFO_EP0 (USB_BASE + 0x20) -+#define USB_FIFO_EP1 (USB_BASE + 0x24) -+#define USB_FIFO_EP2 (USB_BASE + 0x28) -+ -+#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */ -+#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */ -+ -+#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */ -+#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */ -+#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */ -+#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */ -+#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */ -+#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */ -+#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */ -+ -+ -+/* Power register bit masks */ -+#define USB_POWER_SUSPENDM 0x01 -+#define USB_POWER_RESUME 0x04 -+#define USB_POWER_HSMODE 0x10 -+#define USB_POWER_HSENAB 0x20 -+#define USB_POWER_SOFTCONN 0x40 -+ -+/* Interrupt register bit masks */ -+#define USB_INTR_SUSPEND 0x01 -+#define USB_INTR_RESUME 0x02 -+#define USB_INTR_RESET 0x04 -+ -+#define USB_INTR_EP0 0x0001 -+#define USB_INTR_INEP1 0x0002 -+#define USB_INTR_INEP2 0x0004 -+#define USB_INTR_OUTEP1 0x0002 -+ -+/* CSR0 bit masks */ -+#define USB_CSR0_OUTPKTRDY 0x01 -+#define USB_CSR0_INPKTRDY 0x02 -+#define USB_CSR0_SENTSTALL 0x04 -+#define USB_CSR0_DATAEND 0x08 -+#define USB_CSR0_SETUPEND 0x10 -+#define USB_CSR0_SENDSTALL 0x20 -+#define USB_CSR0_SVDOUTPKTRDY 0x40 -+#define USB_CSR0_SVDSETUPEND 0x80 -+ -+/* Endpoint CSR register bits */ -+#define USB_INCSRH_AUTOSET 0x80 -+#define USB_INCSRH_ISO 0x40 -+#define USB_INCSRH_MODE 0x20 -+#define USB_INCSRH_DMAREQENAB 0x10 -+#define USB_INCSRH_DMAREQMODE 0x04 -+#define USB_INCSR_CDT 0x40 -+#define USB_INCSR_SENTSTALL 0x20 -+#define USB_INCSR_SENDSTALL 0x10 -+#define USB_INCSR_FF 0x08 -+#define USB_INCSR_UNDERRUN 0x04 -+#define USB_INCSR_FFNOTEMPT 0x02 -+#define USB_INCSR_INPKTRDY 0x01 -+#define USB_OUTCSRH_AUTOCLR 0x80 -+#define USB_OUTCSRH_ISO 0x40 -+#define USB_OUTCSRH_DMAREQENAB 0x20 -+#define USB_OUTCSRH_DNYT 0x10 -+#define USB_OUTCSRH_DMAREQMODE 0x08 -+#define USB_OUTCSR_CDT 0x80 -+#define USB_OUTCSR_SENTSTALL 0x40 -+#define USB_OUTCSR_SENDSTALL 0x20 -+#define USB_OUTCSR_FF 0x10 -+#define USB_OUTCSR_DATAERR 0x08 -+#define USB_OUTCSR_OVERRUN 0x04 -+#define USB_OUTCSR_FFFULL 0x02 -+#define USB_OUTCSR_OUTPKTRDY 0x01 -+ -+/* Testmode register bits */ -+#define USB_TEST_SE0NAK 0x01 -+#define USB_TEST_J 0x02 -+#define USB_TEST_K 0x04 -+#define USB_TEST_PACKET 0x08 -+ -+/* DMA control bits */ -+#define USB_CNTL_ENA 0x01 -+#define USB_CNTL_DIR_IN 0x02 -+#define USB_CNTL_MODE_1 0x04 -+#define USB_CNTL_INTR_EN 0x08 -+#define USB_CNTL_EP(n) ((n) << 4) -+#define USB_CNTL_BURST_0 (0 << 9) -+#define USB_CNTL_BURST_4 (1 << 9) -+#define USB_CNTL_BURST_8 (2 << 9) -+#define USB_CNTL_BURST_16 (3 << 9) -+ -+#endif /* __JZ4740_REGS_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/serial.h linux-2.6.24.7/include/asm-mips/mach-jz4740/serial.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/serial.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/serial.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,30 @@ -+/* -+ * linux/include/asm-mips/mach-jz4740/serial.h -+ * -+ * Ingenic's JZ4740 common include. -+ * -+ * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_BOARD_SERIAL_H__ -+#define __ASM_BOARD_SERIAL_H__ -+ -+#ifndef CONFIG_SERIAL_MANY_PORTS -+#undef RS_TABLE_SIZE -+#define RS_TABLE_SIZE 1 -+#endif -+ -+#define JZ_BASE_BAUD (12000000/16) -+ -+#define JZ_SERIAL_PORT_DEFNS \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, -+ -+#endif /* __ASM_BORAD_SERIAL_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4740/war.h linux-2.6.24.7/include/asm-mips/mach-jz4740/war.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4740/war.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4740/war.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle -+ */ -+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H -+#define __ASM_MIPS_MACH_JZ4740_WAR_H -+ -+#define R4600_V1_INDEX_ICACHEOP_WAR 0 -+#define R4600_V1_HIT_CACHEOP_WAR 0 -+#define R4600_V2_HIT_CACHEOP_WAR 0 -+#define R5432_CP0_INTERRUPT_WAR 0 -+#define BCM1250_M3_WAR 0 -+#define SIBYTE_1956_WAR 0 -+#define MIPS4K_ICACHE_REFILL_WAR 0 -+#define MIPS_CACHE_SYNC_WAR 0 -+#define TX49XX_ICACHE_INDEX_INV_WAR 0 -+#define RM9000_CDEX_SMP_WAR 0 -+#define ICACHE_REFILLS_WORKAROUND_WAR 0 -+#define R10000_LLSC_WAR 0 -+#define MIPS34K_MISSED_ITLB_WAR 0 -+ -+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/board-apus.h linux-2.6.24.7/include/asm-mips/mach-jz4750/board-apus.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/board-apus.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/board-apus.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,119 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/board-apus.h -+ * -+ * JZ4750-based APUS board ver 1.x definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_APUS_H__ -+#define __ASM_JZ4750_APUS_H__ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 24000000 /* Main extal freq: 24 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_DISP_OFF_N (32*4+25) /* GPE25 */ -+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */ -+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */ -+#define GPIO_SD0_WP (32*2+12) /* GPC12 */ -+#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */ -+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */ -+#define GPIO_USB_DETE (32*2+11) /* GPC15 */ -+#define GPIO_DC_DETE_N (32*2+8) /* GPC8 */ -+#define GPIO_CHARG_STAT_N (32*2+9) /* GPC9 */ -+#define GPIO_LCD_VCC_EN_N (32*3+30) /* GPC10 */ -+#define GPIO_LCD_PWM (32*4+24) /* GPE24 */ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+ -+ -+/*====================================================================== -+ * LCD backlight -+ */ -+#define LCD_PWM_CHN 4 /* pwm channel */ -+#define LCD_PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_set_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+#define __lcd_close_backlight() \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_clear_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC0_WP_PIN GPIO_SD0_WP -+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N -+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) -+ -+#define MSC1_WP_PIN GPIO_SD1_WP -+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N -+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) -+ -+#define __msc0_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD0_CD_N); \ -+} while (0) -+ -+#define __msc0_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ -+} while (0) -+ -+#define __msc0_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ -+} while (0) -+ -+#define __msc0_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#define __msc1_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD1_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD1_CD_N); \ -+} while (0) -+ -+#define __msc1_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD1_VCC_EN_N); \ -+} while (0) -+ -+#define __msc1_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD1_VCC_EN_N); \ -+} while (0) -+ -+#define __msc1_card_detected(s) \ -+({ \ -+ int detected = 0; \ -+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ -+ detected = 1; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4750_APUS_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/board-fuwa.h linux-2.6.24.7/include/asm-mips/mach-jz4750/board-fuwa.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/board-fuwa.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/board-fuwa.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,93 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/board-fuwa.h -+ * -+ * JZ4750-based FUWA board ver 1.x definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_FUWA_H__ -+#define __ASM_JZ4750_FUWA_H__ -+ -+#define CONFIG_FPGA /* fuwa is an FPGA board */ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ -+#define GPIO_SD_CD_N 110 /* GPD14 */ -+#define GPIO_SD_WP 112 /* GPD16 */ -+#define GPIO_USB_DETE 102 /* GPD6 */ -+#define GPIO_DC_DETE_N 103 /* GPD7 */ -+#define GPIO_CHARG_STAT_N 111 /* GPD15 */ -+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */ -+#define GPIO_LED_EN 124 /* GPD28 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+ -+/*====================================================================== -+ * LCD backlight -+ */ -+#define GPIO_LCD_PWM (32*4+20) /* GPE20 */ -+ -+#define LCD_PWM_CHN 0 /* pwm channel */ -+#define LCD_PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_set_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+#define __lcd_close_backlight() \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_clear_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC_WP_PIN GPIO_SD_WP -+#define MSC_HOTPLUG_PIN GPIO_SD_CD_N -+#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) -+ -+#define __msc_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD_CD_N); \ -+} while (0) -+ -+#define __msc_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD_VCC_EN_N); \ -+} while (0) -+ -+#define __msc_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4750_FUWA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/clock.h linux-2.6.24.7/include/asm-mips/mach-jz4750/clock.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/clock.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/clock.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,204 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/clock.h -+ * -+ * JZ4750 clocks definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_CLOCK_H__ -+#define __ASM_JZ4750_CLOCK_H__ -+ -+#ifndef JZ_EXTAL -+#define JZ_EXTAL 12000000 /* 3.6864 MHz */ -+#endif -+#ifndef JZ_EXTAL2 -+#define JZ_EXTAL2 32768 /* 32.768 KHz */ -+#endif -+ -+/* -+ * JZ4750 clocks structure -+ */ -+typedef struct { -+ unsigned int cclk; /* CPU clock */ -+ unsigned int hclk; /* System bus clock */ -+ unsigned int pclk; /* Peripheral bus clock */ -+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ -+ unsigned int lcdclk; /* LCDC module clock */ -+ unsigned int pixclk; /* LCD pixel clock */ -+ unsigned int i2sclk; /* AIC module clock */ -+ unsigned int usbclk; /* USB module clock */ -+ unsigned int mscclk; /* MSC module clock */ -+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+} jz_clocks_t; -+ -+extern jz_clocks_t jz_clocks; -+ -+ -+/* PLL output frequency */ -+static __inline__ unsigned int __cpm_get_pllout(void) -+{ -+ unsigned long m, n, no, pllout; -+ unsigned long cppcr = REG_CPM_CPPCR; -+ unsigned long od[4] = {1, 2, 2, 4}; -+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { -+ m = __cpm_get_pllm() + 2; -+ n = __cpm_get_plln() + 2; -+ no = od[__cpm_get_pllod()]; -+ pllout = ((JZ_EXTAL) / (n * no)) * m; -+ } else -+ pllout = JZ_EXTAL; -+ return pllout; -+} -+ -+/* PLL output frequency for MSC/I2S/LCD/USB */ -+static __inline__ unsigned int __cpm_get_pllout2(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) -+ return __cpm_get_pllout(); -+ else -+ return __cpm_get_pllout()/2; -+} -+ -+/* CPU core clock */ -+static __inline__ unsigned int __cpm_get_cclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; -+} -+ -+/* AHB system bus clock */ -+static __inline__ unsigned int __cpm_get_hclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; -+} -+ -+/* Memory bus clock */ -+static __inline__ unsigned int __cpm_get_mclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; -+} -+ -+/* APB peripheral bus clock */ -+static __inline__ unsigned int __cpm_get_pclk(void) -+{ -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; -+} -+ -+/* LCDC module clock */ -+static __inline__ unsigned int __cpm_get_lcdclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); -+} -+ -+/* LCD pixel clock */ -+static __inline__ unsigned int __cpm_get_pixclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); -+} -+ -+/* I2S clock */ -+static __inline__ unsigned int __cpm_get_i2sclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { -+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* USB clock */ -+static __inline__ unsigned int __cpm_get_usbclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { -+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* -+ * MSC clock -+ * @n: the index of MMC/SD controller -+ */ -+static __inline__ unsigned int __cpm_get_mscclk(int n) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1); -+} -+ -+/* EXTAL clock */ -+static __inline__ unsigned int __cpm_get_extalclk0(void) -+{ -+ return JZ_EXTAL; -+} -+ -+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+static __inline__ unsigned int __cpm_get_extalclk(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL; -+#else -+ if (REG_CPM_CPCCR & CPM_CPCCR_ECS) -+ return __cpm_get_extalclk0()/2; -+ else -+ return __cpm_get_extalclk0(); -+#endif -+} -+ -+/* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+static __inline__ unsigned int __cpm_get_rtcclk(void) -+{ -+ return JZ_EXTAL2; -+} -+ -+/* -+ * Output 24MHz for SD and 16MHz for MMC. -+ * @n: the index of MMC/SD controller -+ */ -+static inline void __cpm_select_msc_clk(int n, int sd) -+{ -+ unsigned int pllout2 = __cpm_get_pllout2(); -+ unsigned int div = 0; -+ -+ if (sd) { -+ div = pllout2 / 24000000; -+ } -+ else { -+ div = pllout2 / 16000000; -+ } -+ -+ REG_CPM_MSCCDR(n) = div - 1; -+ REG_CPM_CPCCR |= CPM_CPCCR_CE; -+} -+ -+/* -+ * Output 48MHz for high speed card. -+ */ -+static inline void __cpm_select_msc_clk_high(int n, int sd) -+{ -+ unsigned int pllout2 = __cpm_get_pllout2(); -+ unsigned int div = 0; -+ -+ div = pllout2 / 48000000; -+ -+ REG_CPM_MSCCDR(n) = div - 1; -+ REG_CPM_CPCCR |= CPM_CPCCR_CE; -+} -+ -+#endif /* __ASM_JZ4750_CLOCK_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/dma.h linux-2.6.24.7/include/asm-mips/mach-jz4750/dma.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/dma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/dma.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,307 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/dma.h -+ * -+ * JZ4750 DMA definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_DMA_H__ -+#define __ASM_JZ4750_DMA_H__ -+ -+#include -+#include /* need byte IO */ -+#include /* And spinlocks */ -+#include -+#include -+ -+/* -+ * Descriptor structure for JZ4750 DMA engine -+ * Note: this structure must always be aligned to a 16-bytes boundary. -+ */ -+ -+/* old descriptor 4-word */ -+typedef struct { -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+ volatile u32 dsadr; /* DSAR value for the current transfer */ -+ volatile u32 dtadr; /* DTAR value for the current transfer */ -+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ -+} jz_dma_desc; -+ -+/* new descriptor 8-word */ -+typedef struct { -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+ volatile u32 dsadr; /* DSAR value for the current transfer */ -+ volatile u32 dtadr; /* DTAR value for the current transfer */ -+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ -+ volatile u32 dstrd; /* DMA source and target stride address */ -+ volatile u32 dreqt; /* DMA request type for current transfer */ -+ volatile u32 reserved0; /* Reserved */ -+ volatile u32 reserved1; /* Reserved */ -+} jz_dma_desc_8word; -+ -+/* DMA Device ID's follow */ -+enum { -+ DMA_ID_EXT = 0, /* External request with DREQn */ -+ DMA_ID_NAND, /* NAND DMA request */ -+ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */ -+ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */ -+ DMA_ID_AUTO, /* Auto-request */ -+// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */ -+ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */ -+ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */ -+ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */ -+ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */ -+ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */ -+ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */ -+ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */ -+ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */ -+ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */ -+ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */ -+ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */ -+ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */ -+ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */ -+ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */ -+ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */ -+ DMA_ID_SADC, /* SADC transfer request */ -+ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */ -+ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */ -+ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */ -+ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */ -+ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */ -+ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */ -+ DMA_ID_RAW_SET, -+ DMA_ID_MAX -+}; -+ -+/* DMA modes, simulated by sw */ -+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ -+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ -+#define DMA_AUTOINIT 0x2 -+#define DMA_MODE_MASK 0x3 -+ -+struct jz_dma_chan { -+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ -+ unsigned int io; /* DMA channel number */ -+ const char *dev_str; /* string describes the DMA channel */ -+ int irq; /* DMA irq number */ -+ void *irq_dev; /* DMA private device structure */ -+ unsigned int fifo_addr; /* physical fifo address of the requested device */ -+ unsigned int cntl; /* DMA controll */ -+ unsigned int mode; /* DMA configuration */ -+ unsigned int source; /* DMA request source */ -+}; -+ -+extern struct jz_dma_chan jz_dma_table[]; -+ -+ -+#define DMA_8BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_8BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_32BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+#define DMA_AIC_32_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD_UC \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+extern int jz_request_dma(int dev_id, -+ const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id); -+extern void jz_free_dma(unsigned int dmanr); -+ -+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data); -+extern void dump_jz_dma_channel(unsigned int dmanr); -+ -+extern void enable_dma(unsigned int dmanr); -+extern void disable_dma(unsigned int dmanr); -+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); -+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); -+extern void set_dma_mode(unsigned int dmanr, unsigned int mode); -+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_dma_src_width(int dmanr, int nbit); -+extern void jz_set_dma_dest_width(int dmanr, int nbit); -+extern void jz_set_dma_block_size(int dmanr, int nbyte); -+extern unsigned int get_dma_residue(unsigned int dmanr); -+ -+extern spinlock_t dma_spin_lock; -+ -+static __inline__ unsigned long claim_dma_lock(void) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&dma_spin_lock, flags); -+ return flags; -+} -+ -+static __inline__ void release_dma_lock(unsigned long flags) -+{ -+ spin_unlock_irqrestore(&dma_spin_lock, flags); -+} -+ -+/* Clear the 'DMA Pointer Flip Flop'. -+ * Write 0 for LSB/MSB, 1 for MSB/LSB access. -+ */ -+#define clear_dma_ff(channel) -+ -+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) -+{ -+ if (dmanr > MAX_DMA_NUM -+ || jz_dma_table[dmanr].dev_id < 0) -+ return NULL; -+ return &jz_dma_table[dmanr]; -+} -+ -+static __inline__ int dma_halted(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 1; -+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; -+} -+ -+static __inline__ unsigned int get_dma_mode(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ return chan->mode; -+} -+ -+static __inline__ void clear_dma_done(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ void clear_dma_halt(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); -+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT); -+} -+ -+static __inline__ void clear_dma_flag(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); -+} -+ -+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -+{ -+} -+ -+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) -+{ -+ unsigned long dccsr; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ dccsr = REG_DMAC_DCCSR(chan->io); -+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ int get_dma_done_irq(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return -1; -+ return chan->irq; -+} -+ -+#endif /* __ASM_JZ4750_DMA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/jz4750.h linux-2.6.24.7/include/asm-mips/mach-jz4750/jz4750.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/jz4750.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/jz4750.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/jz4750.h -+ * -+ * JZ4750 common definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_H__ -+#define __ASM_JZ4750_H__ -+ -+#include -+#include -+#include -+#include -+ -+/*------------------------------------------------------------------ -+ * Platform definitions -+ */ -+#ifdef CONFIG_JZ4750_FUWA -+#include -+#endif -+ -+#ifdef CONFIG_JZ4750_APUS -+#include -+#endif -+ -+/* Add other platform definition here ... */ -+ -+ -+/*------------------------------------------------------------------ -+ * Follows are related to platform definitions -+ */ -+ -+#include -+#include -+ -+#endif /* __ASM_JZ4750_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/misc.h linux-2.6.24.7/include/asm-mips/mach-jz4750/misc.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/misc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/misc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/misc.h -+ * -+ * Ingenic's JZ4750 common include. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_MISC_H__ -+#define __ASM_JZ4750_MISC_H__ -+ -+/*========================================================== -+ * I2C -+ *===========================================================*/ -+ -+#define I2C_EEPROM_DEV 0xA /* b'1010 */ -+#define I2C_RTC_DEV 0xD /* b'1101 */ -+#define DIMM0_SPD_ADDR 0 -+#define DIMM1_SPD_ADDR 1 -+#define DIMM2_SPD_ADDR 2 -+#define DIMM3_SPD_ADDR 3 -+#define JZ_HCI_ADDR 7 -+ -+#define DIMM_SPD_LEN 128 -+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ -+#define I2C_RTC_LEN 16 -+#define HCI_MAC_OFFSET 64 -+ -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern void i2c_setclk(unsigned int i2cclk); -+ -+extern int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+extern int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+ -+#endif /* __ASM_JZ4750_MISC_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/ops.h linux-2.6.24.7/include/asm-mips/mach-jz4750/ops.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/ops.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/ops.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3569 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750/ops.h -+ * -+ * JZ4750 register definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * 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 __JZ4750_OPS_H__ -+#define __JZ4750_OPS_H__ -+ -+/* -+ * Definition of Module Operations -+ */ -+ -+/*************************************************************************** -+ * EMC -+ ***************************************************************************/ -+#define is_share_mode() ((REG_EMC_BCR & EMC_BCR_BSR_MASK) == EMC_BCR_BSR_SHARE) -+#define is_normal_order() (!(REG_EMC_BCR & EMC_BCR_PK_SEL)) -+ -+/*************************************************************************** -+ * GPIO -+ ***************************************************************************/ -+ -+//------------------------------------------------------ -+// GPIO Pins Description -+// -+// PORT 0: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 D0 - -+// 1 D1 - -+// 2 D2 - -+// 3 D3 - -+// 4 D4 - -+// 5 D5 - -+// 6 D6 - -+// 7 D7 - -+// 8 D8 - -+// 9 D9 - -+// 10 D10 - -+// 11 D11 - -+// 12 D12 - -+// 13 D13 - -+// 14 D14 - -+// 15 D15 - -+// 16 D16 - -+// 17 D17 - -+// 18 D18 - -+// 19 D19 - -+// 20 D20 - -+// 21 D21 - -+// 22 D22 - -+// 23 D23 - -+// 24 D24 - -+// 25 D25 - -+// 26 D26 - -+// 27 D27 - -+// 28 D28 - -+// 29 D29 - -+// 30 D30 - -+// 31 D31 - -+// -+//------------------------------------------------------ -+// PORT 1: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 A0 - -+// 1 A1 - -+// 2 A2 - -+// 3 A3 - -+// 4 A4 - -+// 5 A5 - -+// 6 A6 - -+// 7 A7 - -+// 8 A8 - -+// 9 A9 - -+// 10 A10 - -+// 11 A11 - -+// 12 A12 - -+// 13 A13 - -+// 14 A14 - -+// 15 A15/CLE SA3 -+// 16 DCS0# - -+// 17 RAS# - -+// 18 CAS# - -+// 19 RDWE#/BUFD# - -+// 20 WE0# - -+// 21 WE1# - -+// 22 WE2# - -+// 23 WE3# - -+// 24 CKO - Note1 -+// 25 CKE - -+// 26 SSI0_CLK - -+// 27 SSI0_DT - -+// 28 SSI0_DR - -+// 29 SSI0_CE0# - -+// 30 SSI0_CE1#_GPC - -+// 31 SSI0_CE2# - -+// -+// Note1: BIT24: it is CKO when chip is reset -+// -+//------------------------------------------------------ -+// PORT 2: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 SD0 A20 -+// 1 SD1 A21 -+// 2 SD2 A22 -+// 3 SD3 A23 -+// 4 SD4 A24 -+// 5 SD5 A25 -+// 6 SD6 - -+// 7 SD7 - -+// 8 SD8 TSDI0 -+// 9 SD9 TSDI1 -+// 10 SD10 TSDI2 -+// 11 SD11 TSDI3 -+// 12 SD12 TSDI4 -+// 13 SD13 TSDI5 -+// 14 SD14 TSDI6 -+// 15 SD15 TSDI7 -+// 16 A16/ALE SA4 -+// 17 SA0 A17 -+// 18 SA1 A18 -+// 19 SA2 A19 -+// 20 WAIT# - Note2 -+// 21 CS1# - -+// 22 CS2# - -+// 23 CS3# - -+// 24 CS4# - -+// 25 RD# - -+// 26 WR# - -+// 27 FRB# - Note3 -+// 28 FRE# - -+// 29 FWE# - -+// 30 BOOT_SEL0 - Note4 -+// 31 BOOT_SEL1 - Note5 -+// -+// Note2: BIT20: it is WAIT# pin when chip is reset -+// -+// Note3: BIT27: when NAND is used, it should connect to NANF FRB#. -+// -+// Note4: BIT30: it is BOOT_SEL0 when chip is reset, it can used as output GPIO. -+// -+// Note5: BIT31: it is BOOT_SEL1 when chip is reset, it can used as general GPIO. -+// -+//------------------------------------------------------ -+// PORT 3: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 LCD_D0 - -+// 1 LCD_D1 - -+// 2 LCD_D2 - -+// 3 LCD_D3 - -+// 4 LCD_D4 - -+// 5 LCD_D5 - -+// 6 LCD_D6 - -+// 7 LCD_D7 - -+// 8 LCD_D8 - -+// 9 LCD_D9 - -+// 10 LCD_D10 - -+// 11 LCD_D11 - -+// 12 LCD_D12 - -+// 13 LCD_D13 - -+// 14 LCD_D14 - -+// 15 LCD_D15 - -+// 16 LCD_D16 - -+// 17 LCD_D17 - -+// 18 LCD_PCLK - -+// 19 LCD_HSYNC - -+// 20 LCD_VSYNC - -+// 21 LCD_DE - -+// 22 LCD_CLS - -+// 23 LCD_SPL - -+// 24 LCD_PS - -+// 25 LCD_REV - -+// 26 SSI1_CLK - -+// 27 SSI1_DT - -+// 28 SSI1_DR - -+// 29 SSI1_CE0# - -+// 30 SSI1_CE1# - -+// 31 - - -+// -+//------------------------------------------------------ -+// PORT 4: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 CIM_D0 - -+// 1 CIM_D1 - -+// 2 CIM_D2 - -+// 3 CIM_D3 - -+// 4 CIM_D4 - -+// 5 CIM_D5 - -+// 6 CIM_D6 - -+// 7 CIM_D7 - -+// 8 CIM_MCLK - -+// 9 CIM_PCLK - -+// 10 CIM_VSYNC - -+// 11 CIM_HSYNC - -+// 12 I2C_SDA - -+// 13 I2C_SCK - -+// 14 - - -+// 15 - - -+// 16 UART1_RxD - -+// 17 UART1_TxD - -+// 18 UART1_CTS PCM_DIN -+// 19 UART1_RTS PCM_DOUT -+// 20 PWM0 PCM_CLK -+// 21 PWM1 PCM_SYN -+// 22 PWM2 SCLK_RSTN -+// 23 PWM3 BCLK -+// 24 PWM4 SYNC -+// 25 PWM5 OWI -+// 26 SDATO UART2_TxD -+// 27 SDATI UART2_RxD -+// 28 DCS1# - -+// 29 - - -+// 30 WKUP - Note6 -+// 31 - - Note7 -+// -+// Note6: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down -+// -+// Note7: BIT31: it is used to select the function of UART or JTAG set by PESEL[31] -+// PESEL[31] = 0, select JTAG function -+// PESEL[31] = 1, select UART function -+// -+//------------------------------------------------------ -+// PORT 5: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 MSC0_D0 - -+// 1 MSC0_D1 - -+// 2 MSC0_D2 DREQ -+// 3 MSC0_D3 DACK -+// 4 MSC0_D4 UART0_RxD -+// 5 MSC0_D5 UART0_TxD -+// 6 MSC0_D6 UART0_CTS -+// 7 MSC0_D7 UART0_RTS -+// 8 MSC0_CLK - -+// 9 MSC0_CMD - -+// 10 MSC1_D0 - -+// 11 MSC1_D1 - -+// 12 MSC1_D2 - -+// 13 MSC1_D3 - -+// 14 MSC1_CLK - -+// 15 MSC1_CMD - -+// 16 UART3_RxD - -+// 17 UART3_TxD - -+// 18 UART3_CTS - -+// 19 UART3_RTS - -+// 20 TSCLK - -+// 21 TSSTR - -+// 22 TSFRM - -+// 23 TSFAIL - -+// 24 - - -+// 25 - - -+// 26 - - -+// 27 - - -+// 28 - - -+// 29 - - -+// 30 - - -+// 31 - - -+// -+////////////////////////////////////////////////////////// -+ -+/* -+ * p is the port number (0,1,2,3,4,5) -+ * o is the pin offset (0-31) inside the port -+ * n is the absolute number of a pin (0-191), regardless of the port -+ */ -+ -+//------------------------------------------- -+// Function Pins Mode -+ -+#define __gpio_as_func0(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXSELC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_func1(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+} while (0) -+ -+/* -+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, -+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# -+ */ -+#define __gpio_as_sdram_32bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0xffffffff; \ -+ REG_GPIO_PXSELC(0) = 0xffffffff; \ -+ REG_GPIO_PXPES(0) = 0xffffffff; \ -+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0x03ff7fff; \ -+} while (0) -+ -+/* -+ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#, -+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# -+ */ -+#define __gpio_as_sdram_16bit() \ -+do { \ -+ if (is_normal_order()) { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ -+ REG_GPIO_PXSELC(0) = 0x0000ffff; \ -+ REG_GPIO_PXPES(0) = 0x0000ffff; \ -+ } else { \ -+ /* 16-bit data special order */ \ -+ REG_GPIO_PXFUNS(0) = 0x00ffff00; \ -+ REG_GPIO_PXSELC(0) = 0x00ffff00; \ -+ REG_GPIO_PXPES(0) = 0x00ffff00; \ -+ } \ -+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0x03ff7fff; \ -+} while (0) -+ -+/* -+ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nand_8bit(n) \ -+do { \ -+ if (!is_share_mode()) { \ -+ /* unshare mode */ \ -+ REG_GPIO_PXFUNS(2) = 0x000000ff; /* SD0~SD7 */ \ -+ REG_GPIO_PXSELS(2) = 0x000000ff; \ -+ REG_GPIO_PXPES(2) = 0x000000ff; \ -+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(SA3) */ \ -+ REG_GPIO_PXSELS(1) = 0x00008000; \ -+ REG_GPIO_PXPES(1) = 0x00008000; \ -+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(SA4) */ \ -+ REG_GPIO_PXSELS(2) = 0x00010000; \ -+ REG_GPIO_PXPES(2) = 0x00010000; \ -+ } else { \ -+ /* share mode */ \ -+ if (is_normal_order()) { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \ -+ REG_GPIO_PXSELC(0) = 0x000000ff; \ -+ REG_GPIO_PXPES(0) = 0x000000ff; \ -+ } else { \ -+ /* 16-bit data special order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ff00; /* D0~D7 */ \ -+ REG_GPIO_PXSELC(0) = 0x0000ff00; \ -+ REG_GPIO_PXPES(0) = 0x0000ff00; \ -+ } \ -+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \ -+ REG_GPIO_PXSELC(1) = 0x00008000; \ -+ REG_GPIO_PXPES(1) = 0x00008000; \ -+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \ -+ REG_GPIO_PXSELC(2) = 0x00010000; \ -+ REG_GPIO_PXPES(2) = 0x00010000; \ -+ } \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \ -+ REG_GPIO_PXSELC(1) = 0x00080000; \ -+ REG_GPIO_PXPES(1) = 0x00080000; \ -+ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \ -+ REG_GPIO_PXSELC(2) = 0x30000000; \ -+ REG_GPIO_PXPES(2) = 0x30000000; \ -+ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \ -+ REG_GPIO_PXSELC(2) = 0x08000000; \ -+ REG_GPIO_PXDIRC(2) = 0x08000000; \ -+ REG_GPIO_PXPES(2) = 0x08000000; \ -+} while (0) -+ -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nor_8bit(n) \ -+do { \ -+ if (is_normal_order()) { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x000000ff; \ -+ REG_GPIO_PXSELC(0) = 0x000000ff; \ -+ REG_GPIO_PXPES(0) = 0x000000ff; \ -+ } else { \ -+ /* 16-bit data special order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ff00; \ -+ REG_GPIO_PXSELC(0) = 0x0000ff00; \ -+ REG_GPIO_PXPES(0) = 0x0000ff00; \ -+ } \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ -+ REG_GPIO_PXSELC(1) = 0x0000ffff; \ -+ REG_GPIO_PXPES(1) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ -+ REG_GPIO_PXSELC(2) = 0x06110007; \ -+ REG_GPIO_PXPES(2) = 0x06110007; \ -+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ -+ REG_GPIO_PXSELS(2) = 0x000e0000; \ -+ REG_GPIO_PXPES(2) = 0x000e0000; \ -+} while (0) -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nor_16bit(n) \ -+do { \ -+ if (is_normal_order()) { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ -+ REG_GPIO_PXSELC(0) = 0x0000ffff; \ -+ REG_GPIO_PXPES(0) = 0x0000ffff; \ -+ } else { \ -+ /* 16-bit data special order */ \ -+ REG_GPIO_PXFUNS(0) = 0x00ffff00; \ -+ REG_GPIO_PXSELC(0) = 0x00ffff00; \ -+ REG_GPIO_PXPES(0) = 0x00ffff00; \ -+ } \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ -+ REG_GPIO_PXSELC(1) = 0x0000ffff; \ -+ REG_GPIO_PXPES(1) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ -+ REG_GPIO_PXSELC(2) = 0x06110007; \ -+ REG_GPIO_PXPES(2) = 0x06110007; \ -+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ -+ REG_GPIO_PXSELS(2) = 0x000e0000; \ -+ REG_GPIO_PXPES(2) = 0x000e0000; \ -+} while (0) -+ -+/* -+ * UART0_TxD, UART0_RxD -+ */ -+#define __gpio_as_uart0() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000030; \ -+ REG_GPIO_PXSELS(5) = 0x00000030; \ -+ REG_GPIO_PXPES(5) = 0x00000030; \ -+} while (0) -+ -+/* -+ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS -+ */ -+#define __gpio_as_uart0_ctsrts() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x000000f0; \ -+ REG_GPIO_PXSELS(5) = 0x000000f0; \ -+ REG_GPIO_PXPES(5) = 0x000000f0; \ -+} while (0) -+ -+/* -+ * UART1_TxD, UART1_RxD -+ */ -+#define __gpio_as_uart1() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00030000; \ -+ REG_GPIO_PXSELC(4) = 0x00030000; \ -+ REG_GPIO_PXPES(4) = 0x00030000; \ -+} while (0) -+ -+/* -+ * UART1_TxD, UART1_RxD, UART1_CTS, UART1_RTS -+ */ -+#define __gpio_as_uart1_ctsrts() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x000f0000; \ -+ REG_GPIO_PXSELC(4) = 0x000f0000; \ -+ REG_GPIO_PXPES(4) = 0x000f0000; \ -+} while (0) -+ -+/* -+ * UART2_TxD, UART2_RxD -+ */ -+#define __gpio_as_uart2() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x0c000000; \ -+ REG_GPIO_PXSELS(4) = 0x0c000000; \ -+ REG_GPIO_PXPES(4) = 0x0c000000; \ -+} while (0) -+ -+/* -+ * UART3_TxD, UART3_RxD -+ */ -+#define __gpio_as_uart3() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00030000; \ -+ REG_GPIO_PXSELC(5) = 0x00030000; \ -+ REG_GPIO_PXPES(5) = 0x00030000; \ -+} while (0) -+ -+/* -+ * UART3_TxD, UART3_RxD, UART3_CTS, UART3_RTS -+ */ -+#define __gpio_as_uart3_ctsrts() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x000f0000; \ -+ REG_GPIO_PXSELC(5) = 0x000f0000; \ -+ REG_GPIO_PXPES(5) = 0x000f0000; \ -+} while (0) -+ -+/* -+ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 -+ */ -+#define __gpio_as_tssi() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x0000ff00; \ -+ REG_GPIO_PXSELS(2) = 0x0000ff00; \ -+ REG_GPIO_PXPES(2) = 0x0000ff00; \ -+ REG_GPIO_PXFUNS(5) = 0x00f00000; \ -+ REG_GPIO_PXSELC(5) = 0x00f00000; \ -+ REG_GPIO_PXPES(5) = 0x00f00000; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003c00ff; \ -+ REG_GPIO_PXSELC(3) = 0x003c00ff; \ -+ REG_GPIO_PXPES(3) = 0x003c00ff; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003cffff; \ -+ REG_GPIO_PXSELC(3) = 0x003cffff; \ -+ REG_GPIO_PXPES(3) = 0x003cffff; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_18bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003fffff; \ -+ REG_GPIO_PXSELC(3) = 0x003fffff; \ -+ REG_GPIO_PXPES(3) = 0x003fffff; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D17, LCD_D_R1, LCD_D_G0, LCD_D_G1, LCD_D_B1, -+ * LCD_D_R0, LCD_D_B0, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_24bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003fffff; \ -+ REG_GPIO_PXSELC(3) = 0x003fffff; \ -+ REG_GPIO_PXPES(3) = 0x003fffff; \ -+ REG_GPIO_PXFUNS(3) = 0x03c00000; \ -+ REG_GPIO_PXSELS(3) = 0x03c00000; \ -+ REG_GPIO_PXPES(3) = 0x03c00000; \ -+ REG_GPIO_PXFUNS(5) = 0x000c0000; \ -+ REG_GPIO_PXSELS(5) = 0x000c0000; \ -+ REG_GPIO_PXPES(5) = 0x000c0000; \ -+} while (0) -+ -+/* -+ * SLCD_DAT0~7, SLCD_CLK, SLCD_RS, SLCD_CS -+ */ -+#define __gpio_as_lcd_smart_pal_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x001c00ff; \ -+ REG_GPIO_PXSELC(3) = 0x001c00ff; \ -+ REG_GPIO_PXPES(3) = 0x001c00ff; \ -+} while (0) -+ -+/* -+ * SLCD_DAT0~15, SLCD_CLK, SLCD_RS, SLCD_CS -+ */ -+#define __gpio_as_lcd_smart_pal_15bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x001cffff; \ -+ REG_GPIO_PXSELC(3) = 0x001cffff; \ -+ REG_GPIO_PXPES(3) = 0x001cffff; \ -+} while (0) -+ -+/* -+ * SLCD_DAT0~17, SLCD_CLK, SLCD_RS, SLCD_CS -+ */ -+#define __gpio_as_lcd_smart_pal_17bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x001fffff; \ -+ REG_GPIO_PXSELC(3) = 0x001fffff; \ -+ REG_GPIO_PXPES(3) = 0x001fffff; \ -+} while (0) -+ -+/* -+ * SLCD_DAT15, SLCD_CLK, SLCD_RS, SLCD_CS -+ */ -+#define __gpio_as_lcd_smart_serial() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x001c8000; \ -+ REG_GPIO_PXSELC(3) = 0x001c8000; \ -+ REG_GPIO_PXPES(3) = 0x001c8000; \ -+} while (0) -+ -+/* -+ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV -+ */ -+#define __gpio_as_lcd_special() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x03C00000; \ -+ REG_GPIO_PXSELC(3) = 0x03C00000; \ -+ REG_GPIO_PXPES(3) = 0x03C00000; \ -+} while (0) -+ -+/* -+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC -+ */ -+#define __gpio_as_cim() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00000fff; \ -+ REG_GPIO_PXSELC(4) = 0x00000fff; \ -+ REG_GPIO_PXPES(4) = 0x00000fff; \ -+} while (0) -+ -+/* -+ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or -+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec) -+ */ -+#define __gpio_as_aic() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x0c000000; \ -+ REG_GPIO_PXSELS(4) = 0x0c000000; \ -+ REG_GPIO_PXPES(4) = 0x0c000000; \ -+ REG_GPIO_PXFUNS(4) = 0x00e00000; \ -+ REG_GPIO_PXSELC(4) = 0x00e00000; \ -+ REG_GPIO_PXPES(4) = 0x00e00000; \ -+} while (0) -+ -+/* -+ * PCM_DIN, PCM_DOUT, PCM_CLK, PCM_SYN -+*/ -+#define __gpio_as_pcm() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x003c0000; \ -+ REG_GPIO_PXSELS(4) = 0x003c0000; \ -+ REG_GPIO_PXPES(4) = 0x003c0000; \ -+} while (0) -+ -+/* -+ * OWI -+*/ -+#define __gpio_as_owi() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x02000000; \ -+ REG_GPIO_PXSELS(4) = 0x02000000; \ -+ REG_GPIO_PXPES(4) = 0x02000000; \ -+} while (0) -+ -+/* -+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3 -+ */ -+#define __gpio_as_msc0_4bit() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x0000030f; \ -+ REG_GPIO_PXSELC(5) = 0x0000030f; \ -+ REG_GPIO_PXPES(5) = 0x0000030f; \ -+} while (0) -+ -+/* -+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D7 -+ */ -+#define __gpio_as_msc0_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x000003ff; \ -+ REG_GPIO_PXSELC(5) = 0x000003ff; \ -+ REG_GPIO_PXPES(5) = 0x000003ff; \ -+} while (0) -+ -+/* -+ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3 -+ */ -+#define __gpio_as_msc1_4bit() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x0000fc00; \ -+ REG_GPIO_PXSELC(5) = 0x0000fc00; \ -+ REG_GPIO_PXPES(5) = 0x0000fc00; \ -+} while (0) -+ -+#define __gpio_as_msc __gpio_as_msc0_8bit /* default as msc0 8bit */ -+#define __gpio_as_msc0 __gpio_as_msc0_8bit /* msc0 default as 8bit */ -+#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */ -+ -+/* -+ * SSI0_CE0, SSI0_CE1#_GPC, SSI0_CE2, SSI0_CLK, SSI0_DT, SSI0_DR -+ */ -+#define __gpio_as_ssi0() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0xfc000000; \ -+ REG_GPIO_PXSELC(1) = 0xfc000000; \ -+ REG_GPIO_PXPES(1) = 0xfc000000; \ -+} while (0) -+ -+/* -+ * SSI1_CE0, SSI1_CE1, SSI1_CLK, SSI1_DT, SSI1_DR -+ */ -+#define __gpio_as_ssi1() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x7c000000; \ -+ REG_GPIO_PXSELC(3) = 0x7c000000; \ -+ REG_GPIO_PXPES(3) = 0x7c000000; \ -+} while (0) -+ -+/* n = 0(SSI0), 1(SSI1) */ -+#define __gpio_as_ssi(n) __gpio_as_ssi##n() -+ -+/* -+ * I2C_SCK, I2C_SDA -+ */ -+#define __gpio_as_i2c() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00003000; \ -+ REG_GPIO_PXSELC(4) = 0x00003000; \ -+ REG_GPIO_PXPES(4) = 0x00003000; \ -+} while (0) -+ -+/* -+ * PWM0 -+ */ -+#define __gpio_as_pwm0() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00100000; \ -+ REG_GPIO_PXSELC(4) = 0x00100000; \ -+ REG_GPIO_PXPES(4) = 0x00100000; \ -+} while (0) -+ -+/* -+ * PWM1 -+ */ -+#define __gpio_as_pwm1() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00200000; \ -+ REG_GPIO_PXSELC(4) = 0x00200000; \ -+ REG_GPIO_PXPES(4) = 0x00200000; \ -+} while (0) -+ -+/* -+ * PWM2 -+ */ -+#define __gpio_as_pwm2() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00400000; \ -+ REG_GPIO_PXSELC(4) = 0x00400000; \ -+ REG_GPIO_PXPES(4) = 0x00400000; \ -+} while (0) -+ -+/* -+ * PWM3 -+ */ -+#define __gpio_as_pwm3() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00800000; \ -+ REG_GPIO_PXSELC(4) = 0x00800000; \ -+ REG_GPIO_PXPES(4) = 0x00800000; \ -+} while (0) -+ -+/* -+ * PWM4 -+ */ -+#define __gpio_as_pwm4() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x01000000; \ -+ REG_GPIO_PXSELC(4) = 0x01000000; \ -+ REG_GPIO_PXPES(4) = 0x01000000; \ -+} while (0) -+ -+/* -+ * PWM5 -+ */ -+#define __gpio_as_pwm5() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x02000000; \ -+ REG_GPIO_PXSELC(4) = 0x02000000; \ -+ REG_GPIO_PXPES(4) = 0x02000000; \ -+} while (0) -+ -+/* -+ * n = 0 ~ 5 -+ */ -+#define __gpio_as_pwm(n) __gpio_as_pwm##n() -+ -+/* -+ * DREQ -+ */ -+#define __gpio_as_dreq() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000004; \ -+ REG_GPIO_PXSELS(5) = 0x00000004; \ -+ REG_GPIO_PXPES(5) = 0x00000004; \ -+} while (0) -+ -+/* -+ * DACK -+ */ -+#define __gpio_as_dack() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000008; \ -+ REG_GPIO_PXSELS(5) = 0x00000008; \ -+ REG_GPIO_PXPES(5) = 0x00000008; \ -+} while (0) -+ -+/* -+ * GPIO or Interrupt Mode -+ */ -+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) -+ -+#define __gpio_port_as_output(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRS(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_port_as_input(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRC(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_as_output(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_output(p, o); \ -+} while (0) -+ -+#define __gpio_as_input(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_input(p, o); \ -+} while (0) -+ -+#define __gpio_set_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_clear_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_pin(n) \ -+({ \ -+ unsigned int p, o, v; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ if (__gpio_get_port(p) & (1 << o)) \ -+ v = 1; \ -+ else \ -+ v = 0; \ -+ v; \ -+}) -+ -+#define __gpio_as_irq_high_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_low_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_rise_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_fall_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_mask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_unmask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_ack_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_irq() \ -+({ \ -+ unsigned int p, i, tmp, v = 0; \ -+ for (p = 3; p >= 0; p--) { \ -+ tmp = REG_GPIO_PXFLG(p); \ -+ for (i = 0; i < 32; i++) \ -+ if (tmp & (1 << i)) \ -+ v = (32*p + i); \ -+ } \ -+ v; \ -+}) -+ -+#define __gpio_group_irq(n) \ -+({ \ -+ register int tmp, i; \ -+ tmp = REG_GPIO_PXFLG((n)); \ -+ for (i=31;i>=0;i--) \ -+ if (tmp & (1 << i)) \ -+ break; \ -+ i; \ -+}) -+ -+#define __gpio_enable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPEC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_disable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPES(p) = (1 << o); \ -+} while (0) -+ -+ -+/*************************************************************************** -+ * CPM -+ ***************************************************************************/ -+#define __cpm_get_pllm() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) -+#define __cpm_get_plln() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) -+#define __cpm_get_pllod() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) -+ -+#define __cpm_get_cdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) -+#define __cpm_get_hdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) -+#define __cpm_get_pdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) -+#define __cpm_get_mdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) -+#define __cpm_get_ldiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) -+#define __cpm_get_udiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) -+#define __cpm_get_i2sdiv() \ -+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) -+#define __cpm_get_pixdiv() \ -+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) -+#define __cpm_get_mscdiv(n) \ -+ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) -+#define __cpm_get_uhcdiv() \ -+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) -+#define __cpm_get_ssidiv() \ -+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) -+#define __cpm_get_pcmdiv(v) \ -+ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT) -+ -+#define __cpm_set_cdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) -+#define __cpm_set_hdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) -+#define __cpm_set_pdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) -+#define __cpm_set_mdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) -+#define __cpm_set_ldiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) -+#define __cpm_set_udiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) -+#define __cpm_set_i2sdiv(v) \ -+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) -+#define __cpm_set_pixdiv(v) \ -+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) -+#define __cpm_set_mscdiv(n, v) \ -+ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) -+#define __cpm_set_uhcdiv(v) \ -+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) -+#define __cpm_set_ssidiv(v) \ -+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) -+#define __cpm_set_pcmdiv(v) \ -+ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT))) -+ -+#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS) -+#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS) -+#define __cpm_select_pixclk_ext() (REG_CPM_LPCDR |= CPM_LPCDR_LPCS) -+#define __cpm_select_pixclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LPCS) -+#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS) -+#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS) -+#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS) -+#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS) -+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) -+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) -+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) -+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) -+ -+#define __cpm_enable_cko() -+#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS) -+#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS) -+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) -+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) -+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) -+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) -+ -+#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF) -+#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON) -+#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP) -+ -+#define __cpm_get_cclk_doze_duty() \ -+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) -+#define __cpm_set_cclk_doze_duty(v) \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) -+ -+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) -+#define __cpm_idle_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) -+#define __cpm_sleep_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) -+ -+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff) -+#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM) -+#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT) -+#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB) -+#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME) -+#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC) -+#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE) -+#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI) -+#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI) -+#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM) -+#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3) -+#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2) -+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) -+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) -+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) -+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) -+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) -+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) -+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) -+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) -+#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n) -+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) -+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) -+#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n) -+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) -+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) -+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) -+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) -+ -+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) -+#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM) -+#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT) -+#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB) -+#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME) -+#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC) -+#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE) -+#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI) -+#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI) -+#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM) -+#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3) -+#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2) -+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) -+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) -+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) -+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) -+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) -+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) -+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) -+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) -+#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n) -+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) -+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) -+#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n) -+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) -+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) -+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) -+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) -+ -+#define __cpm_get_o1st() \ -+ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT) -+#define __cpm_set_o1st(v) \ -+ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT))) -+#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE) -+#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE) -+#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE) -+#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE) -+#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE) -+#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE) -+#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS) -+#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS) -+ -+ -+/*************************************************************************** -+ * TCU -+ ***************************************************************************/ -+// where 'n' is the TCU channel -+#define __tcu_select_extalclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) -+#define __tcu_select_rtcclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) -+#define __tcu_select_pclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) -+#define __tcu_disable_pclk(n) \ -+ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN); -+#define __tcu_select_clk_div1(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) -+#define __tcu_select_clk_div4(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) -+#define __tcu_select_clk_div16(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) -+#define __tcu_select_clk_div64(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) -+#define __tcu_select_clk_div256(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) -+#define __tcu_select_clk_div1024(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) -+ -+#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN) -+#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN) -+ -+#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH) -+#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH) -+ -+#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD) -+#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD) -+ -+#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ) -+ -+#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN) -+#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST) -+#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL) -+ -+#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n))) -+#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n))) -+#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n))) -+ -+#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16))) -+#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n))) -+#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16))) -+#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n))) -+#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16))) -+#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n))) -+#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16))) -+#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n))) -+#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16))) -+#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n))) -+ -+#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG) -+#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST) -+#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL) -+#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK) -+#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST) -+#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL) -+ -+#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC) -+#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST) -+#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n))) -+ -+#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC) -+#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC) -+#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n))) -+ -+#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC) -+#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS) -+#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n))) -+ -+#define __tcu_get_count(n) (REG_TCU_TCNT((n))) -+#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v)) -+#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v)) -+#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v)) -+ -+/* TCU2, counter 1, 2*/ -+#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) -+#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) -+#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n))) -+#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n))) -+ -+#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16))) -+#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16))) -+#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n))) -+#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n))) -+ -+/* ost counter */ -+#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD) -+#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD) -+#define __ostcu_select_clk_div1() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1) -+#define __ostcu_select_clk_div4() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4) -+#define __ostcu_select_clk_div16() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16) -+#define __ostcu_select_clk_div64() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64) -+#define __ostcu_select_clk_div256() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256) -+#define __ostcu_select_clk_div1024() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024) -+#define __ostcu_select_rtcclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN) -+#define __ostcu_select_extalclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN) -+#define __ostcu_select_pclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN) -+ -+ -+/*************************************************************************** -+ * WDT -+ ***************************************************************************/ -+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) -+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) -+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) -+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) -+ -+#define __wdt_select_extalclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) -+#define __wdt_select_rtcclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) -+#define __wdt_select_pclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) -+ -+#define __wdt_select_clk_div1() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) -+#define __wdt_select_clk_div4() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) -+#define __wdt_select_clk_div16() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) -+#define __wdt_select_clk_div64() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) -+#define __wdt_select_clk_div256() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) -+#define __wdt_select_clk_div1024() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) -+ -+ -+/*************************************************************************** -+ * UART -+ ***************************************************************************/ -+ -+#define __uart_enable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) -+#define __uart_disable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) -+ -+#define __uart_enable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) -+#define __uart_disable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) -+ -+#define __uart_enable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) -+#define __uart_disable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) -+ -+#define __uart_enable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) -+#define __uart_disable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) -+ -+#define __uart_set_8n1(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) -+ -+#define __uart_set_baud(n, devclk, baud) \ -+ do { \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ -+ } while (0) -+ -+#define __uart_parity_error(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) -+ -+#define __uart_clear_errors(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) -+ -+#define __uart_transmit_fifo_empty(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) -+ -+#define __uart_transmit_end(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) -+ -+#define __uart_transmit_char(n, ch) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) -+ -+#define __uart_receive_fifo_full(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_ready(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_char(n) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) -+ -+#define __uart_disable_irda() \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) -+#define __uart_enable_irda() \ -+ /* Tx high pulse as 0, Rx low pulse as 0 */ \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) -+ -+ -+/*************************************************************************** -+ * DMAC -+ ***************************************************************************/ -+ -+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */ -+ -+#define __dmac_enable_module(m) \ -+ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 ) -+#define __dmac_disable_module(m) \ -+ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE ) -+ -+/* p=0,1,2,3 */ -+#define __dmac_set_priority(m,p) \ -+do { \ -+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \ -+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \ -+} while (0) -+ -+#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT ) -+#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR ) -+ -+#define __dmac_channel_enable_clk(n) \ -+ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM); -+ -+#define __dmac_enable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) -+#define __dmac_disable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) -+ -+#define __dmac_enable_channel(n) \ -+do { \ -+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \ -+} while (0) -+#define __dmac_disable_channel(n) \ -+do { \ -+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \ -+} while (0) -+#define __dmac_channel_enabled(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) -+ -+#define __dmac_channel_enable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) -+#define __dmac_channel_disable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) -+ -+#define __dmac_channel_transmit_halt_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) -+#define __dmac_channel_transmit_end_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) -+#define __dmac_channel_address_error_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) -+#define __dmac_channel_count_terminated_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) -+#define __dmac_channel_descriptor_invalid_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_clear_transmit_halt(n) \ -+ do { \ -+ /* clear both channel halt error and globle halt error */ \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \ -+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \ -+ } while (0) -+#define __dmac_channel_clear_transmit_end(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) -+#define __dmac_channel_clear_address_error(n) \ -+ do { \ -+ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \ -+ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \ -+ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \ -+ /* clear both channel addr error and globle address error */ \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \ -+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \ -+ } while (0) -+#define __dmac_channel_clear_count_terminated(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) -+#define __dmac_channel_clear_descriptor_invalid(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_set_transfer_unit_32bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_8bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_32byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_dest_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_src_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ -+} while (0) -+ -+/* v=0-15 */ -+#define __dmac_channel_set_rdil(n,v) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ -+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ -+} while (0) -+ -+#define __dmac_channel_dest_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) -+#define __dmac_channel_dest_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) -+ -+#define __dmac_channel_src_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) -+#define __dmac_channel_src_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) -+ -+#define __dmac_channel_set_doorbell(n) \ -+ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+ -+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+ -+static __inline__ int __dmac_get_irq(void) -+{ -+ int i; -+ for (i = 0; i < MAX_DMA_NUM; i++) -+ if (__dmac_channel_irq_detected(i)) -+ return i; -+ return -1; -+} -+ -+ -+/*************************************************************************** -+ * AIC (AC'97 & I2S Controller) -+ ***************************************************************************/ -+ -+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) -+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) -+ -+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) -+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) -+ -+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) -+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) -+ -+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) -+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) -+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) -+ -+#define __aic_reset() \ -+do { \ -+ REG_AIC_FR |= AIC_FR_RST; \ -+} while(0) -+ -+ -+#define __aic_set_transmit_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ -+} while(0) -+ -+#define __aic_set_receive_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ -+} while(0) -+ -+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) -+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) -+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) -+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) -+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) -+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) -+ -+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) -+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) -+ -+#define __aic_enable_transmit_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_disable_transmit_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_enable_receive_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) -+#define __aic_disable_receive_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) -+ -+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) -+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) -+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) -+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) -+ -+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) -+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) -+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) -+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) -+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) -+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) -+ -+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 -+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 -+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 -+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 -+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 -+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 -+ -+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 -+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 -+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 -+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 -+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 -+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 -+ -+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) -+#define __ac97_set_xs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ -+} while(0) -+#define __ac97_set_xs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ -+} while(0) -+ -+/* In fact, only stereo is support now. */ -+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) -+#define __ac97_set_rs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ -+} while(0) -+#define __ac97_set_rs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ -+} while(0) -+ -+#define __ac97_warm_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ -+ } while (0) -+ -+#define __ac97_cold_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ -+ } while (0) -+ -+/* n=8,16,18,20 */ -+#define __ac97_set_iass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) -+#define __ac97_set_oass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) -+ -+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) -+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) -+ -+/* n=8,16,18,20,24 */ -+/*#define __i2s_set_sample_size(n) \ -+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ -+ -+#define __i2s_set_oss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) -+#define __i2s_set_iss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) -+ -+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) -+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) -+ -+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) -+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) -+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) -+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) -+ -+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) -+ -+#define __aic_get_transmit_resident() \ -+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) -+#define __aic_get_receive_count() \ -+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) -+ -+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) -+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) -+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) -+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) -+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) -+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) -+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) -+ -+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) -+ -+#define CODEC_READ_CMD (1 << 19) -+#define CODEC_WRITE_CMD (0 << 19) -+#define CODEC_REG_INDEX_BIT 12 -+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ -+#define CODEC_REG_DATA_BIT 4 -+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ -+ -+#define __ac97_out_rcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_wcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_data(value) \ -+do { \ -+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ -+} while (0) -+ -+#define __ac97_in_data() \ -+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) -+ -+#define __ac97_in_status_addr() \ -+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) -+ -+#define __i2s_set_sample_rate(i2sclk, sync) \ -+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) -+ -+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) -+#define __aic_read_rfifo() ( REG_AIC_DR ) -+ -+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) -+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) -+ -+// -+// Define next ops for AC97 compatible -+// -+ -+#define AC97_ACSR AIC_ACSR -+ -+#define __ac97_enable() __aic_enable(); __aic_select_ac97() -+#define __ac97_disable() __aic_disable() -+#define __ac97_reset() __aic_reset() -+ -+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __ac97_enable_record() __aic_enable_record() -+#define __ac97_disable_record() __aic_disable_record() -+#define __ac97_enable_replay() __aic_enable_replay() -+#define __ac97_disable_replay() __aic_disable_replay() -+#define __ac97_enable_loopback() __aic_enable_loopback() -+#define __ac97_disable_loopback() __aic_disable_loopback() -+ -+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __ac97_enable_receive_dma() __aic_enable_receive_dma() -+#define __ac97_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __ac97_transmit_request() __aic_transmit_request() -+#define __ac97_receive_request() __aic_receive_request() -+#define __ac97_transmit_underrun() __aic_transmit_underrun() -+#define __ac97_receive_overrun() __aic_receive_overrun() -+ -+#define __ac97_clear_errors() __aic_clear_errors() -+ -+#define __ac97_get_transmit_resident() __aic_get_transmit_resident() -+#define __ac97_get_receive_count() __aic_get_receive_count() -+ -+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __ac97_enable_receive_intr() __aic_enable_receive_intr() -+#define __ac97_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __ac97_write_tfifo(v) __aic_write_tfifo(v) -+#define __ac97_read_rfifo() __aic_read_rfifo() -+ -+// -+// Define next ops for I2S compatible -+// -+ -+#define I2S_ACSR AIC_I2SSR -+ -+#define __i2s_enable() __aic_enable(); __aic_select_i2s() -+#define __i2s_disable() __aic_disable() -+#define __i2s_reset() __aic_reset() -+ -+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __i2s_enable_record() __aic_enable_record() -+#define __i2s_disable_record() __aic_disable_record() -+#define __i2s_enable_replay() __aic_enable_replay() -+#define __i2s_disable_replay() __aic_disable_replay() -+#define __i2s_enable_loopback() __aic_enable_loopback() -+#define __i2s_disable_loopback() __aic_disable_loopback() -+ -+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __i2s_enable_receive_dma() __aic_enable_receive_dma() -+#define __i2s_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __i2s_transmit_request() __aic_transmit_request() -+#define __i2s_receive_request() __aic_receive_request() -+#define __i2s_transmit_underrun() __aic_transmit_underrun() -+#define __i2s_receive_overrun() __aic_receive_overrun() -+ -+#define __i2s_clear_errors() __aic_clear_errors() -+ -+#define __i2s_get_transmit_resident() __aic_get_transmit_resident() -+#define __i2s_get_receive_count() __aic_get_receive_count() -+ -+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __i2s_enable_receive_intr() __aic_enable_receive_intr() -+#define __i2s_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __i2s_write_tfifo(v) __aic_write_tfifo(v) -+#define __i2s_read_rfifo() __aic_read_rfifo() -+ -+#define __i2s_reset_codec() \ -+ do { \ -+ } while (0) -+ -+/************************************************************************* -+ * PCM Controller operation -+ *************************************************************************/ -+ -+#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN ) -+#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN ) -+ -+#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN ) -+#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN ) -+ -+#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST ) -+#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH ) -+ -+#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC ) -+#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC ) -+#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL ) -+#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL ) -+ -+#define __pcm_enable_rxfifo() __pcm_enable_record() -+#define __pcm_disable_rxfifo() __pcm_disable_record() -+#define __pcm_enable_txfifo() __pcm_enable_playback() -+#define __pcm_disable_txfifo() __pcm_disable_playback() -+ -+#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP ) -+#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP ) -+ -+#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA ) -+#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA ) -+#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA ) -+#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA ) -+ -+#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE ) -+#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE ) -+ -+#define __pcm_set_transmit_trigger(n) \ -+do { \ -+ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \ -+ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \ -+} while(0) -+ -+#define __pcm_set_receive_trigger(n) \ -+do { \ -+ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \ -+ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \ -+} while(0) -+ -+#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS ) -+#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS ) -+ -+#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS ) -+#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS ) -+ -+/* set input sample size 8 or 16*/ -+#define __pcm_set_iss(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n ) -+/* set output sample size 8 or 16*/ -+#define __pcm_set_oss(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n ) -+ -+#define __pcm_set_valid_slot(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n ) -+ -+#define __pcm_write_data(v) ( REG_PCM_DP = (v) ) -+#define __pcm_read_data() ( REG_PCM_DP ) -+ -+#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS ) -+#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS ) -+ -+#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR ) -+#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR ) -+ -+#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS ) -+#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS ) -+ -+#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR ) -+#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR ) -+ -+#define __pcm_ints_valid_tx() \ -+( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) ) -+#define __pcm_ints_valid_rx() \ -+( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) ) -+ -+#define __pcm_set_clk_div(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) ) -+ -+/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */ -+#define __pcm_set_clk_rate(sysclk, pcmclk) \ -+__pcm_set_clk_div(((sysclk) / (pcmclk) - 1)) -+ -+#define __pcm_set_sync_div(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) ) -+ -+/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */ -+#define __pcm_set_sync_rate(pcmclk, sync) \ -+__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1)) -+ -+ /* set sync length in pcmclk n = 0 ... 63 */ -+#define __pcm_set_sync_len(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) ) -+ -+ -+/*************************************************************************** -+ * ICDC -+ ***************************************************************************/ -+#define __i2s_internal_codec() __aic_internal_codec() -+#define __i2s_external_codec() __aic_external_codec() -+ -+#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY ) -+#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD ) -+#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD ) -+ -+#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR ) -+#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR ) -+#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR ) -+ -+#define __icdc_set_addr(n) \ -+do { \ -+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \ -+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \ -+} while(0) -+ -+#define __icdc_set_cmd(n) \ -+do { \ -+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \ -+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \ -+} while(0) -+ -+#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ ) -+#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK ) -+ -+/*************************************************************************** -+ * INTC -+ ***************************************************************************/ -+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) -+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) -+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */ -+ -+ -+/*************************************************************************** -+ * I2C -+ ***************************************************************************/ -+ -+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) -+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) -+ -+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) -+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) -+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) -+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) -+ -+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) -+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) -+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) -+ -+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) -+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) -+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) -+ -+#define __i2c_set_clk(dev_clk, i2c_clk) \ -+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) -+ -+#define __i2c_read() ( REG_I2C_DR ) -+#define __i2c_write(val) ( REG_I2C_DR = (val) ) -+ -+ -+/*************************************************************************** -+ * MSC -+ ***************************************************************************/ -+/* n = 0, 1 (MSC0, MSC1) */ -+ -+#define __msc_start_op(n) \ -+ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) -+ -+#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to ) -+#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to ) -+#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd ) -+#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg ) -+#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob ) -+#define __msc_get_nob(n) ( REG_MSC_NOB(n) ) -+#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len ) -+#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat ) -+#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT ) -+#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT ) -+ -+#define __msc_set_cmdat_bus_width1(n) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_bus_width4(n) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN ) -+#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT ) -+#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY ) -+#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN ) -+ -+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ -+#define __msc_set_cmdat_res_format(n, r) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ -+ REG_MSC_CMDAT(n) |= (r); \ -+} while(0) -+ -+#define __msc_clear_cmdat(n) \ -+ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ -+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ -+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) -+ -+#define __msc_get_imask(n) ( REG_MSC_IMASK(n) ) -+#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff ) -+#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 ) -+#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES ) -+#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES ) -+#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE ) -+#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE ) -+ -+/* m=0,1,2,3,4,5,6,7 */ -+#define __msc_set_clkrt(n, m) \ -+do { \ -+ REG_MSC_CLKRT(n) = m; \ -+} while(0) -+ -+#define __msc_get_ireg(n) ( REG_MSC_IREG(n) ) -+#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ ) -+#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ ) -+#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE ) -+#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE ) -+ -+#define __msc_get_stat(n) ( REG_MSC_STAT(n) ) -+#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0) -+#define __msc_stat_crc_err(n) \ -+ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) -+#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR ) -+#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR ) -+#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES ) -+#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES ) -+#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ ) -+ -+#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) ) -+#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) ) -+#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v ) -+ -+#define __msc_reset(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \ -+ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \ -+} while (0) -+ -+#define __msc_start_clk(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \ -+} while (0) -+ -+#define __msc_stop_clk(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \ -+} while (0) -+ -+#define MMC_CLK 19169200 -+#define SD_CLK 24576000 -+ -+/* msc_clk should little than pclk and little than clk retrieve from card */ -+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ -+do { \ -+ unsigned int rate, pclk, i; \ -+ pclk = dev_clk; \ -+ rate = type?SD_CLK:MMC_CLK; \ -+ if (msc_clk && msc_clk < pclk) \ -+ pclk = msc_clk; \ -+ i = 0; \ -+ while (pclk < rate) \ -+ { \ -+ i ++; \ -+ rate >>= 1; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+/* divide rate to little than or equal to 400kHz */ -+#define __msc_calc_slow_clk_divisor(type, lv) \ -+do { \ -+ unsigned int rate, i; \ -+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ -+ i = 0; \ -+ while (rate > 0) \ -+ { \ -+ rate >>= 1; \ -+ i ++; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+ -+/*************************************************************************** -+ * SSI (Synchronous Serial Interface) -+ ***************************************************************************/ -+/* n = 0, 1 (SSI0, SSI1) */ -+#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE ) -+#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE ) -+#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL ) -+ -+#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK ) -+ -+#define __ssi_select_ce2(n) \ -+do { \ -+ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_select_gpc(n) \ -+do { \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \ -+ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_underrun_auto_clear(n) \ -+do { \ -+ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \ -+} while (0) -+ -+#define __ssi_underrun_clear_manually(n) \ -+do { \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \ -+} while (0) -+ -+#define __ssi_enable_tx_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE ) -+ -+#define __ssi_disable_tx_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) -+ -+#define __ssi_enable_rx_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE ) -+ -+#define __ssi_disable_rx_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) -+ -+#define __ssi_enable_txfifo_half_empty_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE ) -+#define __ssi_disable_txfifo_half_empty_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE ) -+#define __ssi_enable_tx_error_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE ) -+#define __ssi_disable_tx_error_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE ) -+#define __ssi_enable_rxfifo_half_full_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE ) -+#define __ssi_disable_rxfifo_half_full_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE ) -+#define __ssi_enable_rx_error_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_REIE ) -+#define __ssi_disable_rx_error_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE ) -+ -+#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP ) -+#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP ) -+ -+#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV ) -+#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV ) -+ -+#define __ssi_finish_receive(n) \ -+ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_disable_recvfinish(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH ) -+#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH ) -+ -+#define __ssi_flush_fifo(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) -+ -+#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN ) -+#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN ) -+#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n) -+#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n) -+ -+#define __ssi_spi_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ -+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ -+ } while (0) -+ -+/* TI's SSP format, must clear SSI_CR1.UNFIN */ -+#define __ssi_ssp_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \ -+ } while (0) -+ -+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ -+#define __ssi_microwire_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ -+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \ -+ } while (0) -+ -+/* CE# level (FRMHL), CE# in interval time (ITFRM), -+ clock phase and polarity (PHA POL), -+ interval time (SSIITR), interval characters/frame (SSIICR) */ -+ -+/* frmhl,endian,mcom,flen,pha,pol MASK */ -+#define SSICR1_MISC_MASK \ -+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ -+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) -+ -+#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \ -+ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \ -+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ -+ ((pha) << 1) | (pol); \ -+ } while(0) -+ -+/* Transfer with MSB or LSB first */ -+#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST ) -+#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST ) -+ -+#define __ssi_set_frame_length(n, m) \ -+ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4) -+ -+/* m = 1 - 16 */ -+#define __ssi_set_microwire_command_length(n,m) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) ) -+ -+/* Set the clock phase for SPI */ -+#define __ssi_set_spi_clock_phase(n, m) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1))) -+ -+/* Set the clock polarity for SPI */ -+#define __ssi_set_spi_clock_polarity(n, p) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) ) -+ -+/* SSI tx trigger, m = i x 8 */ -+#define __ssi_set_tx_trigger(n, m) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \ -+ REG_SSI_CR1(n) |= ((m)/8)<> SSI_SR_TFIFONUM_BIT ) -+ -+#define __ssi_get_rxfifo_count(n) \ -+ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) -+ -+#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END ) -+#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY ) -+ -+#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF ) -+#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE ) -+#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF ) -+#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE ) -+#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR ) -+#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER ) -+#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR ) -+#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER ) -+#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) -+ -+#define __ssi_set_clk(n, dev_clk, ssi_clk) \ -+ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 ) -+ -+#define __ssi_receive_data(n) REG_SSI_DR(n) -+#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v)) -+ -+ -+/*************************************************************************** -+ * CIM -+ ***************************************************************************/ -+ -+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) -+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) -+ -+/* n = 0, 1, 2, 3 */ -+#define __cim_set_input_data_stream_order(n) \ -+ do { \ -+ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \ -+ REG_CIM_CFG |= ((n)<>CIM_SIZE_LPF_BIT) -+#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT) -+ -+#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<>CIM_OFFSET_V_BIT) -+#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT) -+ -+/************************************************************************* -+ * SLCD (Smart LCD Controller) -+ *************************************************************************/ -+#define __slcd_set_data_18bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT ) -+#define __slcd_set_data_16bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT ) -+#define __slcd_set_data_8bit_x3() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 ) -+#define __slcd_set_data_8bit_x2() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 ) -+#define __slcd_set_data_8bit_x1() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 ) -+#define __slcd_set_data_24bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT ) -+#define __slcd_set_data_9bit_x2() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 ) -+ -+#define __slcd_set_cmd_16bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT ) -+#define __slcd_set_cmd_8bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT ) -+#define __slcd_set_cmd_18bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT ) -+#define __slcd_set_cmd_24bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT ) -+ -+#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH ) -+#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH ) -+ -+#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH ) -+#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH ) -+ -+#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING ) -+#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING ) -+ -+#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL ) -+#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL ) -+ -+/* SLCD Control Register */ -+#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN ) -+#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN ) -+ -+/* SLCD Status Register */ -+#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY ) -+ -+/* SLCD Data Register */ -+#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND) -+#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND) -+ -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) -+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) -+ -+#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH ) -+#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH ) -+ -+#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD ) -+#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD ) -+ -+#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES ) -+#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES ) -+ -+#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP ) -+#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP ) -+ -+#define __lcd_set_lcdpnl_term() ( REG_LCD_CTRL |= LCD_CFG_TVEN ) -+#define __lcd_set_tv_term() ( REG_LCD_CTRL &= ~LCD_CFG_TVEN ) -+ -+#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER ) -+#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER ) -+ -+#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER ) -+#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER ) -+ -+#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM ) -+#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM ) -+ -+#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM ) -+#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM ) -+ -+#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM ) -+#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM ) -+ -+#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM ) -+#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM ) -+ -+#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM ) -+#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM ) -+ -+#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM ) -+#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM ) -+ -+#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT ) -+#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT ) -+ -+#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN ) -+#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN ) -+ -+#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP ) -+#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP ) -+ -+#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP ) -+#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP ) -+ -+#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP ) -+#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP ) -+ -+#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP ) -+#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP ) -+ -+#define __lcd_set_16_tftpnl() \ -+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT ) -+ -+#define __lcd_set_18_tftpnl() \ -+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT ) -+ -+#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT ) -+ -+/* -+ * n=1,2,4,8 for single mono-STN -+ * n=4,8 for dual mono-STN -+ */ -+#define __lcd_set_panel_datawidth(n) \ -+do { \ -+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \ -+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \ -+} while (0) -+ -+/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */ -+#define __lcd_set_panel_mode(m) \ -+do { \ -+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \ -+ REG_LCD_CFG |= (m); \ -+} while(0) -+ -+/* n=4,8,16 */ -+#define __lcd_set_burst_length(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ -+} while (0) -+ -+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) -+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) -+ -+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) -+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) -+ -+/* n=2,4,16 */ -+#define __lcd_set_stn_frc(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ -+} while (0) -+ -+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) -+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) -+ -+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) -+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) -+ -+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) -+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) -+ -+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) -+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) -+ -+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) -+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) -+ -+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) -+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) -+ -+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) -+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) -+ -+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) -+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) -+ -+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) -+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) -+ -+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) -+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) -+ -+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) -+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) -+ -+/* n=1,2,4,8,16 */ -+#define __lcd_set_bpp(n) \ -+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) -+ -+/* LCD status register indication */ -+ -+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) -+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) -+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) -+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) -+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) -+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) -+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) -+ -+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) -+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) -+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) -+ -+/* OSD functions */ -+#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN) -+#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN) -+#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN) -+#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN) -+#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD) -+ -+#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN) -+#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN) -+#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN) -+#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN) -+#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD) -+ -+/* OSD Controll Register */ -+#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU) -+#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU) -+#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1() -+#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 ) -+#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 ) -+#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES ) -+#define __lcd_osd_bpp_15_16() \ -+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 ) -+#define __lcd_osd_bpp_18_24() \ -+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 ) -+ -+/* OSD State Register */ -+#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 ) -+#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 ) -+#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 ) -+#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 ) -+#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY ) -+ -+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */ -+#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN) -+#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN) -+#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD) -+#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD) -+#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key)) -+#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key)) -+ -+#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN) -+#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN) -+#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD) -+#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD) -+ -+/* IPU Restart Register */ -+#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN) -+#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN) -+#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n)) -+ -+/* RGB Control Register */ -+#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM) -+#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM) -+ -+#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM) -+#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM) -+ -+#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC) -+#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC) -+ -+#define __lcd_odd_mode_rgb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB ) -+#define __lcd_odd_mode_rbg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG ) -+#define __lcd_odd_mode_grb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB) -+ -+#define __lcd_odd_mode_gbr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR) -+#define __lcd_odd_mode_brg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG) -+#define __lcd_odd_mode_bgr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR) -+ -+#define __lcd_even_mode_rgb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB ) -+#define __lcd_even_mode_rbg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG ) -+#define __lcd_even_mode_grb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB) -+ -+#define __lcd_even_mode_gbr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR) -+#define __lcd_even_mode_brg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG) -+#define __lcd_even_mode_bgr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR) -+ -+/* Vertical Synchronize Register */ -+#define __lcd_vsync_get_vps() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) -+ -+#define __lcd_vsync_get_vpe() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) -+#define __lcd_vsync_set_vpe(n) \ -+do { \ -+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ -+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hps() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) -+#define __lcd_hsync_set_hps(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hpe() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) -+#define __lcd_hsync_set_hpe(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_ht() \ -+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) -+#define __lcd_vat_set_ht(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_vt() \ -+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) -+#define __lcd_vat_set_vt(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hds() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) -+#define __lcd_dah_set_hds(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hde() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) -+#define __lcd_dah_set_hde(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vds() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) -+#define __lcd_dav_set_vds(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vde() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) -+#define __lcd_dav_set_vde(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ -+} while (0) -+ -+/* DMA Command Register */ -+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) -+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) -+ -+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) -+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) -+ -+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) -+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) -+ -+#define __lcd_cmd0_get_len() \ -+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+#define __lcd_cmd1_get_len() \ -+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+ -+/************************************************************************* -+ * TVE (TV Encoder Controller) ops -+ *************************************************************************/ -+/* TV Encoder Control register ops */ -+#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST) -+ -+#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR) -+#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR) -+ -+#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST) -+#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST) -+ -+#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK) -+#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK) -+ -+#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV) -+#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV) -+ -+#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL) -+#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL) -+ -+#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT) -+#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT) -+ -+/* n = 0 ~ 3 */ -+#define __tve_set_c_bandwidth(n) \ -+do {\ -+ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\ -+ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \ -+}while(0) -+ -+/* n = 0 ~ 3 */ -+#define __tve_set_c_gain(n) \ -+do {\ -+ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\ -+ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \ -+}while(0) -+ -+/* n = 0 ~ 7 */ -+#define __tve_set_yc_delay(n) \ -+do { \ -+ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \ -+ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \ -+} while(0) -+ -+#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD) -+#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1) -+#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1) -+#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2) -+#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2) -+#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3) -+#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3) -+ -+#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS) -+#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS) -+ -+/* TV Encoder Frame Configure register ops */ -+/* n = 0 ~ 255 */ -+#define __tve_set_first_video_line(n) \ -+do {\ -+ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\ -+ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_line_num_per_frm(n) \ -+do {\ -+ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\ -+ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\ -+} while(0) -+#define __tve_get_video_line_num()\ -+ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT)) -+ -+/* TV Encoder Signal Level Configure register ops */ -+/* n = 0 ~ 1023 */ -+#define __tve_set_white_level(n) \ -+do {\ -+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\ -+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_black_level(n) \ -+do {\ -+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\ -+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_blank_level(n) \ -+do {\ -+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\ -+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_vbi_blank_level(n) \ -+do {\ -+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\ -+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_sync_level(n) \ -+do {\ -+ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\ -+ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\ -+} while(0) -+ -+/* TV Encoder Signal Level Configure register ops */ -+/* n = 0 ~ 31 */ -+#define __tve_set_front_porch(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \ -+} while(0) -+/* n = 0 ~ 127 */ -+#define __tve_set_hsync_width(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \ -+} while(0) -+/* n = 0 ~ 127 */ -+#define __tve_set_back_porch(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \ -+} while(0) -+/* n = 0 ~ 2047 */ -+#define __tve_set_active_linec(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \ -+} while(0) -+/* n = 0 ~ 31 */ -+#define __tve_set_breezy_way(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \ -+} while(0) -+ -+/* n = 0 ~ 127 */ -+#define __tve_set_burst_width(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \ -+} while(0) -+ -+/* TV Encoder Chrominance filter and Modulation register ops */ -+/* n = 0 ~ (2^32-1) */ -+#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_sub_carrier_init_phase(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_sub_carrier_act_phase(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_phase_rst_period(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cb_burst_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cr_burst_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cb_gain_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cr_gain_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \ -+} while(0) -+ -+/* TV Encoder Wide Screen Signal Control register ops */ -+/* n = 0 ~ 7 */ -+#define __tve_set_notch_freq(n) \ -+do { \ -+ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \ -+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \ -+} while(0) -+/* n = 0 ~ 7 */ -+#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT) -+#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT) -+#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT) -+#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT) -+/* n = 0 ~ 7 */ -+#define __tve_set_wss_edge(n) \ -+do { \ -+ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \ -+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \ -+} while(0) -+#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT) -+#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT) -+#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT) -+#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT) -+ -+/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */ -+/* n = 0 ~ 1023 */ -+#define __tve_set_wss_level(n) \ -+do { \ -+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \ -+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \ -+} while(0) -+/* n = 0 ~ 4095 */ -+#define __tve_set_wss_freq(n) \ -+do { \ -+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \ -+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \ -+} while(0) -+/* n = 0, 1; l = 0 ~ 255 */ -+#define __tve_set_wss_line(n,v) \ -+do { \ -+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ -+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ -+} while(0) -+/* n = 0, 1; d = 0 ~ (2^20-1) */ -+#define __tve_set_wss_data(n, v) \ -+do { \ -+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ -+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ -+} while(0) -+ -+/*************************************************************************** -+ * RTC ops -+ ***************************************************************************/ -+ -+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) -+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) -+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) -+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) -+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) -+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) -+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) -+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) -+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) -+ -+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) -+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) -+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) -+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) -+ -+#define __rtc_get_second() ( REG_RTC_RSR ) -+#define __rtc_set_second(v) ( REG_RTC_RSR = v ) -+ -+#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) -+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) -+ -+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) -+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) -+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) -+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) -+#define __rtc_set_adjc_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) -+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) -+#define __rtc_set_nc1Hz_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) -+ -+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) -+ -+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) -+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) -+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) -+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) -+ -+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) -+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) -+ -+#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) -+#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) -+#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) -+#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) -+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) -+ -+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) -+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) -+ -+/************************************************************************* -+ * BCH -+ *************************************************************************/ -+#define __ecc_encoding_4bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_BSEL8; \ -+} while(0) -+#define __ecc_decoding_4bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \ -+} while(0) -+#define __ecc_encoding_8bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ -+} while(0) -+#define __ecc_decoding_8bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_ENCE; \ -+} while(0) -+#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE ) -+#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE ) -+#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF)) -+#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF)) -+#define __ecc_cnt_dec(n) \ -+do { \ -+ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \ -+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \ -+} while(0) -+#define __ecc_cnt_enc(n) \ -+do { \ -+ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \ -+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \ -+} while(0) -+ -+/*************************************************************************** -+ * OWI (one-wire bus) ops -+ ***************************************************************************/ -+ -+/* OW control register ops */ -+#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) ) -+#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 ) -+ -+#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE ) -+#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE ) -+#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT ) -+#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT ) -+#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST ) -+#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST ) -+ -+/* OW configure register ops */ -+#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE ) -+#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE ) -+ -+#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA ) -+#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA ) -+#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA ) -+ -+#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA ) -+#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA ) -+#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA ) -+ -+#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST ) -+ -+#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD ) -+#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD ) -+#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD ) -+ -+#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 ) -+#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 ) -+#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 ) -+ -+#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST ) -+#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST ) -+#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST ) -+ -+#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA ) -+#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA ) -+#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA ) -+ -+#define __owi_wait_ops_rdy() \ -+ do { \ -+ while(__owi_get_enable()); \ -+ udelay(1); \ -+ } while(0); -+ -+/* OW status register ops */ -+#define __owi_clr_sts() ( REG_OWI_STS = 0 ) -+#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST ) -+#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY ) -+#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY ) -+#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY ) -+ -+/************************************************************************* -+ * TSSI MPEG 2-TS slave interface operation -+ *************************************************************************/ -+#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA ) -+#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA ) -+#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST ) -+#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN ) -+#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN ) -+#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN ) -+#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN ) -+ -+/* n = 4, 8, 16 */ -+#define __tssi_set_tigger_num(n) \ -+ do { \ -+ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \ -+ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \ -+ } while (0) -+ -+#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD ) -+#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD ) -+ -+#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD ) -+#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD ) -+ -+#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H ) -+#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H ) -+ -+#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 ) -+#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 ) -+ -+#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH ) -+#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH ) -+ -+#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL ) -+#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL ) -+ -+#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P ) -+#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P ) -+ -+#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H ) -+#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H ) -+ -+#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H ) -+#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H ) -+ -+#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H ) -+#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H ) -+ -+#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM ) -+#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM ) -+ -+#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM ) -+#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM ) -+ -+#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN ) -+#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG ) -+#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */ -+#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN ) -+ -+#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 ) -+#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 ) -+ -+/* m = 0, ..., 15 */ -+#define __tssi_enable_pid_filter(m) \ -+ do { \ -+ int n = (m); \ -+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ -+ if ( n >= TSSI_PID_MAX ) n += 8; \ -+ REG_TSSI_PEN |= ( 1 << n ); \ -+ } \ -+ } while (0) -+ -+/* m = 0, ..., 15 */ -+#define __tssi_disable_pid_filter(m) \ -+ do { \ -+ int n = (m); \ -+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ -+ if ( n >= TSSI_PID_MAX ) n += 8; \ -+ REG_TSSI_PEN &= ~( 1 << n ); \ -+ } \ -+ } while (0) -+ -+/* n = 0, ..., 7 */ -+#define __tssi_set_pid0(n, pid0) \ -+ do { \ -+ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \ -+ REG_TSSI_PID(n) |= ((pid0)<=0 && n < TSSI_PID_MAX*2) { \ -+ if ( n < TSSI_PID_MAX ) \ -+ __tssi_set_pid0(n, pid); \ -+ else \ -+ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \ -+ } \ -+ }while (0) -+ -+ -+#if 0 -+/************************************************************************* -+ * IPU (Image Processing Unit) -+ *************************************************************************/ -+#define u32 volatile unsigned long -+ -+#define write_reg(reg, val) \ -+do { \ -+ *(u32 *)(reg) = (val); \ -+} while(0) -+ -+#define read_reg(reg, off) (*(u32 *)((reg)+(off))) -+ -+ -+#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \ -+({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)< Unsigned toggle enable */ -+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ -+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ -+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ -+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ -+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ -+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ -+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ -+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ -+ -+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ -+ -+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ -+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) -+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ -+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ -+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) -+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ -+ -+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ -+ -+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ -+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ -+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ -+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) -+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) -+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ -+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ -+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ -+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ -+ -+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ -+ -+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) -+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ -+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ -+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ -+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ -+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ -+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ -+ -+/* AIC Controller FIFO Status Register (AIC_SR) */ -+ -+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ -+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) -+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ -+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) -+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ -+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ -+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ -+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ -+ -+/* AIC Controller AC-link Status Register (AIC_ACSR) */ -+ -+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ -+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ -+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ -+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ -+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ -+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ -+ -+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ -+ -+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ -+ -+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ -+ -+#define AIC_ACCAR_CAR_BIT 0 -+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) -+ -+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ -+ -+#define AIC_ACCDR_CDR_BIT 0 -+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) -+ -+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ -+ -+#define AIC_ACSAR_SAR_BIT 0 -+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) -+ -+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ -+ -+#define AIC_ACSDR_SDR_BIT 0 -+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) -+ -+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ -+ -+#define AIC_I2SDIV_DIV_BIT 0 -+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) -+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ -+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ -+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ -+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ -+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ -+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ -+ -+ -+/************************************************************************* -+ * ICDC (Internal CODEC) -+ *************************************************************************/ -+ -+#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */ -+#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */ -+#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */ -+ -+#define REG_ICDC_CKCFG REG32(ICDC_CKCFG) -+#define REG_ICDC_RGADW REG32(ICDC_RGADW) -+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA) -+ -+/* ICDC Clock Configure Register */ -+#define ICDC_CKCFG_CKRDY (1 << 1) -+#define ICDC_CKCFG_SELAD (1 << 0) -+ -+/* ICDC internal register access control Register */ -+#define ICDC_RGADW_RGWR (1 << 16) -+#define ICDC_RGADW_RGADDR_BIT 8 -+#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT) -+#define ICDC_RGADW_RGDIN_BIT 0 -+#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT) -+ -+/* ICDC internal register data output Register */ -+#define ICDC_RGDATA_IRQ (1 << 8) -+#define ICDC_RGDATA_RGDOUT_BIT 0 -+#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT) -+ -+/************************************************************************* -+ * PCM Controller -+ *************************************************************************/ -+ -+#define PCM_CTL (PCM_BASE + 0x000) -+#define PCM_CFG (PCM_BASE + 0x004) -+#define PCM_DP (PCM_BASE + 0x008) -+#define PCM_INTC (PCM_BASE + 0x00c) -+#define PCM_INTS (PCM_BASE + 0x010) -+#define PCM_DIV (PCM_BASE + 0x014) -+ -+#define REG_PCM_CTL REG32(PCM_CTL) -+#define REG_PCM_CFG REG32(PCM_CFG) -+#define REG_PCM_DP REG32(PCM_DP) -+#define REG_PCM_INTC REG32(PCM_INTC) -+#define REG_PCM_INTS REG32(PCM_INTS) -+#define REG_PCM_DIV REG32(PCM_DIV) -+ -+/* PCM Controller control Register (PCM_CTL) */ -+ -+#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */ -+#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */ -+#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */ -+#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */ -+#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */ -+#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */ -+#define PCM_CTL_RST (1 << 3) /* Reset PCM */ -+#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */ -+#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */ -+ -+/* PCM Controller configure Register (PCM_CFG) */ -+ -+#define PCM_CFG_SLOT_BIT 13 -+#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT) -+ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */ -+ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */ -+ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */ -+ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */ -+#define PCM_CFG_ISS_BIT 12 -+#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT) -+ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT) -+ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT) -+#define PCM_CFG_OSS_BIT 11 -+#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT) -+ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT) -+ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT) -+#define PCM_CFG_IMSBPOS (1 << 10) -+#define PCM_CFG_OMSBPOS (1 << 9) -+#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */ -+#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT) -+#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */ -+#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT) -+#define PCM_CFG_MODE (0x0 << 0) -+ -+/* PCM Controller interrupt control Register (PCM_INTC) */ -+ -+#define PCM_INTC_ETFS (1 << 3) -+#define PCM_INTC_ETUR (1 << 2) -+#define PCM_INTC_ERFS (1 << 1) -+#define PCM_INTC_EROR (1 << 0) -+ -+/* PCM Controller interrupt status Register (PCM_INTS) */ -+ -+#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */ -+#define PCM_INTS_TFL_BIT 9 -+#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT) -+#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */ -+#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */ -+#define PCM_INTS_RFL_BIT 2 -+#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT) -+#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */ -+#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */ -+ -+/* PCM Controller clock division Register (PCM_DIV) */ -+#define PCM_DIV_SYNL_BIT 11 -+#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT) -+#define PCM_DIV_SYNDIV_BIT 6 -+#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT) -+#define PCM_DIV_CLKDIV_BIT 0 -+#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT) -+ -+ -+/************************************************************************* -+ * I2C -+ *************************************************************************/ -+#define I2C_DR (I2C_BASE + 0x000) -+#define I2C_CR (I2C_BASE + 0x004) -+#define I2C_SR (I2C_BASE + 0x008) -+#define I2C_GR (I2C_BASE + 0x00C) -+ -+#define REG_I2C_DR REG8(I2C_DR) -+#define REG_I2C_CR REG8(I2C_CR) -+#define REG_I2C_SR REG8(I2C_SR) -+#define REG_I2C_GR REG16(I2C_GR) -+ -+/* I2C Control Register (I2C_CR) */ -+ -+#define I2C_CR_IEN (1 << 4) -+#define I2C_CR_STA (1 << 3) -+#define I2C_CR_STO (1 << 2) -+#define I2C_CR_AC (1 << 1) -+#define I2C_CR_I2CE (1 << 0) -+ -+/* I2C Status Register (I2C_SR) */ -+ -+#define I2C_SR_STX (1 << 4) -+#define I2C_SR_BUSY (1 << 3) -+#define I2C_SR_TEND (1 << 2) -+#define I2C_SR_DRF (1 << 1) -+#define I2C_SR_ACKF (1 << 0) -+ -+ -+/************************************************************************* -+ * SSI (Synchronous Serial Interface) -+ *************************************************************************/ -+/* n = 0, 1 (SSI0, SSI1) */ -+#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000) -+#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000) -+#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000) -+#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000) -+#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000) -+#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000) -+#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000) -+ -+#define REG_SSI_DR(n) REG32(SSI_DR(n)) -+#define REG_SSI_CR0(n) REG16(SSI_CR0(n)) -+#define REG_SSI_CR1(n) REG32(SSI_CR1(n)) -+#define REG_SSI_SR(n) REG32(SSI_SR(n)) -+#define REG_SSI_ITR(n) REG16(SSI_ITR(n)) -+#define REG_SSI_ICR(n) REG8(SSI_ICR(n)) -+#define REG_SSI_GR(n) REG16(SSI_GR(n)) -+ -+/* SSI Data Register (SSI_DR) */ -+ -+#define SSI_DR_GPC_BIT 0 -+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) -+ -+#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */ -+ -+/* SSI Control Register 0 (SSI_CR0) */ -+ -+#define SSI_CR0_SSIE (1 << 15) -+#define SSI_CR0_TIE (1 << 14) -+#define SSI_CR0_RIE (1 << 13) -+#define SSI_CR0_TEIE (1 << 12) -+#define SSI_CR0_REIE (1 << 11) -+#define SSI_CR0_LOOP (1 << 10) -+#define SSI_CR0_RFINE (1 << 9) -+#define SSI_CR0_RFINC (1 << 8) -+#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ -+#define SSI_CR0_FSEL (1 << 6) -+#define SSI_CR0_TFLUSH (1 << 2) -+#define SSI_CR0_RFLUSH (1 << 1) -+#define SSI_CR0_DISREV (1 << 0) -+ -+/* SSI Control Register 1 (SSI_CR1) */ -+ -+#define SSI_CR1_FRMHL_BIT 30 -+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) -+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ -+#define SSI_CR1_TFVCK_BIT 28 -+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) -+#define SSI_CR1_TCKFI_BIT 26 -+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) -+#define SSI_CR1_LFST (1 << 25) -+#define SSI_CR1_ITFRM (1 << 24) -+#define SSI_CR1_UNFIN (1 << 23) -+#define SSI_CR1_MULTS (1 << 22) -+#define SSI_CR1_FMAT_BIT 20 -+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) -+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ -+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ -+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ -+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ -+#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */ -+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) -+#define SSI_CR1_MCOM_BIT 12 -+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) -+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ -+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ -+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ -+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ -+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ -+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ -+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ -+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ -+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ -+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ -+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ -+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ -+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ -+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ -+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ -+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ -+#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */ -+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) -+#define SSI_CR1_FLEN_BIT 4 -+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) -+#define SSI_CR1_PHA (1 << 1) -+#define SSI_CR1_POL (1 << 0) -+ -+/* SSI Status Register (SSI_SR) */ -+ -+#define SSI_SR_TFIFONUM_BIT 16 -+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) -+#define SSI_SR_RFIFONUM_BIT 8 -+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) -+#define SSI_SR_END (1 << 7) -+#define SSI_SR_BUSY (1 << 6) -+#define SSI_SR_TFF (1 << 5) -+#define SSI_SR_RFE (1 << 4) -+#define SSI_SR_TFHE (1 << 3) -+#define SSI_SR_RFHF (1 << 2) -+#define SSI_SR_UNDR (1 << 1) -+#define SSI_SR_OVER (1 << 0) -+ -+/* SSI Interval Time Control Register (SSI_ITR) */ -+ -+#define SSI_ITR_CNTCLK (1 << 15) -+#define SSI_ITR_IVLTM_BIT 0 -+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) -+ -+ -+/************************************************************************* -+ * MSC -+ ************************************************************************/ -+/* n = 0, 1 (MSC0, MSC1) */ -+#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000) -+#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004) -+#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008) -+#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C) -+#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010) -+#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014) -+#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018) -+#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C) -+#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020) -+#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024) -+#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028) -+#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C) -+#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030) -+#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034) -+#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038) -+#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C) -+#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040) -+ -+#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n)) -+#define REG_MSC_STAT(n) REG32(MSC_STAT(n)) -+#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n)) -+#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n)) -+#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n)) -+#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n)) -+#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n)) -+#define REG_MSC_NOB(n) REG16(MSC_NOB(n)) -+#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n)) -+#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n)) -+#define REG_MSC_IREG(n) REG16(MSC_IREG(n)) -+#define REG_MSC_CMD(n) REG8(MSC_CMD(n)) -+#define REG_MSC_ARG(n) REG32(MSC_ARG(n)) -+#define REG_MSC_RES(n) REG16(MSC_RES(n)) -+#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n)) -+#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n)) -+#define REG_MSC_LPM(n) REG32(MSC_LPM(n)) -+ -+/* MSC Clock and Control Register (MSC_STRPCL) */ -+#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ -+#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ -+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) -+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) -+#define MSC_STRPCL_START_READWAIT (1 << 5) -+#define MSC_STRPCL_STOP_READWAIT (1 << 4) -+#define MSC_STRPCL_RESET (1 << 3) -+#define MSC_STRPCL_START_OP (1 << 2) -+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 -+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) -+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ -+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ -+ -+/* MSC Status Register (MSC_STAT) */ -+#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */ -+#define MSC_STAT_IS_RESETTING (1 << 15) -+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) -+#define MSC_STAT_PRG_DONE (1 << 13) -+#define MSC_STAT_DATA_TRAN_DONE (1 << 12) -+#define MSC_STAT_END_CMD_RES (1 << 11) -+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) -+#define MSC_STAT_IS_READWAIT (1 << 9) -+#define MSC_STAT_CLK_EN (1 << 8) -+#define MSC_STAT_DATA_FIFO_FULL (1 << 7) -+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) -+#define MSC_STAT_CRC_RES_ERR (1 << 5) -+#define MSC_STAT_CRC_READ_ERROR (1 << 4) -+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 -+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) -+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ -+#define MSC_STAT_TIME_OUT_RES (1 << 1) -+#define MSC_STAT_TIME_OUT_READ (1 << 0) -+ -+/* MSC Bus Clock Control Register (MSC_CLKRT) */ -+#define MSC_CLKRT_CLK_RATE_BIT 0 -+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) -+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ -+ -+/* MSC Command Sequence Control Register (MSC_CMDAT) */ -+#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ -+#define MSC_CMDAT_READ_CEATA (1 << 30) -+#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ -+#define MSC_CMDAT_SEND_AS_STOP (1 << 16) -+#define MSC_CMDAT_RTRG_BIT 14 -+ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT) -+ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */ -+ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT) -+ -+#define MSC_CMDAT_TTRG_BIT 12 -+ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT) -+ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */ -+ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT) -+#define MSC_CMDAT_STOP_ABORT (1 << 11) -+#define MSC_CMDAT_BUS_WIDTH_BIT 9 -+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */ -+#define MSC_CMDAT_DMA_EN (1 << 8) -+#define MSC_CMDAT_INIT (1 << 7) -+#define MSC_CMDAT_BUSY (1 << 6) -+#define MSC_CMDAT_STREAM_BLOCK (1 << 5) -+#define MSC_CMDAT_WRITE (1 << 4) -+#define MSC_CMDAT_READ (0 << 4) -+#define MSC_CMDAT_DATA_EN (1 << 3) -+#define MSC_CMDAT_RESPONSE_BIT 0 -+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) -+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ -+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ -+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ -+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ -+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ -+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ -+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ -+ -+#define CMDAT_DMA_EN (1 << 8) -+#define CMDAT_INIT (1 << 7) -+#define CMDAT_BUSY (1 << 6) -+#define CMDAT_STREAM (1 << 5) -+#define CMDAT_WRITE (1 << 4) -+#define CMDAT_DATA_EN (1 << 3) -+ -+/* MSC Interrupts Mask Register (MSC_IMASK) */ -+#define MSC_IMASK_AUTO_CMD_DONE (1 << 8) -+#define MSC_IMASK_SDIO (1 << 7) -+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IMASK_END_CMD_RES (1 << 2) -+#define MSC_IMASK_PRG_DONE (1 << 1) -+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) -+ -+/* MSC Interrupts Status Register (MSC_IREG) */ -+#define MSC_IREG_AUTO_CMD_DONE (1 << 8) -+#define MSC_IREG_SDIO (1 << 7) -+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IREG_END_CMD_RES (1 << 2) -+#define MSC_IREG_PRG_DONE (1 << 1) -+#define MSC_IREG_DATA_TRAN_DONE (1 << 0) -+ -+/* MSC Low Power Mode Register (MSC_LPM) */ -+#define MSC_SET_LPM (1 << 0) -+ -+/************************************************************************* -+ * EMC (External Memory Controller) -+ *************************************************************************/ -+#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */ -+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ -+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ -+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ -+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ -+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ -+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ -+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ -+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ -+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ -+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ -+ -+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ -+ -+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ -+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ -+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ -+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ -+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ -+#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */ -+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ -+ -+#define REG_EMC_BCR REG32(EMC_BCR) -+#define REG_EMC_SMCR0 REG32(EMC_SMCR0) -+#define REG_EMC_SMCR1 REG32(EMC_SMCR1) -+#define REG_EMC_SMCR2 REG32(EMC_SMCR2) -+#define REG_EMC_SMCR3 REG32(EMC_SMCR3) -+#define REG_EMC_SMCR4 REG32(EMC_SMCR4) -+#define REG_EMC_SACR0 REG32(EMC_SACR0) -+#define REG_EMC_SACR1 REG32(EMC_SACR1) -+#define REG_EMC_SACR2 REG32(EMC_SACR2) -+#define REG_EMC_SACR3 REG32(EMC_SACR3) -+#define REG_EMC_SACR4 REG32(EMC_SACR4) -+ -+#define REG_EMC_NFCSR REG32(EMC_NFCSR) -+ -+#define REG_EMC_DMCR REG32(EMC_DMCR) -+#define REG_EMC_RTCSR REG16(EMC_RTCSR) -+#define REG_EMC_RTCNT REG16(EMC_RTCNT) -+#define REG_EMC_RTCOR REG16(EMC_RTCOR) -+#define REG_EMC_DMAR0 REG32(EMC_DMAR0) -+#define REG_EMC_DMAR1 REG32(EMC_DMAR1) -+ -+/* Bus Control Register */ -+#define EMC_BCR_BT_SEL_BIT 30 -+#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT) -+#define EMC_BCR_PK_SEL (1 << 24) -+#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */ -+ #define EMC_BCR_BSR_SHARE (0 << 2) -+ #define EMC_BCR_BSR_UNSHARE (1 << 2) -+#define EMC_BCR_BRE (1 << 1) -+#define EMC_BCR_ENDIAN (1 << 0) -+ -+/* Static Memory Control Register */ -+#define EMC_SMCR_STRV_BIT 24 -+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) -+#define EMC_SMCR_TAW_BIT 20 -+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) -+#define EMC_SMCR_TBP_BIT 16 -+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) -+#define EMC_SMCR_TAH_BIT 12 -+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) -+#define EMC_SMCR_TAS_BIT 8 -+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) -+#define EMC_SMCR_BW_BIT 6 -+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) -+#define EMC_SMCR_BCM (1 << 3) -+#define EMC_SMCR_BL_BIT 1 -+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) -+#define EMC_SMCR_SMT (1 << 0) -+ -+/* Static Memory Bank Addr Config Reg */ -+#define EMC_SACR_BASE_BIT 8 -+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) -+#define EMC_SACR_MASK_BIT 0 -+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) -+ -+/* NAND Flash Control/Status Register */ -+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ -+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ -+#define EMC_NFCSR_NFCE3 (1 << 5) -+#define EMC_NFCSR_NFE3 (1 << 4) -+#define EMC_NFCSR_NFCE2 (1 << 3) -+#define EMC_NFCSR_NFE2 (1 << 2) -+#define EMC_NFCSR_NFCE1 (1 << 1) -+#define EMC_NFCSR_NFE1 (1 << 0) -+ -+/* DRAM Control Register */ -+#define EMC_DMCR_BW_BIT 31 -+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) -+#define EMC_DMCR_CA_BIT 26 -+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) -+#define EMC_DMCR_RMODE (1 << 25) -+#define EMC_DMCR_RFSH (1 << 24) -+#define EMC_DMCR_MRSET (1 << 23) -+#define EMC_DMCR_RA_BIT 20 -+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) -+#define EMC_DMCR_BA_BIT 19 -+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) -+#define EMC_DMCR_PDM (1 << 18) -+#define EMC_DMCR_EPIN (1 << 17) -+#define EMC_DMCR_MBSEL (1 << 16) -+#define EMC_DMCR_TRAS_BIT 13 -+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) -+#define EMC_DMCR_RCD_BIT 11 -+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) -+#define EMC_DMCR_TPC_BIT 8 -+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) -+#define EMC_DMCR_TRWL_BIT 5 -+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) -+#define EMC_DMCR_TRC_BIT 2 -+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) -+#define EMC_DMCR_TCL_BIT 0 -+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) -+ -+/* Refresh Time Control/Status Register */ -+#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */ -+#define EMC_RTCSR_CMF (1 << 7) -+#define EMC_RTCSR_CKS_BIT 0 -+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) -+ -+/* SDRAM Bank Address Configuration Register */ -+#define EMC_DMAR_BASE_BIT 8 -+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) -+#define EMC_DMAR_MASK_BIT 0 -+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) -+ -+/* Mode Register of SDRAM bank 0 */ -+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ -+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ -+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) -+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) -+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ -+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) -+#define EMC_SDMR_BT_BIT 3 /* Burst Type */ -+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) -+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ -+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ -+#define EMC_SDMR_BL_BIT 0 /* Burst Length */ -+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) -+ -+#define EMC_SDMR_CAS2_16BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS2_32BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+#define EMC_SDMR_CAS3_16BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS3_32BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+ -+ -+/************************************************************************* -+ * CIM -+ *************************************************************************/ -+#define CIM_CFG (CIM_BASE + 0x0000) -+#define CIM_CTRL (CIM_BASE + 0x0004) -+#define CIM_STATE (CIM_BASE + 0x0008) -+#define CIM_IID (CIM_BASE + 0x000C) -+#define CIM_RXFIFO (CIM_BASE + 0x0010) -+#define CIM_DA (CIM_BASE + 0x0020) -+#define CIM_FA (CIM_BASE + 0x0024) -+#define CIM_FID (CIM_BASE + 0x0028) -+#define CIM_CMD (CIM_BASE + 0x002C) -+#define CIM_SIZE (CIM_BASE + 0x0030) -+#define CIM_OFFSET (CIM_BASE + 0x0034) -+#define CIM_RAM_ADDR (CIM_BASE + 0x1000) -+ -+#define REG_CIM_CFG REG32(CIM_CFG) -+#define REG_CIM_CTRL REG32(CIM_CTRL) -+#define REG_CIM_STATE REG32(CIM_STATE) -+#define REG_CIM_IID REG32(CIM_IID) -+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) -+#define REG_CIM_DA REG32(CIM_DA) -+#define REG_CIM_FA REG32(CIM_FA) -+#define REG_CIM_FID REG32(CIM_FID) -+#define REG_CIM_CMD REG32(CIM_CMD) -+#define REG_CIM_SIZE REG32(CIM_SIZE) -+#define REG_CIM_OFFSET REG32(CIM_OFFSET) -+ -+/* CIM Configuration Register (CIM_CFG) */ -+ -+#define CIM_CFG_ORDER_BIT 18 -+#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT) -+ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) -+ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) -+ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) -+ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) -+#define CIM_CFG_DF_BIT 16 -+#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT) -+ #define CIM_CFG_DF_RGB (0x0 << CIM_CFG_DF_BIT) -+ #define CIM_CFG_DF_RAWRGB CIM_CFG_DF_RGB -+ #define CIM_CFG_DF_BAYERRGB CIM_CFG_DF_RGB -+ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) -+ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) -+ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) -+#define CIM_CFG_INV_DAT (1 << 15) -+#define CIM_CFG_VSP (1 << 14) -+#define CIM_CFG_HSP (1 << 13) -+#define CIM_CFG_PCP (1 << 12) /* PCLK working edge */ -+#define CIM_CFG_DMA_BUSRT_TYPE_BIT 10 -+#define CIM_CFG_DMA_BUSRT_TYPE_MASK (0x3 << CIM_CFG_DMA_BUSRT_TYPE_BIT) -+#define CIM_CFG_DMA_BUSRT_INCR (0 << CIM_CFG_DMA_BUSRT_TYPE_BIT) -+#define CIM_CFG_DMA_BUSRT_INCR4 (1 << CIM_CFG_DMA_BUSRT_TYPE_BIT) -+#define CIM_CFG_DMA_BUSRT_INCR8 (2 << CIM_CFG_DMA_BUSRT_TYPE_BIT) -+#define CIM_CFG_DUMMY_ZERO (1 << 9) -+#define CIM_CFG_EXT_VSYNC (1 << 8) -+#define CIM_CFG_PACK_BIT 4 -+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 */ -+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 */ -+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 */ -+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 */ -+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 */ -+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 */ -+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 */ -+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 */ -+#define CIM_CFG_BYPASS_BIT 2 -+#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT) -+ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT) -+#define CIM_CFG_DSM_BIT 0 -+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) -+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ -+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ -+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ -+ #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ -+ -+/* CIM Control Register (CIM_CTRL) */ -+ -+#define CIM_CTRL_MCLKDIV_BIT 24 -+#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) -+#define CIM_CTRL_FRC_BIT 16 -+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) -+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ -+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ -+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ -+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ -+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ -+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ -+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ -+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ -+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ -+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ -+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ -+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ -+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ -+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ -+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ -+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ -+#define CIM_CTRL_SIZEEN_BIT 14 -+#define CIM_CTRL_SIZEEN_MASK (0x1 << CIM_CTRL_SIZEEN_BIT) -+#define CIM_CTRL_SIZEEN (0x1 << CIM_CTRL_SIZEEN_BIT) -+#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */ -+#define CIM_CTRL_DMA_SOFM (1 << 12) -+#define CIM_CTRL_DMA_EOFM (1 << 11) -+#define CIM_CTRL_DMA_STOPM (1 << 10) -+#define CIM_CTRL_RXF_TRIGM (1 << 9) -+#define CIM_CTRL_RXF_OFM (1 << 8) -+#define CIM_CTRL_RXF_TRIG_BIT 4 -+#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) -+ #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ -+ #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ -+ #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ -+ #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ -+ #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ -+ #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ -+ #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ -+ #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ -+#define CIM_CTRL_FAST_MODE_MASK (1 << 3) /* CIM fast mode mask */ -+#define CIM_CTRL_FAST_MODE (1 << 3) /* CIM works in fast mode */ -+#define CIM_CTRL_NORMAL_MODE (0 << 3) /* CIM works in normal mode */ -+#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */ -+#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */ -+#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */ -+ -+/* CIM State Register (CIM_STATE) */ -+ -+#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */ -+#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */ -+#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */ -+#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */ -+#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */ -+#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */ -+#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */ -+ -+/* CIM DMA Command Register (CIM_CMD) */ -+ -+#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */ -+#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */ -+#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */ -+#define CIM_CMD_LEN_BIT 0 -+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) -+ -+/* CIM Image Size Register (CIM_SIZE) */ -+#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */ -+#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT) -+#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */ -+#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT) -+ -+/* CIM Image Offset Register (CIM_OFFSET) */ -+#define CIM_OFFSET_V_BIT 16 /* Vertical offset */ -+#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT) -+#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */ -+#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/ -+ -+/************************************************************************* -+ * SADC (Smart A/D Controller) -+ *************************************************************************/ -+ -+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ -+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ -+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ -+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ -+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ -+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ -+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ -+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ -+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ -+#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */ -+ -+#define REG_SADC_ENA REG8(SADC_ENA) -+#define REG_SADC_CFG REG32(SADC_CFG) -+#define REG_SADC_CTRL REG8(SADC_CTRL) -+#define REG_SADC_STATE REG8(SADC_STATE) -+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) -+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) -+#define REG_SADC_TSDAT REG32(SADC_TSDAT) -+#define REG_SADC_BATDAT REG16(SADC_BATDAT) -+#define REG_SADC_SADDAT REG16(SADC_SADDAT) -+#define REG_SADC_ADCLK REG32(SADC_ADCLK) -+ -+/* ADC Enable Register */ -+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ -+#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */ -+#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */ -+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ -+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ -+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ -+ -+/* ADC Configure Register */ -+#define SADC_CFG_EXIN (1 << 30) -+#define SADC_CFG_CLKOUT_NUM_BIT 16 -+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) -+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ -+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ -+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) -+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ -+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) -+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ -+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) -+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ -+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ -+#define SADC_CFG_CMD_BIT 0 /* ADC Command */ -+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) -+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ -+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ -+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ -+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ -+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ -+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ -+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ -+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ -+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ -+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ -+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ -+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ -+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ -+ -+/* ADC Control Register */ -+#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */ -+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ -+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ -+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ -+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ -+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ -+ -+/* ADC Status Register */ -+#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ -+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ -+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ -+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ -+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ -+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ -+ -+/* ADC Touch Screen Data Register */ -+#define SADC_TSDAT_DATA0_BIT 0 -+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) -+#define SADC_TSDAT_TYPE0 (1 << 15) -+#define SADC_TSDAT_DATA1_BIT 16 -+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) -+#define SADC_TSDAT_TYPE1 (1 << 31) -+ -+/* ADC Clock Divide Register */ -+#define SADC_ADCLK_CLKDIV_10_BIT 16 -+#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT) -+#define SADC_ADCLK_CLKDIV_BIT 0 -+#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT) -+ -+/************************************************************************* -+ * SLCD (Smart LCD Controller) -+ *************************************************************************/ -+ -+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ -+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ -+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ -+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ -+ -+#define REG_SLCD_CFG REG32(SLCD_CFG) -+#define REG_SLCD_CTRL REG8(SLCD_CTRL) -+#define REG_SLCD_STATE REG8(SLCD_STATE) -+#define REG_SLCD_DATA REG32(SLCD_DATA) -+ -+/* SLCD Configure Register */ -+#define SLCD_CFG_DWIDTH_BIT 10 -+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_BIT (8) -+#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) -+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) -+#define SLCD_CFG_RS_CMD_LOW (0 << 3) -+#define SLCD_CFG_RS_CMD_HIGH (1 << 3) -+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) -+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) -+#define SLCD_CFG_TYPE_PARALLEL (0 << 0) -+#define SLCD_CFG_TYPE_SERIAL (1 << 0) -+ -+/* SLCD Control Register */ -+#define SLCD_CTRL_DMA_EN (1 << 0) -+ -+/* SLCD Status Register */ -+#define SLCD_STATE_BUSY (1 << 0) -+ -+/* SLCD Data Register */ -+#define SLCD_DATA_RS_DATA (0 << 31) -+#define SLCD_DATA_RS_COMMAND (1 << 31) -+ -+/************************************************************************* -+ * LCD (LCD Controller) -+ *************************************************************************/ -+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ -+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ -+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ -+ -+#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */ -+#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */ -+#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */ -+#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */ -+#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */ -+#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */ -+#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */ -+#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */ -+ -+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ -+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ -+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ -+ -+#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */ -+#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */ -+#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */ -+#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */ -+#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */ -+ -+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ -+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ -+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ -+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ -+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ -+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ -+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ -+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ -+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ -+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ -+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ -+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ -+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ -+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ -+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ -+ -+#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */ -+#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */ -+#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */ -+#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/ -+#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */ -+#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */ -+#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */ -+#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/ -+ -+#define REG_LCD_CFG REG32(LCD_CFG) -+#define REG_LCD_CTRL REG32(LCD_CTRL) -+#define REG_LCD_STATE REG32(LCD_STATE) -+ -+#define REG_LCD_OSDC REG16(LCD_OSDC) -+#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL) -+#define REG_LCD_OSDS REG16(LCD_OSDS) -+#define REG_LCD_BGC REG32(LCD_BGC) -+#define REG_LCD_KEY0 REG32(LCD_KEY0) -+#define REG_LCD_KEY1 REG32(LCD_KEY1) -+#define REG_LCD_ALPHA REG8(LCD_ALPHA) -+#define REG_LCD_IPUR REG32(LCD_IPUR) -+ -+#define REG_LCD_VAT REG32(LCD_VAT) -+#define REG_LCD_DAH REG32(LCD_DAH) -+#define REG_LCD_DAV REG32(LCD_DAV) -+ -+#define REG_LCD_XYP0 REG32(LCD_XYP0) -+#define REG_LCD_XYP1 REG32(LCD_XYP1) -+#define REG_LCD_SIZE0 REG32(LCD_SIZE0) -+#define REG_LCD_SIZE1 REG32(LCD_SIZE1) -+#define REG_LCD_RGBC REG16(LCD_RGBC) -+ -+#define REG_LCD_VSYNC REG32(LCD_VSYNC) -+#define REG_LCD_HSYNC REG32(LCD_HSYNC) -+#define REG_LCD_PS REG32(LCD_PS) -+#define REG_LCD_CLS REG32(LCD_CLS) -+#define REG_LCD_SPL REG32(LCD_SPL) -+#define REG_LCD_REV REG32(LCD_REV) -+#define REG_LCD_IID REG32(LCD_IID) -+#define REG_LCD_DA0 REG32(LCD_DA0) -+#define REG_LCD_SA0 REG32(LCD_SA0) -+#define REG_LCD_FID0 REG32(LCD_FID0) -+#define REG_LCD_CMD0 REG32(LCD_CMD0) -+#define REG_LCD_DA1 REG32(LCD_DA1) -+#define REG_LCD_SA1 REG32(LCD_SA1) -+#define REG_LCD_FID1 REG32(LCD_FID1) -+#define REG_LCD_CMD1 REG32(LCD_CMD1) -+ -+#define REG_LCD_OFFS0 REG32(LCD_OFFS0) -+#define REG_LCD_PW0 REG32(LCD_PW0) -+#define REG_LCD_CNUM0 REG32(LCD_CNUM0) -+#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0) -+#define REG_LCD_OFFS1 REG32(LCD_OFFS1) -+#define REG_LCD_PW1 REG32(LCD_PW1) -+#define REG_LCD_CNUM1 REG32(LCD_CNUM1) -+#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1) -+ -+/* LCD Configure Register */ -+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ -+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) -+#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */ -+#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */ -+#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */ -+#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */ -+#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */ -+#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */ -+#define LCD_CFG_DITHER (1 << 24) /* Dither function */ -+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ -+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ -+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ -+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ -+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ -+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ -+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ -+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ -+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ -+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ -+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ -+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ -+#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */ -+#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */ -+#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */ -+#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */ -+#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */ -+#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */ -+#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */ -+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ -+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) -+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ -+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ -+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ -+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ -+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ -+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ -+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM -+ -+/* LCD Control Register */ -+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ -+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ -+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ -+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ -+ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */ -+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */ -+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */ -+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ -+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ -+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ -+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ -+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ -+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ -+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) -+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ -+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ -+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ -+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ -+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ -+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ -+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ -+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ -+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ -+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ -+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ -+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ -+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ -+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ -+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ -+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ -+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ -+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ -+ -+/* LCD Status Register */ -+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ -+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ -+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ -+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ -+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ -+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ -+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ -+ -+/* OSD Configure Register */ -+#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */ -+#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */ -+#define LCD_OSDC_REM1 (1 << 13) /* Real end of frame mask for foreground 1 */ -+#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */ -+#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */ -+#define LCD_OSDC_REM0 (1 << 9) /* Real end of frame mask for foreground 0 */ -+#define LCD_OSDC_REMB (1 << 7) /* Real end of frame mask for background */ -+#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */ -+#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */ -+#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */ -+#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */ -+#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */ -+ -+/* OSD Controll Register */ -+#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */ -+#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ -+#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ -+#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */ -+#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */ -+#define LCD_OSDCTRL_OSDBPP_MASK (0x7< -+ * -+ * 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 __ASM_BOARD_SERIAL_H__ -+#define __ASM_BOARD_SERIAL_H__ -+ -+#ifndef CONFIG_SERIAL_MANY_PORTS -+#undef RS_TABLE_SIZE -+#define RS_TABLE_SIZE 1 -+#endif -+ -+#define JZ_BASE_BAUD (12000000/16) -+ -+#define JZ_SERIAL_PORT_DEFNS \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, -+ -+#endif /* __ASM_BORAD_SERIAL_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750/war.h linux-2.6.24.7/include/asm-mips/mach-jz4750/war.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750/war.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750/war.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle -+ */ -+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H -+#define __ASM_MIPS_MACH_JZ4740_WAR_H -+ -+#define R4600_V1_INDEX_ICACHEOP_WAR 0 -+#define R4600_V1_HIT_CACHEOP_WAR 0 -+#define R4600_V2_HIT_CACHEOP_WAR 0 -+#define R5432_CP0_INTERRUPT_WAR 0 -+#define BCM1250_M3_WAR 0 -+#define SIBYTE_1956_WAR 0 -+#define MIPS4K_ICACHE_REFILL_WAR 0 -+#define MIPS_CACHE_SYNC_WAR 0 -+#define TX49XX_ICACHE_INDEX_INV_WAR 0 -+#define RM9000_CDEX_SMP_WAR 0 -+#define ICACHE_REFILLS_WORKAROUND_WAR 0 -+#define R10000_LLSC_WAR 0 -+#define MIPS34K_MISSED_ITLB_WAR 0 -+ -+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/board-fuwa1.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/board-fuwa1.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/board-fuwa1.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/board-fuwa1.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,124 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/board-fuwa1.h -+ * -+ * JZ4750D-based FUWA1 board ver 1.x definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750D_FUWA1_H__ -+#define __ASM_JZ4750D_FUWA1_H__ -+ -+#define CONFIG_FPGA /* fuwa is an FPGA board */ -+ -+/*====================================================================== -+ * Frequencies of on-board oscillators -+ */ -+#define JZ_EXTAL 48000000 /* Main extal freq: 12 MHz */ -+#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ -+#define CFG_DIV 1 /* hclk=pclk=mclk=CFG_EXTAL/CFG_DIV, just for FPGA board */ -+ -+ -+/*====================================================================== -+ * GPIO -+ */ -+#define GPIO_SD0_VCC_EN_N (32*2+10) /* GPC10 */ -+#define GPIO_SD0_CD_N (32*2+11) /* GPC11 */ -+#define GPIO_SD0_WP (32*2+12) /* GPC12 */ -+#define GPIO_SD1_VCC_EN_N (32*2+13) /* GPC13 */ -+#define GPIO_SD1_CD_N (32*2+14) /* GPC14 */ -+#define GPIO_USB_DETE 102 /* GPD6 */ -+#define GPIO_DC_DETE_N 103 /* GPD7 */ -+#define GPIO_CHARG_STAT_N 111 /* GPD15 */ -+#define GPIO_DISP_OFF_N 121 /* GPD25, LCD_REV */ -+//#define GPIO_LED_EN 124 /* GPD28 */ -+ -+#define GPIO_UDC_HOTPLUG GPIO_USB_DETE -+ -+/*====================================================================== -+ * LCD backlight -+ */ -+#define GPIO_LCD_PWM (32*4+20) /* GPE20 */ -+ -+#define LCD_PWM_CHN 0 /* pwm channel */ -+#define LCD_PWM_FULL 101 -+/* 100 level: 0,1,...,100 */ -+#define __lcd_set_backlight_level(n) \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_set_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+#define __lcd_close_backlight() \ -+do { \ -+ __gpio_as_output(GPIO_LCD_PWM); \ -+ __gpio_clear_pin(GPIO_LCD_PWM); \ -+} while (0) -+ -+/*====================================================================== -+ * MMC/SD -+ */ -+ -+#define MSC0_WP_PIN GPIO_SD0_WP -+#define MSC0_HOTPLUG_PIN GPIO_SD0_CD_N -+#define MSC0_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD0_CD_N) -+ -+#define MSC1_WP_PIN GPIO_SD1_WP -+#define MSC1_HOTPLUG_PIN GPIO_SD1_CD_N -+#define MSC1_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD1_CD_N) -+ -+#define __msc0_init_io() \ -+do { \ -+ __gpio_as_output(GPIO_SD0_VCC_EN_N); \ -+ __gpio_as_input(GPIO_SD0_CD_N); \ -+} while (0) -+ -+#define __msc0_enable_power() \ -+do { \ -+ __gpio_clear_pin(GPIO_SD0_VCC_EN_N); \ -+} while (0) -+ -+#define __msc0_disable_power() \ -+do { \ -+ __gpio_set_pin(GPIO_SD0_VCC_EN_N); \ -+} while (0) -+ -+#define __msc0_card_detected(s) \ -+({ \ -+ int detected = 1; \ -+ if (__gpio_get_pin(GPIO_SD0_CD_N)) \ -+ detected = 0; \ -+ detected; \ -+}) -+ -+#define __msc1_init_io() \ -+do { \ -+ /* __gpio_as_output(GPIO_SD1_VCC_EN_N);*/ \ -+ /* __gpio_as_input(GPIO_SD1_CD_N);*/ \ -+} while (0) -+ -+#define __msc1_enable_power() \ -+do { \ -+ /* __gpio_clear_pin(GPIO_SD1_VCC_EN_N);*/ \ -+} while (0) -+ -+#define __msc1_disable_power() \ -+do { \ -+ /* __gpio_set_pin(GPIO_SD1_VCC_EN_N);*/ \ -+} while (0) -+ -+#define __msc1_card_detected(s) \ -+({ \ -+ int detected = 0; \ -+ if (__gpio_get_pin(GPIO_SD1_CD_N)) \ -+ detected = 1; \ -+ detected; \ -+}) -+ -+#endif /* __ASM_JZ4750d_FUWA1_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/clock.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/clock.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/clock.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/clock.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,230 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/clock.h -+ * -+ * JZ4750D clocks definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750D_CLOCK_H__ -+#define __ASM_JZ4750D_CLOCK_H__ -+ -+#ifndef JZ_EXTAL -+#define JZ_EXTAL 12000000 /* 3.6864 MHz */ -+#endif -+#ifndef JZ_EXTAL2 -+#define JZ_EXTAL2 32768 /* 32.768 KHz */ -+#endif -+ -+/* -+ * JZ4750D clocks structure -+ */ -+typedef struct { -+ unsigned int cclk; /* CPU clock */ -+ unsigned int hclk; /* System bus clock */ -+ unsigned int pclk; /* Peripheral bus clock */ -+ unsigned int mclk; /* Flash/SRAM/SDRAM clock */ -+ unsigned int lcdclk; /* LCDC module clock */ -+ unsigned int pixclk; /* LCD pixel clock */ -+ unsigned int i2sclk; /* AIC module clock */ -+ unsigned int usbclk; /* USB module clock */ -+ unsigned int mscclk; /* MSC module clock */ -+ unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+ unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+} jz_clocks_t; -+ -+extern jz_clocks_t jz_clocks; -+ -+ -+/* PLL output frequency */ -+static __inline__ unsigned int __cpm_get_pllout(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL/CFG_DIV; -+#else -+ unsigned long m, n, no, pllout; -+ unsigned long cppcr = REG_CPM_CPPCR; -+ unsigned long od[4] = {1, 2, 2, 4}; -+ if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { -+ m = __cpm_get_pllm() + 2; -+ n = __cpm_get_plln() + 2; -+ no = od[__cpm_get_pllod()]; -+ pllout = ((JZ_EXTAL) / (n * no)) * m; -+ } else -+ pllout = JZ_EXTAL; -+ return pllout; -+#endif -+} -+ -+/* PLL output frequency for MSC/I2S/LCD/USB */ -+static __inline__ unsigned int __cpm_get_pllout2(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL/CFG_DIV; -+#else -+ if (REG_CPM_CPCCR & CPM_CPCCR_PCS) -+ return __cpm_get_pllout(); -+ else -+ return __cpm_get_pllout()/2; -+#endif -+} -+ -+/* CPU core clock */ -+static __inline__ unsigned int __cpm_get_cclk(void) -+{ -+ -+#if defined(CONFIG_FGPA) -+ return JZ_EXTAL; -+#else -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ return __cpm_get_pllout() / div[__cpm_get_cdiv()]; -+#endif -+} -+ -+/* AHB system bus clock */ -+static __inline__ unsigned int __cpm_get_hclk(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL/CFG_DIV; -+#else -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_hdiv()]; -+#endif -+ -+} -+ -+/* Memory bus clock */ -+static __inline__ unsigned int __cpm_get_mclk(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL/CFG_DIV; -+#else -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_mdiv()]; -+#endif -+} -+ -+/* APB peripheral bus clock */ -+static __inline__ unsigned int __cpm_get_pclk(void) -+{ -+#if defined(CONFIG_FPGA) -+ return JZ_EXTAL/CFG_DIV; -+#else -+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+ -+ return __cpm_get_pllout() / div[__cpm_get_pdiv()]; -+#endif -+} -+ -+/* LCDC module clock */ -+static __inline__ unsigned int __cpm_get_lcdclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); -+} -+ -+/* LCD pixel clock */ -+static __inline__ unsigned int __cpm_get_pixclk(void) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); -+} -+ -+/* I2S clock */ -+static __inline__ unsigned int __cpm_get_i2sclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { -+ return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* USB clock */ -+static __inline__ unsigned int __cpm_get_usbclk(void) -+{ -+ if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { -+ return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); -+ } -+ else { -+ return JZ_EXTAL; -+ } -+} -+ -+/* -+ * MSC clock -+ * @n: the index of MMC/SD controller -+ */ -+static __inline__ unsigned int __cpm_get_mscclk(int n) -+{ -+ return __cpm_get_pllout2() / (__cpm_get_mscdiv(n) + 1); -+} -+ -+/* EXTAL clock */ -+static __inline__ unsigned int __cpm_get_extalclk0(void) -+{ -+ return JZ_EXTAL; -+} -+ -+/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ -+static __inline__ unsigned int __cpm_get_extalclk(void) -+{ -+#if defined(CONFIG_FPGA) -+ return __cpm_get_pllout(); -+#else -+ if (REG_CPM_CPCCR & CPM_CPCCR_ECS) -+ return __cpm_get_extalclk0()/2; -+ else -+ return __cpm_get_extalclk0(); -+#endif -+ -+} -+ -+/* RTC clock for CPM,INTC,RTC,TCU,WDT */ -+static __inline__ unsigned int __cpm_get_rtcclk(void) -+{ -+ return JZ_EXTAL2; -+} -+ -+/* -+ * Output 24MHz for SD and 16MHz for MMC. -+ * @n: the index of MMC/SD controller -+ */ -+static inline void __cpm_select_msc_clk(int n, int sd) -+{ -+ unsigned int pllout2 = __cpm_get_pllout2(); -+ unsigned int div = 0; -+ -+ if (sd) { -+ div = pllout2 / 24000000; -+ } -+ else { -+ div = pllout2 / 16000000; -+ } -+ -+ REG_CPM_MSCCDR(n) = div - 1; -+ REG_CPM_CPCCR |= CPM_CPCCR_CE; -+} -+ -+/* -+ * Output 48MHz for high speed card. -+ */ -+static inline void __cpm_select_msc_clk_high(int n, int sd) -+{ -+ unsigned int pllout2 = __cpm_get_pllout2(); -+ unsigned int div = 0; -+ -+ div = pllout2 / 48000000; -+ -+ REG_CPM_MSCCDR(n) = div - 1; -+ REG_CPM_CPCCR |= CPM_CPCCR_CE; -+} -+ -+#endif /* __ASM_JZ4750D_CLOCK_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/dma.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/dma.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/dma.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/dma.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,307 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/dma.h -+ * -+ * JZ4750D DMA definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750D_DMA_H__ -+#define __ASM_JZ4750D_DMA_H__ -+ -+#include -+#include /* need byte IO */ -+#include /* And spinlocks */ -+#include -+#include -+ -+/* -+ * Descriptor structure for JZ4750D DMA engine -+ * Note: this structure must always be aligned to a 16-bytes boundary. -+ */ -+ -+/* old descriptor 4-word */ -+typedef struct { -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+ volatile u32 dsadr; /* DSAR value for the current transfer */ -+ volatile u32 dtadr; /* DTAR value for the current transfer */ -+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ -+} jz_dma_desc; -+ -+/* new descriptor 8-word */ -+typedef struct { -+ volatile u32 dcmd; /* DCMD value for the current transfer */ -+ volatile u32 dsadr; /* DSAR value for the current transfer */ -+ volatile u32 dtadr; /* DTAR value for the current transfer */ -+ volatile u32 ddadr; /* Points to the next descriptor + transfer count */ -+ volatile u32 dstrd; /* DMA source and target stride address */ -+ volatile u32 dreqt; /* DMA request type for current transfer */ -+ volatile u32 reserved0; /* Reserved */ -+ volatile u32 reserved1; /* Reserved */ -+} jz_dma_desc_8word; -+ -+/* DMA Device ID's follow */ -+enum { -+ DMA_ID_EXT = 0, /* External request with DREQn */ -+ DMA_ID_NAND, /* NAND DMA request */ -+ DMA_ID_BCH_ENC, /* BCH Encoding DMA request */ -+ DMA_ID_BCH_DEC, /* BCH Decoding DMA request */ -+ DMA_ID_AUTO, /* Auto-request */ -+// DMA_ID_TSSI_RX, /* TSSI receive fifo full request */ -+ DMA_ID_UART3_TX, /* UART3 transmit-fifo-empty request */ -+ DMA_ID_UART3_RX, /* UART3 receve-fifo-full request */ -+ DMA_ID_UART2_TX, /* UART2 transmit-fifo-empty request */ -+ DMA_ID_UART2_RX, /* UART2 receve-fifo-full request */ -+ DMA_ID_UART1_TX, /* UART1 transmit-fifo-empty request */ -+ DMA_ID_UART1_RX, /* UART1 receve-fifo-full request */ -+ DMA_ID_UART0_TX, /* UART0 transmit-fifo-empty request */ -+ DMA_ID_UART0_RX, /* UART0 receve-fifo-full request */ -+ DMA_ID_SSI0_TX, /* SSI0 transmit-fifo-full request */ -+ DMA_ID_SSI0_RX, /* SSI0 receive-fifo-empty request */ -+ DMA_ID_AIC_TX, /* AIC transmit-fifo-full request */ -+ DMA_ID_AIC_RX, /* AIC receive-fifo-empty request */ -+ DMA_ID_MSC0_TX, /* MSC0 transmit-fifo-full request */ -+ DMA_ID_MSC0_RX, /* MSC0 receive-fifo-empty request */ -+ DMA_ID_TCU_OVERFLOW, /* TCU channel n overflow interrupt */ -+ DMA_ID_SADC, /* SADC transfer request */ -+ DMA_ID_MSC1_TX, /* MSC1 transmit-fifo-full request */ -+ DMA_ID_MSC1_RX, /* MSC1 receive-fifo-empty request */ -+ DMA_ID_SSI1_TX, /* SSI1 transmit-fifo-full request */ -+ DMA_ID_SSI1_RX, /* SSI1 receive-fifo-empty request */ -+ DMA_ID_PCM_TX, /* PM transmit-fifo-full request */ -+ DMA_ID_PCM_RX, /* PM receive-fifo-empty request */ -+ DMA_ID_RAW_SET, -+ DMA_ID_MAX -+}; -+ -+/* DMA modes, simulated by sw */ -+#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ -+#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ -+#define DMA_AUTOINIT 0x2 -+#define DMA_MODE_MASK 0x3 -+ -+struct jz_dma_chan { -+ int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ -+ unsigned int io; /* DMA channel number */ -+ const char *dev_str; /* string describes the DMA channel */ -+ int irq; /* DMA irq number */ -+ void *irq_dev; /* DMA private device structure */ -+ unsigned int fifo_addr; /* physical fifo address of the requested device */ -+ unsigned int cntl; /* DMA controll */ -+ unsigned int mode; /* DMA configuration */ -+ unsigned int source; /* DMA request source */ -+}; -+ -+extern struct jz_dma_chan jz_dma_table[]; -+ -+ -+#define DMA_8BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_8BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_32BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_32BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN -+#define DMA_AIC_32_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_32_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BIT_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_RX_CMD \ -+ DMAC_DCMD_DAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+#define DMA_AIC_16BYTE_TX_CMD_UC \ -+ DMAC_DCMD_SAI | \ -+ DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ -+ DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN -+ -+extern int jz_request_dma(int dev_id, -+ const char *dev_str, -+ irqreturn_t (*irqhandler)(int, void *), -+ unsigned long irqflags, -+ void *irq_dev_id); -+extern void jz_free_dma(unsigned int dmanr); -+ -+extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, -+ int length, int *eof, void *data); -+extern void dump_jz_dma_channel(unsigned int dmanr); -+ -+extern void enable_dma(unsigned int dmanr); -+extern void disable_dma(unsigned int dmanr); -+extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); -+extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); -+extern void set_dma_mode(unsigned int dmanr, unsigned int mode); -+extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); -+extern void jz_set_dma_src_width(int dmanr, int nbit); -+extern void jz_set_dma_dest_width(int dmanr, int nbit); -+extern void jz_set_dma_block_size(int dmanr, int nbyte); -+extern unsigned int get_dma_residue(unsigned int dmanr); -+ -+extern spinlock_t dma_spin_lock; -+ -+static __inline__ unsigned long claim_dma_lock(void) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&dma_spin_lock, flags); -+ return flags; -+} -+ -+static __inline__ void release_dma_lock(unsigned long flags) -+{ -+ spin_unlock_irqrestore(&dma_spin_lock, flags); -+} -+ -+/* Clear the 'DMA Pointer Flip Flop'. -+ * Write 0 for LSB/MSB, 1 for MSB/LSB access. -+ */ -+#define clear_dma_ff(channel) -+ -+static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) -+{ -+ if (dmanr > MAX_DMA_NUM -+ || jz_dma_table[dmanr].dev_id < 0) -+ return NULL; -+ return &jz_dma_table[dmanr]; -+} -+ -+static __inline__ int dma_halted(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 1; -+ return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; -+} -+ -+static __inline__ unsigned int get_dma_mode(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ return chan->mode; -+} -+ -+static __inline__ void clear_dma_done(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ void clear_dma_halt(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); -+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT); -+} -+ -+static __inline__ void clear_dma_flag(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return; -+ REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+ REG_DMAC_DMACR((chan->io)/HALF_DMA_NUM) &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); -+} -+ -+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) -+{ -+} -+ -+static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) -+{ -+ unsigned long dccsr; -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return 0; -+ dccsr = REG_DMAC_DCCSR(chan->io); -+ return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); -+} -+ -+static __inline__ int get_dma_done_irq(unsigned int dmanr) -+{ -+ struct jz_dma_chan *chan = get_dma_chan(dmanr); -+ if (!chan) -+ return -1; -+ return chan->irq; -+} -+ -+#endif /* __ASM_JZ4750D_DMA_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/jz4750d.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/jz4750d.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/jz4750d.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/jz4750d.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,40 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/jz4750d.h -+ * -+ * JZ4750 common definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750_H__ -+#define __ASM_JZ4750_H__ -+ -+#include -+#include -+#include -+#include -+ -+/*------------------------------------------------------------------ -+ * Platform definitions -+ */ -+#ifdef CONFIG_JZ4750D_FUWA1 -+#include -+#endif -+ -+/* Add other platform definition here ... */ -+ -+ -+/*------------------------------------------------------------------ -+ * Follows are related to platform definitions -+ */ -+ -+#include -+#include -+ -+#endif /* __ASM_JZ4750_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/misc.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/misc.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/misc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/misc.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,44 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/misc.h -+ * -+ * Ingenic's JZ4750D common include. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __ASM_JZ4750D_MISC_H__ -+#define __ASM_JZ4750D_MISC_H__ -+ -+/*========================================================== -+ * I2C -+ *===========================================================*/ -+ -+#define I2C_EEPROM_DEV 0xA /* b'1010 */ -+#define I2C_RTC_DEV 0xD /* b'1101 */ -+#define DIMM0_SPD_ADDR 0 -+#define DIMM1_SPD_ADDR 1 -+#define DIMM2_SPD_ADDR 2 -+#define DIMM3_SPD_ADDR 3 -+#define JZ_HCI_ADDR 7 -+ -+#define DIMM_SPD_LEN 128 -+#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ -+#define I2C_RTC_LEN 16 -+#define HCI_MAC_OFFSET 64 -+ -+extern void i2c_open(void); -+extern void i2c_close(void); -+extern void i2c_setclk(unsigned int i2cclk); -+ -+extern int i2c_read(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+extern int i2c_write(unsigned char device, unsigned char *buf, -+ unsigned char address, int count); -+ -+#endif /* __ASM_JZ4750D_MISC_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/ops.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/ops.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/ops.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/ops.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3450 @@ -+/* -+ * linux/include/asm-mips/mach-jz4750d/ops.h -+ * -+ * JZ4750D register definition. -+ * -+ * Copyright (C) 2008 Ingenic Semiconductor Inc. -+ * -+ * 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 __JZ4750D_OPS_H__ -+#define __JZ4750D_OPS_H__ -+ -+/* -+ * Definition of Module Operations -+ */ -+ -+/*************************************************************************** -+ * EMC -+ ***************************************************************************/ -+#define is_share_mode() ((REG_EMC_BCR & EMC_BCR_BSR_MASK) == EMC_BCR_BSR_SHARE) -+ -+/*************************************************************************** -+ * GPIO -+ ***************************************************************************/ -+ -+//------------------------------------------------------ -+// GPIO Pins Description -+// -+// PORT 0: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 D0 - -+// 1 D1 - -+// 2 D2 - -+// 3 D3 - -+// 4 D4 - -+// 5 D5 - -+// 6 D6 - -+// 7 D7 - -+// 8 D8 - -+// 9 D9 - -+// 10 D10 - -+// 11 D11 - -+// 12 D12 - -+// 13 D13 - -+// 14 D14 - -+// 15 D15 - -+// 16 D16 - -+// 17 D17 - -+// 18 D18 - -+// 19 D19 - -+// 20 D20 - -+// 21 D21 - -+// 22 D22 - -+// 23 D23 - -+// 24 D24 - -+// 25 D25 - -+// 26 D26 - -+// 27 D27 - -+// 28 D28 - -+// 29 D29 - -+// 30 D30 - -+// 31 D31 - -+// -+//------------------------------------------------------ -+// PORT 1: -+// -+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE -+// 0 A0 - - -+// 1 A1 - - -+// 2 A2 - - -+// 3 A3 - - -+// 4 A4 - - -+// 5 A5 - - -+// 6 A6 - - -+// 7 A7 - - -+// 8 A8 - - -+// 9 A9 - - -+// 10 A10 - - -+// 11 A11 - - -+// 12 A12 - - -+// 13 A13 - - -+// 14 A14 - - -+// 15 A15/CLE CL(unshare) MSC0_CLK -+// 16 DCS0# - - -+// 17 RAS# - - -+// 18 CAS# - - -+// 19 SDWE#/BUFD# - - -+// 20 WE0# - - -+// 21 WE1# - - -+// 22 WE2# - - -+// 23 WE3# - - -+// 24 CKO - - Note1 -+// 25 CKE - - -+// 26 SSI_CLK MSC1_CLK - -+// 27 SSI_DT MSC1_D1 - -+// 28 SSI_DR MSC1_D0 - -+// 29 SSI_CE0# MSC1_CMD - -+// 30 SSI_GPC MSC1_D2 - -+// 31 SSI_CE1# MSC1_D3 - -+// -+// Note1: BIT24: it is CKO when chip is reset -+// -+//------------------------------------------------------ -+// PORT 2: -+// -+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE -+// 0 SD0 A20 - -+// 1 SD1 A21 - -+// 2 SD2 A22 - -+// 3 SD3 A23 - -+// 4 SD4 A24 - -+// 5 SD5 A25 - -+// 6 SD6 - - -+// 7 SD7 - - -+// 8 SD8 TSDI0 - -+// 9 SD9 TSDI1 - -+// 10 SD10 TSDI2 - -+// 11 SD11 TSDI3 - -+// 12 SD12 TSDI4 - -+// 13 SD13 TSDI5 - -+// 14 SD14 TSDI6 - -+// 15 SD15 TSDI7 - -+// 16 A16/ALE AL(unshare) MSC0_CMD -+// 17 A17 MSC0_D3 - -+// 18 A18 DREQ - -+// 19 A19 DACK - -+// 20 WAIT# - - Note2 -+// 21 CS1# - - -+// 22 CS2# - - -+// 23 CS3# - - -+// 24 CS4# - - -+// 25 RD# - - -+// 26 WR# - - -+// 27 FRB# - - Note3 -+// 28 FRE# MSC0_D0 - -+// 29 FWE# MSC0_D1 - -+// 30 - - - Note4 -+// 31 - - - Note5 -+// -+// Note2: BIT20: it is WIAT# pin when chip is reset -+// -+// Note3: BIT27: when NAND is used, it should connect to NANF FRB#. -+// -+// Note4: BIT30: it is BOOT_SEL0 which would be set as input without pulling when chip is reset. -+// -+// Note5: BIT31: it is BOOT_SEL1 which would be set as input without pulling when chip is reset. -+// -+//------------------------------------------------------ -+// PORT 3: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 0 LCD_B2 - -+// 1 LCD_B3 - -+// 2 LCD_B4 - -+// 3 LCD_B5 - -+// 4 LCD_B6 - -+// 5 LCD_B7 - -+// 6 LCD_G2 - -+// 7 LCD_G3 - -+// 8 LCD_G4 - -+// 9 LCD_G5 - -+// 10 LCD_G6 - -+// 11 LCD_G7 - -+// 12 LCD_R2 - -+// 13 LCD_R3 - -+// 14 LCD_R4 - -+// 15 LCD_R5 - -+// 16 LCD_R6 - -+// 17 LCD_R7 - -+// 18 LCD_PCLK - -+// 19 LCD_HSYNC - -+// 20 LCD_VSYNC - -+// 21 LCD_DE - -+// 22 LCD_CLS LCD_R1 -+// 23 LCD_SPL LCD_G0 -+// 24 LCD_PS LCD_G1 -+// 25 LCD_REV LCD_B1 -+// 26 LCD_B0 - -+// 27 LCD_R0 - -+// 28 UART0_RXD TSCLK -+// 29 UART0_TXD TSSTR -+// 30 UART0_CTS TSFRM -+// 31 UART0_RTS TSFAIL -+// -+//------------------------------------------------------ -+// PORT 4: -+// -+// PIN/BIT N FUNC0 FUNC1 FUNC2 NOTE -+// 0 CIM_D0 TSDI0 - -+// 1 CIM_D1 TSDI1 - -+// 2 CIM_D2 TSDI2 - -+// 3 CIM_D3 TSDI3 - -+// 4 CIM_D4 TSDI4 - -+// 5 CIM_D5 TSDI5 - -+// 6 CIM_D6 TSDI6 - -+// 7 CIM_D7 TSDI7 - -+// 8 CIM_MCLK TSFAIL - -+// 9 CIM_PCLK TSCLK - -+// 10 CIM_VSYNC TSSTR - -+// 11 CIM_HSYNC TSFRM - -+// 12 I2C_SDA - - -+// 13 I2C_SCK - - -+// 18 SDATO - - -+// 19 SDATI - - -+// 20 PWM0 - - -+// 22 PWM2 SYNC - -+// 23 PWM3 UART1_RxD BCLK -+// 24 PWM4 - - -+// 25 PWM5 UART1_TxD SCLK_RSTN -+// 28 DCS1# - - -+// 29 - - - Note6 -+// 30 WKUP - - Note7 -+// 31 - - - Note8 -+// -+// Note6: BIT29: it is BOOT_SEL2 which would be set as input without pulling when chip is reset. -+// Note7: BIT30: it is only used as input and interrupt, and with no pull-up and pull-down -+// Note8: BIT31: it is used to select the function of UART or JTAG set by PESEL[31] -+// PESEL[31] = 0, select JTAG function -+// PESEL[31] = 1, select UART function -+// -+//------------------------------------------------------ -+// PORT 5: -+// -+// PIN/BIT N FUNC0 FUNC1 NOTE -+// 10 SSI_CLK - -+// 11 SSI_DT PWM1 -+// 12 SSI_DR - -+// 13 SSI_CE0# - -+// 14 SSI_GPC - -+// 15 SSI_CE2# - -+// -+////////////////////////////////////////////////////////// -+ -+/*---------------------------------------------------------------- -+ * p is the port number (0,1,2,3,4,5) -+ * o is the pin offset (0-31) inside the port -+ * n is the absolute number of a pin (0-127), regardless of the port -+ */ -+ -+//------------------------------------------- -+// Function Pins Mode -+ -+#define __gpio_as_func0(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXSELC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_func1(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_func2(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFUNS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXSELC(p) = (1 << o); \ -+} while (0) -+ -+/* -+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, -+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# -+ */ -+#define __gpio_as_sdram_32bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0xffffffff; \ -+ REG_GPIO_PXSELC(0) = 0xffffffff; \ -+ REG_GPIO_PXPES(0) = 0xffffffff; \ -+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0x03ff7fff; \ -+} while (0) -+ -+ -+/* -+ * D0 ~ D31, A0 ~ A14, DCS0#, RAS#, CAS#, -+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# -+ * !!!!DCS1# -+ */ -+#define __gpio_as_sdram_x2_32bit() \ -+do { \ -+ REG_GPIO_PXFUNS(0) = 0xffffffff; \ -+ REG_GPIO_PXSELC(0) = 0xffffffff; \ -+ REG_GPIO_PXPES(0) = 0xffffffff; \ -+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0x03ff7fff; \ -+ REG_GPIO_PXFUNS(4) = 0x10000000; \ -+ REG_GPIO_PXSELC(4) = 0x10000000; \ -+ REG_GPIO_PXPES(4) = 0x10000000; \ -+} while (0) -+ -+/* -+ * D0 ~ D15, A0 ~ A14, DCS0#, RAS#, CAS#, -+ * RDWE#, WE0#, WE1#, WE2#, WE3#, CKO#, CKE# -+ */ -+#define __gpio_as_sdram_16bit() \ -+do { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ -+ REG_GPIO_PXSELC(0) = 0x0000ffff; \ -+ REG_GPIO_PXPES(0) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(1) = 0x03ff7fff; \ -+ REG_GPIO_PXSELC(1) = 0x03ff7fff; \ -+ REG_GPIO_PXPES(1) = 0x03ff7fff; \ -+} while (0) -+ -+/* -+ * D0 ~ D7, CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nand_8bit(n) \ -+do { \ -+ if (!is_share_mode()) { \ -+ /* unshare mode */ \ -+ REG_GPIO_PXFUNS(2) = 0x000000ff; /* SD0~SD7 */ \ -+ REG_GPIO_PXSELS(2) = 0x000000ff; \ -+ REG_GPIO_PXPES(2) = 0x000000ff; \ -+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(SA3) */ \ -+ REG_GPIO_PXSELS(1) = 0x00008000; \ -+ REG_GPIO_PXPES(1) = 0x00008000; \ -+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(SA4) */ \ -+ REG_GPIO_PXSELS(2) = 0x00010000; \ -+ REG_GPIO_PXPES(2) = 0x00010000; \ -+ } else { \ -+ /* 32/16-bit data bus */ \ -+ REG_GPIO_PXFUNS(0) = 0x000000ff; /* D0~D7 */ \ -+ REG_GPIO_PXSELC(0) = 0x000000ff; \ -+ REG_GPIO_PXPES(0) = 0x000000ff; \ -+ REG_GPIO_PXFUNS(1) = 0x00008000; /* CLE(A15) */ \ -+ REG_GPIO_PXSELC(1) = 0x00008000; \ -+ REG_GPIO_PXPES(1) = 0x00008000; \ -+ REG_GPIO_PXFUNS(2) = 0x00010000; /* ALE(A16) */ \ -+ REG_GPIO_PXSELC(2) = 0x00010000; \ -+ REG_GPIO_PXPES(2) = 0x00010000; \ -+ } \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x00080000; /* RDWE#/BUFD# */ \ -+ REG_GPIO_PXSELC(1) = 0x00080000; \ -+ REG_GPIO_PXPES(1) = 0x00080000; \ -+ REG_GPIO_PXFUNS(2) = 0x30000000; /* FRE#, FWE# */ \ -+ REG_GPIO_PXSELC(2) = 0x30000000; \ -+ REG_GPIO_PXPES(2) = 0x30000000; \ -+ REG_GPIO_PXFUNC(2) = 0x08000000; /* FRB#(input) */ \ -+ REG_GPIO_PXSELC(2) = 0x08000000; \ -+ REG_GPIO_PXDIRC(2) = 0x08000000; \ -+ REG_GPIO_PXPES(2) = 0x08000000; \ -+} while (0) -+ -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nor_8bit(n) \ -+do { \ -+ /* 32/16-bit data bus */ \ -+ REG_GPIO_PXFUNS(0) = 0x000000ff; \ -+ REG_GPIO_PXSELC(0) = 0x000000ff; \ -+ REG_GPIO_PXPES(0) = 0x000000ff; \ -+ \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ -+ REG_GPIO_PXSELC(1) = 0x0000ffff; \ -+ REG_GPIO_PXPES(1) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ -+ REG_GPIO_PXSELC(2) = 0x06110007; \ -+ REG_GPIO_PXPES(2) = 0x06110007; \ -+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ -+ REG_GPIO_PXSELS(2) = 0x000e0000; \ -+ REG_GPIO_PXPES(2) = 0x000e0000; \ -+} while (0) -+ -+/* -+ * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 -+ * @n: chip select number(1 ~ 4) -+ */ -+#define __gpio_as_nor_16bit(n) \ -+do { \ -+ /* 32/16-bit data normal order */ \ -+ REG_GPIO_PXFUNS(0) = 0x0000ffff; \ -+ REG_GPIO_PXSELC(0) = 0x0000ffff; \ -+ REG_GPIO_PXPES(0) = 0x0000ffff; \ -+ \ -+ REG_GPIO_PXFUNS(2) = 0x00200000 << ((n)-1); /* CSn */ \ -+ REG_GPIO_PXSELC(2) = 0x00200000 << ((n)-1); \ -+ REG_GPIO_PXPES(2) = 0x00200000 << ((n)-1); \ -+ \ -+ REG_GPIO_PXFUNS(1) = 0x0000ffff; /* A0~A15 */ \ -+ REG_GPIO_PXSELC(1) = 0x0000ffff; \ -+ REG_GPIO_PXPES(1) = 0x0000ffff; \ -+ REG_GPIO_PXFUNS(2) = 0x06110007; /* RD#, WR#, WAIT#, A20~A22 */ \ -+ REG_GPIO_PXSELC(2) = 0x06110007; \ -+ REG_GPIO_PXPES(2) = 0x06110007; \ -+ REG_GPIO_PXFUNS(2) = 0x000e0000; /* A17~A19 */ \ -+ REG_GPIO_PXSELS(2) = 0x000e0000; \ -+ REG_GPIO_PXPES(2) = 0x000e0000; \ -+} while (0) -+ -+/* -+ * UART0_TxD, UART0_RxD -+ */ -+#define __gpio_as_uart0() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x30000000; \ -+ REG_GPIO_PXSELC(3) = 0x30000000; \ -+ REG_GPIO_PXPES(3) = 0x30000000; \ -+} while (0) -+ -+/* -+ * UART0_TxD, UART0_RxD, UART0_CTS, UART0_RTS -+ */ -+#define __gpio_as_uart0_ctsrts() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0xf0000000; \ -+ REG_GPIO_PXSELC(3) = 0xf0000000; \ -+ REG_GPIO_PXPES(3) = 0xf0000000; \ -+} while (0) -+ -+/* -+ * UART1_TxD, UART1_RxD -+ */ -+#define __gpio_as_uart1() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x02800000; \ -+ REG_GPIO_PXSELC(4) = 0x02800000; \ -+ REG_GPIO_PXPES(4) = 0x02800000; \ -+} while (0) -+ -+/* -+ * UART2_TxD, UART2_RxD, UART2_CTS, UART2_RTS using JTAG pins -+ */ -+#define __gpio_as_uart2() \ -+do { \ -+ REG_GPIO_PXSELS(4) = 0x80000000; \ -+} while (0) -+ -+/* -+ * TSCLK, TSSTR, TSFRM, TSFAIL, TSDI0~7 -+ */ -+#define __gpio_as_tssi() \ -+do { \ -+ REG_GPIO_PXFUNS(2) = 0x0000ff00; \ -+ REG_GPIO_PXSELS(2) = 0x0000ff00; \ -+ REG_GPIO_PXPES(2) = 0x0000ff00; \ -+ REG_GPIO_PXFUNS(5) = 0x00f00000; \ -+ REG_GPIO_PXSELC(5) = 0x00f00000; \ -+ REG_GPIO_PXPES(5) = 0x00f00000; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D7, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_8bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003c00ff; \ -+ REG_GPIO_PXTRGC(3) = 0x003c00ff; \ -+ REG_GPIO_PXSELC(3) = 0x003c00ff; \ -+ REG_GPIO_PXPES(3) = 0x003c00ff; \ -+} while (0) -+ -+/* -+ * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_16bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003cffff; \ -+ REG_GPIO_PXTRGC(3) = 0x003cffff; \ -+ REG_GPIO_PXSELC(3) = 0x003cffff; \ -+ REG_GPIO_PXPES(3) = 0x003cffff; \ -+} while (0) -+ -+/* -+ * LCD_R2~LCD_R7, LCD_G2~LCD_G7, LCD_B2~LCD_B7, -+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_18bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x003fffff; \ -+ REG_GPIO_PXTRGC(3) = 0x003fffff; \ -+ REG_GPIO_PXSELC(3) = 0x003fffff; \ -+ REG_GPIO_PXPES(3) = 0x003fffff; \ -+} while (0) -+ -+/* -+ * LCD_R0~LCD_R7, LCD_G0~LCD_G7, LCD_B0~LCD_B7, -+ * LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE -+ */ -+#define __gpio_as_lcd_24bit() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x0fffffff; \ -+ REG_GPIO_PXTRGC(3) = 0x0fffffff; \ -+ REG_GPIO_PXSELC(3) = 0x0c3fffff; \ -+ REG_GPIO_PXSELS(3) = 0x03c00000; \ -+ REG_GPIO_PXPES(3) = 0x0fffffff; \ -+} while (0) -+ -+/* -+ * LCD_CLS, LCD_SPL, LCD_PS, LCD_REV -+ */ -+#define __gpio_as_lcd_special() \ -+do { \ -+ REG_GPIO_PXFUNS(3) = 0x03C00000; \ -+ REG_GPIO_PXSELC(3) = 0x03C00000; \ -+ REG_GPIO_PXPES(3) = 0x03C00000; \ -+} while (0) -+ -+/* -+ * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC -+ */ -+#define __gpio_as_cim() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00000fff; \ -+ REG_GPIO_PXSELC(4) = 0x00000fff; \ -+ REG_GPIO_PXPES(4) = 0x00000fff; \ -+} while (0) -+ -+/* -+ * SDATO, SDATI, BCLK, SYNC, SCLK_RSTN(gpio sepc) or -+ * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET(aic spec) -+ */ -+#define __gpio_as_aic() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x16c00000; \ -+ REG_GPIO_PXTRGC(4) = 0x02c00000; \ -+ REG_GPIO_PXTRGS(4) = 0x14000000; \ -+ REG_GPIO_PXSELC(4) = 0x14c00000; \ -+ REG_GPIO_PXSELS(4) = 0x02000000; \ -+ REG_GPIO_PXPES(4) = 0x16c00000; \ -+} while (0) -+ -+/* -+ * MSC0_CMD, MSC0_CLK, MSC0_D0 ~ MSC0_D3 -+ */ -+#define __gpio_as_msc0_4bit() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0x00008000; \ -+ REG_GPIO_PXTRGS(1) = 0x00008000; \ -+ REG_GPIO_PXSELC(1) = 0x00008000; \ -+ REG_GPIO_PXPES(1) = 0x00008000; \ -+ REG_GPIO_PXFUNS(2) = 0x38030000; \ -+ REG_GPIO_PXTRGS(2) = 0x00010000; \ -+ REG_GPIO_PXTRGC(2) = 0x38020000; \ -+ REG_GPIO_PXSELC(2) = 0x08010000; \ -+ REG_GPIO_PXSELS(2) = 0x30020000; \ -+ REG_GPIO_PXPES(2) = 0x38030000; \ -+} while (0) -+ -+ -+/* -+ * MSC1_CMD, MSC1_CLK, MSC1_D0 ~ MSC1_D3 -+ */ -+#define __gpio_as_msc1_4bit() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0xfc000000; \ -+ REG_GPIO_PXTRGC(1) = 0xfc000000; \ -+ REG_GPIO_PXSELS(1) = 0xfc000000; \ -+ REG_GPIO_PXPES(1) = 0xfc000000; \ -+} while (0) -+ -+#define __gpio_as_msc __gpio_as_msc0_4bit /* default as msc0 4bit */ -+#define __gpio_as_msc0 __gpio_as_msc0_4bit /* msc0 default as 4bit */ -+#define __gpio_as_msc1 __gpio_as_msc1_4bit /* msc1 only support 4bit */ -+ -+/* -+ * SSI_CE0, SSI_CE1, SSI_GPC, SSI_CLK, SSI_DT, SSI_DR -+ */ -+#define __gpio_as_ssi() \ -+do { \ -+ REG_GPIO_PXFUNS(1) = 0xfc000000; \ -+ REG_GPIO_PXTRGC(1) = 0xfc000000; \ -+ REG_GPIO_PXSELC(1) = 0xfc000000; \ -+ REG_GPIO_PXPES(1) = 0xfc000000; \ -+} while (0) -+ -+/* -+ * SSI_CE0, SSI_CE2, SSI_GPC, SSI_CLK, SSI_DT, SSI1_DR -+ */ -+#define __gpio_as_ssi_1() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x0000fc00; \ -+ REG_GPIO_PXTRGC(5) = 0x0000fc00; \ -+ REG_GPIO_PXSELC(5) = 0x0000fc00; \ -+ REG_GPIO_PXPES(5) = 0x0000fc00; \ -+} while (0) -+ -+/* -+ * I2C_SCK, I2C_SDA -+ */ -+#define __gpio_as_i2c() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00003000; \ -+ REG_GPIO_PXSELC(4) = 0x00003000; \ -+ REG_GPIO_PXPES(4) = 0x00003000; \ -+} while (0) -+ -+/* -+ * PWM0 -+ */ -+#define __gpio_as_pwm0() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00100000; \ -+ REG_GPIO_PXSELC(4) = 0x00100000; \ -+ REG_GPIO_PXPES(4) = 0x00100000; \ -+} while (0) -+ -+/* -+ * PWM1 -+ */ -+#define __gpio_as_pwm1() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000800; \ -+ REG_GPIO_PXSELC(5) = 0x00000800; \ -+ REG_GPIO_PXPES(5) = 0x00000800; \ -+} while (0) -+ -+/* -+ * PWM2 -+ */ -+#define __gpio_as_pwm2() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00400000; \ -+ REG_GPIO_PXSELC(4) = 0x00400000; \ -+ REG_GPIO_PXPES(4) = 0x00400000; \ -+} while (0) -+ -+/* -+ * PWM3 -+ */ -+#define __gpio_as_pwm3() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x00800000; \ -+ REG_GPIO_PXSELC(4) = 0x00800000; \ -+ REG_GPIO_PXPES(4) = 0x00800000; \ -+} while (0) -+ -+/* -+ * PWM4 -+ */ -+#define __gpio_as_pwm4() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x01000000; \ -+ REG_GPIO_PXSELC(4) = 0x01000000; \ -+ REG_GPIO_PXPES(4) = 0x01000000; \ -+} while (0) -+ -+/* -+ * PWM5 -+ */ -+#define __gpio_as_pwm5() \ -+do { \ -+ REG_GPIO_PXFUNS(4) = 0x02000000; \ -+ REG_GPIO_PXSELC(4) = 0x02000000; \ -+ REG_GPIO_PXPES(4) = 0x02000000; \ -+} while (0) -+ -+/* -+ * n = 0 ~ 5 -+ */ -+#define __gpio_as_pwm(n) __gpio_as_pwm##n() -+ -+/* -+ * DREQ -+ */ -+#define __gpio_as_dreq() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000004; \ -+ REG_GPIO_PXSELS(5) = 0x00000004; \ -+ REG_GPIO_PXPES(5) = 0x00000004; \ -+} while (0) -+ -+/* -+ * DACK -+ */ -+#define __gpio_as_dack() \ -+do { \ -+ REG_GPIO_PXFUNS(5) = 0x00000008; \ -+ REG_GPIO_PXSELS(5) = 0x00000008; \ -+ REG_GPIO_PXPES(5) = 0x00000008; \ -+} while (0) -+ -+/* -+ * GPIO or Interrupt Mode -+ */ -+#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) -+ -+#define __gpio_port_as_output(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRS(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_port_as_input(p, o) \ -+do { \ -+ REG_GPIO_PXFUNC(p) = (1 << (o)); \ -+ REG_GPIO_PXSELC(p) = (1 << (o)); \ -+ REG_GPIO_PXDIRC(p) = (1 << (o)); \ -+} while (0) -+ -+#define __gpio_as_output(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_output(p, o); \ -+} while (0) -+ -+#define __gpio_as_input(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ __gpio_port_as_input(p, o); \ -+} while (0) -+ -+#define __gpio_set_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_clear_pin(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXDATC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_pin(n) \ -+({ \ -+ unsigned int p, o, v; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ if (__gpio_get_port(p) & (1 << o)) \ -+ v = 1; \ -+ else \ -+ v = 0; \ -+ v; \ -+}) -+ -+#define __gpio_as_irq_high_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_low_level(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGC(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_rise_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRS(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_as_irq_fall_edge(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+ REG_GPIO_PXTRGS(p) = (1 << o); \ -+ REG_GPIO_PXFUNC(p) = (1 << o); \ -+ REG_GPIO_PXSELS(p) = (1 << o); \ -+ REG_GPIO_PXDIRC(p) = (1 << o); \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_mask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMS(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_unmask_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXIMC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_ack_irq(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXFLGC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_get_irq() \ -+({ \ -+ unsigned int p, i, tmp, v = 0; \ -+ for (p = 3; p >= 0; p--) { \ -+ tmp = REG_GPIO_PXFLG(p); \ -+ for (i = 0; i < 32; i++) \ -+ if (tmp & (1 << i)) \ -+ v = (32*p + i); \ -+ } \ -+ v; \ -+}) -+ -+#define __gpio_group_irq(n) \ -+({ \ -+ register int tmp, i; \ -+ tmp = REG_GPIO_PXFLG((n)); \ -+ for (i=31;i>=0;i--) \ -+ if (tmp & (1 << i)) \ -+ break; \ -+ i; \ -+}) -+ -+#define __gpio_enable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPEC(p) = (1 << o); \ -+} while (0) -+ -+#define __gpio_disable_pull(n) \ -+do { \ -+ unsigned int p, o; \ -+ p = (n) / 32; \ -+ o = (n) % 32; \ -+ REG_GPIO_PXPES(p) = (1 << o); \ -+} while (0) -+ -+ -+/*************************************************************************** -+ * CPM -+ ***************************************************************************/ -+#define __cpm_get_pllm() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) -+#define __cpm_get_plln() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) -+#define __cpm_get_pllod() \ -+ ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) -+ -+#define __cpm_get_cdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) -+#define __cpm_get_hdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) -+#define __cpm_get_pdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) -+#define __cpm_get_mdiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) -+#define __cpm_get_ldiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) -+#define __cpm_get_udiv() \ -+ ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) -+#define __cpm_get_i2sdiv() \ -+ ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) -+#define __cpm_get_pixdiv() \ -+ ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) -+#define __cpm_get_mscdiv(n) \ -+ ((REG_CPM_MSCCDR(n) & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) -+#define __cpm_get_uhcdiv() \ -+ ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) -+#define __cpm_get_ssidiv() \ -+ ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) -+#define __cpm_get_pcmdiv(v) \ -+ ((REG_CPM_PCMCDR & CPM_PCMCDR_PCMCD_MASK) >> CPM_PCMCDR_PCMCD_BIT) -+ -+#define __cpm_set_cdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) -+#define __cpm_set_hdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) -+#define __cpm_set_pdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) -+#define __cpm_set_mdiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) -+#define __cpm_set_ldiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) -+#define __cpm_set_udiv(v) \ -+ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) -+#define __cpm_set_i2sdiv(v) \ -+ (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) -+#define __cpm_set_pixdiv(v) \ -+ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) -+#define __cpm_set_mscdiv(n, v) \ -+ (REG_CPM_MSCCDR(n) = (REG_CPM_MSCCDR(n) & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) -+#define __cpm_set_uhcdiv(v) \ -+ (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) -+#define __cpm_set_ssidiv(v) \ -+ (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) -+#define __cpm_set_pcmdiv(v) \ -+ (REG_CPM_PCMCDR = (REG_CPM_PCMCDR & ~CPM_PCMCDR_PCMCD_MASK) | ((v) << (CPM_PCMCDR_PCMCD_BIT))) -+ -+#define __cpm_select_pcmclk_pll() (REG_CPM_PCMCDR |= CPM_PCMCDR_PCMS) -+#define __cpm_select_pcmclk_exclk() (REG_CPM_PCMCDR &= ~CPM_PCMCDR_PCMS) -+#define __cpm_select_pixclk_ext() (REG_CPM_LPCDR |= CPM_LPCDR_LPCS) -+#define __cpm_select_pixclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LPCS) -+#define __cpm_select_tveclk_exclk() (REG_CPM_LPCDR |= CPM_CPCCR_LSCS) -+#define __cpm_select_tveclk_pll() (REG_CPM_LPCDR &= ~CPM_LPCDR_LSCS) -+#define __cpm_select_pixclk_lcd() (REG_CPM_LPCDR &= ~CPM_LPCDR_LTCS) -+#define __cpm_select_pixclk_tve() (REG_CPM_LPCDR |= CPM_LPCDR_LTCS) -+#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) -+#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) -+#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) -+#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) -+ -+#define __cpm_enable_cko() -+#define __cpm_exclk_direct() (REG_CPM_CPCCR &= ~CPM_CPCCR_ECS) -+#define __cpm_exclk_div2() (REG_CPM_CPCCR |= CPM_CPCCR_ECS) -+#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) -+#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) -+#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) -+#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) -+ -+#define __cpm_pll_is_off() (REG_CPM_CPPSR & CPM_CPPSR_PLLOFF) -+#define __cpm_pll_is_on() (REG_CPM_CPPSR & CPM_CPPSR_PLLON) -+#define __cpm_pll_bypass() (REG_CPM_CPPSR |= CPM_CPPSR_PLLBP) -+ -+#define __cpm_get_cclk_doze_duty() \ -+ ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) -+#define __cpm_set_cclk_doze_duty(v) \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) -+ -+#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) -+#define __cpm_idle_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) -+#define __cpm_sleep_mode() \ -+ (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) -+ -+#define __cpm_stop_all() (REG_CPM_CLKGR = 0x1fffffff) -+#define __cpm_stop_cimram() (REG_CPM_CLKGR |= CPM_CLKGR_CIMRAM) -+#define __cpm_stop_idct() (REG_CPM_CLKGR |= CPM_CLKGR_IDCT) -+#define __cpm_stop_db() (REG_CPM_CLKGR |= CPM_CLKGR_DB) -+#define __cpm_stop_me() (REG_CPM_CLKGR |= CPM_CLKGR_ME) -+#define __cpm_stop_mc() (REG_CPM_CLKGR |= CPM_CLKGR_MC) -+#define __cpm_stop_tve() (REG_CPM_CLKGR |= CPM_CLKGR_TVE) -+#define __cpm_stop_tssi() (REG_CPM_CLKGR |= CPM_CLKGR_TSSI) -+#define __cpm_stop_owi() (REG_CPM_CLKGR |= CPM_CLKGR_OWI) -+#define __cpm_stop_pcm() (REG_CPM_CLKGR |= CPM_CLKGR_PCM) -+#define __cpm_stop_uart3() (REG_CPM_CLKGR |= CPM_CLKGR_UART3) -+#define __cpm_stop_uart2() (REG_CPM_CLKGR |= CPM_CLKGR_UART2) -+#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) -+#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) -+#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) -+#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) -+#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) -+#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) -+#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) -+#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) -+#define __cpm_stop_msc(n) (REG_CPM_CLKGR |= CPM_CLKGR_MSC##n) -+#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) -+#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) -+#define __cpm_stop_ssi(n) (REG_CPM_CLKGR |= CPM_CLKGR_SSI##n) -+#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) -+#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) -+#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) -+#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) -+ -+#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) -+#define __cpm_start_cimram() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIMRAM) -+#define __cpm_start_idct() (REG_CPM_CLKGR &= ~CPM_CLKGR_IDCT) -+#define __cpm_start_db() (REG_CPM_CLKGR &= ~CPM_CLKGR_DB) -+#define __cpm_start_me() (REG_CPM_CLKGR &= ~CPM_CLKGR_ME) -+#define __cpm_start_mc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MC) -+#define __cpm_start_tve() (REG_CPM_CLKGR &= ~CPM_CLKGR_TVE) -+#define __cpm_start_tssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_TSSI) -+#define __cpm_start_owi() (REG_CPM_CLKGR &= ~CPM_CLKGR_OWI) -+#define __cpm_start_pcm() (REG_CPM_CLKGR &= ~CPM_CLKGR_PCM) -+#define __cpm_start_uart3() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART3) -+#define __cpm_start_uart2() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART2) -+#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) -+#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) -+#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) -+#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) -+#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) -+#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) -+#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) -+#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) -+#define __cpm_start_msc(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC##n) -+#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) -+#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) -+#define __cpm_start_ssi(n) (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI##n) -+#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) -+#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) -+#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) -+#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) -+ -+#define __cpm_get_o1st() \ -+ ((REG_CPM_OPCR & CPM_OPCR_O1ST_MASK) >> CPM_OPCR_O1ST_BIT) -+#define __cpm_set_o1st(v) \ -+ (REG_CPM_OPCR = (REG_CPM_OPCR & ~CPM_OPCR_O1ST_MASK) | ((v) << (CPM_OPCR_O1ST_BIT))) -+#define __cpm_enable_uhcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UHCPHY_DISABLE) -+#define __cpm_suspend_uhcphy() (REG_CPM_OPCR |= CPM_OPCR_UHCPHY_DISABLE) -+#define __cpm_enable_udcphy() (REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE) -+#define __cpm_suspend_udcphy() (REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE) -+#define __cpm_enable_osc_in_sleep() (REG_CPM_OPCR |= CPM_OPCR_OSC_ENABLE) -+#define __cpm_disable_osc_in_sleep() (REG_CPM_OPCR &= ~CPM_OPCR_OSC_ENABLE) -+#define __cpm_select_rtcclk_rtc() (REG_CPM_OPCR |= CPM_OPCR_ERCS) -+#define __cpm_select_rtcclk_exclk() (REG_CPM_OPCR &= ~CPM_OPCR_ERCS) -+ -+ -+/*************************************************************************** -+ * TCU -+ ***************************************************************************/ -+// where 'n' is the TCU channel -+#define __tcu_select_extalclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) -+#define __tcu_select_rtcclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) -+#define __tcu_select_pclk(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) -+#define __tcu_disable_pclk(n) \ -+ REG_TCU_TCSR(n) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PCK_EN); -+#define __tcu_select_clk_div1(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) -+#define __tcu_select_clk_div4(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) -+#define __tcu_select_clk_div16(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) -+#define __tcu_select_clk_div64(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) -+#define __tcu_select_clk_div256(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) -+#define __tcu_select_clk_div1024(n) \ -+ (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) -+ -+#define __tcu_enable_pwm_output(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN) -+#define __tcu_disable_pwm_output(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN) -+ -+#define __tcu_init_pwm_output_high(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH) -+#define __tcu_init_pwm_output_low(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH) -+ -+#define __tcu_set_pwm_output_shutdown_graceful(n) (REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD) -+#define __tcu_set_pwm_output_shutdown_abrupt(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD) -+ -+#define __tcu_clear_counter_to_zero(n) (REG_TCU_TCSR((n)) |= TCU_TCSR_CNT_CLRZ) -+ -+#define __tcu_ost_enabled() (REG_TCU_TER & TCU_TER_OSTEN) -+#define __tcu_enable_ost() (REG_TCU_TESR = TCU_TESR_OSTST) -+#define __tcu_disable_ost() (REG_TCU_TECR = TCU_TECR_OSTCL) -+ -+#define __tcu_counter_enabled(n) (REG_TCU_TER & (1 << (n))) -+#define __tcu_start_counter(n) (REG_TCU_TESR |= (1 << (n))) -+#define __tcu_stop_counter(n) (REG_TCU_TECR |= (1 << (n))) -+ -+#define __tcu_half_match_flag(n) (REG_TCU_TFR & (1 << ((n) + 16))) -+#define __tcu_full_match_flag(n) (REG_TCU_TFR & (1 << (n))) -+#define __tcu_set_half_match_flag(n) (REG_TCU_TFSR = (1 << ((n) + 16))) -+#define __tcu_set_full_match_flag(n) (REG_TCU_TFSR = (1 << (n))) -+#define __tcu_clear_half_match_flag(n) (REG_TCU_TFCR = (1 << ((n) + 16))) -+#define __tcu_clear_full_match_flag(n) (REG_TCU_TFCR = (1 << (n))) -+#define __tcu_mask_half_match_irq(n) (REG_TCU_TMSR = (1 << ((n) + 16))) -+#define __tcu_mask_full_match_irq(n) (REG_TCU_TMSR = (1 << (n))) -+#define __tcu_unmask_half_match_irq(n) (REG_TCU_TMCR = (1 << ((n) + 16))) -+#define __tcu_unmask_full_match_irq(n) (REG_TCU_TMCR = (1 << (n))) -+ -+#define __tcu_ost_match_flag() (REG_TCU_TFR & TCU_TFR_OSTFLAG) -+#define __tcu_set_ost_match_flag() (REG_TCU_TFSR = TCU_TFSR_OSTFST) -+#define __tcu_clear_ost_match_flag() (REG_TCU_TFCR = TCU_TFCR_OSTFCL) -+#define __tcu_ost_match_irq_masked() (REG_TCU_TMR & TCU_TMR_OSTMASK) -+#define __tcu_mask_ost_match_irq() (REG_TCU_TMSR = TCU_TMSR_OSTMST) -+#define __tcu_unmask_ost_match_irq() (REG_TCU_TMCR = TCU_TMCR_OSTMCL) -+ -+#define __tcu_wdt_clock_stopped() (REG_TCU_TSR & TCU_TSSR_WDTSC) -+#define __tcu_ost_clock_stopped() (REG_TCU_TSR & TCU_TSR_OST) -+#define __tcu_timer_clock_stopped(n) (REG_TCU_TSR & (1 << (n))) -+ -+#define __tcu_start_wdt_clock() (REG_TCU_TSCR = TCU_TSSR_WDTSC) -+#define __tcu_start_ost_clock() (REG_TCU_TSCR = TCU_TSCR_OSTSC) -+#define __tcu_start_timer_clock(n) (REG_TCU_TSCR = (1 << (n))) -+ -+#define __tcu_stop_wdt_clock() (REG_TCU_TSSR = TCU_TSSR_WDTSC) -+#define __tcu_stop_ost_clock() (REG_TCU_TSSR = TCU_TSSR_OSTSS) -+#define __tcu_stop_timer_clock(n) (REG_TCU_TSSR = (1 << (n))) -+ -+#define __tcu_get_count(n) (REG_TCU_TCNT((n))) -+#define __tcu_set_count(n,v) (REG_TCU_TCNT((n)) = (v)) -+#define __tcu_set_full_data(n,v) (REG_TCU_TDFR((n)) = (v)) -+#define __tcu_set_half_data(n,v) (REG_TCU_TDHR((n)) = (v)) -+ -+/* TCU2, counter 1, 2*/ -+#define __tcu_read_real_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) -+#define __tcu_read_false_value(n) (REG_TCU_TSTR & (1 << ((n) + 16))) -+#define __tcu_counter_busy(n) (REG_TCU_TSTR & (1 << (n))) -+#define __tcu_counter_ready(n) (REG_TCU_TSTR & (1 << (n))) -+ -+#define __tcu_set_read_real_value(n) (REG_TCU_TSTSR = (1 << ((n) + 16))) -+#define __tcu_set_read_false_value(n) (REG_TCU_TSTCR = (1 << ((n) + 16))) -+#define __tcu_set_counter_busy(n) (REG_TCU_TSTSR = (1 << (n))) -+#define __tcu_set_counter_ready(n) (REG_TCU_TSTCR = (1 << (n))) -+ -+/* ost counter */ -+#define __ostcu_set_pwm_output_shutdown_graceful() (REG_TCU_OSTCSR &= ~TCU_TCSR_PWM_SD) -+#define __ostcu_set_ost_output_shutdown_abrupt() (REG_TCU_OSTCSR |= TCU_TCSR_PWM_SD) -+#define __ostcu_select_clk_div1() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1) -+#define __ostcu_select_clk_div4() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE4) -+#define __ostcu_select_clk_div16() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE16) -+#define __ostcu_select_clk_div64() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE64) -+#define __ostcu_select_clk_div256() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE256) -+#define __ostcu_select_clk_div1024() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~TCU_OSTCSR_PRESCALE_MASK) | TCU_OSTCSR_PRESCALE1024) -+#define __ostcu_select_rtcclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_RTC_EN) -+#define __ostcu_select_extalclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_EXT_EN) -+#define __ostcu_select_pclk() \ -+ (REG_TCU_OSTCSR = (REG_TCU_OSTCSR & ~(TCU_OSTCSR_EXT_EN | TCU_OSTCSR_RTC_EN | TCU_OSTCSR_PCK_EN)) | TCU_OSTCSR_PCK_EN) -+ -+ -+/*************************************************************************** -+ * WDT -+ ***************************************************************************/ -+#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) -+#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) -+#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) -+#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) -+ -+#define __wdt_select_extalclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) -+#define __wdt_select_rtcclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) -+#define __wdt_select_pclk() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) -+ -+#define __wdt_select_clk_div1() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) -+#define __wdt_select_clk_div4() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) -+#define __wdt_select_clk_div16() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) -+#define __wdt_select_clk_div64() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) -+#define __wdt_select_clk_div256() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) -+#define __wdt_select_clk_div1024() \ -+ (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) -+ -+ -+/*************************************************************************** -+ * UART -+ ***************************************************************************/ -+ -+#define __uart_enable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) -+#define __uart_disable(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) -+ -+#define __uart_enable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) -+#define __uart_disable_transmit_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) -+ -+#define __uart_enable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) -+#define __uart_disable_receive_irq(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) -+ -+#define __uart_enable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) -+#define __uart_disable_loopback(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) -+ -+#define __uart_set_8n1(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) -+ -+#define __uart_set_baud(n, devclk, baud) \ -+ do { \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ -+ } while (0) -+ -+#define __uart_parity_error(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) -+ -+#define __uart_clear_errors(n) \ -+ ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) -+ -+#define __uart_transmit_fifo_empty(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) -+ -+#define __uart_transmit_end(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) -+ -+#define __uart_transmit_char(n, ch) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) -+ -+#define __uart_receive_fifo_full(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_ready(n) \ -+ ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) -+ -+#define __uart_receive_char(n) \ -+ REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) -+ -+#define __uart_disable_irda() \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) -+#define __uart_enable_irda() \ -+ /* Tx high pulse as 0, Rx low pulse as 0 */ \ -+ ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) -+ -+ -+/*************************************************************************** -+ * DMAC -+ ***************************************************************************/ -+ -+/* m is the DMA controller index (0, 1), n is the DMA channel index (0 - 11) */ -+ -+#define __dmac_enable_module(m) \ -+ ( REG_DMAC_DMACR(m) |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_012345 ) -+#define __dmac_disable_module(m) \ -+ ( REG_DMAC_DMACR(m) &= ~DMAC_DMACR_DMAE ) -+ -+/* p=0,1,2,3 */ -+#define __dmac_set_priority(m,p) \ -+do { \ -+ REG_DMAC_DMACR(m) &= ~DMAC_DMACR_PR_MASK; \ -+ REG_DMAC_DMACR(m) |= ((p) << DMAC_DMACR_PR_BIT); \ -+} while (0) -+ -+#define __dmac_test_halt_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_HLT ) -+#define __dmac_test_addr_error(m) ( REG_DMAC_DMACR(m) & DMAC_DMACR_AR ) -+ -+#define __dmac_channel_enable_clk(n) \ -+ REG_DMAC_DMACKE((n)/HALF_DMA_NUM) |= 1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM); -+ -+#define __dmac_enable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) -+#define __dmac_disable_descriptor(n) \ -+ ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) -+ -+#define __dmac_enable_channel(n) \ -+do { \ -+ REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN; \ -+} while (0) -+#define __dmac_disable_channel(n) \ -+do { \ -+ REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN; \ -+} while (0) -+#define __dmac_channel_enabled(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) -+ -+#define __dmac_channel_enable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) -+#define __dmac_channel_disable_irq(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) -+ -+#define __dmac_channel_transmit_halt_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) -+#define __dmac_channel_transmit_end_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) -+#define __dmac_channel_address_error_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) -+#define __dmac_channel_count_terminated_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) -+#define __dmac_channel_descriptor_invalid_detected(n) \ -+ ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_clear_transmit_halt(n) \ -+ do { \ -+ /* clear both channel halt error and globle halt error */ \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT; \ -+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_HLT; \ -+ } while (0) -+#define __dmac_channel_clear_transmit_end(n) \ -+ ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) -+#define __dmac_channel_clear_address_error(n) \ -+ do { \ -+ REG_DMAC_DDA(n) = 0; /* clear descriptor address register */ \ -+ REG_DMAC_DSAR(n) = 0; /* clear source address register */ \ -+ REG_DMAC_DTAR(n) = 0; /* clear target address register */ \ -+ /* clear both channel addr error and globle address error */ \ -+ REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR; \ -+ REG_DMAC_DMACR(n/HALF_DMA_NUM) &= ~DMAC_DMACR_AR; \ -+ } while (0) -+#define __dmac_channel_clear_count_terminated(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) -+#define __dmac_channel_clear_descriptor_invalid(n) \ -+ ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) -+ -+#define __dmac_channel_set_transfer_unit_32bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_8bit(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_16byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ -+} while (0) -+ -+#define __dmac_channel_set_transfer_unit_32byte(n) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_dest_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ -+} while (0) -+ -+/* w=8,16,32 */ -+#define __dmac_channel_set_src_port_width(n,w) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ -+ REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ -+} while (0) -+ -+/* v=0-15 */ -+#define __dmac_channel_set_rdil(n,v) \ -+do { \ -+ REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ -+ REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ -+} while (0) -+ -+#define __dmac_channel_dest_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) -+#define __dmac_channel_dest_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) -+ -+#define __dmac_channel_src_addr_fixed(n) \ -+ ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) -+#define __dmac_channel_src_addr_increment(n) \ -+ ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) -+ -+#define __dmac_channel_set_doorbell(n) \ -+ ( REG_DMAC_DMADBSR((n)/HALF_DMA_NUM) = (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+ -+#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) & (1 << ((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR((n)/HALF_DMA_NUM) &= ~(1 <<((n)-(n)/HALF_DMA_NUM*HALF_DMA_NUM)) ) -+ -+static __inline__ int __dmac_get_irq(void) -+{ -+ int i; -+ for (i = 0; i < MAX_DMA_NUM; i++) -+ if (__dmac_channel_irq_detected(i)) -+ return i; -+ return -1; -+} -+ -+ -+/*************************************************************************** -+ * AIC (AC'97 & I2S Controller) -+ ***************************************************************************/ -+ -+#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) -+#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) -+ -+#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) -+#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) -+ -+#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) -+#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) -+ -+#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) -+#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) -+#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) -+ -+#define __aic_reset() \ -+do { \ -+ REG_AIC_FR |= AIC_FR_RST; \ -+} while(0) -+ -+ -+#define __aic_set_transmit_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ -+} while(0) -+ -+#define __aic_set_receive_trigger(n) \ -+do { \ -+ REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ -+ REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ -+} while(0) -+ -+#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) -+#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) -+#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) -+#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) -+#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) -+#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) -+ -+#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) -+#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) -+ -+#define __aic_enable_transmit_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_disable_transmit_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) -+#define __aic_enable_receive_intr() \ -+ ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) -+#define __aic_disable_receive_intr() \ -+ ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) -+ -+#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) -+#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) -+#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) -+#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) -+ -+#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) -+#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) -+#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) -+#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) -+#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) -+#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) -+ -+#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 -+#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 -+#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 -+#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 -+#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 -+#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 -+ -+#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 -+#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 -+#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 -+#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 -+#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 -+#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 -+ -+#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) -+#define __ac97_set_xs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ -+} while(0) -+#define __ac97_set_xs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ -+} while(0) -+ -+/* In fact, only stereo is support now. */ -+#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) -+#define __ac97_set_rs_mono() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ -+} while(0) -+#define __ac97_set_rs_stereo() \ -+do { \ -+ REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ -+ REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ -+} while(0) -+ -+#define __ac97_warm_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ -+ } while (0) -+ -+#define __ac97_cold_reset_codec() \ -+ do { \ -+ REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ -+ udelay(2); \ -+ REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ -+ } while (0) -+ -+/* n=8,16,18,20 */ -+#define __ac97_set_iass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) -+#define __ac97_set_oass(n) \ -+ ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) -+ -+#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) -+#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) -+ -+/* n=8,16,18,20,24 */ -+/*#define __i2s_set_sample_size(n) \ -+ ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ -+ -+#define __i2s_set_oss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) -+#define __i2s_set_iss_sample_size(n) \ -+ ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) -+ -+#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) -+#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) -+ -+#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) -+#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) -+#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) -+#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) -+ -+#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) -+ -+#define __aic_get_transmit_resident() \ -+ ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) -+#define __aic_get_receive_count() \ -+ ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) -+ -+#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) -+#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) -+#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) -+#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) -+#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) -+#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) -+#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) -+ -+#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) -+ -+#define CODEC_READ_CMD (1 << 19) -+#define CODEC_WRITE_CMD (0 << 19) -+#define CODEC_REG_INDEX_BIT 12 -+#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ -+#define CODEC_REG_DATA_BIT 4 -+#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ -+ -+#define __ac97_out_rcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_wcmd_addr(reg) \ -+do { \ -+ REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ -+} while (0) -+ -+#define __ac97_out_data(value) \ -+do { \ -+ REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ -+} while (0) -+ -+#define __ac97_in_data() \ -+ ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) -+ -+#define __ac97_in_status_addr() \ -+ ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) -+ -+#define __i2s_set_sample_rate(i2sclk, sync) \ -+ ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) -+ -+#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) -+#define __aic_read_rfifo() ( REG_AIC_DR ) -+ -+#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) -+#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) -+ -+// -+// Define next ops for AC97 compatible -+// -+ -+#define AC97_ACSR AIC_ACSR -+ -+#define __ac97_enable() __aic_enable(); __aic_select_ac97() -+#define __ac97_disable() __aic_disable() -+#define __ac97_reset() __aic_reset() -+ -+#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __ac97_enable_record() __aic_enable_record() -+#define __ac97_disable_record() __aic_disable_record() -+#define __ac97_enable_replay() __aic_enable_replay() -+#define __ac97_disable_replay() __aic_disable_replay() -+#define __ac97_enable_loopback() __aic_enable_loopback() -+#define __ac97_disable_loopback() __aic_disable_loopback() -+ -+#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __ac97_enable_receive_dma() __aic_enable_receive_dma() -+#define __ac97_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __ac97_transmit_request() __aic_transmit_request() -+#define __ac97_receive_request() __aic_receive_request() -+#define __ac97_transmit_underrun() __aic_transmit_underrun() -+#define __ac97_receive_overrun() __aic_receive_overrun() -+ -+#define __ac97_clear_errors() __aic_clear_errors() -+ -+#define __ac97_get_transmit_resident() __aic_get_transmit_resident() -+#define __ac97_get_receive_count() __aic_get_receive_count() -+ -+#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __ac97_enable_receive_intr() __aic_enable_receive_intr() -+#define __ac97_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __ac97_write_tfifo(v) __aic_write_tfifo(v) -+#define __ac97_read_rfifo() __aic_read_rfifo() -+ -+// -+// Define next ops for I2S compatible -+// -+ -+#define I2S_ACSR AIC_I2SSR -+ -+#define __i2s_enable() __aic_enable(); __aic_select_i2s() -+#define __i2s_disable() __aic_disable() -+#define __i2s_reset() __aic_reset() -+ -+#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) -+#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) -+ -+#define __i2s_enable_record() __aic_enable_record() -+#define __i2s_disable_record() __aic_disable_record() -+#define __i2s_enable_replay() __aic_enable_replay() -+#define __i2s_disable_replay() __aic_disable_replay() -+#define __i2s_enable_loopback() __aic_enable_loopback() -+#define __i2s_disable_loopback() __aic_disable_loopback() -+ -+#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() -+#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() -+#define __i2s_enable_receive_dma() __aic_enable_receive_dma() -+#define __i2s_disable_receive_dma() __aic_disable_receive_dma() -+ -+#define __i2s_transmit_request() __aic_transmit_request() -+#define __i2s_receive_request() __aic_receive_request() -+#define __i2s_transmit_underrun() __aic_transmit_underrun() -+#define __i2s_receive_overrun() __aic_receive_overrun() -+ -+#define __i2s_clear_errors() __aic_clear_errors() -+ -+#define __i2s_get_transmit_resident() __aic_get_transmit_resident() -+#define __i2s_get_receive_count() __aic_get_receive_count() -+ -+#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() -+#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() -+#define __i2s_enable_receive_intr() __aic_enable_receive_intr() -+#define __i2s_disable_receive_intr() __aic_disable_receive_intr() -+ -+#define __i2s_write_tfifo(v) __aic_write_tfifo(v) -+#define __i2s_read_rfifo() __aic_read_rfifo() -+ -+#define __i2s_reset_codec() \ -+ do { \ -+ } while (0) -+ -+/************************************************************************* -+ * PCM Controller operation -+ *************************************************************************/ -+ -+#define __pcm_enable() ( REG_PCM_CTL |= PCM_CTL_PCMEN ) -+#define __pcm_disable() ( REG_PCM_CTL &= ~PCM_CTL_PCMEN ) -+ -+#define __pcm_clk_enable() ( REG_PCM_CTL |= PCM_CTL_CLKEN ) -+#define __pcm_clk_disable() ( REG_PCM_CTL &= ~PCM_CTL_CLKEN ) -+ -+#define __pcm_reset() ( REG_PCM_CTL |= PCM_CTL_RST ) -+#define __pcm_flush_fifo() ( REG_PCM_CTL |= PCM_CTL_FLUSH ) -+ -+#define __pcm_enable_record() ( REG_PCM_CTL |= PCM_CTL_EREC ) -+#define __pcm_disable_record() ( REG_PCM_CTL &= ~PCM_CTL_EREC ) -+#define __pcm_enable_playback() ( REG_PCM_CTL |= PCM_CTL_ERPL ) -+#define __pcm_disable_playback() ( REG_PCM_CTL &= ~PCM_CTL_ERPL ) -+ -+#define __pcm_enable_rxfifo() __pcm_enable_record() -+#define __pcm_disable_rxfifo() __pcm_disable_record() -+#define __pcm_enable_txfifo() __pcm_enable_playback() -+#define __pcm_disable_txfifo() __pcm_disable_playback() -+ -+#define __pcm_last_sample() ( REG_PCM_CTL |= PCM_CTL_LSMP ) -+#define __pcm_zero_sample() ( REG_PCM_CTL &= ~PCM_CTL_LSMP ) -+ -+#define __pcm_enable_transmit_dma() ( REG_PCM_CTL |= PCM_CTL_ETDMA ) -+#define __pcm_disable_transmit_dma() ( REG_PCM_CTL &= ~PCM_CTL_ETDMA ) -+#define __pcm_enable_receive_dma() ( REG_PCM_CTL |= PCM_CTL_ERDMA ) -+#define __pcm_disable_receive_dma() ( REG_PCM_CTL &= ~PCM_CTL_ERDMA ) -+ -+#define __pcm_as_master() ( REG_PCM_CFG &= PCM_CFG_MODE ) -+#define __pcm_as_slave() ( REG_PCM_CFG |= ~PCM_CFG_MODE ) -+ -+#define __pcm_set_transmit_trigger(n) \ -+do { \ -+ REG_PCM_CFG &= ~PCM_CFG_TFTH_MASK; \ -+ REG_PCM_CFG |= ((n) << PCM_CFG_TFTH_BIT); \ -+} while(0) -+ -+#define __pcm_set_receive_trigger(n) \ -+do { \ -+ REG_PCM_CFG &= ~PCM_CFG_RFTH_MASK; \ -+ REG_PCM_CFG |= ((n) << PCM_CFG_RFTH_BIT); \ -+} while(0) -+ -+#define __pcm_omsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_OMSBPOS ) -+#define __pcm_omsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_OMSBPOS ) -+ -+#define __pcm_imsb_same_sync() ( REG_PCM_CFG &= ~PCM_CFG_IMSBPOS ) -+#define __pcm_imsb_next_sync() ( REG_PCM_CFG |= PCM_CFG_IMSBPOS ) -+ -+/* set input sample size 8 or 16*/ -+#define __pcm_set_iss(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_ISS_MASK) | PCM_CFG_ISS_##n ) -+/* set output sample size 8 or 16*/ -+#define __pcm_set_oss(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_OSS_MASK) | PCM_CFG_OSS_##n ) -+ -+#define __pcm_set_valid_slot(n) \ -+( REG_PCM_CFG = (REG_PCM_CFG & ~PCM_CFG_SLOT_MASK) | PCM_CFG_SLOT_##n ) -+ -+#define __pcm_write_data(v) ( REG_PCM_DP = (v) ) -+#define __pcm_read_data() ( REG_PCM_DP ) -+ -+#define __pcm_enable_tfs_intr() ( REG_PCM_INTC |= PCM_INTC_ETFS ) -+#define __pcm_disable_tfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETFS ) -+ -+#define __pcm_enable_tur_intr() ( REG_PCM_INTC |= PCM_INTC_ETUR ) -+#define __pcm_disable_tur_intr() ( REG_PCM_INTC &= ~PCM_INTC_ETUR ) -+ -+#define __pcm_enable_rfs_intr() ( REG_PCM_INTC |= PCM_INTC_ERFS ) -+#define __pcm_disable_rfs_intr() ( REG_PCM_INTC &= ~PCM_INTC_ERFS ) -+ -+#define __pcm_enable_ror_intr() ( REG_PCM_INTC |= PCM_INTC_EROR ) -+#define __pcm_disable_ror_intr() ( REG_PCM_INTC &= ~PCM_INTC_EROR ) -+ -+#define __pcm_ints_valid_tx() \ -+( ((REG_PCM_INTS & PCM_INTS_TFL_MASK) >> PCM_INTS_TFL_BIT) ) -+#define __pcm_ints_valid_rx() \ -+( ((REG_PCM_INTS & PCM_INTS_RFL_MASK) >> PCM_INTS_RFL_BIT) ) -+ -+#define __pcm_set_clk_div(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_CLKDIV_MASK) | ((n) << PCM_DIV_CLKDIV_BIT) ) -+ -+/* sysclk(cpm_pcm_sysclk) Hz is created by cpm logic, and pcmclk Hz is the pcm in/out clock wanted */ -+#define __pcm_set_clk_rate(sysclk, pcmclk) \ -+__pcm_set_clk_div(((sysclk) / (pcmclk) - 1)) -+ -+#define __pcm_set_sync_div(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNDIV_MASK) | ((n) << PCM_DIV_SYNDIV_BIT) ) -+ -+/* pcmclk is source clock Hz, and sync is the frame sync clock Hz wanted */ -+#define __pcm_set_sync_rate(pcmclk, sync) \ -+__pcm_set_sync_div(((pcmclk) / (8 * (sync)) - 1)) -+ -+ /* set sync length in pcmclk n = 0 ... 63 */ -+#define __pcm_set_sync_len(n) \ -+( REG_PCM_DIV = (REG_PCM_DIV & ~PCM_DIV_SYNL_MASK) | (n << PCM_DIV_SYNL_BIT) ) -+ -+ -+/*************************************************************************** -+ * ICDC -+ ***************************************************************************/ -+#define __i2s_internal_codec() __aic_internal_codec() -+#define __i2s_external_codec() __aic_external_codec() -+ -+#define __icdc_clk_ready() ( REG_ICDC_CKCFG & ICDC_CKCFG_CKRDY ) -+#define __icdc_sel_adc() ( REG_ICDC_CKCFG |= ICDC_CKCFG_SELAD ) -+#define __icdc_sel_dac() ( REG_ICDC_CKCFG &= ~ICDC_CKCFG_SELAD ) -+ -+#define __icdc_set_rgwr() ( REG_ICDC_RGADW |= ICDC_RGADW_RGWR ) -+#define __icdc_clear_rgwr() ( REG_ICDC_RGADW &= ~ICDC_RGADW_RGWR ) -+#define __icdc_rgwr_ready() ( REG_ICDC_RGADW & ICDC_RGADW_RGWR ) -+ -+#define __icdc_set_addr(n) \ -+do { \ -+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGADDR_MASK; \ -+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGADDR_BIT; \ -+} while(0) -+ -+#define __icdc_set_cmd(n) \ -+do { \ -+ REG_ICDC_RGADW &= ~ICDC_RGADW_RGDIN_MASK; \ -+ REG_ICDC_RGADW |= (n) << ICDC_RGADW_RGDIN_BIT; \ -+} while(0) -+ -+#define __icdc_irq_pending() ( REG_ICDC_RGDATA & ICDC_RGDATA_IRQ ) -+#define __icdc_get_value() ( REG_ICDC_RGDATA & ICDC_RGDATA_RGDOUT_MASK ) -+ -+/*************************************************************************** -+ * INTC -+ ***************************************************************************/ -+#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) -+#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) -+#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) /* A dummy ack, as the Pending Register is Read Only. Should we remove __intc_ack_irq() */ -+ -+ -+/*************************************************************************** -+ * I2C -+ ***************************************************************************/ -+ -+#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) -+#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) -+ -+#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) -+#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) -+#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) -+#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) -+ -+#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) -+#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) -+#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) -+ -+#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) -+#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) -+#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) -+ -+#define __i2c_set_clk(dev_clk, i2c_clk) \ -+ ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) -+ -+#define __i2c_read() ( REG_I2C_DR ) -+#define __i2c_write(val) ( REG_I2C_DR = (val) ) -+ -+ -+/*************************************************************************** -+ * MSC -+ ***************************************************************************/ -+/* n = 0, 1 (MSC0, MSC1) */ -+ -+#define __msc_start_op(n) \ -+ ( REG_MSC_STRPCL(n) = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) -+ -+#define __msc_set_resto(n, to) ( REG_MSC_RESTO(n) = to ) -+#define __msc_set_rdto(n, to) ( REG_MSC_RDTO(n) = to ) -+#define __msc_set_cmd(n, cmd) ( REG_MSC_CMD(n) = cmd ) -+#define __msc_set_arg(n, arg) ( REG_MSC_ARG(n) = arg ) -+#define __msc_set_nob(n, nob) ( REG_MSC_NOB(n) = nob ) -+#define __msc_get_nob(n) ( REG_MSC_NOB(n) ) -+#define __msc_set_blklen(n, len) ( REG_MSC_BLKLEN(n) = len ) -+#define __msc_set_cmdat(n, cmdat) ( REG_MSC_CMDAT(n) = cmdat ) -+#define __msc_set_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_IO_ABORT ) -+#define __msc_clear_cmdat_ioabort(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_IO_ABORT ) -+ -+#define __msc_set_cmdat_bus_width1(n) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_1BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_bus_width4(n) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ -+ REG_MSC_CMDAT(n) |= MSC_CMDAT_BUS_WIDTH_4BIT; \ -+} while(0) -+ -+#define __msc_set_cmdat_dma_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DMA_EN ) -+#define __msc_set_cmdat_init(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_INIT ) -+#define __msc_set_cmdat_busy(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_BUSY ) -+#define __msc_set_cmdat_stream(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_block(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_STREAM_BLOCK ) -+#define __msc_set_cmdat_read(n) ( REG_MSC_CMDAT(n) &= ~MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_write(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_WRITE_READ ) -+#define __msc_set_cmdat_data_en(n) ( REG_MSC_CMDAT(n) |= MSC_CMDAT_DATA_EN ) -+ -+/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ -+#define __msc_set_cmdat_res_format(n, r) \ -+do { \ -+ REG_MSC_CMDAT(n) &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ -+ REG_MSC_CMDAT(n) |= (r); \ -+} while(0) -+ -+#define __msc_clear_cmdat(n) \ -+ REG_MSC_CMDAT(n) &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ -+ MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ -+ MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) -+ -+#define __msc_get_imask(n) ( REG_MSC_IMASK(n) ) -+#define __msc_mask_all_intrs(n) ( REG_MSC_IMASK(n) = 0xff ) -+#define __msc_unmask_all_intrs(n) ( REG_MSC_IMASK(n) = 0x00 ) -+#define __msc_mask_rd(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_unmask_rd(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_RXFIFO_RD_REQ ) -+#define __msc_mask_wr(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_unmask_wr(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_TXFIFO_WR_REQ ) -+#define __msc_mask_endcmdres(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_END_CMD_RES ) -+#define __msc_unmask_endcmdres(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_END_CMD_RES ) -+#define __msc_mask_datatrandone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_unmask_datatrandone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_DATA_TRAN_DONE ) -+#define __msc_mask_prgdone(n) ( REG_MSC_IMASK(n) |= MSC_IMASK_PRG_DONE ) -+#define __msc_unmask_prgdone(n) ( REG_MSC_IMASK(n) &= ~MSC_IMASK_PRG_DONE ) -+ -+/* m=0,1,2,3,4,5,6,7 */ -+#define __msc_set_clkrt(n, m) \ -+do { \ -+ REG_MSC_CLKRT(n) = m; \ -+} while(0) -+ -+#define __msc_get_ireg(n) ( REG_MSC_IREG(n) ) -+#define __msc_ireg_rd(n) ( REG_MSC_IREG(n) & MSC_IREG_RXFIFO_RD_REQ ) -+#define __msc_ireg_wr(n) ( REG_MSC_IREG(n) & MSC_IREG_TXFIFO_WR_REQ ) -+#define __msc_ireg_end_cmd_res(n) ( REG_MSC_IREG(n) & MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_data_tran_done(n) ( REG_MSC_IREG(n) & MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_prg_done(n) ( REG_MSC_IREG(n) & MSC_IREG_PRG_DONE ) -+#define __msc_ireg_clear_end_cmd_res(n) ( REG_MSC_IREG(n) = MSC_IREG_END_CMD_RES ) -+#define __msc_ireg_clear_data_tran_done(n) ( REG_MSC_IREG(n) = MSC_IREG_DATA_TRAN_DONE ) -+#define __msc_ireg_clear_prg_done(n) ( REG_MSC_IREG(n) = MSC_IREG_PRG_DONE ) -+ -+#define __msc_get_stat(n) ( REG_MSC_STAT(n) ) -+#define __msc_stat_not_end_cmd_res(n) ( (REG_MSC_STAT(n) & MSC_STAT_END_CMD_RES) == 0) -+#define __msc_stat_crc_err(n) \ -+ ( REG_MSC_STAT(n) & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) -+#define __msc_stat_res_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_RES_ERR ) -+#define __msc_stat_rd_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_READ_ERROR ) -+#define __msc_stat_wr_crc_err(n) ( REG_MSC_STAT(n) & MSC_STAT_CRC_WRITE_ERROR_YES ) -+#define __msc_stat_resto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_RES ) -+#define __msc_stat_rdto_err(n) ( REG_MSC_STAT(n) & MSC_STAT_TIME_OUT_READ ) -+ -+#define __msc_rd_resfifo(n) ( REG_MSC_RES(n) ) -+#define __msc_rd_rxfifo(n) ( REG_MSC_RXFIFO(n) ) -+#define __msc_wr_txfifo(n, v) ( REG_MSC_TXFIFO(n) = v ) -+ -+#define __msc_reset(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_RESET; \ -+ while (REG_MSC_STAT(n) & MSC_STAT_IS_RESETTING); \ -+} while (0) -+ -+#define __msc_start_clk(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_START; \ -+} while (0) -+ -+#define __msc_stop_clk(n) \ -+do { \ -+ REG_MSC_STRPCL(n) = MSC_STRPCL_CLOCK_CONTROL_STOP; \ -+} while (0) -+ -+#define MMC_CLK 19169200 -+#define SD_CLK 24576000 -+ -+/* msc_clk should little than pclk and little than clk retrieve from card */ -+#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ -+do { \ -+ unsigned int rate, pclk, i; \ -+ pclk = dev_clk; \ -+ rate = type?SD_CLK:MMC_CLK; \ -+ if (msc_clk && msc_clk < pclk) \ -+ pclk = msc_clk; \ -+ i = 0; \ -+ while (pclk < rate) \ -+ { \ -+ i ++; \ -+ rate >>= 1; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+/* divide rate to little than or equal to 400kHz */ -+#define __msc_calc_slow_clk_divisor(type, lv) \ -+do { \ -+ unsigned int rate, i; \ -+ rate = (type?SD_CLK:MMC_CLK)/1000/400; \ -+ i = 0; \ -+ while (rate > 0) \ -+ { \ -+ rate >>= 1; \ -+ i ++; \ -+ } \ -+ lv = i; \ -+} while(0) -+ -+ -+/*************************************************************************** -+ * SSI (Synchronous Serial Interface) -+ ***************************************************************************/ -+/* n = 0, 1 (SSI0, SSI1) */ -+#define __ssi_enable(n) ( REG_SSI_CR0(n) |= SSI_CR0_SSIE ) -+#define __ssi_disable(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_SSIE ) -+#define __ssi_select_ce(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_FSEL ) -+ -+#define __ssi_normal_mode(n) ( REG_SSI_ITR(n) &= ~SSI_ITR_IVLTM_MASK ) -+ -+#define __ssi_select_ce2(n) \ -+do { \ -+ REG_SSI_CR0(n) |= SSI_CR0_FSEL; \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_select_gpc(n) \ -+do { \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_FSEL; \ -+ REG_SSI_CR1(n) |= SSI_CR1_MULTS; \ -+} while (0) -+ -+#define __ssi_underrun_auto_clear(n) \ -+do { \ -+ REG_SSI_CR0(n) |= SSI_CR0_EACLRUN; \ -+} while (0) -+ -+#define __ssi_underrun_clear_manually(n) \ -+do { \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_EACLRUN; \ -+} while (0) -+ -+#define __ssi_enable_tx_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE | SSI_CR0_TEIE ) -+ -+#define __ssi_disable_tx_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) -+ -+#define __ssi_enable_rx_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE | SSI_CR0_REIE ) -+ -+#define __ssi_disable_rx_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) -+ -+#define __ssi_enable_txfifo_half_empty_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TIE ) -+#define __ssi_disable_txfifo_half_empty_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TIE ) -+#define __ssi_enable_tx_error_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TEIE ) -+#define __ssi_disable_tx_error_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_TEIE ) -+#define __ssi_enable_rxfifo_half_full_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_RIE ) -+#define __ssi_disable_rxfifo_half_full_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_RIE ) -+#define __ssi_enable_rx_error_intr(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_REIE ) -+#define __ssi_disable_rx_error_intr(n) \ -+ ( REG_SSI_CR0(n) &= ~SSI_CR0_REIE ) -+ -+#define __ssi_enable_loopback(n) ( REG_SSI_CR0(n) |= SSI_CR0_LOOP ) -+#define __ssi_disable_loopback(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_LOOP ) -+ -+#define __ssi_enable_receive(n) ( REG_SSI_CR0(n) &= ~SSI_CR0_DISREV ) -+#define __ssi_disable_receive(n) ( REG_SSI_CR0(n) |= SSI_CR0_DISREV ) -+ -+#define __ssi_finish_receive(n) \ -+ ( REG_SSI_CR0(n) |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_disable_recvfinish(n) \ -+ ( REG_SSI_CR0(n) &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) -+ -+#define __ssi_flush_txfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH ) -+#define __ssi_flush_rxfifo(n) ( REG_SSI_CR0(n) |= SSI_CR0_RFLUSH ) -+ -+#define __ssi_flush_fifo(n) \ -+ ( REG_SSI_CR0(n) |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) -+ -+#define __ssi_finish_transmit(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_UNFIN ) -+#define __ssi_wait_transmit(n) ( REG_SSI_CR1(n) |= SSI_CR1_UNFIN ) -+#define __ssi_use_busy_wait_mode(n) __ssi_wait_transmit(n) -+#define __ssi_unset_busy_wait_mode(n) __ssi_finish_transmit(n) -+ -+#define __ssi_spi_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SPI; \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ -+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ -+ } while (0) -+ -+/* TI's SSP format, must clear SSI_CR1.UNFIN */ -+#define __ssi_ssp_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_SSP; \ -+ } while (0) -+ -+/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ -+#define __ssi_microwire_format(n) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_FMAT_MASK; \ -+ REG_SSI_CR1(n) |= SSI_CR1_FMAT_MW1; \ -+ REG_SSI_CR1(n) &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK); \ -+ REG_SSI_CR1(n) |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ -+ REG_SSI_CR0(n) &= ~SSI_CR0_RFINE; \ -+ } while (0) -+ -+/* CE# level (FRMHL), CE# in interval time (ITFRM), -+ clock phase and polarity (PHA POL), -+ interval time (SSIITR), interval characters/frame (SSIICR) */ -+ -+/* frmhl,endian,mcom,flen,pha,pol MASK */ -+#define SSICR1_MISC_MASK \ -+ ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ -+ | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) -+ -+#define __ssi_spi_set_misc(n,frmhl,endian,flen,mcom,pha,pol) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSICR1_MISC_MASK; \ -+ REG_SSI_CR1(n) |= ((frmhl) << 30) | ((endian) << 25) | \ -+ (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ -+ ((pha) << 1) | (pol); \ -+ } while(0) -+ -+/* Transfer with MSB or LSB first */ -+#define __ssi_set_msb(n) ( REG_SSI_CR1(n) &= ~SSI_CR1_LFST ) -+#define __ssi_set_lsb(n) ( REG_SSI_CR1(n) |= SSI_CR1_LFST ) -+ -+#define __ssi_set_frame_length(n, m) \ -+ REG_SSI_CR1(n) = (REG_SSI_CR1(n) & ~SSI_CR1_FLEN_MASK) | (((m) - 2) << 4) -+ -+/* m = 1 - 16 */ -+#define __ssi_set_microwire_command_length(n,m) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##m##BIT) ) -+ -+/* Set the clock phase for SPI */ -+#define __ssi_set_spi_clock_phase(n, m) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_PHA) | (((m)&0x1)<< 1))) -+ -+/* Set the clock polarity for SPI */ -+#define __ssi_set_spi_clock_polarity(n, p) \ -+ ( REG_SSI_CR1(n) = ((REG_SSI_CR1(n) & ~SSI_CR1_POL) | ((p)&0x1)) ) -+ -+/* SSI tx trigger, m = i x 8 */ -+#define __ssi_set_tx_trigger(n, m) \ -+ do { \ -+ REG_SSI_CR1(n) &= ~SSI_CR1_TTRG_MASK; \ -+ REG_SSI_CR1(n) |= ((m)/8)<> SSI_SR_TFIFONUM_BIT ) -+ -+#define __ssi_get_rxfifo_count(n) \ -+ ( (REG_SSI_SR(n) & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) -+ -+#define __ssi_transfer_end(n) ( REG_SSI_SR(n) & SSI_SR_END ) -+#define __ssi_is_busy(n) ( REG_SSI_SR(n) & SSI_SR_BUSY ) -+ -+#define __ssi_txfifo_full(n) ( REG_SSI_SR(n) & SSI_SR_TFF ) -+#define __ssi_rxfifo_empty(n) ( REG_SSI_SR(n) & SSI_SR_RFE ) -+#define __ssi_rxfifo_half_full(n) ( REG_SSI_SR(n) & SSI_SR_RFHF ) -+#define __ssi_txfifo_half_empty(n) ( REG_SSI_SR(n) & SSI_SR_TFHE ) -+#define __ssi_underrun(n) ( REG_SSI_SR(n) & SSI_SR_UNDR ) -+#define __ssi_overrun(n) ( REG_SSI_SR(n) & SSI_SR_OVER ) -+#define __ssi_clear_underrun(n) ( REG_SSI_SR(n) = ~SSI_SR_UNDR ) -+#define __ssi_clear_overrun(n) ( REG_SSI_SR(n) = ~SSI_SR_OVER ) -+#define __ssi_clear_errors(n) ( REG_SSI_SR(n) &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) -+ -+#define __ssi_set_clk(n, dev_clk, ssi_clk) \ -+ ( REG_SSI_GR(n) = (dev_clk) / (2*(ssi_clk)) - 1 ) -+ -+#define __ssi_receive_data(n) REG_SSI_DR(n) -+#define __ssi_transmit_data(n, v) (REG_SSI_DR(n) = (v)) -+ -+ -+/*************************************************************************** -+ * CIM -+ ***************************************************************************/ -+ -+#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) -+#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) -+ -+/* n = 0, 1, 2, 3 */ -+#define __cim_set_input_data_stream_order(n) \ -+ do { \ -+ REG_CIM_CFG &= CIM_CFG_ORDER_MASK; \ -+ REG_CIM_CFG |= ((n)<>CIM_SIZE_LPF_BIT) -+#define __cim_get_pixel() ((REG_CIM_SIZE&CIM_SIZE_PPL_MASK)>>CIM_SIZE_PPL_BIT) -+ -+#define __cim_set_v_offset(a) ( REG_CIM_OFFSET = (REG_CIM_OFFSET&(~CIM_OFFSET_V_MASK)) | ((a)<>CIM_OFFSET_V_BIT) -+#define __cim_get_h_offset() ((REG_CIM_OFFSET&CIM_OFFSET_H_MASK)>>CIM_OFFSET_H_BIT) -+ -+/************************************************************************* -+ * SLCD (Smart LCD Controller) -+ *************************************************************************/ -+#define __slcd_set_data_18bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_18BIT ) -+#define __slcd_set_data_16bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_16BIT ) -+#define __slcd_set_data_8bit_x3() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x3 ) -+#define __slcd_set_data_8bit_x2() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x2 ) -+#define __slcd_set_data_8bit_x1() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_8BIT_x1 ) -+#define __slcd_set_data_24bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_24BIT ) -+#define __slcd_set_data_9bit_x2() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_DWIDTH_MASK) | SLCD_CFG_DWIDTH_9BIT_x2 ) -+ -+#define __slcd_set_cmd_16bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_16BIT ) -+#define __slcd_set_cmd_8bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_8BIT ) -+#define __slcd_set_cmd_18bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_18BIT ) -+#define __slcd_set_cmd_24bit() \ -+ ( REG_SLCD_CFG = (REG_SLCD_CFG & ~SLCD_CFG_CWIDTH_MASK) | SLCD_CFG_CWIDTH_24BIT ) -+ -+#define __slcd_set_cs_high() ( REG_SLCD_CFG |= SLCD_CFG_CS_ACTIVE_HIGH ) -+#define __slcd_set_cs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_CS_ACTIVE_HIGH ) -+ -+#define __slcd_set_rs_high() ( REG_SLCD_CFG |= SLCD_CFG_RS_CMD_HIGH ) -+#define __slcd_set_rs_low() ( REG_SLCD_CFG &= ~SLCD_CFG_RS_CMD_HIGH ) -+ -+#define __slcd_set_clk_falling() ( REG_SLCD_CFG &= ~SLCD_CFG_CLK_ACTIVE_RISING ) -+#define __slcd_set_clk_rising() ( REG_SLCD_CFG |= SLCD_CFG_CLK_ACTIVE_RISING ) -+ -+#define __slcd_set_parallel_type() ( REG_SLCD_CFG &= ~SLCD_CFG_TYPE_SERIAL ) -+#define __slcd_set_serial_type() ( REG_SLCD_CFG |= SLCD_CFG_TYPE_SERIAL ) -+ -+/* SLCD Control Register */ -+#define __slcd_enable_dma() ( REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN ) -+#define __slcd_disable_dma() ( REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN ) -+ -+/* SLCD Status Register */ -+#define __slcd_is_busy() ( REG_SLCD_STATE & SLCD_STATE_BUSY ) -+ -+/* SLCD Data Register */ -+#define __slcd_set_cmd_rs() ( REG_SLCD_DATA |= SLCD_DATA_RS_COMMAND) -+#define __slcd_set_data_rs() ( REG_SLCD_DATA &= ~SLCD_DATA_RS_COMMAND) -+ -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+ -+/*************************************************************************** -+ * LCD -+ ***************************************************************************/ -+#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= ( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) -+#define __lcd_as_general_lcd() ( REG_LCD_CFG &= ~( LCD_CFG_LCDPIN_SLCD | LCD_CFG_MODE_SLCD)) -+ -+#define __lcd_enable_tvepeh() ( REG_LCD_CFG |= LCD_CFG_TVEPEH ) -+#define __lcd_disable_tvepeh() ( REG_LCD_CFG &= ~LCD_CFG_TVEPEH ) -+ -+#define __lcd_enable_fuhold() ( REG_LCD_CFG |= LCD_CFG_FUHOLD ) -+#define __lcd_disable_fuhold() ( REG_LCD_CFG &= ~LCD_CFG_FUHOLD ) -+ -+#define __lcd_des_8word() ( REG_LCD_CFG |= LCD_CFG_NEWDES ) -+#define __lcd_des_4word() ( REG_LCD_CFG &= ~LCD_CFG_NEWDES ) -+ -+#define __lcd_enable_bypass_pal() ( REG_LCD_CFG |= LCD_CFG_PALBP ) -+#define __lcd_disable_bypass_pal() ( REG_LCD_CFG &= ~LCD_CFG_PALBP ) -+ -+#define __lcd_set_lcdpnl_term() ( REG_LCD_CTRL |= LCD_CFG_TVEN ) -+#define __lcd_set_tv_term() ( REG_LCD_CTRL &= ~LCD_CFG_TVEN ) -+ -+#define __lcd_enable_auto_recover() ( REG_LCD_CFG |= LCD_CFG_RECOVER ) -+#define __lcd_disable_auto_recover() ( REG_LCD_CFG &= ~LCD_CFG_RECOVER ) -+ -+#define __lcd_enable_dither() ( REG_LCD_CFG |= LCD_CFG_DITHER ) -+#define __lcd_disable_dither() ( REG_LCD_CFG &= ~LCD_CFG_DITHER ) -+ -+#define __lcd_disable_ps_mode() ( REG_LCD_CFG |= LCD_CFG_PSM ) -+#define __lcd_enable_ps_mode() ( REG_LCD_CFG &= ~LCD_CFG_PSM ) -+ -+#define __lcd_disable_cls_mode() ( REG_LCD_CFG |= LCD_CFG_CLSM ) -+#define __lcd_enable_cls_mode() ( REG_LCD_CFG &= ~LCD_CFG_CLSM ) -+ -+#define __lcd_disable_spl_mode() ( REG_LCD_CFG |= LCD_CFG_SPLM ) -+#define __lcd_enable_spl_mode() ( REG_LCD_CFG &= ~LCD_CFG_SPLM ) -+ -+#define __lcd_disable_rev_mode() ( REG_LCD_CFG |= LCD_CFG_REVM ) -+#define __lcd_enable_rev_mode() ( REG_LCD_CFG &= ~LCD_CFG_REVM ) -+ -+#define __lcd_disable_hsync_mode() ( REG_LCD_CFG |= LCD_CFG_HSYNM ) -+#define __lcd_enable_hsync_mode() ( REG_LCD_CFG &= ~LCD_CFG_HSYNM ) -+ -+#define __lcd_disable_pclk_mode() ( REG_LCD_CFG |= LCD_CFG_PCLKM ) -+#define __lcd_enable_pclk_mode() ( REG_LCD_CFG &= ~LCD_CFG_PCLKM ) -+ -+#define __lcd_normal_outdata() ( REG_LCD_CFG &= ~LCD_CFG_INVDAT ) -+#define __lcd_inverse_outdata() ( REG_LCD_CFG |= LCD_CFG_INVDAT ) -+ -+#define __lcd_sync_input() ( REG_LCD_CFG |= LCD_CFG_SYNDIR_IN ) -+#define __lcd_sync_output() ( REG_LCD_CFG &= ~LCD_CFG_SYNDIR_IN ) -+ -+#define __lcd_hsync_active_high() ( REG_LCD_CFG &= ~LCD_CFG_HSP ) -+#define __lcd_hsync_active_low() ( REG_LCD_CFG |= LCD_CFG_HSP ) -+ -+#define __lcd_pclk_rising() ( REG_LCD_CFG &= ~LCD_CFG_PCP ) -+#define __lcd_pclk_falling() ( REG_LCD_CFG |= LCD_CFG_PCP ) -+ -+#define __lcd_de_active_high() ( REG_LCD_CFG &= ~LCD_CFG_DEP ) -+#define __lcd_de_active_low() ( REG_LCD_CFG |= LCD_CFG_DEP ) -+ -+#define __lcd_vsync_rising() ( REG_LCD_CFG &= ~LCD_CFG_VSP ) -+#define __lcd_vsync_falling() ( REG_LCD_CFG |= LCD_CFG_VSP ) -+ -+#define __lcd_set_16_tftpnl() \ -+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_16BIT ) -+ -+#define __lcd_set_18_tftpnl() \ -+ ( REG_LCD_CFG = (REG_LCD_CFG & ~LCD_CFG_MODE_TFT_MASK) | LCD_CFG_MODE_TFT_18BIT ) -+ -+#define __lcd_set_24_tftpnl() ( REG_LCD_CFG |= LCD_CFG_MODE_TFT_24BIT ) -+ -+/* -+ * n=1,2,4,8 for single mono-STN -+ * n=4,8 for dual mono-STN -+ */ -+#define __lcd_set_panel_datawidth(n) \ -+do { \ -+ REG_LCD_CFG &= ~LCD_CFG_PDW_MASK; \ -+ REG_LCD_CFG |= LCD_CFG_PDW_n##; \ -+} while (0) -+ -+/* m = LCD_CFG_MODE_GENERUIC_TFT_xxx */ -+#define __lcd_set_panel_mode(m) \ -+do { \ -+ REG_LCD_CFG &= ~LCD_CFG_MODE_MASK; \ -+ REG_LCD_CFG |= (m); \ -+} while(0) -+ -+/* n=4,8,16 */ -+#define __lcd_set_burst_length(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_BST_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_BST_n##; \ -+} while (0) -+ -+#define __lcd_select_rgb565() ( REG_LCD_CTRL &= ~LCD_CTRL_RGB555 ) -+#define __lcd_select_rgb555() ( REG_LCD_CTRL |= LCD_CTRL_RGB555 ) -+ -+#define __lcd_set_ofup() ( REG_LCD_CTRL |= LCD_CTRL_OFUP ) -+#define __lcd_clr_ofup() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUP ) -+ -+/* n=2,4,16 */ -+#define __lcd_set_stn_frc(n) \ -+do { \ -+ REG_LCD_CTRL &= ~LCD_CTRL_FRC_MASK; \ -+ REG_LCD_CTRL |= LCD_CTRL_FRC_n##; \ -+} while (0) -+ -+#define __lcd_enable_eof_intr() ( REG_LCD_CTRL |= LCD_CTRL_EOFM ) -+#define __lcd_disable_eof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_EOFM ) -+ -+#define __lcd_enable_sof_intr() ( REG_LCD_CTRL |= LCD_CTRL_SOFM ) -+#define __lcd_disable_sof_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_SOFM ) -+ -+#define __lcd_enable_ofu_intr() ( REG_LCD_CTRL |= LCD_CTRL_OFUM ) -+#define __lcd_disable_ofu_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_OFUM ) -+ -+#define __lcd_enable_ifu0_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM0 ) -+#define __lcd_disable_ifu0_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM0 ) -+ -+#define __lcd_enable_ifu1_intr() ( REG_LCD_CTRL |= LCD_CTRL_IFUM1 ) -+#define __lcd_disable_ifu1_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_IFUM1 ) -+ -+#define __lcd_enable_ldd_intr() ( REG_LCD_CTRL |= LCD_CTRL_LDDM ) -+#define __lcd_disable_ldd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_LDDM ) -+ -+#define __lcd_enable_qd_intr() ( REG_LCD_CTRL |= LCD_CTRL_QDM ) -+#define __lcd_disable_qd_intr() ( REG_LCD_CTRL &= ~LCD_CTRL_QDM ) -+ -+#define __lcd_reverse_byte_endian() ( REG_LCD_CTRL |= LCD_CTRL_BEDN ) -+#define __lcd_normal_byte_endian() ( REG_LCD_CTRL &= ~LCD_CTRL_BEDN ) -+ -+#define __lcd_pixel_endian_little() ( REG_LCD_CTRL |= LCD_CTRL_PEDN ) -+#define __lcd_pixel_endian_big() ( REG_LCD_CTRL &= ~LCD_CTRL_PEDN ) -+ -+#define __lcd_set_dis() ( REG_LCD_CTRL |= LCD_CTRL_DIS ) -+#define __lcd_clr_dis() ( REG_LCD_CTRL &= ~LCD_CTRL_DIS ) -+ -+#define __lcd_set_ena() ( REG_LCD_CTRL |= LCD_CTRL_ENA ) -+#define __lcd_clr_ena() ( REG_LCD_CTRL &= ~LCD_CTRL_ENA ) -+ -+/* n=1,2,4,8,16 */ -+#define __lcd_set_bpp(n) \ -+ ( REG_LCD_CTRL = (REG_LCD_CTRL & ~LCD_CTRL_BPP_MASK) | LCD_CTRL_BPP_##n ) -+ -+/* LCD status register indication */ -+ -+#define __lcd_quick_disable_done() ( REG_LCD_STATE & LCD_STATE_QD ) -+#define __lcd_disable_done() ( REG_LCD_STATE & LCD_STATE_LDD ) -+#define __lcd_infifo0_underrun() ( REG_LCD_STATE & LCD_STATE_IFU0 ) -+#define __lcd_infifo1_underrun() ( REG_LCD_STATE & LCD_STATE_IFU1 ) -+#define __lcd_outfifo_underrun() ( REG_LCD_STATE & LCD_STATE_OFU ) -+#define __lcd_start_of_frame() ( REG_LCD_STATE & LCD_STATE_SOF ) -+#define __lcd_end_of_frame() ( REG_LCD_STATE & LCD_STATE_EOF ) -+ -+#define __lcd_clr_outfifounderrun() ( REG_LCD_STATE &= ~LCD_STATE_OFU ) -+#define __lcd_clr_sof() ( REG_LCD_STATE &= ~LCD_STATE_SOF ) -+#define __lcd_clr_eof() ( REG_LCD_STATE &= ~LCD_STATE_EOF ) -+ -+/* OSD functions */ -+#define __lcd_enable_osd() (REG_LCD_OSDC |= LCD_OSDC_OSDEN) -+#define __lcd_enable_f0() (REG_LCD_OSDC |= LCD_OSDC_F0EN) -+#define __lcd_enable_f1() (REG_LCD_OSDC |= LCD_OSDC_F1EN) -+#define __lcd_enable_alpha() (REG_LCD_OSDC |= LCD_OSDC_ALPHAEN) -+#define __lcd_enable_alphamd() (REG_LCD_OSDC |= LCD_OSDC_ALPHAMD) -+ -+#define __lcd_disable_osd() (REG_LCD_OSDC &= ~LCD_OSDC_OSDEN) -+#define __lcd_disable_f0() (REG_LCD_OSDC &= ~LCD_OSDC_F0EN) -+#define __lcd_disable_f1() (REG_LCD_OSDC &= ~LCD_OSDC_F1EN) -+#define __lcd_disable_alpha() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAEN) -+#define __lcd_disable_alphamd() (REG_LCD_OSDC &= ~LCD_OSDC_ALPHAMD) -+ -+/* OSD Controll Register */ -+#define __lcd_fg1_use_ipu() (REG_LCD_OSDCTRL |= LCD_OSDCTRL_IPU) -+#define __lcd_fg1_use_dma_chan1() (REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_IPU) -+#define __lcd_fg1_unuse_ipu() __lcd_fg1_use_dma_chan1() -+#define __lcd_osd_rgb555_mode() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_RGB555 ) -+#define __lcd_osd_rgb565_mode() ( REG_LCD_OSDCTRL &= ~LCD_OSDCTRL_RGB555 ) -+#define __lcd_osd_change_size() ( REG_LCD_OSDCTRL |= LCD_OSDCTRL_CHANGES ) -+#define __lcd_osd_bpp_15_16() \ -+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_15_16 ) -+#define __lcd_osd_bpp_18_24() \ -+ ( REG_LCD_OSDCTRL = (REG_LCD_OSDCTRL & ~LCD_OSDCTRL_OSDBPP_MASK) | LCD_OSDCTRL_OSDBPP_18_24 ) -+ -+/* OSD State Register */ -+#define __lcd_start_of_fg1() ( REG_LCD_STATE & LCD_OSDS_SOF1 ) -+#define __lcd_end_of_fg1() ( REG_LCD_STATE & LCD_OSDS_EOF1 ) -+#define __lcd_start_of_fg0() ( REG_LCD_STATE & LCD_OSDS_SOF0 ) -+#define __lcd_end_of_fg0() ( REG_LCD_STATE & LCD_OSDS_EOF0 ) -+#define __lcd_change_is_rdy() ( REG_LCD_STATE & LCD_OSDS_READY ) -+ -+/* Foreground Color Key Register 0,1(foreground 0, foreground 1) */ -+#define __lcd_enable_colorkey0() (REG_LCD_KEY0 |= LCD_KEY_KEYEN) -+#define __lcd_enable_colorkey1() (REG_LCD_KEY1 |= LCD_KEY_KEYEN) -+#define __lcd_enable_colorkey0_md() (REG_LCD_KEY0 |= LCD_KEY_KEYMD) -+#define __lcd_enable_colorkey1_md() (REG_LCD_KEY1 |= LCD_KEY_KEYMD) -+#define __lcd_set_colorkey0(key) (REG_LCD_KEY0 = (REG_LCD_KEY0&~0xFFFFFF)|(key)) -+#define __lcd_set_colorkey1(key) (REG_LCD_KEY1 = (REG_LCD_KEY1&~0xFFFFFF)|(key)) -+ -+#define __lcd_disable_colorkey0() (REG_LCD_KEY0 &= ~LCD_KEY_KEYEN) -+#define __lcd_disable_colorkey1() (REG_LCD_KEY1 &= ~LCD_KEY_KEYEN) -+#define __lcd_disable_colorkey0_md() (REG_LCD_KEY0 &= ~LCD_KEY_KEYMD) -+#define __lcd_disable_colorkey1_md() (REG_LCD_KEY1 &= ~LCD_KEY_KEYMD) -+ -+/* IPU Restart Register */ -+#define __lcd_enable_ipu_restart() (REG_LCD_IPUR |= LCD_IPUR_IPUREN) -+#define __lcd_disable_ipu_restart() (REG_LCD_IPUR &= ~LCD_IPUR_IPUREN) -+#define __lcd_set_ipu_restart_triger(n) (REG_LCD_IPUR = (REG_LCD_IPUR&(~0xFFFFFF))|(n)) -+ -+/* RGB Control Register */ -+#define __lcd_enable_rgb_dummy() (REG_LCD_RGBC |= LCD_RGBC_RGBDM) -+#define __lcd_disable_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_RGBDM) -+ -+#define __lcd_dummy_rgb() (REG_LCD_RGBC |= LCD_RGBC_DMM) -+#define __lcd_rgb_dummy() (REG_LCD_RGBC &= ~LCD_RGBC_DMM) -+ -+#define __lcd_rgb2ycc() (REG_LCD_RGBC |= LCD_RGBC_YCC) -+#define __lcd_notrgb2ycc() (REG_LCD_RGBC &= ~LCD_RGBC_YCC) -+ -+#define __lcd_odd_mode_rgb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RGB ) -+#define __lcd_odd_mode_rbg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_RBG ) -+#define __lcd_odd_mode_grb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GRB) -+ -+#define __lcd_odd_mode_gbr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_GBR) -+#define __lcd_odd_mode_brg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BRG) -+#define __lcd_odd_mode_bgr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_ODDRGB_MASK) | LCD_RGBC_ODD_BGR) -+ -+#define __lcd_even_mode_rgb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RGB ) -+#define __lcd_even_mode_rbg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_RBG ) -+#define __lcd_even_mode_grb() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GRB) -+ -+#define __lcd_even_mode_gbr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_GBR) -+#define __lcd_even_mode_brg() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BRG) -+#define __lcd_even_mode_bgr() \ -+ ( REG_LCD_RGBC = (REG_LCD_RGBC & ~LCD_RGBC_EVENRGB_MASK) | LCD_RGBC_EVEN_BGR) -+ -+/* Vertical Synchronize Register */ -+#define __lcd_vsync_get_vps() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPS_MASK) >> LCD_VSYNC_VPS_BIT ) -+ -+#define __lcd_vsync_get_vpe() \ -+ ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) -+#define __lcd_vsync_set_vpe(n) \ -+do { \ -+ REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ -+ REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hps() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) -+#define __lcd_hsync_set_hps(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ -+} while (0) -+ -+#define __lcd_hsync_get_hpe() \ -+ ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) -+#define __lcd_hsync_set_hpe(n) \ -+do { \ -+ REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ -+ REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_ht() \ -+ ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) -+#define __lcd_vat_set_ht(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ -+} while (0) -+ -+#define __lcd_vat_get_vt() \ -+ ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) -+#define __lcd_vat_set_vt(n) \ -+do { \ -+ REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ -+ REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hds() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) -+#define __lcd_dah_set_hds(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ -+} while (0) -+ -+#define __lcd_dah_get_hde() \ -+ ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) -+#define __lcd_dah_set_hde(n) \ -+do { \ -+ REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ -+ REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vds() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) -+#define __lcd_dav_set_vds(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ -+} while (0) -+ -+#define __lcd_dav_get_vde() \ -+ ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) -+#define __lcd_dav_set_vde(n) \ -+do { \ -+ REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ -+ REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ -+} while (0) -+ -+/* DMA Command Register */ -+#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) -+#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) -+#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) -+ -+#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) -+#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) -+#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) -+ -+#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) -+#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) -+ -+#define __lcd_cmd0_get_len() \ -+ ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+#define __lcd_cmd1_get_len() \ -+ ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) -+ -+/************************************************************************* -+ * TVE (TV Encoder Controller) ops -+ *************************************************************************/ -+/* TV Encoder Control register ops */ -+#define __tve_soft_reset() (REG_TVE_CTRL |= TVE_CTRL_SWRST) -+ -+#define __tve_output_colorbar() (REG_TVE_CTRL |= TVE_CTRL_CLBAR) -+#define __tve_output_video() (REG_TVE_CTRL &= ~TVE_CTRL_CLBAR) -+ -+#define __tve_input_cr_first() (REG_TVE_CTRL |= TVE_CTRL_CR1ST) -+#define __tve_input_cb_first() (REG_TVE_CTRL &= ~TVE_CTRL_CR1ST) -+ -+#define __tve_set_0_as_black() (REG_TVE_CTRL |= TVE_CTRL_ZBLACK) -+#define __tve_set_16_as_black() (REG_TVE_CTRL &= ~TVE_CTRL_ZBLACK) -+ -+#define __tve_ena_invert_top_bottom() (REG_TVE_CTRL |= TVE_CTRL_FINV) -+#define __tve_dis_invert_top_bottom() (REG_TVE_CTRL &= ~TVE_CTRL_FINV) -+ -+#define __tve_set_pal_mode() (REG_TVE_CTRL |= TVE_CTRL_PAL) -+#define __tve_set_ntsc_mode() (REG_TVE_CTRL &= ~TVE_CTRL_PAL) -+ -+#define __tve_set_pal_dura() (REG_TVE_CTRL |= TVE_CTRL_SYNCT) -+#define __tve_set_ntsc_dura() (REG_TVE_CTRL &= ~TVE_CTRL_SYNCT) -+ -+/* n = 0 ~ 3 */ -+#define __tve_set_c_bandwidth(n) \ -+do {\ -+ REG_TVE_CTRL &= ~TVE_CTRL_CBW_MASK;\ -+ REG_TVE_CTRL |= (n) << TVE_CTRL_CBW_BIT; \ -+}while(0) -+ -+/* n = 0 ~ 3 */ -+#define __tve_set_c_gain(n) \ -+do {\ -+ REG_TVE_CTRL &= ~TVE_CTRL_CGAIN_MASK;\ -+ (REG_TVE_CTRL |= (n) << TVE_CTRL_CGAIN_BIT; \ -+}while(0) -+ -+/* n = 0 ~ 7 */ -+#define __tve_set_yc_delay(n) \ -+do { \ -+ REG_TVE_CTRL &= ~TVE_CTRL_YCDLY_MASK \ -+ REG_TVE_CTRL |= ((n) << TVE_CTRL_YCDLY_BIT); \ -+} while(0) -+ -+#define __tve_disable_all_dacs() (REG_TVE_CTRL |= TVE_CTRL_DAPD) -+#define __tve_disable_dac1() (REG_TVE_CTRL |= TVE_CTRL_DAPD1) -+#define __tve_enable_dac1() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD1) -+#define __tve_disable_dac2() (REG_TVE_CTRL |= TVE_CTRL_DAPD2) -+#define __tve_enable_dac2() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD2) -+#define __tve_disable_dac3() (REG_TVE_CTRL |= TVE_CTRL_DAPD3) -+#define __tve_enable_dac3() (REG_TVE_CTRL &= ~TVE_CTRL_DAPD3) -+ -+#define __tve_enable_svideo_fmt() (REG_TVE_CTRL |= TVE_CTRL_ECVBS) -+#define __tve_enable_cvbs_fmt() (REG_TVE_CTRL &= ~TVE_CTRL_ECVBS) -+ -+/* TV Encoder Frame Configure register ops */ -+/* n = 0 ~ 255 */ -+#define __tve_set_first_video_line(n) \ -+do {\ -+ REG_TVE_FRCFG &= ~TVE_FRCFG_L1ST_MASK;\ -+ REG_TVE_FRCFG |= (n) << TVE_FRCFG_L1ST_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_line_num_per_frm(n) \ -+do {\ -+ REG_TVE_FRCFG &= ~TVE_FRCFG_NLINE_MASK;\ -+ REG_TVE_CFG |= (n) << TVE_FRCFG_NLINE_BIT;\ -+} while(0) -+#define __tve_get_video_line_num()\ -+ (((REG_TVE_FRCFG & TVE_FRCFG_NLINE_MASK) >> TVE_FRCFG_NLINE_BIT) - 1 - 2 * ((REG_TVE_FRCFG & TVE_FRCFG_L1ST_MASK) >> TVE_FRCFG_L1ST_BIT)) -+ -+/* TV Encoder Signal Level Configure register ops */ -+/* n = 0 ~ 1023 */ -+#define __tve_set_white_level(n) \ -+do {\ -+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_WHITEL_MASK;\ -+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_WHITEL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_black_level(n) \ -+do {\ -+ REG_TVE_SLCFG1 &= ~TVE_SLCFG1_BLACKL_MASK;\ -+ REG_TVE_SLCFG1 |= (n) << TVE_SLCFG1_BLACKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_blank_level(n) \ -+do {\ -+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_BLANKL_MASK;\ -+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_BLANKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_vbi_blank_level(n) \ -+do {\ -+ REG_TVE_SLCFG2 &= ~TVE_SLCFG2_VBLANKL_MASK;\ -+ REG_TVE_SLCFG2 |= (n) << TVE_SLCFG2_VBLANKL_BIT;\ -+} while(0) -+/* n = 0 ~ 1023 */ -+#define __tve_set_sync_level(n) \ -+do {\ -+ REG_TVE_SLCFG3 &= ~TVE_SLCFG3_SYNCL_MASK;\ -+ REG_TVE_SLCFG3 |= (n) << TVE_SLCFG3_SYNCL_BIT;\ -+} while(0) -+ -+/* TV Encoder Signal Level Configure register ops */ -+/* n = 0 ~ 31 */ -+#define __tve_set_front_porch(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_FRONTP_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_FRONTP_BIT; \ -+} while(0) -+/* n = 0 ~ 127 */ -+#define __tve_set_hsync_width(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_HSYNCW_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_HSYNCW_BIT; \ -+} while(0) -+/* n = 0 ~ 127 */ -+#define __tve_set_back_porch(n) \ -+do {\ -+ REG_TVE_LTCFG1 &= ~TVE_LTCFG1_BACKP_MASK;\ -+ REG_TVE_LTCFG1 |= (n) << TVE_LTCFG1_BACKP_BIT; \ -+} while(0) -+/* n = 0 ~ 2047 */ -+#define __tve_set_active_linec(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_ACTLIN_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_ACTLIN_BIT; \ -+} while(0) -+/* n = 0 ~ 31 */ -+#define __tve_set_breezy_way(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_PREBW_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_PREBW_BIT; \ -+} while(0) -+ -+/* n = 0 ~ 127 */ -+#define __tve_set_burst_width(n) \ -+do {\ -+ REG_TVE_LTCFG2 &= ~TVE_LTCFG2_BURSTW_MASK;\ -+ REG_TVE_LTCFG2 |= (n) << TVE_LTCFG2_BURSTW_BIT; \ -+} while(0) -+ -+/* TV Encoder Chrominance filter and Modulation register ops */ -+/* n = 0 ~ (2^32-1) */ -+#define __tve_set_c_sub_carrier_freq(n) REG_TVE_CFREQ = (n) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_sub_carrier_init_phase(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_INITPH_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_INITPH_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_sub_carrier_act_phase(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_ACTPH_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_ACTPH_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_c_phase_rst_period(n) \ -+do { \ -+ REG_TVE_CPHASE &= ~TVE_CPHASE_CCRSTP_MASK; \ -+ REG_TVE_CPHASE |= (n) << TVE_CPHASE_CCRSTP_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cb_burst_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBBA_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBBA_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cr_burst_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRBA_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRBA_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cb_gain_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CBGAIN_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CBGAIN_BIT; \ -+} while(0) -+/* n = 0 ~ 255 */ -+#define __tve_set_cr_gain_amp(n) \ -+do { \ -+ REG_TVE_CBCRCFG &= ~TVE_CBCRCFG_CRGAIN_MASK; \ -+ REG_TVE_CBCRCFG |= (n) << TVE_CBCRCFG_CRGAIN_BIT; \ -+} while(0) -+ -+/* TV Encoder Wide Screen Signal Control register ops */ -+/* n = 0 ~ 7 */ -+#define __tve_set_notch_freq(n) \ -+do { \ -+ REG_TVE_WSSCR &= ~TVE_WSSCR_NCHFREQ_MASK; \ -+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_NCHFREQ_BIT; \ -+} while(0) -+/* n = 0 ~ 7 */ -+#define __tve_set_notch_width() (REG_TVE_WSSCR |= TVE_WSSCR_NCHW_BIT) -+#define __tve_clear_notch_width() (REG_TVE_WSSCR &= ~TVE_WSSCR_NCHW_BIT) -+#define __tve_enable_notch() (REG_TVE_WSSCR |= TVE_WSSCR_ENCH_BIT) -+#define __tve_disable_notch() (REG_TVE_WSSCR &= ~TVE_WSSCR_ENCH_BIT) -+/* n = 0 ~ 7 */ -+#define __tve_set_wss_edge(n) \ -+do { \ -+ REG_TVE_WSSCR &= ~TVE_WSSCR_WSSEDGE_MASK; \ -+ REG_TVE_WSSCR |= (n) << TVE_WSSCR_WSSEDGE_BIT; \ -+} while(0) -+#define __tve_set_wss_clkbyp() (REG_TVE_WSSCR |= TVE_WSSCR_WSSCKBP_BIT) -+#define __tve_set_wss_type() (REG_TVE_WSSCR |= TVE_WSSCR_WSSTP_BIT) -+#define __tve_enable_wssf1() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS1_BIT) -+#define __tve_enable_wssf0() (REG_TVE_WSSCR |= TVE_WSSCR_EWSS0_BIT) -+ -+/* TV Encoder Wide Screen Signal Configure register 1, 2 and 3 ops */ -+/* n = 0 ~ 1023 */ -+#define __tve_set_wss_level(n) \ -+do { \ -+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSL_MASK; \ -+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSL_BIT; \ -+} while(0) -+/* n = 0 ~ 4095 */ -+#define __tve_set_wss_freq(n) \ -+do { \ -+ REG_TVE_WSSCFG1 &= ~TVE_WSSCFG1_WSSFREQ_MASK; \ -+ REG_TVE_WSSCFG1 |= (n) << TVE_WSSCFG1_WSSFREQ_BIT; \ -+} while(0) -+/* n = 0, 1; l = 0 ~ 255 */ -+#define __tve_set_wss_line(n,v) \ -+do { \ -+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ -+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ -+} while(0) -+/* n = 0, 1; d = 0 ~ (2^20-1) */ -+#define __tve_set_wss_data(n, v) \ -+do { \ -+ REG_TVE_WSSCFG##n &= ~TVE_WSSCFG_WSSLINE_MASK; \ -+ REG_TVE_WSSCFG##n |= (v) << TVE_WSSCFG_WSSLINE_BIT; \ -+} while(0) -+ -+/*************************************************************************** -+ * RTC ops -+ ***************************************************************************/ -+ -+#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) -+#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) -+#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) -+#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) -+#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) -+#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) -+#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) -+#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) -+#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) -+ -+#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) -+#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) -+#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) -+#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) -+ -+#define __rtc_get_second() ( REG_RTC_RSR ) -+#define __rtc_set_second(v) ( REG_RTC_RSR = v ) -+ -+#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) -+#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) -+ -+#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) -+#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) -+#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) -+#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) -+#define __rtc_set_adjc_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) -+#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) -+#define __rtc_set_nc1Hz_val(v) \ -+ ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) -+ -+#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) -+ -+#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) -+#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) -+#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) -+#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) -+ -+#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) -+#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) -+ -+#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) -+#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) -+#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) -+#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) -+#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) -+ -+#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) -+#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) -+ -+/************************************************************************* -+ * BCH -+ *************************************************************************/ -+#define __ecc_encoding_4bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_BSEL8; \ -+} while(0) -+#define __ecc_decoding_4bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_ENCE | BCH_CR_BSEL8; \ -+} while(0) -+#define __ecc_encoding_8bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_ENCE | BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ -+} while(0) -+#define __ecc_decoding_8bit() \ -+do { \ -+ REG_BCH_CRS = BCH_CR_BRST | BCH_CR_BSEL8 | BCH_CR_BCHE; \ -+ REG_BCH_CRC = BCH_CR_ENCE; \ -+} while(0) -+#define __ecc_dma_enable() ( REG_BCH_CRS = BCH_CR_DMAE ) -+#define __ecc_disable() ( REG_BCH_CRC = BCH_CR_BCHE ) -+#define __ecc_encode_sync() while (!(REG_BCH_INTS & BCH_INTS_ENCF)) -+#define __ecc_decode_sync() while (!(REG_BCH_INTS & BCH_INTS_DECF)) -+#define __ecc_cnt_dec(n) \ -+do { \ -+ REG_BCH_CNT &= ~(BCH_CNT_DEC_MASK << BCH_CNT_DEC_BIT); \ -+ REG_BCH_CNT = (n) << BCH_CNT_DEC_BIT; \ -+} while(0) -+#define __ecc_cnt_enc(n) \ -+do { \ -+ REG_BCH_CNT &= ~(BCH_CNT_ENC_MASK << BCH_CNT_ENC_BIT); \ -+ REG_BCH_CNT = (n) << BCH_CNT_ENC_BIT; \ -+} while(0) -+ -+/*************************************************************************** -+ * OWI (one-wire bus) ops -+ ***************************************************************************/ -+ -+/* OW control register ops */ -+#define __owi_enable_all_interrupts() ( REG_OWI_CTL = (OWI_CTL_EBYTE | OWI_CTL_EBIT | OWI_CTL_ERST) ) -+#define __owi_disable_all_interrupts() ( REG_OWI_CTL = 0 ) -+ -+#define __owi_enable_byte_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBYTE ) -+#define __owi_disable_byte_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBYTE ) -+#define __owi_enable_bit_interrupt() ( REG_OWI_CTL |= OWI_CTL_EBIT ) -+#define __owi_disable_bit_interrupt() ( REG_OWI_CTL &= ~OWI_CTL_EBIT ) -+#define __owi_enable_rst_interrupt() ( REG_OWI_CTL |= OWI_CTL_ERST ) -+#define __owi_disable_rst_interrupt() ( REG_OWI_CTL &=~OWI_CTL_ERST ) -+ -+/* OW configure register ops */ -+#define __owi_select_regular_mode() ( REG_OWI_CFG &= ~OWI_CFG_MODE ) -+#define __owi_select_overdrive_mode() ( REG_OWI_CFG |= OWI_CFG_MODE ) -+ -+#define __owi_set_rddata() ( REG_OWI_CFG |= OWI_CFG_RDDATA ) -+#define __owi_clr_rddata() ( REG_OWI_CFG &= ~OWI_CFG_RDDATA ) -+#define __owi_get_rddata() ( REG_OWI_CFG & OWI_CFG_RDDATA ) -+ -+#define __owi_set_wrdata() ( REG_OWI_CFG |= OWI_CFG_WRDATA ) -+#define __owi_clr_wrdata() ( REG_OWI_CFG &= ~OWI_CFG_WRDATA ) -+#define __owi_get_wrdata() ( REG_OWI_CFG & OWI_CFG_WRDATA ) -+ -+#define __owi_get_rdst() ( REG_OWI_CFG & OWI_CFG_RDST ) -+ -+#define __owi_set_wr1rd() ( REG_OWI_CFG |= OWI_CFG_WR1RD ) -+#define __owi_clr_wr1rd() ( REG_OWI_CFG &= ~OWI_CFG_WR1RD ) -+#define __owi_get_wr1rd() ( REG_OWI_CFG & OWI_CFG_WR1RD ) -+ -+#define __owi_set_wr0() ( REG_OWI_CFG |= OWI_CFG_WR0 ) -+#define __owi_clr_wr0() ( REG_OWI_CFG &= ~OWI_CFG_WR0 ) -+#define __owi_get_wr0() ( REG_OWI_CFG & OWI_CFG_WR0 ) -+ -+#define __owi_set_rst() ( REG_OWI_CFG |= OWI_CFG_RST ) -+#define __owi_clr_rst() ( REG_OWI_CFG &= ~OWI_CFG_RST ) -+#define __owi_get_rst() ( REG_OWI_CFG & OWI_CFG_RST ) -+ -+#define __owi_enable_ow_ops() ( REG_OWI_CFG |= OWI_CFG_ENA ) -+#define __owi_disable_ow_ops() ( REG_OWI_CFG &= ~OWI_CFG_ENA ) -+#define __owi_get_enable() ( REG_OWI_CFG & OWI_CFG_ENA ) -+ -+#define __owi_wait_ops_rdy() \ -+ do { \ -+ while(__owi_get_enable()); \ -+ udelay(1); \ -+ } while(0); -+ -+/* OW status register ops */ -+#define __owi_clr_sts() ( REG_OWI_STS = 0 ) -+#define __owi_get_sts_pst() ( REG_OWI_STS & OWI_STS_PST ) -+#define __owi_get_sts_byte_rdy() ( REG_OWI_STS & OWI_STS_BYTE_RDY ) -+#define __owi_get_sts_bit_rdy() ( REG_OWI_STS & OWI_STS_BIT_RDY ) -+#define __owi_get_sts_pst_rdy() ( REG_OWI_STS & OWI_STS_PST_RDY ) -+ -+/************************************************************************* -+ * TSSI MPEG 2-TS slave interface operation -+ *************************************************************************/ -+#define __tssi_enable() ( REG_TSSI_ENA |= TSSI_ENA_ENA ) -+#define __tssi_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_ENA ) -+#define __tssi_soft_reset() ( REG_TSSI_ENA |= TSSI_ENA_SFT_RST ) -+#define __tssi_dma_enable() ( REG_TSSI_ENA |= TSSI_ENA_DMA_EN ) -+#define __tssi_dma_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_DMA_EN ) -+#define __tssi_filter_enable() ( REG_TSSI_ENA |= TSSI_ENA_PID_EN ) -+#define __tssi_filter_disable() ( REG_TSSI_ENA &= ~TSSI_ENA_PID_EN ) -+ -+/* n = 4, 8, 16 */ -+#define __tssi_set_tigger_num(n) \ -+ do { \ -+ REG_TSSI_CFG &= ~TSSI_CFG_TRIG_MASK; \ -+ REG_TSSI_CFG |= TSSI_CFG_TRIG_##n; \ -+ } while (0) -+ -+#define __tssi_set_wd_1() ( REG_TSSI_CFG |= TSSI_CFG_END_WD ) -+#define __tssi_set_wd_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_WD ) -+ -+#define __tssi_set_bt_1() ( REG_TSSI_CFG |= TSSI_CFG_END_BD ) -+#define __tssi_set_bt_0() ( REG_TSSI_CFG &= ~TSSI_CFG_END_BD ) -+ -+#define __tssi_set_data_pola_high() ( REG_TSSI_CFG |= TSSI_CFG_TSDI_H ) -+#define __tssi_set_data_pola_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSDI_H ) -+ -+#define __tssi_set_data_use_data0() ( REG_TSSI_CFG |= TSSI_CFG_USE_0 ) -+#define __tssi_set_data_use_data7() ( REG_TSSI_CFG &= ~TSSI_CFG_USE_0 ) -+ -+#define __tssi_select_clk_fast() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_CH ) -+#define __tssi_select_clk_slow() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_CH ) -+ -+#define __tssi_select_serail_mode() ( REG_TSSI_CFG &= ~TSSI_CFG_PARAL ) -+#define __tssi_select_paral_mode() ( REG_TSSI_CFG |= TSSI_CFG_PARAL ) -+ -+#define __tssi_select_clk_nega_edge() ( REG_TSSI_CFG &= ~TSSI_CFG_TSCLK_P ) -+#define __tssi_select_clk_posi_edge() ( REG_TSSI_CFG |= TSSI_CFG_TSCLK_P ) -+ -+#define __tssi_select_frm_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFRM_H ) -+#define __tssi_select_frm_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFRM_H ) -+ -+#define __tssi_select_str_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSSTR_H ) -+#define __tssi_select_str_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSSTR_H ) -+ -+#define __tssi_select_fail_act_high() ( REG_TSSI_CFG |= TSSI_CFG_TSFAIL_H ) -+#define __tssi_select_fail_act_low() ( REG_TSSI_CFG &= ~TSSI_CFG_TSFAIL_H ) -+ -+#define __tssi_enable_ovrn_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_OVRNM ) -+#define __tssi_disable_ovrn_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_OVRNM ) -+ -+#define __tssi_enable_trig_irq() ( REG_TSSI_CTRL &= ~TSSI_CTRL_TRIGM ) -+#define __tssi_disable_trig_irq() ( REG_TSSI_CTRL |= TSSI_CTRL_TRIGM ) -+ -+#define __tssi_state_is_overrun() ( REG_TSSI_STAT & TSSI_STAT_OVRN ) -+#define __tssi_state_trigger_meet() ( REG_TSSI_STAT & TSSI_STAT_TRIG ) -+#define __tssi_clear_state() ( REG_TSSI_STAT = 0 ) /* write 0??? */ -+#define __tssi_state_clear_overrun() ( REG_TSSI_STAT = TSSI_STAT_OVRN ) -+ -+#define __tssi_enable_filte_pid0() ( REG_TSSI_PEN |= TSSI_PEN_PID0 ) -+#define __tssi_disable_filte_pid0() ( REG_TSSI_PEN &= ~TSSI_PEN_PID0 ) -+ -+/* m = 0, ..., 15 */ -+#define __tssi_enable_pid_filter(m) \ -+ do { \ -+ int n = (m); \ -+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ -+ if ( n >= TSSI_PID_MAX ) n += 8; \ -+ REG_TSSI_PEN |= ( 1 << n ); \ -+ } \ -+ } while (0) -+ -+/* m = 0, ..., 15 */ -+#define __tssi_disable_pid_filter(m) \ -+ do { \ -+ int n = (m); \ -+ if ( n>=0 && n <(TSSI_PID_MAX*2) ) { \ -+ if ( n >= TSSI_PID_MAX ) n += 8; \ -+ REG_TSSI_PEN &= ~( 1 << n ); \ -+ } \ -+ } while (0) -+ -+/* n = 0, ..., 7 */ -+#define __tssi_set_pid0(n, pid0) \ -+ do { \ -+ REG_TSSI_PID(n) &= ~TSSI_PID_PID0_MASK; \ -+ REG_TSSI_PID(n) |= ((pid0)<=0 && n < TSSI_PID_MAX*2) { \ -+ if ( n < TSSI_PID_MAX ) \ -+ __tssi_set_pid0(n, pid); \ -+ else \ -+ __tssi_set_pid1(n-TSSI_PID_MAX, pid); \ -+ } \ -+ }while (0) -+ -+ -+#if 0 -+/************************************************************************* -+ * IPU (Image Processing Unit) -+ *************************************************************************/ -+#define u32 volatile unsigned long -+ -+#define write_reg(reg, val) \ -+do { \ -+ *(u32 *)(reg) = (val); \ -+} while(0) -+ -+#define read_reg(reg, off) (*(u32 *)((reg)+(off))) -+ -+ -+#define set_ipu_fmt(rgb_888_out_fmt, rgb_out_oft, out_fmt, yuv_pkg_out, in_oft, in_fmt ) \ -+({ write_reg( (IPU_V_BASE + REG_D_FMT), ((in_fmt) & IN_FMT_MSK)< Unsigned toggle enable */ -+#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ -+#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ -+#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ -+#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ -+#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ -+#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ -+#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ -+#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ -+ -+/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ -+ -+#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ -+#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) -+ #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ -+#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ -+#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) -+ #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ -+ #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ -+ #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ -+ #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ -+ #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ -+ #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ -+ #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ -+ #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ -+ #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ -+ #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ -+ -+/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ -+ -+#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ -+#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ -+#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ -+#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) -+ #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ -+#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) -+ #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ -+ #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ -+ #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ -+ #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ -+#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ -+#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ -+#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ -+#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ -+ -+/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ -+ -+#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ -+#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) -+ #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ -+ #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ -+ #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ -+ #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ -+ #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ -+#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ -+ -+/* AIC Controller FIFO Status Register (AIC_SR) */ -+ -+#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ -+#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) -+#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ -+#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) -+#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ -+#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ -+#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ -+#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ -+ -+/* AIC Controller AC-link Status Register (AIC_ACSR) */ -+ -+#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ -+#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ -+#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ -+#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ -+#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ -+#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ -+ -+/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ -+ -+#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ -+ -+/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ -+ -+#define AIC_ACCAR_CAR_BIT 0 -+#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) -+ -+/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ -+ -+#define AIC_ACCDR_CDR_BIT 0 -+#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) -+ -+/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ -+ -+#define AIC_ACSAR_SAR_BIT 0 -+#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) -+ -+/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ -+ -+#define AIC_ACSDR_SDR_BIT 0 -+#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) -+ -+/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ -+ -+#define AIC_I2SDIV_DIV_BIT 0 -+#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) -+ #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ -+ #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ -+ #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ -+ #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ -+ #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ -+ #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ -+ -+ -+/************************************************************************* -+ * ICDC (Internal CODEC) -+ *************************************************************************/ -+ -+#define ICDC_CKCFG (ICDC_BASE + 0x00a0) /* Clock Configure Register */ -+#define ICDC_RGADW (ICDC_BASE + 0x00a4) /* internal register access control */ -+#define ICDC_RGDATA (ICDC_BASE + 0x00a8) /* internal register data output */ -+ -+#define REG_ICDC_CKCFG REG32(ICDC_CKCFG) -+#define REG_ICDC_RGADW REG32(ICDC_RGADW) -+#define REG_ICDC_RGDATA REG32(ICDC_RGDATA) -+ -+/* ICDC Clock Configure Register */ -+#define ICDC_CKCFG_CKRDY (1 << 1) -+#define ICDC_CKCFG_SELAD (1 << 0) -+ -+/* ICDC internal register access control Register */ -+#define ICDC_RGADW_RGWR (1 << 16) -+#define ICDC_RGADW_RGADDR_BIT 8 -+#define ICDC_RGADW_RGADDR_MASK (0x7f << ICDC_RGADW_RGADDR_BIT) -+#define ICDC_RGADW_RGDIN_BIT 0 -+#define ICDC_RGADW_RGDIN_MASK (0xff << ICDC_RGADW_RGDIN_BIT) -+ -+/* ICDC internal register data output Register */ -+#define ICDC_RGDATA_IRQ (1 << 8) -+#define ICDC_RGDATA_RGDOUT_BIT 0 -+#define ICDC_RGDATA_RGDOUT_MASK (0xff << ICDC_RGDATA_RGDOUT_BIT) -+ -+/************************************************************************* -+ * PCM Controller -+ *************************************************************************/ -+ -+#define PCM_CTL (PCM_BASE + 0x000) -+#define PCM_CFG (PCM_BASE + 0x004) -+#define PCM_DP (PCM_BASE + 0x008) -+#define PCM_INTC (PCM_BASE + 0x00c) -+#define PCM_INTS (PCM_BASE + 0x010) -+#define PCM_DIV (PCM_BASE + 0x014) -+ -+#define REG_PCM_CTL REG32(PCM_CTL) -+#define REG_PCM_CFG REG32(PCM_CFG) -+#define REG_PCM_DP REG32(PCM_DP) -+#define REG_PCM_INTC REG32(PCM_INTC) -+#define REG_PCM_INTS REG32(PCM_INTS) -+#define REG_PCM_DIV REG32(PCM_DIV) -+ -+/* PCM Controller control Register (PCM_CTL) */ -+ -+#define PCM_CTL_ERDMA (1 << 9) /* Enable Receive DMA */ -+#define PCM_CTL_ETDMA (1 << 8) /* Enable Transmit DMA */ -+#define PCM_CTL_LSMP (1 << 7) /* Play Zero sample or last sample */ -+#define PCM_CTL_ERPL (1 << 6) /* Enable Playing Back Function */ -+#define PCM_CTL_EREC (1 << 5) /* Enable Recording Function */ -+#define PCM_CTL_FLUSH (1 << 4) /* FIFO flush */ -+#define PCM_CTL_RST (1 << 3) /* Reset PCM */ -+#define PCM_CTL_CLKEN (1 << 1) /* Enable the clock division logic */ -+#define PCM_CTL_PCMEN (1 << 0) /* Enable PCM module */ -+ -+/* PCM Controller configure Register (PCM_CFG) */ -+ -+#define PCM_CFG_SLOT_BIT 13 -+#define PCM_CFG_SLOT_MASK (0x3 << PCM_CFG_SLOT_BIT) -+ #define PCM_CFG_SLOT_0 (0 << PCM_CFG_SLOT_BIT) /* Slot is 0 */ -+ #define PCM_CFG_SLOT_1 (1 << PCM_CFG_SLOT_BIT) /* Slot is 1 */ -+ #define PCM_CFG_SLOT_2 (2 << PCM_CFG_SLOT_BIT) /* Slot is 2 */ -+ #define PCM_CFG_SLOT_3 (3 << PCM_CFG_SLOT_BIT) /* Slot is 3 */ -+#define PCM_CFG_ISS_BIT 12 -+#define PCM_CFG_ISS_MASK (0x1 << PCM_CFG_ISS_BIT) -+ #define PCM_CFG_ISS_8 (0 << PCM_CFG_ISS_BIT) -+ #define PCM_CFG_ISS_16 (1 << PCM_CFG_ISS_BIT) -+#define PCM_CFG_OSS_BIT 11 -+#define PCM_CFG_OSS_MASK (0x1 << PCM_CFG_OSS_BIT) -+ #define PCM_CFG_OSS_8 (0 << PCM_CFG_OSS_BIT) -+ #define PCM_CFG_OSS_16 (1 << PCM_CFG_OSS_BIT) -+#define PCM_CFG_IMSBPOS (1 << 10) -+#define PCM_CFG_OMSBPOS (1 << 9) -+#define PCM_CFG_RFTH_BIT 5 /* Receive FIFO Threshold */ -+#define PCM_CFG_RFTH_MASK (0xf << PCM_CFG_RFTH_BIT) -+#define PCM_CFG_TFTH_BIT 1 /* Transmit FIFO Threshold */ -+#define PCM_CFG_TFTH_MASK (0xf << PCM_CFG_TFTH_BIT) -+#define PCM_CFG_MODE (0x0 << 0) -+ -+/* PCM Controller interrupt control Register (PCM_INTC) */ -+ -+#define PCM_INTC_ETFS (1 << 3) -+#define PCM_INTC_ETUR (1 << 2) -+#define PCM_INTC_ERFS (1 << 1) -+#define PCM_INTC_EROR (1 << 0) -+ -+/* PCM Controller interrupt status Register (PCM_INTS) */ -+ -+#define PCM_INTS_RSTS (1 << 14) /* Reset or flush has not complete */ -+#define PCM_INTS_TFL_BIT 9 -+#define PCM_INTS_TFL_MASK (0x1f << PCM_INTS_TFL_BIT) -+#define PCM_INTS_TFS (1 << 8) /* Tranmit FIFO Service Request */ -+#define PCM_INTS_TUR (1 << 7) /* Transmit FIFO Under Run */ -+#define PCM_INTS_RFL_BIT 2 -+#define PCM_INTS_RFL_MASK (0x1f << PCM_INTS_RFL_BIT) -+#define PCM_INTS_RFS (1 << 1) /* Receive FIFO Service Request */ -+#define PCM_INTS_ROR (1 << 0) /* Receive FIFO Over Run */ -+ -+/* PCM Controller clock division Register (PCM_DIV) */ -+#define PCM_DIV_SYNL_BIT 11 -+#define PCM_DIV_SYNL_MASK (0x3f << PCM_DIV_SYNL_BIT) -+#define PCM_DIV_SYNDIV_BIT 6 -+#define PCM_DIV_SYNDIV_MASK (0x1f << PCM_DIV_SYNDIV_BIT) -+#define PCM_DIV_CLKDIV_BIT 0 -+#define PCM_DIV_CLKDIV_MASK (0x3f << PCM_DIV_CLKDIV_BIT) -+ -+ -+/************************************************************************* -+ * I2C -+ *************************************************************************/ -+#define I2C_DR (I2C_BASE + 0x000) -+#define I2C_CR (I2C_BASE + 0x004) -+#define I2C_SR (I2C_BASE + 0x008) -+#define I2C_GR (I2C_BASE + 0x00C) -+ -+#define REG_I2C_DR REG8(I2C_DR) -+#define REG_I2C_CR REG8(I2C_CR) -+#define REG_I2C_SR REG8(I2C_SR) -+#define REG_I2C_GR REG16(I2C_GR) -+ -+/* I2C Control Register (I2C_CR) */ -+ -+#define I2C_CR_IEN (1 << 4) -+#define I2C_CR_STA (1 << 3) -+#define I2C_CR_STO (1 << 2) -+#define I2C_CR_AC (1 << 1) -+#define I2C_CR_I2CE (1 << 0) -+ -+/* I2C Status Register (I2C_SR) */ -+ -+#define I2C_SR_STX (1 << 4) -+#define I2C_SR_BUSY (1 << 3) -+#define I2C_SR_TEND (1 << 2) -+#define I2C_SR_DRF (1 << 1) -+#define I2C_SR_ACKF (1 << 0) -+ -+ -+/************************************************************************* -+ * SSI (Synchronous Serial Interface) -+ *************************************************************************/ -+/* n = 0, 1 (SSI0, SSI1) */ -+#define SSI_DR(n) (SSI_BASE + 0x000 + (n)*0x2000) -+#define SSI_CR0(n) (SSI_BASE + 0x004 + (n)*0x2000) -+#define SSI_CR1(n) (SSI_BASE + 0x008 + (n)*0x2000) -+#define SSI_SR(n) (SSI_BASE + 0x00C + (n)*0x2000) -+#define SSI_ITR(n) (SSI_BASE + 0x010 + (n)*0x2000) -+#define SSI_ICR(n) (SSI_BASE + 0x014 + (n)*0x2000) -+#define SSI_GR(n) (SSI_BASE + 0x018 + (n)*0x2000) -+ -+#define REG_SSI_DR(n) REG32(SSI_DR(n)) -+#define REG_SSI_CR0(n) REG16(SSI_CR0(n)) -+#define REG_SSI_CR1(n) REG32(SSI_CR1(n)) -+#define REG_SSI_SR(n) REG32(SSI_SR(n)) -+#define REG_SSI_ITR(n) REG16(SSI_ITR(n)) -+#define REG_SSI_ICR(n) REG8(SSI_ICR(n)) -+#define REG_SSI_GR(n) REG16(SSI_GR(n)) -+ -+/* SSI Data Register (SSI_DR) */ -+ -+#define SSI_DR_GPC_BIT 0 -+#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) -+ -+#define SSI_MAX_FIFO_ENTRIES 128 /* 128 txfifo and 128 rxfifo */ -+ -+/* SSI Control Register 0 (SSI_CR0) */ -+ -+#define SSI_CR0_SSIE (1 << 15) -+#define SSI_CR0_TIE (1 << 14) -+#define SSI_CR0_RIE (1 << 13) -+#define SSI_CR0_TEIE (1 << 12) -+#define SSI_CR0_REIE (1 << 11) -+#define SSI_CR0_LOOP (1 << 10) -+#define SSI_CR0_RFINE (1 << 9) -+#define SSI_CR0_RFINC (1 << 8) -+#define SSI_CR0_EACLRUN (1 << 7) /* hardware auto clear underrun when TxFifo no empty */ -+#define SSI_CR0_FSEL (1 << 6) -+#define SSI_CR0_TFLUSH (1 << 2) -+#define SSI_CR0_RFLUSH (1 << 1) -+#define SSI_CR0_DISREV (1 << 0) -+ -+/* SSI Control Register 1 (SSI_CR1) */ -+ -+#define SSI_CR1_FRMHL_BIT 30 -+#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) -+ #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ -+ #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ -+ #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ -+#define SSI_CR1_TFVCK_BIT 28 -+#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) -+ #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) -+#define SSI_CR1_TCKFI_BIT 26 -+#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) -+ #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) -+#define SSI_CR1_LFST (1 << 25) -+#define SSI_CR1_ITFRM (1 << 24) -+#define SSI_CR1_UNFIN (1 << 23) -+#define SSI_CR1_MULTS (1 << 22) -+#define SSI_CR1_FMAT_BIT 20 -+#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) -+ #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ -+ #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ -+ #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ -+ #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ -+#define SSI_CR1_TTRG_BIT 16 /* SSI1 TX trigger */ -+#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) -+#define SSI_CR1_MCOM_BIT 12 -+#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) -+ #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ -+ #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ -+ #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ -+ #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ -+ #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ -+ #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ -+ #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ -+ #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ -+ #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ -+ #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ -+ #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ -+ #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ -+ #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ -+ #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ -+ #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ -+ #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ -+#define SSI_CR1_RTRG_BIT 8 /* SSI RX trigger */ -+#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) -+#define SSI_CR1_FLEN_BIT 4 -+#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) -+ #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) -+#define SSI_CR1_PHA (1 << 1) -+#define SSI_CR1_POL (1 << 0) -+ -+/* SSI Status Register (SSI_SR) */ -+ -+#define SSI_SR_TFIFONUM_BIT 16 -+#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) -+#define SSI_SR_RFIFONUM_BIT 8 -+#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) -+#define SSI_SR_END (1 << 7) -+#define SSI_SR_BUSY (1 << 6) -+#define SSI_SR_TFF (1 << 5) -+#define SSI_SR_RFE (1 << 4) -+#define SSI_SR_TFHE (1 << 3) -+#define SSI_SR_RFHF (1 << 2) -+#define SSI_SR_UNDR (1 << 1) -+#define SSI_SR_OVER (1 << 0) -+ -+/* SSI Interval Time Control Register (SSI_ITR) */ -+ -+#define SSI_ITR_CNTCLK (1 << 15) -+#define SSI_ITR_IVLTM_BIT 0 -+#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) -+ -+ -+/************************************************************************* -+ * MSC -+ ************************************************************************/ -+/* n = 0, 1 (MSC0, MSC1) */ -+#define MSC_STRPCL(n) (MSC_BASE + (n)*0x1000 + 0x000) -+#define MSC_STAT(n) (MSC_BASE + (n)*0x1000 + 0x004) -+#define MSC_CLKRT(n) (MSC_BASE + (n)*0x1000 + 0x008) -+#define MSC_CMDAT(n) (MSC_BASE + (n)*0x1000 + 0x00C) -+#define MSC_RESTO(n) (MSC_BASE + (n)*0x1000 + 0x010) -+#define MSC_RDTO(n) (MSC_BASE + (n)*0x1000 + 0x014) -+#define MSC_BLKLEN(n) (MSC_BASE + (n)*0x1000 + 0x018) -+#define MSC_NOB(n) (MSC_BASE + (n)*0x1000 + 0x01C) -+#define MSC_SNOB(n) (MSC_BASE + (n)*0x1000 + 0x020) -+#define MSC_IMASK(n) (MSC_BASE + (n)*0x1000 + 0x024) -+#define MSC_IREG(n) (MSC_BASE + (n)*0x1000 + 0x028) -+#define MSC_CMD(n) (MSC_BASE + (n)*0x1000 + 0x02C) -+#define MSC_ARG(n) (MSC_BASE + (n)*0x1000 + 0x030) -+#define MSC_RES(n) (MSC_BASE + (n)*0x1000 + 0x034) -+#define MSC_RXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x038) -+#define MSC_TXFIFO(n) (MSC_BASE + (n)*0x1000 + 0x03C) -+#define MSC_LPM(n) (MSC_BASE + (n)*0x1000 + 0x040) -+ -+#define REG_MSC_STRPCL(n) REG16(MSC_STRPCL(n)) -+#define REG_MSC_STAT(n) REG32(MSC_STAT(n)) -+#define REG_MSC_CLKRT(n) REG16(MSC_CLKRT(n)) -+#define REG_MSC_CMDAT(n) REG32(MSC_CMDAT(n)) -+#define REG_MSC_RESTO(n) REG16(MSC_RESTO(n)) -+#define REG_MSC_RDTO(n) REG16(MSC_RDTO(n)) -+#define REG_MSC_BLKLEN(n) REG16(MSC_BLKLEN(n)) -+#define REG_MSC_NOB(n) REG16(MSC_NOB(n)) -+#define REG_MSC_SNOB(n) REG16(MSC_SNOB(n)) -+#define REG_MSC_IMASK(n) REG32(MSC_IMASK(n)) -+#define REG_MSC_IREG(n) REG16(MSC_IREG(n)) -+#define REG_MSC_CMD(n) REG8(MSC_CMD(n)) -+#define REG_MSC_ARG(n) REG32(MSC_ARG(n)) -+#define REG_MSC_RES(n) REG16(MSC_RES(n)) -+#define REG_MSC_RXFIFO(n) REG32(MSC_RXFIFO(n)) -+#define REG_MSC_TXFIFO(n) REG32(MSC_TXFIFO(n)) -+#define REG_MSC_LPM(n) REG32(MSC_LPM(n)) -+ -+/* MSC Clock and Control Register (MSC_STRPCL) */ -+#define MSC_STRPCL_SEND_CCSD (1 << 15) /*send command completion signal disable to ceata */ -+#define MSC_STRPCL_SEND_AS_CCSD (1 << 14) /*send internally generated stop after sending ccsd */ -+#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) -+#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) -+#define MSC_STRPCL_START_READWAIT (1 << 5) -+#define MSC_STRPCL_STOP_READWAIT (1 << 4) -+#define MSC_STRPCL_RESET (1 << 3) -+#define MSC_STRPCL_START_OP (1 << 2) -+#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 -+#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) -+ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ -+ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ -+ -+/* MSC Status Register (MSC_STAT) */ -+#define MSC_STAT_AUTO_CMD_DONE (1 << 31) /*12 is internally generated by controller has finished */ -+#define MSC_STAT_IS_RESETTING (1 << 15) -+#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) -+#define MSC_STAT_PRG_DONE (1 << 13) -+#define MSC_STAT_DATA_TRAN_DONE (1 << 12) -+#define MSC_STAT_END_CMD_RES (1 << 11) -+#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) -+#define MSC_STAT_IS_READWAIT (1 << 9) -+#define MSC_STAT_CLK_EN (1 << 8) -+#define MSC_STAT_DATA_FIFO_FULL (1 << 7) -+#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) -+#define MSC_STAT_CRC_RES_ERR (1 << 5) -+#define MSC_STAT_CRC_READ_ERROR (1 << 4) -+#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 -+#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) -+ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ -+ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ -+#define MSC_STAT_TIME_OUT_RES (1 << 1) -+#define MSC_STAT_TIME_OUT_READ (1 << 0) -+ -+/* MSC Bus Clock Control Register (MSC_CLKRT) */ -+#define MSC_CLKRT_CLK_RATE_BIT 0 -+#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) -+ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ -+ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ -+ -+/* MSC Command Sequence Control Register (MSC_CMDAT) */ -+#define MSC_CMDAT_CCS_EXPECTED (1 << 31) /* interrupts are enabled in ce-ata */ -+#define MSC_CMDAT_READ_CEATA (1 << 30) -+#define MSC_CMDAT_SDIO_PRDT (1 << 17) /* exact 2 cycle */ -+#define MSC_CMDAT_SEND_AS_STOP (1 << 16) -+#define MSC_CMDAT_RTRG_BIT 14 -+ #define MSC_CMDAT_RTRG_EQUALT_8 (0x0 << MSC_CMDAT_RTRG_BIT) -+ #define MSC_CMDAT_RTRG_EQUALT_16 (0x1 << MSC_CMDAT_RTRG_BIT) /* reset value */ -+ #define MSC_CMDAT_RTRG_EQUALT_24 (0x2 << MSC_CMDAT_RTRG_BIT) -+ -+#define MSC_CMDAT_TTRG_BIT 12 -+ #define MSC_CMDAT_TTRG_LESS_8 (0x0 << MSC_CMDAT_TTRG_BIT) -+ #define MSC_CMDAT_TTRG_LESS_16 (0x1 << MSC_CMDAT_TTRG_BIT) /*reset value */ -+ #define MSC_CMDAT_TTRG_LESS_24 (0x2 << MSC_CMDAT_TTRG_BIT) -+#define MSC_CMDAT_STOP_ABORT (1 << 11) -+#define MSC_CMDAT_BUS_WIDTH_BIT 9 -+#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) -+ #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ -+ #define MSC_CMDAT_BUS_WIDTH_8BIT (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) /* 8-bit data bus */ -+#define MSC_CMDAT_DMA_EN (1 << 8) -+#define MSC_CMDAT_INIT (1 << 7) -+#define MSC_CMDAT_BUSY (1 << 6) -+#define MSC_CMDAT_STREAM_BLOCK (1 << 5) -+#define MSC_CMDAT_WRITE (1 << 4) -+#define MSC_CMDAT_READ (0 << 4) -+#define MSC_CMDAT_DATA_EN (1 << 3) -+#define MSC_CMDAT_RESPONSE_BIT 0 -+#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) -+ #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ -+ #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ -+ #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ -+ #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ -+ #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ -+ #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ -+ #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ -+ -+#define CMDAT_DMA_EN (1 << 8) -+#define CMDAT_INIT (1 << 7) -+#define CMDAT_BUSY (1 << 6) -+#define CMDAT_STREAM (1 << 5) -+#define CMDAT_WRITE (1 << 4) -+#define CMDAT_DATA_EN (1 << 3) -+ -+/* MSC Interrupts Mask Register (MSC_IMASK) */ -+#define MSC_IMASK_AUTO_CMD_DONE (1 << 8) -+#define MSC_IMASK_SDIO (1 << 7) -+#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IMASK_END_CMD_RES (1 << 2) -+#define MSC_IMASK_PRG_DONE (1 << 1) -+#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) -+ -+/* MSC Interrupts Status Register (MSC_IREG) */ -+#define MSC_IREG_AUTO_CMD_DONE (1 << 8) -+#define MSC_IREG_SDIO (1 << 7) -+#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) -+#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) -+#define MSC_IREG_END_CMD_RES (1 << 2) -+#define MSC_IREG_PRG_DONE (1 << 1) -+#define MSC_IREG_DATA_TRAN_DONE (1 << 0) -+ -+/* MSC Low Power Mode Register (MSC_LPM) */ -+#define MSC_SET_LPM (1 << 0) -+ -+/************************************************************************* -+ * EMC (External Memory Controller) -+ *************************************************************************/ -+#define EMC_BCR (EMC_BASE + 0x00) /* Bus Control Register */ -+#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ -+#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ -+#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ -+#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ -+#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ -+#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ -+#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ -+#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ -+#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ -+#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ -+ -+#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ -+ -+#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ -+#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ -+#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ -+#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ -+#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ -+#define EMC_DMAR1 (EMC_BASE + 0x94) /* SDRAM Bank 1 Addr Config Register */ -+#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ -+ -+#define REG_EMC_BCR REG32(EMC_BCR) -+#define REG_EMC_SMCR0 REG32(EMC_SMCR0) -+#define REG_EMC_SMCR1 REG32(EMC_SMCR1) -+#define REG_EMC_SMCR2 REG32(EMC_SMCR2) -+#define REG_EMC_SMCR3 REG32(EMC_SMCR3) -+#define REG_EMC_SMCR4 REG32(EMC_SMCR4) -+#define REG_EMC_SACR0 REG32(EMC_SACR0) -+#define REG_EMC_SACR1 REG32(EMC_SACR1) -+#define REG_EMC_SACR2 REG32(EMC_SACR2) -+#define REG_EMC_SACR3 REG32(EMC_SACR3) -+#define REG_EMC_SACR4 REG32(EMC_SACR4) -+ -+#define REG_EMC_NFCSR REG32(EMC_NFCSR) -+ -+#define REG_EMC_DMCR REG32(EMC_DMCR) -+#define REG_EMC_RTCSR REG16(EMC_RTCSR) -+#define REG_EMC_RTCNT REG16(EMC_RTCNT) -+#define REG_EMC_RTCOR REG16(EMC_RTCOR) -+#define REG_EMC_DMAR0 REG32(EMC_DMAR0) -+#define REG_EMC_DMAR1 REG32(EMC_DMAR1) -+ -+/* Bus Control Register */ -+#define EMC_BCR_BT_SEL_BIT 30 -+#define EMC_BCR_BT_SEL_MASK (0x3 << EMC_BCR_BT_SEL_BIT) -+#define EMC_BCR_PK_SEL (1 << 24) -+#define EMC_BCR_BSR_MASK (1 << 2) /* Nand and SDRAM Bus Share Select: 0, share; 1, unshare */ -+ #define EMC_BCR_BSR_SHARE (0 << 2) -+ #define EMC_BCR_BSR_UNSHARE (1 << 2) -+#define EMC_BCR_BRE (1 << 1) -+#define EMC_BCR_ENDIAN (1 << 0) -+ -+/* Static Memory Control Register */ -+#define EMC_SMCR_STRV_BIT 24 -+#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) -+#define EMC_SMCR_TAW_BIT 20 -+#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) -+#define EMC_SMCR_TBP_BIT 16 -+#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) -+#define EMC_SMCR_TAH_BIT 12 -+#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) -+#define EMC_SMCR_TAS_BIT 8 -+#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) -+#define EMC_SMCR_BW_BIT 6 -+#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) -+ #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) -+#define EMC_SMCR_BCM (1 << 3) -+#define EMC_SMCR_BL_BIT 1 -+#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) -+ #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) -+#define EMC_SMCR_SMT (1 << 0) -+ -+/* Static Memory Bank Addr Config Reg */ -+#define EMC_SACR_BASE_BIT 8 -+#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) -+#define EMC_SACR_MASK_BIT 0 -+#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) -+ -+/* NAND Flash Control/Status Register */ -+#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ -+#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ -+#define EMC_NFCSR_NFCE3 (1 << 5) -+#define EMC_NFCSR_NFE3 (1 << 4) -+#define EMC_NFCSR_NFCE2 (1 << 3) -+#define EMC_NFCSR_NFE2 (1 << 2) -+#define EMC_NFCSR_NFCE1 (1 << 1) -+#define EMC_NFCSR_NFE1 (1 << 0) -+ -+/* DRAM Control Register */ -+#define EMC_DMCR_BW_BIT 31 -+#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) -+#define EMC_DMCR_CA_BIT 26 -+#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) -+ #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) -+#define EMC_DMCR_RMODE (1 << 25) -+#define EMC_DMCR_RFSH (1 << 24) -+#define EMC_DMCR_MRSET (1 << 23) -+#define EMC_DMCR_RA_BIT 20 -+#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) -+ #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) -+#define EMC_DMCR_BA_BIT 19 -+#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) -+#define EMC_DMCR_PDM (1 << 18) -+#define EMC_DMCR_EPIN (1 << 17) -+#define EMC_DMCR_MBSEL (1 << 16) -+#define EMC_DMCR_TRAS_BIT 13 -+#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) -+#define EMC_DMCR_RCD_BIT 11 -+#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) -+#define EMC_DMCR_TPC_BIT 8 -+#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) -+#define EMC_DMCR_TRWL_BIT 5 -+#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) -+#define EMC_DMCR_TRC_BIT 2 -+#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) -+#define EMC_DMCR_TCL_BIT 0 -+#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) -+ -+/* Refresh Time Control/Status Register */ -+#define EMC_RTCSR_SFR (1 << 8) /* self refresh flag */ -+#define EMC_RTCSR_CMF (1 << 7) -+#define EMC_RTCSR_CKS_BIT 0 -+#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) -+ #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) -+ -+/* SDRAM Bank Address Configuration Register */ -+#define EMC_DMAR_BASE_BIT 8 -+#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) -+#define EMC_DMAR_MASK_BIT 0 -+#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) -+ -+/* Mode Register of SDRAM bank 0 */ -+#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ -+#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ -+#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) -+ #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) -+#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ -+#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) -+ #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) -+#define EMC_SDMR_BT_BIT 3 /* Burst Type */ -+#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) -+ #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ -+ #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ -+#define EMC_SDMR_BL_BIT 0 /* Burst Length */ -+#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) -+ #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) -+ -+#define EMC_SDMR_CAS2_16BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS2_32BIT \ -+ (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+#define EMC_SDMR_CAS3_16BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) -+#define EMC_SDMR_CAS3_32BIT \ -+ (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) -+ -+ -+/************************************************************************* -+ * CIM -+ *************************************************************************/ -+#define CIM_CFG (CIM_BASE + 0x0000) -+#define CIM_CTRL (CIM_BASE + 0x0004) -+#define CIM_STATE (CIM_BASE + 0x0008) -+#define CIM_IID (CIM_BASE + 0x000C) -+#define CIM_RXFIFO (CIM_BASE + 0x0010) -+#define CIM_DA (CIM_BASE + 0x0020) -+#define CIM_FA (CIM_BASE + 0x0024) -+#define CIM_FID (CIM_BASE + 0x0028) -+#define CIM_CMD (CIM_BASE + 0x002C) -+#define CIM_SIZE (CIM_BASE + 0x0030) -+#define CIM_OFFSET (CIM_BASE + 0x0034) -+#define CIM_RAM_ADDR (CIM_BASE + 0x1000) -+ -+#define REG_CIM_CFG REG32(CIM_CFG) -+#define REG_CIM_CTRL REG32(CIM_CTRL) -+#define REG_CIM_STATE REG32(CIM_STATE) -+#define REG_CIM_IID REG32(CIM_IID) -+#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) -+#define REG_CIM_DA REG32(CIM_DA) -+#define REG_CIM_FA REG32(CIM_FA) -+#define REG_CIM_FID REG32(CIM_FID) -+#define REG_CIM_CMD REG32(CIM_CMD) -+#define REG_CIM_SIZE REG32(CIM_SIZE) -+#define REG_CIM_OFFSET REG32(CIM_OFFSET) -+ -+#define CIM_CFG_ORDER_BIT 18 -+#define CIM_CFG_ORDER_MASK (0x3 << CIM_CFG_ORDER_BIT) -+ #define CIM_CFG_ORDER_0 (0x0 << CIM_CFG_ORDER_BIT) /* Y0CbY1Cr; YCbCr */ -+ #define CIM_CFG_ORDER_1 (0x1 << CIM_CFG_ORDER_BIT) /* Y0CrY1Cb; YCrCb */ -+ #define CIM_CFG_ORDER_2 (0x2 << CIM_CFG_ORDER_BIT) /* CbY0CrY1; CbCrY */ -+ #define CIM_CFG_ORDER_3 (0x3 << CIM_CFG_ORDER_BIT) /* CrY0CbY1; CrCbY */ -+#define CIM_CFG_DF_BIT 16 -+#define CIM_CFG_DF_MASK (0x3 << CIM_CFG_DF_BIT) -+ #define CIM_CFG_DF_YUV444 (0x1 << CIM_CFG_DF_BIT) /* YCbCr444 */ -+ #define CIM_CFG_DF_YUV422 (0x2 << CIM_CFG_DF_BIT) /* YCbCr422 */ -+ #define CIM_CFG_DF_ITU656 (0x3 << CIM_CFG_DF_BIT) /* ITU656 YCbCr422 */ -+#define CIM_CFG_INV_DAT (1 << 15) -+#define CIM_CFG_VSP (1 << 14) /* VSYNC Polarity:0-rising edge active,1-falling edge active */ -+#define CIM_CFG_HSP (1 << 13) /* HSYNC Polarity:0-rising edge active,1-falling edge active */ -+#define CIM_CFG_PCP (1 << 12) /* PCLK working edge: 0-rising, 1-falling */ -+#define CIM_CFG_DMA_BURST_TYPE_BIT 10 -+#define CIM_CFG_DMA_BURST_TYPE_MASK (0x3 << CIM_CFG_DMA_BURST_TYPE_BIT) -+ #define CIM_CFG_DMA_BURST_INCR4 (0 << CIM_CFG_DMA_BURST_TYPE_BIT) -+ #define CIM_CFG_DMA_BURT_INCR8 (1 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested */ -+ #define CIM_CFG_DMA_BURT_INCR16 (2 << CIM_CFG_DMA_BURST_TYPE_BIT) /* Suggested High speed AHB*/ -+#define CIM_CFG_DUMMY_ZERO (1 << 9) -+#define CIM_CFG_EXT_VSYNC (1 << 8) /* Only for ITU656 Progressive mode */ -+#define CIM_CFG_PACK_BIT 4 -+#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) -+ #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) /* 11 22 33 44 0xY0CbY1Cr */ -+ #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) /* 22 33 44 11 0xCbY1CrY0 */ -+ #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) /* 33 44 11 22 0xY1CrY0Cb */ -+ #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) /* 44 11 22 33 0xCrY0CbY1 */ -+ #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) /* 44 33 22 11 0xCrY1CbY0 */ -+ #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) /* 33 22 11 44 0xY1CbY0Cr */ -+ #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) /* 22 11 44 33 0xCbY0CrY1 */ -+ #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) /* 11 44 33 22 0xY0CrY1Cb */ -+#define CIM_CFG_BYPASS_BIT 2 -+#define CIM_CFG_BYPASS_MASK (1 << CIM_CFG_BYPASS_BIT) -+ #define CIM_CFG_BYPASS (1 << CIM_CFG_BYPASS_BIT) -+#define CIM_CFG_DSM_BIT 0 -+#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) -+ #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ -+ #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ -+ #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ -+ -+/* CIM Control Register (CIM_CTRL) */ -+#define CIM_CTRL_EEOF_LINE_BIT 20 -+#define CIM_CTRL_EEOF_LINE_MASK (0xfff << CIM_CTRL_MCLKDIV_BIT) -+#define CIM_CTRL_FRC_BIT 16 -+#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) -+ #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ -+ #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ -+ #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ -+ #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ -+ #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ -+ #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ -+ #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ -+ #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ -+ #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ -+ #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ -+ #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ -+ #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ -+ #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ -+ #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ -+ #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ -+ #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ -+ -+#define CIM_CTRL_DMA_EEOFM (1 << 15) /* Enable EEOF interrupt */ -+#define CIM_CTRL_WIN_EN (1 << 14) -+#define CIM_CTRL_VDDM (1 << 13) /* VDD interrupt enable */ -+#define CIM_CTRL_DMA_SOFM (1 << 12) -+#define CIM_CTRL_DMA_EOFM (1 << 11) -+#define CIM_CTRL_DMA_STOPM (1 << 10) -+#define CIM_CTRL_RXF_TRIGM (1 << 9) -+#define CIM_CTRL_RXF_OFM (1 << 8) -+#define CIM_CTRL_DMA_SYNC (1 << 7) /*when change DA, do frame sync */ -+#define CIM_CTRL_RXF_TRIG_BIT 3 -+#define CIM_CTRL_RXF_TRIG_MASK (0xf << CIM_CTRL_RXF_TRIG_BIT) /* trigger value = (n+1)*burst_type */ -+#define CIM_CTRL_DMA_EN (1 << 2) /* Enable DMA */ -+#define CIM_CTRL_RXF_RST (1 << 1) /* RxFIFO reset */ -+#define CIM_CTRL_ENA (1 << 0) /* Enable CIM */ -+ -+/* CIM State Register (CIM_STATE) */ -+#define CIM_STATE_DMA_EEOF (1 << 7) /* DMA Line EEOf irq */ -+#define CIM_STATE_DMA_SOF (1 << 6) /* DMA start irq */ -+#define CIM_STATE_DMA_EOF (1 << 5) /* DMA end irq */ -+#define CIM_STATE_DMA_STOP (1 << 4) /* DMA stop irq */ -+#define CIM_STATE_RXF_OF (1 << 3) /* RXFIFO over flow irq */ -+#define CIM_STATE_RXF_TRIG (1 << 2) /* RXFIFO triger meet irq */ -+#define CIM_STATE_RXF_EMPTY (1 << 1) /* RXFIFO empty irq */ -+#define CIM_STATE_VDD (1 << 0) /* CIM disabled irq */ -+ -+/* CIM DMA Command Register (CIM_CMD) */ -+ -+#define CIM_CMD_SOFINT (1 << 31) /* enable DMA start irq */ -+#define CIM_CMD_EOFINT (1 << 30) /* enable DMA end irq */ -+#define CIM_CMD_EEOFINT (1 << 29) /* enable DMA EEOF irq */ -+#define CIM_CMD_STOP (1 << 28) /* enable DMA stop irq */ -+#define CIM_CMD_OFRCV (1 << 27) /* enable recovery when TXFiFo overflow */ -+#define CIM_CMD_LEN_BIT 0 -+#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) -+ -+/* CIM Window-Image Size Register (CIM_SIZE) */ -+#define CIM_SIZE_LPF_BIT 16 /* Lines per freame for csc output image */ -+#define CIM_SIZE_LPF_MASK (0x1fff << CIM_SIZE_LPF_BIT) -+#define CIM_SIZE_PPL_BIT 0 /* Pixels per line for csc output image, should be an even number */ -+#define CIM_SIZE_PPL_MASK (0x1fff << CIM_SIZE_PPL_BIT) -+ -+/* CIM Image Offset Register (CIM_OFFSET) */ -+#define CIM_OFFSET_V_BIT 16 /* Vertical offset */ -+#define CIM_OFFSET_V_MASK (0xfff << CIM_OFFSET_V_BIT) -+#define CIM_OFFSET_H_BIT 0 /* Horizontal offset, should be an enen number */ -+#define CIM_OFFSET_H_MASK (0xfff << CIM_OFFSET_H_BIT) /*OFFSET_H should be even number*/ -+ -+/************************************************************************* -+ * SADC (Smart A/D Controller) -+ *************************************************************************/ -+ -+#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ -+#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ -+#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ -+#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ -+#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ -+#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ -+#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ -+#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ -+#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ -+#define SADC_ADCLK (SADC_BASE + 0x28) /* ADC Clock Divide Register */ -+ -+#define REG_SADC_ENA REG8(SADC_ENA) -+#define REG_SADC_CFG REG32(SADC_CFG) -+#define REG_SADC_CTRL REG8(SADC_CTRL) -+#define REG_SADC_STATE REG8(SADC_STATE) -+#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) -+#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) -+#define REG_SADC_TSDAT REG32(SADC_TSDAT) -+#define REG_SADC_BATDAT REG16(SADC_BATDAT) -+#define REG_SADC_SADDAT REG16(SADC_SADDAT) -+#define REG_SADC_ADCLK REG32(SADC_ADCLK) -+ -+/* ADC Enable Register */ -+#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ -+#define SADC_ENA_ENTR_SLP (1 << 6) /* Touch Screen Enable */ -+#define SADC_ENA_EXIT_SLP (1 << 5) /* Touch Screen Enable */ -+#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ -+#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ -+#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ -+ -+/* ADC Configure Register */ -+#define SADC_CFG_EXIN (1 << 30) -+#define SADC_CFG_CLKOUT_NUM_BIT 16 -+#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) -+#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ -+#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ -+#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) -+ #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) -+#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ -+#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) -+ #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) -+#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ -+#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) -+#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ -+#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ -+#define SADC_CFG_CMD_BIT 0 /* ADC Command */ -+#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) -+ #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ -+ #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ -+ #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ -+ #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ -+ #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ -+ #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ -+ #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ -+ #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ -+ #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ -+ #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ -+ #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ -+ #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ -+ #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ -+ -+/* ADC Control Register */ -+#define SADC_CTRL_SLPENDM (1 << 5) /* sleep Interrupt Mask */ -+#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ -+#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ -+#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ -+#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ -+#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ -+ -+/* ADC Status Register */ -+#define SADC_STATE_SLEEPND (1 << 5) /* Pen Down Interrupt Flag */ -+#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ -+#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ -+#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ -+#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ -+#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ -+ -+/* ADC Touch Screen Data Register */ -+#define SADC_TSDAT_DATA0_BIT 0 -+#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) -+#define SADC_TSDAT_TYPE0 (1 << 15) -+#define SADC_TSDAT_DATA1_BIT 16 -+#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) -+#define SADC_TSDAT_TYPE1 (1 << 31) -+ -+/* ADC Clock Divide Register */ -+#define SADC_ADCLK_CLKDIV_10_BIT 16 -+#define SADC_ADCLK_CLKDIV_10_MASK (0x7f << SADC_ADCLK_CLKDIV_10_BIT) -+#define SADC_ADCLK_CLKDIV_BIT 0 -+#define SADC_ADCLK_CLKDIV_MASK (0x3f << SADC_ADCLK_CLKDIV_BIT) -+ -+/************************************************************************* -+ * SLCD (Smart LCD Controller) -+ *************************************************************************/ -+ -+#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ -+#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ -+#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ -+#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ -+ -+#define REG_SLCD_CFG REG32(SLCD_CFG) -+#define REG_SLCD_CTRL REG8(SLCD_CTRL) -+#define REG_SLCD_STATE REG8(SLCD_STATE) -+#define REG_SLCD_DATA REG32(SLCD_DATA) -+ -+/* SLCD Configure Register */ -+#define SLCD_CFG_DWIDTH_BIT 10 -+#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_18BIT (0 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_16BIT (1 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x3 (2 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x2 (3 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_8BIT_x1 (4 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_24BIT (5 << SLCD_CFG_DWIDTH_BIT) -+ #define SLCD_CFG_DWIDTH_9BIT_x2 (7 << SLCD_CFG_DWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_BIT (8) -+#define SLCD_CFG_CWIDTH_MASK (0x7 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CWIDTH_24BIT (3 << SLCD_CFG_CWIDTH_BIT) -+#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) -+#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) -+#define SLCD_CFG_RS_CMD_LOW (0 << 3) -+#define SLCD_CFG_RS_CMD_HIGH (1 << 3) -+#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) -+#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) -+#define SLCD_CFG_TYPE_PARALLEL (0 << 0) -+#define SLCD_CFG_TYPE_SERIAL (1 << 0) -+ -+/* SLCD Control Register */ -+#define SLCD_CTRL_DMA_EN (1 << 0) -+ -+/* SLCD Status Register */ -+#define SLCD_STATE_BUSY (1 << 0) -+ -+/* SLCD Data Register */ -+#define SLCD_DATA_RS_DATA (0 << 31) -+#define SLCD_DATA_RS_COMMAND (1 << 31) -+ -+/************************************************************************* -+ * LCD (LCD Controller) -+ *************************************************************************/ -+#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ -+#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ -+#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ -+ -+#define LCD_OSDC (LCD_BASE + 0x100) /* LCD OSD Configure Register */ -+#define LCD_OSDCTRL (LCD_BASE + 0x104) /* LCD OSD Control Register */ -+#define LCD_OSDS (LCD_BASE + 0x108) /* LCD OSD Status Register */ -+#define LCD_BGC (LCD_BASE + 0x10C) /* LCD Background Color Register */ -+#define LCD_KEY0 (LCD_BASE + 0x110) /* LCD Foreground Color Key Register 0 */ -+#define LCD_KEY1 (LCD_BASE + 0x114) /* LCD Foreground Color Key Register 1 */ -+#define LCD_ALPHA (LCD_BASE + 0x118) /* LCD ALPHA Register */ -+#define LCD_IPUR (LCD_BASE + 0x11C) /* LCD IPU Restart Register */ -+ -+#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ -+#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ -+#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ -+ -+#define LCD_XYP0 (LCD_BASE + 0x120) /* Foreground 0 XY Position Register */ -+#define LCD_XYP1 (LCD_BASE + 0x124) /* Foreground 1 XY Position Register */ -+#define LCD_SIZE0 (LCD_BASE + 0x128) /* Foreground 0 Size Register */ -+#define LCD_SIZE1 (LCD_BASE + 0x12C) /* Foreground 1 Size Register */ -+#define LCD_RGBC (LCD_BASE + 0x90) /* RGB Controll Register */ -+ -+#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ -+#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ -+#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ -+#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ -+#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ -+#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ -+#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ -+#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ -+#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ -+#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ -+#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ -+#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ -+#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ -+#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ -+#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ -+ -+#define LCD_OFFS0 (LCD_BASE + 0x60) /* DMA Offsize Register 0 */ -+#define LCD_PW0 (LCD_BASE + 0x64) /* DMA Page Width Register 0 */ -+#define LCD_CNUM0 (LCD_BASE + 0x68) /* DMA Command Counter Register 0 */ -+#define LCD_DESSIZE0 (LCD_BASE + 0x6C) /* Foreground Size in Descriptor 0 Register*/ -+#define LCD_OFFS1 (LCD_BASE + 0x70) /* DMA Offsize Register 1 */ -+#define LCD_PW1 (LCD_BASE + 0x74) /* DMA Page Width Register 1 */ -+#define LCD_CNUM1 (LCD_BASE + 0x78) /* DMA Command Counter Register 1 */ -+#define LCD_DESSIZE1 (LCD_BASE + 0x7C) /* Foreground Size in Descriptor 1 Register*/ -+ -+#define REG_LCD_CFG REG32(LCD_CFG) -+#define REG_LCD_CTRL REG32(LCD_CTRL) -+#define REG_LCD_STATE REG32(LCD_STATE) -+ -+#define REG_LCD_OSDC REG16(LCD_OSDC) -+#define REG_LCD_OSDCTRL REG16(LCD_OSDCTRL) -+#define REG_LCD_OSDS REG16(LCD_OSDS) -+#define REG_LCD_BGC REG32(LCD_BGC) -+#define REG_LCD_KEY0 REG32(LCD_KEY0) -+#define REG_LCD_KEY1 REG32(LCD_KEY1) -+#define REG_LCD_ALPHA REG8(LCD_ALPHA) -+#define REG_LCD_IPUR REG32(LCD_IPUR) -+ -+#define REG_LCD_VAT REG32(LCD_VAT) -+#define REG_LCD_DAH REG32(LCD_DAH) -+#define REG_LCD_DAV REG32(LCD_DAV) -+ -+#define REG_LCD_XYP0 REG32(LCD_XYP0) -+#define REG_LCD_XYP1 REG32(LCD_XYP1) -+#define REG_LCD_SIZE0 REG32(LCD_SIZE0) -+#define REG_LCD_SIZE1 REG32(LCD_SIZE1) -+#define REG_LCD_RGBC REG16(LCD_RGBC) -+ -+#define REG_LCD_VSYNC REG32(LCD_VSYNC) -+#define REG_LCD_HSYNC REG32(LCD_HSYNC) -+#define REG_LCD_PS REG32(LCD_PS) -+#define REG_LCD_CLS REG32(LCD_CLS) -+#define REG_LCD_SPL REG32(LCD_SPL) -+#define REG_LCD_REV REG32(LCD_REV) -+#define REG_LCD_IID REG32(LCD_IID) -+#define REG_LCD_DA0 REG32(LCD_DA0) -+#define REG_LCD_SA0 REG32(LCD_SA0) -+#define REG_LCD_FID0 REG32(LCD_FID0) -+#define REG_LCD_CMD0 REG32(LCD_CMD0) -+#define REG_LCD_DA1 REG32(LCD_DA1) -+#define REG_LCD_SA1 REG32(LCD_SA1) -+#define REG_LCD_FID1 REG32(LCD_FID1) -+#define REG_LCD_CMD1 REG32(LCD_CMD1) -+ -+#define REG_LCD_OFFS0 REG32(LCD_OFFS0) -+#define REG_LCD_PW0 REG32(LCD_PW0) -+#define REG_LCD_CNUM0 REG32(LCD_CNUM0) -+#define REG_LCD_DESSIZE0 REG32(LCD_DESSIZE0) -+#define REG_LCD_OFFS1 REG32(LCD_OFFS1) -+#define REG_LCD_PW1 REG32(LCD_PW1) -+#define REG_LCD_CNUM1 REG32(LCD_CNUM1) -+#define REG_LCD_DESSIZE1 REG32(LCD_DESSIZE1) -+ -+/* LCD Configure Register */ -+#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ -+#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) -+ #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) -+#define LCD_CFG_TVEPEH (1 << 30) /* TVE PAL enable extra halfline signal */ -+#define LCD_CFG_FUHOLD (1 << 29) /* hold pixel clock when outFIFO underrun */ -+#define LCD_CFG_NEWDES (1 << 28) /* use new descripter. old: 4words, new:8words */ -+#define LCD_CFG_PALBP (1 << 27) /* bypass data format and alpha blending */ -+#define LCD_CFG_TVEN (1 << 26) /* indicate the terminal is lcd or tv */ -+#define LCD_CFG_RECOVER (1 << 25) /* Auto recover when output fifo underrun */ -+#define LCD_CFG_DITHER (1 << 24) /* Dither function */ -+#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ -+#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ -+#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ -+#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ -+#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ -+#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ -+#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ -+#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ -+#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ -+#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ -+#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ -+#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ -+#define LCD_CFG_HSP (1 << 11) /* HSYNC polarity:0-active high,1-active low */ -+#define LCD_CFG_PCP (1 << 10) /* PCLK polarity:0-rising,1-falling */ -+#define LCD_CFG_DEP (1 << 9) /* DE polarity:0-active high,1-active low */ -+#define LCD_CFG_VSP (1 << 8) /* VSYNC polarity:0-rising,1-falling */ -+#define LCD_CFG_MODE_TFT_18BIT (1 << 7) /* 18bit TFT */ -+#define LCD_CFG_MODE_TFT_16BIT (0 << 7) /* 16bit TFT */ -+#define LCD_CFG_MODE_TFT_24BIT (1 << 6) /* 24bit TFT */ -+#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ -+#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) -+#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ -+ #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ -+ #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ -+ #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ -+#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ -+#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ -+ #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_LCM (13 << LCD_CFG_MODE_BIT) -+ #define LCD_CFG_MODE_SLCD LCD_CFG_MODE_LCM -+ -+/* LCD Control Register */ -+#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ -+#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) -+ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ -+ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ -+ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ -+ #define LCD_CTRL_BST_32 (3 << LCD_CTRL_BST_BIT) /* 32-word */ -+#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode(foreground 0 in OSD mode) */ -+#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode(foreground 0 in OSD mode) */ -+#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ -+#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ -+#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) -+ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ -+ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ -+ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ -+#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ -+#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) -+#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ -+#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ -+#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ -+#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ -+#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ -+#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ -+#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ -+#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ -+#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ -+#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ -+#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ -+#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ -+#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) -+ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ -+ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ -+ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ -+ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ -+ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ -+ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ -+ #define LCD_CTRL_BPP_CMPS_24 (6 << LCD_CTRL_BPP_BIT) /* 24 compress bpp */ -+ -+/* LCD Status Register */ -+#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ -+#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ -+#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ -+#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ -+#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ -+#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ -+#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ -+ -+/* OSD Configure Register */ -+#define LCD_OSDC_SOFM1 (1 << 15) /* Start of frame interrupt mask for foreground 1 */ -+#define LCD_OSDC_EOFM1 (1 << 14) /* End of frame interrupt mask for foreground 1 */ -+#define LCD_OSDC_REM1 (1 << 13) /* Real end of frame mask for foreground 1 */ -+#define LCD_OSDC_SOFM0 (1 << 11) /* Start of frame interrupt mask for foreground 0 */ -+#define LCD_OSDC_EOFM0 (1 << 10) /* End of frame interrupt mask for foreground 0 */ -+#define LCD_OSDC_REM0 (1 << 9) /* Real end of frame mask for foreground 0 */ -+#define LCD_OSDC_REMB (1 << 7) /* Real end of frame mask for background */ -+#define LCD_OSDC_F1EN (1 << 4) /* enable foreground 1 */ -+#define LCD_OSDC_F0EN (1 << 3) /* enable foreground 0 */ -+#define LCD_OSDC_ALPHAEN (1 << 2) /* enable alpha blending */ -+#define LCD_OSDC_ALPHAMD (1 << 1) /* alpha blending mode */ -+#define LCD_OSDC_OSDEN (1 << 0) /* OSD mode enable */ -+ -+/* OSD Controll Register */ -+#define LCD_OSDCTRL_IPU (1 << 15) /* input data from IPU */ -+#define LCD_OSDCTRL_RGB565 (0 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ -+#define LCD_OSDCTRL_RGB555 (1 << 4) /* foreground 1, 16bpp, 0-RGB565, 1-RGB555 */ -+#define LCD_OSDCTRL_CHANGES (1 << 3) /* Change size flag */ -+#define LCD_OSDCTRL_OSDBPP_BIT 0 /* Bits Per Pixel of OSD Channel 1 */ -+#define LCD_OSDCTRL_OSDBPP_MASK (0x7< -+ * -+ * 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 __ASM_BOARD_SERIAL_H__ -+#define __ASM_BOARD_SERIAL_H__ -+ -+#ifndef CONFIG_SERIAL_MANY_PORTS -+#undef RS_TABLE_SIZE -+#define RS_TABLE_SIZE 1 -+#endif -+ -+#define JZ_BASE_BAUD (12000000/16) -+ -+#define JZ_SERIAL_PORT_DEFNS \ -+ { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ -+ .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ -+ .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, -+ -+#endif /* __ASM_BORAD_SERIAL_H__ */ -diff -urN linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/war.h linux-2.6.24.7/include/asm-mips/mach-jz4750d/war.h ---- linux-2.6.24.7.old/include/asm-mips/mach-jz4750d/war.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/mach-jz4750d/war.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,25 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle -+ */ -+#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H -+#define __ASM_MIPS_MACH_JZ4740_WAR_H -+ -+#define R4600_V1_INDEX_ICACHEOP_WAR 0 -+#define R4600_V1_HIT_CACHEOP_WAR 0 -+#define R4600_V2_HIT_CACHEOP_WAR 0 -+#define R5432_CP0_INTERRUPT_WAR 0 -+#define BCM1250_M3_WAR 0 -+#define SIBYTE_1956_WAR 0 -+#define MIPS4K_ICACHE_REFILL_WAR 0 -+#define MIPS_CACHE_SYNC_WAR 0 -+#define TX49XX_ICACHE_INDEX_INV_WAR 0 -+#define RM9000_CDEX_SMP_WAR 0 -+#define ICACHE_REFILLS_WORKAROUND_WAR 0 -+#define R10000_LLSC_WAR 0 -+#define MIPS34K_MISSED_ITLB_WAR 0 -+ -+#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ -diff -urN linux-2.6.24.7.old/include/asm-mips/ptrace.h linux-2.6.24.7/include/asm-mips/ptrace.h ---- linux-2.6.24.7.old/include/asm-mips/ptrace.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/asm-mips/ptrace.h 2009-04-12 18:13:57.000000000 +0200 -@@ -79,7 +79,7 @@ - /* - * Does the process account for user or for system time? - */ --#define user_mode(regs) (((regs)->cp0_status & KU_MASK) == KU_USER) -+#define user_mode(regs) ((((regs)->cp0_status & KU_MASK) == KU_USER) || (((regs)->cp0_status & 0x08000000) == 0x08000000)) - - #define instruction_pointer(regs) ((regs)->cp0_epc) - #define profile_pc(regs) instruction_pointer(regs) -diff -urN linux-2.6.24.7.old/include/asm-mips/r4kcache.h linux-2.6.24.7/include/asm-mips/r4kcache.h ---- linux-2.6.24.7.old/include/asm-mips/r4kcache.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/asm-mips/r4kcache.h 2009-04-12 18:13:57.000000000 +0200 -@@ -17,6 +17,58 @@ - #include - #include - -+#ifdef CONFIG_JZRISC -+ -+#define K0_TO_K1() \ -+do { \ -+ unsigned long __k0_addr; \ -+ \ -+ __asm__ __volatile__( \ -+ "la %0, 1f\n\t" \ -+ "or %0, %0, %1\n\t" \ -+ "jr %0\n\t" \ -+ "nop\n\t" \ -+ "1: nop\n" \ -+ : "=&r"(__k0_addr) \ -+ : "r" (0x20000000) ); \ -+} while(0) -+ -+#define K1_TO_K0() \ -+do { \ -+ unsigned long __k0_addr; \ -+ __asm__ __volatile__( \ -+ "nop;nop;nop;nop;nop;nop;nop\n\t" \ -+ "la %0, 1f\n\t" \ -+ "jr %0\n\t" \ -+ "nop\n\t" \ -+ "1: nop\n" \ -+ : "=&r" (__k0_addr)); \ -+} while (0) -+ -+#define INVALIDATE_BTB() \ -+do { \ -+ unsigned long tmp; \ -+ __asm__ __volatile__( \ -+ ".set mips32\n\t" \ -+ "mfc0 %0, $16, 7\n\t" \ -+ "nop\n\t" \ -+ "ori %0, 2\n\t" \ -+ "mtc0 %0, $16, 7\n\t" \ -+ "nop\n\t" \ -+ : "=&r" (tmp)); \ -+} while (0) -+ -+#define SYNC_WB() __asm__ __volatile__ ("sync") -+ -+#else /* CONFIG_JZRISC */ -+ -+#define K0_TO_K1() do { } while (0) -+#define K1_TO_K0() do { } while (0) -+#define INVALIDATE_BTB() do { } while (0) -+#define SYNC_WB() do { } while (0) -+ -+#endif /* CONFIG_JZRISC */ -+ - /* - * This macro return a properly sign-extended address suitable as base address - * for indexed cache operations. Two issues here: -@@ -144,6 +196,7 @@ - { - __iflush_prologue - cache_op(Index_Invalidate_I, addr); -+ INVALIDATE_BTB(); - __iflush_epilogue - } - -@@ -151,6 +204,7 @@ - { - __dflush_prologue - cache_op(Index_Writeback_Inv_D, addr); -+ SYNC_WB(); - __dflush_epilogue - } - -@@ -163,6 +217,7 @@ - { - __iflush_prologue - cache_op(Hit_Invalidate_I, addr); -+ INVALIDATE_BTB(); - __iflush_epilogue - } - -@@ -170,6 +225,7 @@ - { - __dflush_prologue - cache_op(Hit_Writeback_Inv_D, addr); -+ SYNC_WB(); - __dflush_epilogue - } - -@@ -177,6 +233,7 @@ - { - __dflush_prologue - cache_op(Hit_Invalidate_D, addr); -+ SYNC_WB(); - __dflush_epilogue - } - -@@ -209,6 +266,7 @@ - static inline void protected_flush_icache_line(unsigned long addr) - { - protected_cache_op(Hit_Invalidate_I, addr); -+ INVALIDATE_BTB(); - } - - /* -@@ -220,6 +278,7 @@ - static inline void protected_writeback_dcache_line(unsigned long addr) - { - protected_cache_op(Hit_Writeback_Inv_D, addr); -+ SYNC_WB(); - } - - static inline void protected_writeback_scache_line(unsigned long addr) -@@ -396,13 +455,123 @@ - __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16) - __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16) - __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16) -+#ifndef CONFIG_JZRISC - __BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32) - __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32) -+#endif - __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32) - __BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64) - __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64) - __BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128) - -+#ifdef CONFIG_JZRISC -+ -+static inline void blast_dcache32(void) -+{ -+ unsigned long start = INDEX_BASE; -+ unsigned long end = start + current_cpu_data.dcache.waysize; -+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; -+ unsigned long ws_end = current_cpu_data.dcache.ways << -+ current_cpu_data.dcache.waybit; -+ unsigned long ws, addr; -+ -+ for (ws = 0; ws < ws_end; ws += ws_inc) -+ for (addr = start; addr < end; addr += 0x400) -+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D); -+ -+ SYNC_WB(); -+} -+ -+static inline void blast_dcache32_page(unsigned long page) -+{ -+ unsigned long start = page; -+ unsigned long end = page + PAGE_SIZE; -+ -+ do { -+ cache32_unroll32(start,Hit_Writeback_Inv_D); -+ start += 0x400; -+ } while (start < end); -+ -+ SYNC_WB(); -+} -+ -+static inline void blast_dcache32_page_indexed(unsigned long page) -+{ -+ unsigned long indexmask = current_cpu_data.dcache.waysize - 1; -+ unsigned long start = INDEX_BASE + (page & indexmask); -+ unsigned long end = start + PAGE_SIZE; -+ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; -+ unsigned long ws_end = current_cpu_data.dcache.ways << -+ current_cpu_data.dcache.waybit; -+ unsigned long ws, addr; -+ -+ for (ws = 0; ws < ws_end; ws += ws_inc) -+ for (addr = start; addr < end; addr += 0x400) -+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D); -+ -+ SYNC_WB(); -+} -+ -+static inline void blast_icache32(void) -+{ -+ unsigned long start = INDEX_BASE; -+ unsigned long end = start + current_cpu_data.icache.waysize; -+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; -+ unsigned long ws_end = current_cpu_data.icache.ways << -+ current_cpu_data.icache.waybit; -+ unsigned long ws, addr; -+ -+ K0_TO_K1(); -+ -+ for (ws = 0; ws < ws_end; ws += ws_inc) -+ for (addr = start; addr < end; addr += 0x400) -+ cache32_unroll32(addr|ws,Index_Invalidate_I); -+ -+ INVALIDATE_BTB(); -+ -+ K1_TO_K0(); -+} -+ -+static inline void blast_icache32_page(unsigned long page) -+{ -+ unsigned long start = page; -+ unsigned long end = page + PAGE_SIZE; -+ -+ K0_TO_K1(); -+ -+ do { -+ cache32_unroll32(start,Hit_Invalidate_I); -+ start += 0x400; -+ } while (start < end); -+ -+ INVALIDATE_BTB(); -+ -+ K1_TO_K0(); -+} -+ -+static inline void blast_icache32_page_indexed(unsigned long page) -+{ -+ unsigned long indexmask = current_cpu_data.icache.waysize - 1; -+ unsigned long start = INDEX_BASE + (page & indexmask); -+ unsigned long end = start + PAGE_SIZE; -+ unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; -+ unsigned long ws_end = current_cpu_data.icache.ways << -+ current_cpu_data.icache.waybit; -+ unsigned long ws, addr; -+ -+ K0_TO_K1(); -+ -+ for (ws = 0; ws < ws_end; ws += ws_inc) -+ for (addr = start; addr < end; addr += 0x400) -+ cache32_unroll32(addr|ws,Index_Invalidate_I); -+ -+ INVALIDATE_BTB(); -+ -+ K1_TO_K0(); -+} -+ -+#endif /* CONFIG_JZRISC */ -+ - /* build blast_xxx_range, protected_blast_xxx_range */ - #define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \ - static inline void prot##blast_##pfx##cache##_range(unsigned long start, \ -@@ -424,13 +593,73 @@ - __##pfx##flush_epilogue \ - } - -+#ifndef CONFIG_JZRISC - __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_) -+#endif - __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_) -+#ifndef CONFIG_JZRISC - __BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_) - __BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, ) -+#endif - __BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, ) - /* blast_inv_dcache_range */ - __BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, ) - __BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, ) - -+#ifdef CONFIG_JZRISC -+ -+static inline void protected_blast_dcache_range(unsigned long start, -+ unsigned long end) -+{ -+ unsigned long lsize = cpu_dcache_line_size(); -+ unsigned long addr = start & ~(lsize - 1); -+ unsigned long aend = (end - 1) & ~(lsize - 1); -+ -+ while (1) { -+ protected_cache_op(Hit_Writeback_Inv_D, addr); -+ if (addr == aend) -+ break; -+ addr += lsize; -+ } -+ SYNC_WB(); -+} -+ -+static inline void protected_blast_icache_range(unsigned long start, -+ unsigned long end) -+{ -+ unsigned long lsize = cpu_icache_line_size(); -+ unsigned long addr = start & ~(lsize - 1); -+ unsigned long aend = (end - 1) & ~(lsize - 1); -+ -+ K0_TO_K1(); -+ -+ while (1) { -+ protected_cache_op(Hit_Invalidate_I, addr); -+ if (addr == aend) -+ break; -+ addr += lsize; -+ } -+ INVALIDATE_BTB(); -+ -+ K1_TO_K0(); -+} -+ -+static inline void blast_dcache_range(unsigned long start, -+ unsigned long end) -+{ -+ unsigned long lsize = cpu_dcache_line_size(); -+ unsigned long addr = start & ~(lsize - 1); -+ unsigned long aend = (end - 1) & ~(lsize - 1); -+ -+ while (1) { -+ cache_op(Hit_Writeback_Inv_D, addr); -+ if (addr == aend) -+ break; -+ addr += lsize; -+ } -+ SYNC_WB(); -+} -+ -+#endif /* CONFIG_JZRISC */ -+ - #endif /* _ASM_R4KCACHE_H */ -diff -urN linux-2.6.24.7.old/include/asm-mips/sizes.h linux-2.6.24.7/include/asm-mips/sizes.h ---- linux-2.6.24.7.old/include/asm-mips/sizes.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/asm-mips/sizes.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,56 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+/* DO NOT EDIT!! - this file automatically generated -+ * from .s file by awk -f s2h.awk -+ */ -+/* Size definitions -+ * Copyright (C) ARM Limited 1998. All rights reserved. -+ */ -+ -+#ifndef __sizes_h -+#define __sizes_h 1 -+ -+/* handy sizes */ -+#define SZ_16 0x00000010 -+#define SZ_256 0x00000100 -+#define SZ_512 0x00000200 -+ -+#define SZ_1K 0x00000400 -+#define SZ_4K 0x00001000 -+#define SZ_8K 0x00002000 -+#define SZ_16K 0x00004000 -+#define SZ_64K 0x00010000 -+#define SZ_128K 0x00020000 -+#define SZ_256K 0x00040000 -+#define SZ_512K 0x00080000 -+ -+#define SZ_1M 0x00100000 -+#define SZ_2M 0x00200000 -+#define SZ_4M 0x00400000 -+#define SZ_8M 0x00800000 -+#define SZ_16M 0x01000000 -+#define SZ_32M 0x02000000 -+#define SZ_64M 0x04000000 -+#define SZ_128M 0x08000000 -+#define SZ_256M 0x10000000 -+#define SZ_512M 0x20000000 -+ -+#define SZ_1G 0x40000000 -+#define SZ_2G 0x80000000 -+ -+#endif -+ -+/* END */ -diff -urN linux-2.6.24.7.old/include/linux/fs.h linux-2.6.24.7/include/linux/fs.h ---- linux-2.6.24.7.old/include/linux/fs.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/fs.h 2009-04-12 18:13:57.000000000 +0200 -@@ -1670,6 +1670,8 @@ - extern int invalidate_inode_pages2(struct address_space *mapping); - extern int invalidate_inode_pages2_range(struct address_space *mapping, - pgoff_t start, pgoff_t end); -+extern void generic_sync_sb_inodes(struct super_block *sb, -+ struct writeback_control *wbc); - extern int write_inode_now(struct inode *, int); - extern int filemap_fdatawrite(struct address_space *); - extern int filemap_flush(struct address_space *); -diff -urN linux-2.6.24.7.old/include/linux/i2c-dev.h linux-2.6.24.7/include/linux/i2c-dev.h ---- linux-2.6.24.7.old/include/linux/i2c-dev.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/i2c-dev.h 2009-04-12 18:13:57.000000000 +0200 -@@ -49,7 +49,8 @@ - - #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ - #define I2C_SMBUS 0x0720 /* SMBus transfer */ -- -+#define I2C_SET_SUB_ADDRESS 0x0730 /* SMBus transfer */ -+#define I2C_SET_CLOCK 0x0731 /* SMBus transfer */ - - /* This is the structure as used in the I2C_SMBUS ioctl call */ - struct i2c_smbus_ioctl_data { -@@ -71,4 +72,5 @@ - #define I2C_MAJOR 89 /* Device major number */ - #endif - -+extern void i2c_jz_setclk(unsigned int i2cclk); - #endif /* _LINUX_I2C_DEV_H */ -diff -urN linux-2.6.24.7.old/include/linux/mmc/host.h linux-2.6.24.7/include/linux/mmc/host.h ---- linux-2.6.24.7.old/include/linux/mmc/host.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/mmc/host.h 2009-04-12 18:13:57.000000000 +0200 -@@ -41,6 +41,7 @@ - - #define MMC_BUS_WIDTH_1 0 - #define MMC_BUS_WIDTH_4 2 -+#define MMC_BUS_WIDTH_8 4 - - unsigned char timing; /* timing specification used */ - -diff -urN linux-2.6.24.7.old/include/linux/mtd/mtd.h linux-2.6.24.7/include/linux/mtd/mtd.h ---- linux-2.6.24.7.old/include/linux/mtd/mtd.h 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/include/linux/mtd/mtd.h 2009-04-12 18:13:57.000000000 +0200 -@@ -32,9 +32,9 @@ - specific to any particular block. */ - struct erase_info { - struct mtd_info *mtd; -- u_int32_t addr; -- u_int32_t len; -- u_int32_t fail_addr; -+ u_int64_t addr; -+ u_int64_t len; -+ u_int64_t fail_addr; - u_long time; - u_long retries; - u_int dev; -@@ -46,7 +46,7 @@ - }; - - struct mtd_erase_region_info { -- u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ -+ u_int64_t offset; /* At which this region starts, from the beginning of the MTD */ - u_int32_t erasesize; /* For this region */ - u_int32_t numblocks; /* Number of blocks of erasesize in this region */ - unsigned long *lockmap; /* If keeping bitmap of locks */ -@@ -89,10 +89,10 @@ - */ - struct mtd_oob_ops { - mtd_oob_mode_t mode; -- size_t len; -- size_t retlen; -- size_t ooblen; -- size_t oobretlen; -+ size_mtd_t len; -+ size_mtd_t retlen; -+ size_mtd_t ooblen; -+ size_mtd_t oobretlen; - uint32_t ooboffs; - uint8_t *datbuf; - uint8_t *oobbuf; -@@ -102,7 +102,7 @@ - struct mtd_info { - u_char type; - u_int32_t flags; -- u_int32_t size; // Total size of the MTD -+ u_int64_t size; // Total size of the MTD - - /* "Major" erase size for the device. Naïve users may take this - * to be the only erase size available, or may use the more detailed -@@ -144,18 +144,18 @@ - int (*erase) (struct mtd_info *mtd, struct erase_info *instr); - - /* This stuff for eXecute-In-Place */ -- int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); -+ int (*point) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char **mtdbuf); - - /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ -- void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); -+ void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_mtd_t from, size_mtd_t len); - - -- int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -- int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -+ int (*read) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf); -+ int (*write) (struct mtd_info *mtd, loff_mtd_t to, size_mtd_t len, size_mtd_t *retlen, const u_char *buf); - -- int (*read_oob) (struct mtd_info *mtd, loff_t from, -+ int (*read_oob) (struct mtd_info *mtd, loff_mtd_t from, - struct mtd_oob_ops *ops); -- int (*write_oob) (struct mtd_info *mtd, loff_t to, -+ int (*write_oob) (struct mtd_info *mtd, loff_mtd_t to, - struct mtd_oob_ops *ops); - - /* -@@ -163,33 +163,33 @@ - * flash devices. The user data is one time programmable but the - * factory data is read only. - */ -- int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); -- int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -- int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); -- int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -- int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -- int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); -+ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_mtd_t len); -+ int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf); -+ int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_mtd_t len); -+ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf); -+ int (*write_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, size_mtd_t *retlen, u_char *buf); -+ int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len); - - /* kvec-based read/write methods. - NB: The 'count' parameter is the number of _vectors_, each of - which contains an (ofs, len) tuple. - */ -- int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); -+ int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_mtd_t to, size_mtd_t *retlen); - - /* Sync */ - void (*sync) (struct mtd_info *mtd); - - /* Chip-supported device locking */ -- int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len); -- int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); -+ int (*lock) (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len); -+ int (*unlock) (struct mtd_info *mtd, loff_mtd_t ofs, size_mtd_t len); - - /* Power Management functions */ - int (*suspend) (struct mtd_info *mtd); - void (*resume) (struct mtd_info *mtd); - - /* Bad block management functions */ -- int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); -- int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); -+ int (*block_isbad) (struct mtd_info *mtd, loff_mtd_t ofs); -+ int (*block_markbad) (struct mtd_info *mtd, loff_mtd_t ofs); - - struct notifier_block reboot_notifier; /* default mode before reboot */ - -@@ -237,10 +237,10 @@ - extern int unregister_mtd_user (struct mtd_notifier *old); - - int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, -- unsigned long count, loff_t to, size_t *retlen); -+ unsigned long count, loff_mtd_t to, size_mtd_t *retlen); - - int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, -- unsigned long count, loff_t from, size_t *retlen); -+ unsigned long count, loff_mtd_t from, size_mtd_t *retlen); - - #ifdef CONFIG_MTD_PARTITIONS - void mtd_erase_callback(struct erase_info *instr); -diff -urN linux-2.6.24.7.old/include/linux/mtd/mtd.h.orig linux-2.6.24.7/include/linux/mtd/mtd.h.orig ---- linux-2.6.24.7.old/include/linux/mtd/mtd.h.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/linux/mtd/mtd.h.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,274 @@ -+/* -+ * $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $ -+ * -+ * Copyright (C) 1999-2003 David Woodhouse et al. -+ * -+ * Released under GPL -+ */ -+ -+#ifndef __MTD_MTD_H__ -+#define __MTD_MTD_H__ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#define MTD_CHAR_MAJOR 90 -+#define MTD_BLOCK_MAJOR 31 -+#define MAX_MTD_DEVICES 32 -+ -+#define MTD_ERASE_PENDING 0x01 -+#define MTD_ERASING 0x02 -+#define MTD_ERASE_SUSPEND 0x04 -+#define MTD_ERASE_DONE 0x08 -+#define MTD_ERASE_FAILED 0x10 -+ -+/* If the erase fails, fail_addr might indicate exactly which block failed. If -+ fail_addr = 0xffffffff, the failure was not at the device level or was not -+ specific to any particular block. */ -+struct erase_info { -+ struct mtd_info *mtd; -+ u_int32_t addr; -+ u_int32_t len; -+ u_int32_t fail_addr; -+ u_long time; -+ u_long retries; -+ u_int dev; -+ u_int cell; -+ void (*callback) (struct erase_info *self); -+ u_long priv; -+ u_char state; -+ struct erase_info *next; -+}; -+ -+struct mtd_erase_region_info { -+ u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ -+ u_int32_t erasesize; /* For this region */ -+ u_int32_t numblocks; /* Number of blocks of erasesize in this region */ -+ unsigned long *lockmap; /* If keeping bitmap of locks */ -+}; -+ -+/* -+ * oob operation modes -+ * -+ * MTD_OOB_PLACE: oob data are placed at the given offset -+ * MTD_OOB_AUTO: oob data are automatically placed at the free areas -+ * which are defined by the ecclayout -+ * MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data -+ * is inserted into the data. Thats a raw image of the -+ * flash contents. -+ */ -+typedef enum { -+ MTD_OOB_PLACE, -+ MTD_OOB_AUTO, -+ MTD_OOB_RAW, -+} mtd_oob_mode_t; -+ -+/** -+ * struct mtd_oob_ops - oob operation operands -+ * @mode: operation mode -+ * -+ * @len: number of data bytes to write/read -+ * -+ * @retlen: number of data bytes written/read -+ * -+ * @ooblen: number of oob bytes to write/read -+ * @oobretlen: number of oob bytes written/read -+ * @ooboffs: offset of oob data in the oob area (only relevant when -+ * mode = MTD_OOB_PLACE) -+ * @datbuf: data buffer - if NULL only oob data are read/written -+ * @oobbuf: oob data buffer -+ * -+ * Note, it is allowed to read more then one OOB area at one go, but not write. -+ * The interface assumes that the OOB write requests program only one page's -+ * OOB area. -+ */ -+struct mtd_oob_ops { -+ mtd_oob_mode_t mode; -+ size_t len; -+ size_t retlen; -+ size_t ooblen; -+ size_t oobretlen; -+ uint32_t ooboffs; -+ uint8_t *datbuf; -+ uint8_t *oobbuf; -+}; -+ -+struct mtd_info; -+struct mtd_info { -+ u_char type; -+ u_int32_t flags; -+ u_int32_t size; // Total size of the MTD -+ -+ /* "Major" erase size for the device. Naïve users may take this -+ * to be the only erase size available, or may use the more detailed -+ * information below if they desire -+ */ -+ u_int32_t erasesize; -+ /* Minimal writable flash unit size. In case of NOR flash it is 1 (even -+ * though individual bits can be cleared), in case of NAND flash it is -+ * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR -+ * it is of ECC block size, etc. It is illegal to have writesize = 0. -+ * Any driver registering a struct mtd_info must ensure a writesize of -+ * 1 or larger. -+ */ -+ u_int32_t writesize; -+ -+ u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) -+ u_int32_t oobavail; // Available OOB bytes per block -+ -+ // Kernel-only stuff starts here. -+ char *name; -+ int index; -+ -+ /* ecc layout structure pointer - read only ! */ -+ struct nand_ecclayout *ecclayout; -+ -+ /* Data for variable erase regions. If numeraseregions is zero, -+ * it means that the whole device has erasesize as given above. -+ */ -+ int numeraseregions; -+ struct mtd_erase_region_info *eraseregions; -+ -+ /* -+ * Erase is an asynchronous operation. Device drivers are supposed -+ * to call instr->callback() whenever the operation completes, even -+ * if it completes with a failure. -+ * Callers are supposed to pass a callback function and wait for it -+ * to be called before writing to the block. -+ */ -+ int (*erase) (struct mtd_info *mtd, struct erase_info *instr); -+ -+ /* This stuff for eXecute-In-Place */ -+ int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); -+ -+ /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ -+ void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); -+ -+ -+ int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -+ int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -+ -+ int (*read_oob) (struct mtd_info *mtd, loff_t from, -+ struct mtd_oob_ops *ops); -+ int (*write_oob) (struct mtd_info *mtd, loff_t to, -+ struct mtd_oob_ops *ops); -+ -+ /* -+ * Methods to access the protection register area, present in some -+ * flash devices. The user data is one time programmable but the -+ * factory data is read only. -+ */ -+ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); -+ int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -+ int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); -+ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -+ int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -+ int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); -+ -+ /* kvec-based read/write methods. -+ NB: The 'count' parameter is the number of _vectors_, each of -+ which contains an (ofs, len) tuple. -+ */ -+ int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); -+ -+ /* Sync */ -+ void (*sync) (struct mtd_info *mtd); -+ -+ /* Chip-supported device locking */ -+ int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len); -+ int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); -+ -+ /* Power Management functions */ -+ int (*suspend) (struct mtd_info *mtd); -+ void (*resume) (struct mtd_info *mtd); -+ -+ /* Bad block management functions */ -+ int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); -+ int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); -+ -+ struct notifier_block reboot_notifier; /* default mode before reboot */ -+ -+ /* ECC status information */ -+ struct mtd_ecc_stats ecc_stats; -+ /* Subpage shift (NAND) */ -+ int subpage_sft; -+ -+ void *priv; -+ -+ struct module *owner; -+ int usecount; -+ -+ int (*refresh_device)(struct mtd_info *mtd); -+ struct mtd_info *split; -+ -+ /* If the driver is something smart, like UBI, it may need to maintain -+ * its own reference counting. The below functions are only for driver. -+ * The driver may register its callbacks. These callbacks are not -+ * supposed to be called by MTD users */ -+ int (*get_device) (struct mtd_info *mtd); -+ void (*put_device) (struct mtd_info *mtd); -+}; -+ -+ -+ /* Kernel-side ioctl definitions */ -+ -+extern int add_mtd_device(struct mtd_info *mtd); -+extern int del_mtd_device (struct mtd_info *mtd); -+ -+extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); -+extern struct mtd_info *get_mtd_device_nm(const char *name); -+ -+extern void put_mtd_device(struct mtd_info *mtd); -+ -+ -+struct mtd_notifier { -+ void (*add)(struct mtd_info *mtd); -+ void (*remove)(struct mtd_info *mtd); -+ struct list_head list; -+}; -+ -+ -+extern void register_mtd_user (struct mtd_notifier *new); -+extern int unregister_mtd_user (struct mtd_notifier *old); -+ -+int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, -+ unsigned long count, loff_t to, size_t *retlen); -+ -+int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, -+ unsigned long count, loff_t from, size_t *retlen); -+ -+#ifdef CONFIG_MTD_PARTITIONS -+void mtd_erase_callback(struct erase_info *instr); -+#else -+static inline void mtd_erase_callback(struct erase_info *instr) -+{ -+ if (instr->callback) -+ instr->callback(instr); -+} -+#endif -+ -+/* -+ * Debugging macro and defines -+ */ -+#define MTD_DEBUG_LEVEL0 (0) /* Quiet */ -+#define MTD_DEBUG_LEVEL1 (1) /* Audible */ -+#define MTD_DEBUG_LEVEL2 (2) /* Loud */ -+#define MTD_DEBUG_LEVEL3 (3) /* Noisy */ -+ -+#ifdef CONFIG_MTD_DEBUG -+#define DEBUG(n, args...) \ -+ do { \ -+ if (n <= CONFIG_MTD_DEBUG_VERBOSE) \ -+ printk(KERN_INFO args); \ -+ } while(0) -+#else /* CONFIG_MTD_DEBUG */ -+#define DEBUG(n, args...) do { } while(0) -+ -+#endif /* CONFIG_MTD_DEBUG */ -+ -+#endif /* __MTD_MTD_H__ */ -diff -urN linux-2.6.24.7.old/include/linux/mtd/nand.h linux-2.6.24.7/include/linux/mtd/nand.h ---- linux-2.6.24.7.old/include/linux/mtd/nand.h 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/include/linux/mtd/nand.h 2009-04-12 18:13:57.000000000 +0200 -@@ -39,14 +39,14 @@ - extern void nand_wait_ready(struct mtd_info *mtd); - - /* The maximum number of NAND chips in an array */ --#define NAND_MAX_CHIPS 8 -+#define NAND_MAX_CHIPS 4 - - /* This constant declares the max. oobsize / page, which - * is supported now. If you add a chip with bigger oobsize/page - * adjust this accordingly. - */ --#define NAND_MAX_OOBSIZE 64 --#define NAND_MAX_PAGESIZE 2048 -+#define NAND_MAX_OOBSIZE 256 -+#define NAND_MAX_PAGESIZE 8192 - - /* - * Constants for hardware specific CLE/ALE/NCE function -@@ -55,6 +55,10 @@ - * bits in one go. - */ - /* Select the chip by setting nCE to low */ -+#define NAND_NCE1 0x08 -+#define NAND_NCE2 0x10 -+#define NAND_NCE3 0x20 -+#define NAND_NCE4 0x40 - #define NAND_NCE 0x01 - /* Select the command latch by setting CLE to high */ - #define NAND_CLE 0x02 -@@ -372,8 +376,8 @@ - void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); - int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); - void (*select_chip)(struct mtd_info *mtd, int chip); -- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); -- int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); -+ int (*block_bad)(struct mtd_info *mtd, loff_mtd_t ofs, int getchip); -+ int (*block_markbad)(struct mtd_info *mtd, loff_mtd_t ofs); - void (*cmd_ctrl)(struct mtd_info *mtd, int dat, - unsigned int ctrl); - int (*dev_ready)(struct mtd_info *mtd); -@@ -393,12 +397,14 @@ - int bbt_erase_shift; - int chip_shift; - int numchips; -- unsigned long chipsize; -+ u64 chipsize; - int pagemask; - int pagebuf; - int subpagesize; - uint8_t cellinfo; - int badblockpos; -+ int realplanenum; /* number of planes the NAND has */ -+ int planenum; /* number of planes operating synchronously */ - - nand_state_t state; - -@@ -450,7 +456,7 @@ - char *name; - int id; - unsigned long pagesize; -- unsigned long chipsize; -+ u64 chipsize; - unsigned long erasesize; - unsigned long options; - }; -@@ -538,13 +544,13 @@ - #define NAND_BBT_SCAN_MAXBLOCKS 4 - - extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd); --extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs); -+extern int nand_update_bbt(struct mtd_info *mtd, loff_mtd_t offs); - extern int nand_default_bbt(struct mtd_info *mtd); --extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); -+extern int nand_isbad_bbt(struct mtd_info *mtd, loff_mtd_t offs, int allowbbt); - extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, - int allowbbt); --extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, -- size_t * retlen, uint8_t * buf); -+extern int nand_do_read(struct mtd_info *mtd, loff_mtd_t from, size_mtd_t len, -+ size_mtd_t * retlen, uint8_t * buf); - - /* - * Constants for oob configuration -diff -urN linux-2.6.24.7.old/include/linux/mtd/partitions.h linux-2.6.24.7/include/linux/mtd/partitions.h ---- linux-2.6.24.7.old/include/linux/mtd/partitions.h 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/include/linux/mtd/partitions.h 2009-04-12 18:13:57.000000000 +0200 -@@ -39,8 +39,9 @@ - struct mtd_partition; - struct mtd_partition { - char *name; /* identifier string */ -- u_int32_t size; /* partition size */ -- u_int32_t offset; /* offset within the master MTD space */ -+ u_int64_t size; /* partition size */ -+ u_int64_t offset; /* offset within the master MTD space */ -+ char use_planes; /* flag to specify whether multiple planes of NAND is used in the partition */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ - struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ - struct mtd_info **mtdp; /* pointer to store the MTD object */ -diff -urN linux-2.6.24.7.old/include/linux/mtd/partitions.h.orig linux-2.6.24.7/include/linux/mtd/partitions.h.orig ---- linux-2.6.24.7.old/include/linux/mtd/partitions.h.orig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/linux/mtd/partitions.h.orig 2009-04-12 18:01:55.000000000 +0200 -@@ -0,0 +1,78 @@ -+/* -+ * MTD partitioning layer definitions -+ * -+ * (C) 2000 Nicolas Pitre -+ * -+ * This code is GPL -+ * -+ * $Id: partitions.h,v 1.17 2005/11/07 11:14:55 gleixner Exp $ -+ */ -+ -+#ifndef MTD_PARTITIONS_H -+#define MTD_PARTITIONS_H -+ -+#include -+ -+ -+/* -+ * Partition definition structure: -+ * -+ * An array of struct partition is passed along with a MTD object to -+ * add_mtd_partitions() to create them. -+ * -+ * For each partition, these fields are available: -+ * name: string that will be used to label the partition's MTD device. -+ * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition -+ * will extend to the end of the master MTD device. -+ * offset: absolute starting position within the master MTD device; if -+ * defined as MTDPART_OFS_APPEND, the partition will start where the -+ * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. -+ * mask_flags: contains flags that have to be masked (removed) from the -+ * master MTD flag set for the corresponding MTD partition. -+ * For example, to force a read-only partition, simply adding -+ * MTD_WRITEABLE to the mask_flags will do the trick. -+ * -+ * Note: writeable partitions require their size and offset be -+ * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). -+ */ -+ -+struct mtd_partition; -+struct mtd_partition { -+ char *name; /* identifier string */ -+ u_int32_t size; /* partition size */ -+ u_int32_t offset; /* offset within the master MTD space */ -+ u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ -+ struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/ -+ struct mtd_info **mtdp; /* pointer to store the MTD object */ -+ int (*refresh_partition)(struct mtd_info *); -+}; -+ -+#define MTDPART_OFS_NXTBLK (-2) -+#define MTDPART_OFS_APPEND (-1) -+#define MTDPART_SIZ_FULL (0) -+ -+ -+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); -+int del_mtd_partitions(struct mtd_info *); -+int refresh_mtd_partitions(struct mtd_info *); -+ -+/* -+ * Functions dealing with the various ways of partitioning the space -+ */ -+ -+struct mtd_part_parser { -+ struct list_head list; -+ struct module *owner; -+ const char *name; -+ int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); -+}; -+ -+extern int register_mtd_parser(struct mtd_part_parser *parser); -+extern int deregister_mtd_parser(struct mtd_part_parser *parser); -+extern int parse_mtd_partitions(struct mtd_info *master, const char **types, -+ struct mtd_partition **pparts, unsigned long origin); -+ -+#define put_partition_parser(p) do { module_put((p)->owner); } while(0) -+ -+#endif -+ -diff -urN linux-2.6.24.7.old/include/linux/mtd/ubi.h linux-2.6.24.7/include/linux/mtd/ubi.h ---- linux-2.6.24.7.old/include/linux/mtd/ubi.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/mtd/ubi.h 2009-04-12 18:13:57.000000000 +0200 -@@ -26,23 +26,6 @@ - #include - - /* -- * UBI data type hint constants. -- * -- * UBI_LONGTERM: long-term data -- * UBI_SHORTTERM: short-term data -- * UBI_UNKNOWN: data persistence is unknown -- * -- * These constants are used when data is written to UBI volumes in order to -- * help the UBI wear-leveling unit to find more appropriate physical -- * eraseblocks. -- */ --enum { -- UBI_LONGTERM = 1, -- UBI_SHORTTERM, -- UBI_UNKNOWN --}; -- --/* - * enum ubi_open_mode - UBI volume open mode constants. - * - * UBI_READONLY: read-only mode -@@ -167,6 +150,7 @@ - int len, int dtype); - int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum); - int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum); -+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype); - int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); - - /* -diff -urN linux-2.6.24.7.old/include/linux/vt.h linux-2.6.24.7/include/linux/vt.h ---- linux-2.6.24.7.old/include/linux/vt.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/vt.h 2009-04-12 18:13:57.000000000 +0200 -@@ -18,10 +18,16 @@ - * resizing). - */ - #define MIN_NR_CONSOLES 1 /* must be at least 1 */ --#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ --#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ -- /* Note: the ioctl VT_GETSTATE does not work for -- consoles 16 and higher (since it returns a short) */ -+ -+#if defined(CONFIG_JZSOC) -+#define MAX_NR_CONSOLES 2 -+#define MAX_NR_USER_CONSOLES 2 -+#else -+#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ -+#define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */ -+ /* Note: the ioctl VT_GETSTATE does not work for -+ consoles 16 and higher (since it returns a short) */ -+#endif - - /* 0x56 is 'V', to avoid collision with termios and kd */ - -diff -urN linux-2.6.24.7.old/include/linux/writeback.h linux-2.6.24.7/include/linux/writeback.h ---- linux-2.6.24.7.old/include/linux/writeback.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/linux/writeback.h 2009-04-12 18:13:57.000000000 +0200 -@@ -70,6 +70,7 @@ - void writeback_inodes(struct writeback_control *wbc); - int inode_wait(void *); - void sync_inodes_sb(struct super_block *, int wait); -+void writeback_inodes_sb(struct super_block *sb, struct writeback_control *wbc); - void sync_inodes(int wait); - - /* writeback.h requires fs.h; it, too, is not included from here. */ -diff -urN linux-2.6.24.7.old/include/mtd/mtd-abi.h linux-2.6.24.7/include/mtd/mtd-abi.h ---- linux-2.6.24.7.old/include/mtd/mtd-abi.h 2009-04-12 18:05:07.000000000 +0200 -+++ linux-2.6.24.7/include/mtd/mtd-abi.h 2009-04-12 18:23:10.000000000 +0200 -@@ -7,9 +7,18 @@ - #ifndef __MTD_ABI_H__ - #define __MTD_ABI_H__ - -+ -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif -+ -+typedef unsigned long long size_mtd_t; -+typedef unsigned long long loff_mtd_t; -+ - struct erase_info_user { -- uint32_t start; -- uint32_t length; -+ uint64_t start; -+ uint64_t length; - }; - - struct mtd_oob_buf { -@@ -18,6 +27,14 @@ - unsigned char __user *ptr; - }; - -+struct mtd_page_buf { -+ uint32_t start; //page start address -+ uint32_t ooblength; -+ uint32_t datlength; -+ unsigned char __user *oobptr; -+ unsigned char __user *datptr; -+}; -+ - #define MTD_ABSENT 0 - #define MTD_RAM 1 - #define MTD_ROM 2 -@@ -52,7 +69,7 @@ - struct mtd_info_user { - uint8_t type; - uint32_t flags; -- uint32_t size; // Total size of the MTD -+ uint64_t size; // Total size of the MTD - uint32_t erasesize; - uint32_t writesize; - uint32_t oobsize; // Amount of OOB data per block (e.g. 16) -@@ -63,7 +80,7 @@ - }; - - struct region_info_user { -- uint32_t offset; /* At which this region starts, -+ uint64_t offset; /* At which this region starts, - * from the beginning of the MTD */ - uint32_t erasesize; /* For this region */ - uint32_t numblocks; /* Number of blocks in this region */ -@@ -86,8 +103,8 @@ - #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) - #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) - #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) --#define MEMGETBADBLOCK _IOW('M', 11, loff_t) --#define MEMSETBADBLOCK _IOW('M', 12, loff_t) -+#define MEMGETBADBLOCK _IOW('M', 11, loff_mtd_t) -+#define MEMSETBADBLOCK _IOW('M', 12, loff_mtd_t) - #define OTPSELECT _IOR('M', 13, int) - #define OTPGETREGIONCOUNT _IOW('M', 14, int) - #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) -@@ -95,6 +112,7 @@ - #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) - #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) - #define MTDFILEMODE _IO('M', 19) -+#define MEMWRITEPAGE _IOWR('M', 20, struct mtd_page_buf) - #define MTDREFRESH _IO('M', 23) - - /* -@@ -105,7 +123,7 @@ - uint32_t useecc; - uint32_t eccbytes; - uint32_t oobfree[8][2]; -- uint32_t eccpos[32]; -+ uint32_t eccpos[104]; - }; - - struct nand_oobfree { -@@ -120,7 +138,7 @@ - */ - struct nand_ecclayout { - uint32_t eccbytes; -- uint32_t eccpos[64]; -+ uint32_t eccpos[128]; - uint32_t oobavail; - struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; - }; -diff -urN linux-2.6.24.7.old/include/mtd/ubi-user.h linux-2.6.24.7/include/mtd/ubi-user.h ---- linux-2.6.24.7.old/include/mtd/ubi-user.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/mtd/ubi-user.h 2009-04-12 18:13:57.000000000 +0200 -@@ -21,7 +21,26 @@ - #ifndef __UBI_USER_H__ - #define __UBI_USER_H__ - -+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into -+ separate files was to avoid #ifdef __KERNEL__ */ -+#define __user -+#endif - /* -+ * UBI device creation (the same as MTD device attachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI -+ * control device. The caller has to properly fill and pass -+ * &struct ubi_attach_req object - UBI will attach the MTD device specified in -+ * the request and return the newly created UBI device number as the ioctl -+ * return value. -+ * -+ * UBI device deletion (the same as MTD device detachment) -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI -+ * control device. -+ * - * UBI volume creation - * ~~~~~~~~~~~~~~~~~~~ - * -@@ -48,7 +67,7 @@ - * - * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the - * corresponding UBI volume character device. A pointer to a 64-bit update -- * size should be passed to the IOCTL. After then, UBI expects user to write -+ * size should be passed to the IOCTL. After this, UBI expects user to write - * this number of bytes to the volume character device. The update is finished - * when the claimed number of bytes is passed. So, the volume update sequence - * is something like: -@@ -57,14 +76,24 @@ - * ioctl(fd, UBI_IOCVOLUP, &image_size); - * write(fd, buf, image_size); - * close(fd); -+ * -+ * Atomic eraseblock change -+ * ~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL -+ * command of the corresponding UBI volume character device. A pointer to -+ * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is -+ * expected to write the requested amount of bytes. This is similar to the -+ * "volume update" IOCTL. - */ - - /* -- * When a new volume is created, users may either specify the volume number they -- * want to create or to let UBI automatically assign a volume number using this -- * constant. -+ * When a new UBI volume or UBI device is created, users may either specify the -+ * volume/device number they want to create or to let UBI automatically assign -+ * the number using these constants. - */ - #define UBI_VOL_NUM_AUTO (-1) -+#define UBI_DEV_NUM_AUTO (-1) - - /* Maximum volume name length */ - #define UBI_MAX_VOLUME_NAME 127 -@@ -80,6 +109,15 @@ - /* Re-size an UBI volume */ - #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) - -+/* IOCTL commands of the UBI control character device */ -+ -+#define UBI_CTRL_IOC_MAGIC 'o' -+ -+/* Attach an MTD device */ -+#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) -+/* Detach an MTD device */ -+#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) -+ - /* IOCTL commands of UBI volume character devices */ - - #define UBI_VOL_IOC_MAGIC 'O' -@@ -88,6 +126,30 @@ - #define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) - /* An eraseblock erasure command, used for debugging, disabled by default */ - #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) -+/* An atomic eraseblock change command */ -+#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) -+/* Start UBI leb read */ -+#define UBI_IOCLEBREAD _IOWR(UBI_VOL_IOC_MAGIC, 3, struct ubi_leb) -+ -+/* Maximum MTD device name length supported by UBI */ -+#define MAX_UBI_MTD_NAME_LEN 127 -+ -+/* -+ * UBI data type hint constants. -+ * -+ * UBI_LONGTERM: long-term data -+ * UBI_SHORTTERM: short-term data -+ * UBI_UNKNOWN: data persistence is unknown -+ * -+ * These constants are used when data is written to UBI volumes in order to -+ * help the UBI wear-leveling unit to find more appropriate physical -+ * eraseblocks. -+ */ -+enum { -+ UBI_LONGTERM = 1, -+ UBI_SHORTTERM = 2, -+ UBI_UNKNOWN = 3, -+}; - - /* - * UBI volume type constants. -@@ -97,22 +159,58 @@ - */ - enum { - UBI_DYNAMIC_VOLUME = 3, -- UBI_STATIC_VOLUME = 4 -+ UBI_STATIC_VOLUME = 4, -+}; -+ -+/** -+ * struct ubi_attach_req - attach MTD device request. -+ * @ubi_num: UBI device number to create -+ * @mtd_num: MTD device number to attach -+ * @vid_hdr_offset: VID header offset (use defaults if %0) -+ * @padding: reserved for future, not used, has to be zeroed -+ * -+ * This data structure is used to specify MTD device UBI has to attach and the -+ * parameters it has to use. The number which should be assigned to the new UBI -+ * device is passed in @ubi_num. UBI may automatically assign the number if -+ * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in -+ * @ubi_num. -+ * -+ * Most applications should pass %0 in @vid_hdr_offset to make UBI use default -+ * offset of the VID header within physical eraseblocks. The default offset is -+ * the next min. I/O unit after the EC header. For example, it will be offset -+ * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or -+ * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. -+ * -+ * But in rare cases, if this optimizes things, the VID header may be placed to -+ * a different offset. For example, the boot-loader might do things faster if the -+ * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As -+ * the boot-loader would not normally need to read EC headers (unless it needs -+ * UBI in RW mode), it might be faster to calculate ECC. This is weird example, -+ * but it real-life example. So, in this example, @vid_hdr_offer would be -+ * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes -+ * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page -+ * of the first page and add needed padding. -+ */ -+struct ubi_attach_req { -+ int32_t ubi_num; -+ int32_t mtd_num; -+ int32_t vid_hdr_offset; -+ uint8_t padding[12]; - }; - - /** - * struct ubi_mkvol_req - volume description data structure used in -- * volume creation requests. -+ * volume creation requests. - * @vol_id: volume number - * @alignment: volume alignment - * @bytes: volume size in bytes - * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) -- * @padding1: reserved for future, not used -+ * @padding1: reserved for future, not used, has to be zeroed - * @name_len: volume name length -- * @padding2: reserved for future, not used -+ * @padding2: reserved for future, not used, has to be zeroed - * @name: volume name - * -- * This structure is used by userspace programs when creating new volumes. The -+ * This structure is used by user-space programs when creating new volumes. The - * @used_bytes field is only necessary when creating static volumes. - * - * The @alignment field specifies the required alignment of the volume logical -@@ -139,7 +237,7 @@ - int8_t padding1; - int16_t name_len; - int8_t padding2[4]; -- char name[UBI_MAX_VOLUME_NAME+1]; -+ char name[UBI_MAX_VOLUME_NAME + 1]; - } __attribute__ ((packed)); - - /** -@@ -158,4 +256,29 @@ - int32_t vol_id; - } __attribute__ ((packed)); - -+/** -+ * struct ubi_leb_change_req - a data structure used in atomic logical -+ * eraseblock change requests. -+ * @lnum: logical eraseblock number to change -+ * @bytes: how many bytes will be written to the logical eraseblock -+ * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) -+ * @padding: reserved for future, not used, has to be zeroed -+ */ -+struct ubi_leb_change_req { -+ int32_t lnum; -+ int32_t bytes; -+ uint8_t dtype; -+ uint8_t padding[7]; -+} __attribute__ ((packed)); -+ -+/** -+ * struct ubi_leb - a data structure describe LEB. -+ * @lnum: logical eraseblock number to dump -+ * @lebbuf: LEB data buffer -+ */ -+struct ubi_leb{ -+ unsigned int lnum; -+ char __user *buf; -+}; -+ - #endif /* __UBI_USER_H__ */ -diff -urN linux-2.6.24.7.old/include/sound/pcm.h linux-2.6.24.7/include/sound/pcm.h ---- linux-2.6.24.7.old/include/sound/pcm.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/include/sound/pcm.h 2009-04-12 18:13:57.000000000 +0200 -@@ -107,23 +107,23 @@ - #define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */ - #define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */ - #define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */ --#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */ --#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */ --#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */ --#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */ --#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */ --#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */ --#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */ --#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ --#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ --#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ -+#define SNDRV_PCM_RATE_12000 (1<<3) /* 12000Hz */ -+#define SNDRV_PCM_RATE_16000 (1<<4) /* 16000Hz */ -+#define SNDRV_PCM_RATE_22050 (1<<5) /* 22050Hz */ -+#define SNDRV_PCM_RATE_24000 (1<<6) /* 24000Hz */ -+#define SNDRV_PCM_RATE_32000 (1<<7) /* 32000Hz */ -+#define SNDRV_PCM_RATE_44100 (1<<8) /* 44100Hz */ -+#define SNDRV_PCM_RATE_48000 (1<<9) /* 48000Hz */ -+#define SNDRV_PCM_RATE_64000 (1<<10) /* 64000Hz */ -+#define SNDRV_PCM_RATE_88200 (1<<11) /* 88200Hz */ -+#define SNDRV_PCM_RATE_96000 (1<<12) /* 96000Hz */ -+#define SNDRV_PCM_RATE_176400 (1<<13) /* 176400Hz */ -+#define SNDRV_PCM_RATE_192000 (1<<14) /* 192000Hz */ - - #define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ - #define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ - --#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\ -- SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\ -- SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100) -+#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|SNDRV_PCM_RATE_12000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_24000|SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100) - #define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000) - #define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\ - SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) -diff -urN linux-2.6.24.7.old/include/sound/pcm.h.org linux-2.6.24.7/include/sound/pcm.h.org ---- linux-2.6.24.7.old/include/sound/pcm.h.org 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/include/sound/pcm.h.org 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1011 @@ -+#ifndef __SOUND_PCM_H -+#define __SOUND_PCM_H -+ -+/* -+ * Digital Audio (PCM) abstract layer -+ * Copyright (c) by Jaroslav Kysela -+ * Abramo Bagnara -+ * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define snd_pcm_substream_chip(substream) ((substream)->private_data) -+#define snd_pcm_chip(pcm) ((pcm)->private_data) -+ -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+#include "pcm_oss.h" -+#endif -+ -+/* -+ * Hardware (lowlevel) section -+ */ -+ -+struct snd_pcm_hardware { -+ unsigned int info; /* SNDRV_PCM_INFO_* */ -+ u64 formats; /* SNDRV_PCM_FMTBIT_* */ -+ unsigned int rates; /* SNDRV_PCM_RATE_* */ -+ unsigned int rate_min; /* min rate */ -+ unsigned int rate_max; /* max rate */ -+ unsigned int channels_min; /* min channels */ -+ unsigned int channels_max; /* max channels */ -+ size_t buffer_bytes_max; /* max buffer size */ -+ size_t period_bytes_min; /* min period size */ -+ size_t period_bytes_max; /* max period size */ -+ unsigned int periods_min; /* min # of periods */ -+ unsigned int periods_max; /* max # of periods */ -+ size_t fifo_size; /* fifo size in bytes */ -+}; -+ -+struct snd_pcm_substream; -+ -+struct snd_pcm_ops { -+ int (*open)(struct snd_pcm_substream *substream); -+ int (*close)(struct snd_pcm_substream *substream); -+ int (*ioctl)(struct snd_pcm_substream * substream, -+ unsigned int cmd, void *arg); -+ int (*hw_params)(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params); -+ int (*hw_free)(struct snd_pcm_substream *substream); -+ int (*prepare)(struct snd_pcm_substream *substream); -+ int (*trigger)(struct snd_pcm_substream *substream, int cmd); -+ snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); -+ int (*copy)(struct snd_pcm_substream *substream, int channel, -+ snd_pcm_uframes_t pos, -+ void __user *buf, snd_pcm_uframes_t count); -+ int (*silence)(struct snd_pcm_substream *substream, int channel, -+ snd_pcm_uframes_t pos, snd_pcm_uframes_t count); -+ struct page *(*page)(struct snd_pcm_substream *substream, -+ unsigned long offset); -+ int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma); -+ int (*ack)(struct snd_pcm_substream *substream); -+}; -+ -+/* -+ * -+ */ -+ -+#define SNDRV_PCM_DEVICES 8 -+ -+#define SNDRV_PCM_IOCTL1_FALSE ((void *)0) -+#define SNDRV_PCM_IOCTL1_TRUE ((void *)1) -+ -+#define SNDRV_PCM_IOCTL1_RESET 0 -+#define SNDRV_PCM_IOCTL1_INFO 1 -+#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 -+#define SNDRV_PCM_IOCTL1_GSTATE 3 -+ -+#define SNDRV_PCM_TRIGGER_STOP 0 -+#define SNDRV_PCM_TRIGGER_START 1 -+#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 3 -+#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4 -+#define SNDRV_PCM_TRIGGER_SUSPEND 5 -+#define SNDRV_PCM_TRIGGER_RESUME 6 -+ -+#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1) -+ -+/* If you change this don't forget to change rates[] table in pcm_native.c */ -+#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */ -+#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */ -+#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */ -+#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */ -+#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */ -+#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */ -+#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */ -+#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */ -+#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */ -+#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */ -+#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */ -+#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */ -+#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */ -+ -+#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */ -+#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */ -+ -+#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\ -+ SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\ -+ SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100) -+#define SNDRV_PCM_RATE_8000_48000 (SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000) -+#define SNDRV_PCM_RATE_8000_96000 (SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\ -+ SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000) -+#define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\ -+ SNDRV_PCM_RATE_192000) -+#define SNDRV_PCM_FMTBIT_S8 (1ULL << SNDRV_PCM_FORMAT_S8) -+#define SNDRV_PCM_FMTBIT_U8 (1ULL << SNDRV_PCM_FORMAT_U8) -+#define SNDRV_PCM_FMTBIT_S16_LE (1ULL << SNDRV_PCM_FORMAT_S16_LE) -+#define SNDRV_PCM_FMTBIT_S16_BE (1ULL << SNDRV_PCM_FORMAT_S16_BE) -+#define SNDRV_PCM_FMTBIT_U16_LE (1ULL << SNDRV_PCM_FORMAT_U16_LE) -+#define SNDRV_PCM_FMTBIT_U16_BE (1ULL << SNDRV_PCM_FORMAT_U16_BE) -+#define SNDRV_PCM_FMTBIT_S24_LE (1ULL << SNDRV_PCM_FORMAT_S24_LE) -+#define SNDRV_PCM_FMTBIT_S24_BE (1ULL << SNDRV_PCM_FORMAT_S24_BE) -+#define SNDRV_PCM_FMTBIT_U24_LE (1ULL << SNDRV_PCM_FORMAT_U24_LE) -+#define SNDRV_PCM_FMTBIT_U24_BE (1ULL << SNDRV_PCM_FORMAT_U24_BE) -+#define SNDRV_PCM_FMTBIT_S32_LE (1ULL << SNDRV_PCM_FORMAT_S32_LE) -+#define SNDRV_PCM_FMTBIT_S32_BE (1ULL << SNDRV_PCM_FORMAT_S32_BE) -+#define SNDRV_PCM_FMTBIT_U32_LE (1ULL << SNDRV_PCM_FORMAT_U32_LE) -+#define SNDRV_PCM_FMTBIT_U32_BE (1ULL << SNDRV_PCM_FORMAT_U32_BE) -+#define SNDRV_PCM_FMTBIT_FLOAT_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT_LE) -+#define SNDRV_PCM_FMTBIT_FLOAT_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT_BE) -+#define SNDRV_PCM_FMTBIT_FLOAT64_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE) -+#define SNDRV_PCM_FMTBIT_FLOAT64_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE) -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE) -+#define SNDRV_PCM_FMTBIT_MU_LAW (1ULL << SNDRV_PCM_FORMAT_MU_LAW) -+#define SNDRV_PCM_FMTBIT_A_LAW (1ULL << SNDRV_PCM_FORMAT_A_LAW) -+#define SNDRV_PCM_FMTBIT_IMA_ADPCM (1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM) -+#define SNDRV_PCM_FMTBIT_MPEG (1ULL << SNDRV_PCM_FORMAT_MPEG) -+#define SNDRV_PCM_FMTBIT_GSM (1ULL << SNDRV_PCM_FORMAT_GSM) -+#define SNDRV_PCM_FMTBIT_SPECIAL (1ULL << SNDRV_PCM_FORMAT_SPECIAL) -+#define SNDRV_PCM_FMTBIT_S24_3LE (1ULL << SNDRV_PCM_FORMAT_S24_3LE) -+#define SNDRV_PCM_FMTBIT_U24_3LE (1ULL << SNDRV_PCM_FORMAT_U24_3LE) -+#define SNDRV_PCM_FMTBIT_S24_3BE (1ULL << SNDRV_PCM_FORMAT_S24_3BE) -+#define SNDRV_PCM_FMTBIT_U24_3BE (1ULL << SNDRV_PCM_FORMAT_U24_3BE) -+#define SNDRV_PCM_FMTBIT_S20_3LE (1ULL << SNDRV_PCM_FORMAT_S20_3LE) -+#define SNDRV_PCM_FMTBIT_U20_3LE (1ULL << SNDRV_PCM_FORMAT_U20_3LE) -+#define SNDRV_PCM_FMTBIT_S20_3BE (1ULL << SNDRV_PCM_FORMAT_S20_3BE) -+#define SNDRV_PCM_FMTBIT_U20_3BE (1ULL << SNDRV_PCM_FORMAT_U20_3BE) -+#define SNDRV_PCM_FMTBIT_S18_3LE (1ULL << SNDRV_PCM_FORMAT_S18_3LE) -+#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE) -+#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE) -+#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE) -+ -+#ifdef SNDRV_LITTLE_ENDIAN -+#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE -+#define SNDRV_PCM_FMTBIT_U16 SNDRV_PCM_FMTBIT_U16_LE -+#define SNDRV_PCM_FMTBIT_S24 SNDRV_PCM_FMTBIT_S24_LE -+#define SNDRV_PCM_FMTBIT_U24 SNDRV_PCM_FMTBIT_U24_LE -+#define SNDRV_PCM_FMTBIT_S32 SNDRV_PCM_FMTBIT_S32_LE -+#define SNDRV_PCM_FMTBIT_U32 SNDRV_PCM_FMTBIT_U32_LE -+#define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_LE -+#define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_LE -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE -+#endif -+#ifdef SNDRV_BIG_ENDIAN -+#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_BE -+#define SNDRV_PCM_FMTBIT_U16 SNDRV_PCM_FMTBIT_U16_BE -+#define SNDRV_PCM_FMTBIT_S24 SNDRV_PCM_FMTBIT_S24_BE -+#define SNDRV_PCM_FMTBIT_U24 SNDRV_PCM_FMTBIT_U24_BE -+#define SNDRV_PCM_FMTBIT_S32 SNDRV_PCM_FMTBIT_S32_BE -+#define SNDRV_PCM_FMTBIT_U32 SNDRV_PCM_FMTBIT_U32_BE -+#define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_BE -+#define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_BE -+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE -+#endif -+ -+struct snd_pcm_file { -+ struct snd_pcm_substream *substream; -+ int no_compat_mmap; -+}; -+ -+struct snd_pcm_hw_rule; -+typedef int (*snd_pcm_hw_rule_func_t)(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule); -+ -+struct snd_pcm_hw_rule { -+ unsigned int cond; -+ snd_pcm_hw_rule_func_t func; -+ int var; -+ int deps[4]; -+ void *private; -+}; -+ -+struct snd_pcm_hw_constraints { -+ struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - -+ SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; -+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - -+ SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; -+ unsigned int rules_num; -+ unsigned int rules_all; -+ struct snd_pcm_hw_rule *rules; -+}; -+ -+static inline struct snd_mask *constrs_mask(struct snd_pcm_hw_constraints *constrs, -+ snd_pcm_hw_param_t var) -+{ -+ return &constrs->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK]; -+} -+ -+static inline struct snd_interval *constrs_interval(struct snd_pcm_hw_constraints *constrs, -+ snd_pcm_hw_param_t var) -+{ -+ return &constrs->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; -+} -+ -+struct snd_ratnum { -+ unsigned int num; -+ unsigned int den_min, den_max, den_step; -+}; -+ -+struct snd_ratden { -+ unsigned int num_min, num_max, num_step; -+ unsigned int den; -+}; -+ -+struct snd_pcm_hw_constraint_ratnums { -+ int nrats; -+ struct snd_ratnum *rats; -+}; -+ -+struct snd_pcm_hw_constraint_ratdens { -+ int nrats; -+ struct snd_ratden *rats; -+}; -+ -+struct snd_pcm_hw_constraint_list { -+ unsigned int count; -+ unsigned int *list; -+ unsigned int mask; -+}; -+ -+struct snd_pcm_runtime { -+ /* -- Status -- */ -+ struct snd_pcm_substream *trigger_master; -+ struct timespec trigger_tstamp; /* trigger timestamp */ -+ int overrange; -+ snd_pcm_uframes_t avail_max; -+ snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ -+ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/ -+ -+ /* -- HW params -- */ -+ snd_pcm_access_t access; /* access mode */ -+ snd_pcm_format_t format; /* SNDRV_PCM_FORMAT_* */ -+ snd_pcm_subformat_t subformat; /* subformat */ -+ unsigned int rate; /* rate in Hz */ -+ unsigned int channels; /* channels */ -+ snd_pcm_uframes_t period_size; /* period size */ -+ unsigned int periods; /* periods */ -+ snd_pcm_uframes_t buffer_size; /* buffer size */ -+ unsigned int tick_time; /* tick time */ -+ snd_pcm_uframes_t min_align; /* Min alignment for the format */ -+ size_t byte_align; -+ unsigned int frame_bits; -+ unsigned int sample_bits; -+ unsigned int info; -+ unsigned int rate_num; -+ unsigned int rate_den; -+ -+ /* -- SW params -- */ -+ int tstamp_mode; /* mmap timestamp is updated */ -+ unsigned int period_step; -+ unsigned int sleep_min; /* min ticks to sleep */ -+ snd_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */ -+ snd_pcm_uframes_t start_threshold; -+ snd_pcm_uframes_t stop_threshold; -+ snd_pcm_uframes_t silence_threshold; /* Silence filling happens when -+ noise is nearest than this */ -+ snd_pcm_uframes_t silence_size; /* Silence filling size */ -+ snd_pcm_uframes_t boundary; /* pointers wrap point */ -+ -+ snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ -+ snd_pcm_uframes_t silence_filled; /* size filled with silence */ -+ -+ union snd_pcm_sync_id sync; /* hardware synchronization ID */ -+ -+ /* -- mmap -- */ -+ struct snd_pcm_mmap_status *status; -+ struct snd_pcm_mmap_control *control; -+ -+ /* -- locking / scheduling -- */ -+ wait_queue_head_t sleep; -+ struct timer_list tick_timer; -+ struct fasync_struct *fasync; -+ -+ /* -- private section -- */ -+ void *private_data; -+ void (*private_free)(struct snd_pcm_runtime *runtime); -+ -+ /* -- hardware description -- */ -+ struct snd_pcm_hardware hw; -+ struct snd_pcm_hw_constraints hw_constraints; -+ -+ /* -- interrupt callbacks -- */ -+ void (*transfer_ack_begin)(struct snd_pcm_substream *substream); -+ void (*transfer_ack_end)(struct snd_pcm_substream *substream); -+ -+ /* -- timer -- */ -+ unsigned int timer_resolution; /* timer resolution */ -+ -+ /* -- DMA -- */ -+ unsigned char *dma_area; /* DMA area */ -+ dma_addr_t dma_addr; /* physical bus address (not accessible from main CPU) */ -+ size_t dma_bytes; /* size of DMA area */ -+ -+ struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */ -+ -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ /* -- OSS things -- */ -+ struct snd_pcm_oss_runtime oss; -+#endif -+}; -+ -+struct snd_pcm_group { /* keep linked substreams */ -+ spinlock_t lock; -+ struct list_head substreams; -+ int count; -+}; -+ -+struct snd_pcm_substream { -+ struct snd_pcm *pcm; -+ struct snd_pcm_str *pstr; -+ void *private_data; /* copied from pcm->private_data */ -+ int number; -+ char name[32]; /* substream name */ -+ int stream; /* stream (direction) */ -+ char latency_id[20]; /* latency identifier */ -+ size_t buffer_bytes_max; /* limit ring buffer size */ -+ struct snd_dma_buffer dma_buffer; -+ unsigned int dma_buf_id; -+ size_t dma_max; -+ /* -- hardware operations -- */ -+ struct snd_pcm_ops *ops; -+ /* -- runtime information -- */ -+ struct snd_pcm_runtime *runtime; -+ /* -- timer section -- */ -+ struct snd_timer *timer; /* timer */ -+ unsigned timer_running: 1; /* time is running */ -+ spinlock_t timer_lock; -+ /* -- next substream -- */ -+ struct snd_pcm_substream *next; -+ /* -- linked substreams -- */ -+ struct list_head link_list; /* linked list member */ -+ struct snd_pcm_group self_group; /* fake group for non linked substream (with substream lock inside) */ -+ struct snd_pcm_group *group; /* pointer to current group */ -+ /* -- assigned files -- */ -+ void *file; -+ int ref_count; -+ atomic_t mmap_count; -+ unsigned int f_flags; -+ void (*pcm_release)(struct snd_pcm_substream *); -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ /* -- OSS things -- */ -+ struct snd_pcm_oss_substream oss; -+#endif -+#ifdef CONFIG_SND_VERBOSE_PROCFS -+ struct snd_info_entry *proc_root; -+ struct snd_info_entry *proc_info_entry; -+ struct snd_info_entry *proc_hw_params_entry; -+ struct snd_info_entry *proc_sw_params_entry; -+ struct snd_info_entry *proc_status_entry; -+ struct snd_info_entry *proc_prealloc_entry; -+ struct snd_info_entry *proc_prealloc_max_entry; -+#endif -+ /* misc flags */ -+ unsigned int hw_opened: 1; -+}; -+ -+#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0) -+ -+ -+struct snd_pcm_str { -+ int stream; /* stream (direction) */ -+ struct snd_pcm *pcm; -+ /* -- substreams -- */ -+ unsigned int substream_count; -+ unsigned int substream_opened; -+ struct snd_pcm_substream *substream; -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ /* -- OSS things -- */ -+ struct snd_pcm_oss_stream oss; -+#endif -+#ifdef CONFIG_SND_VERBOSE_PROCFS -+ struct snd_info_entry *proc_root; -+ struct snd_info_entry *proc_info_entry; -+#ifdef CONFIG_SND_PCM_XRUN_DEBUG -+ unsigned int xrun_debug; /* 0 = disabled, 1 = verbose, 2 = stacktrace */ -+ struct snd_info_entry *proc_xrun_debug_entry; -+#endif -+#endif -+}; -+ -+struct snd_pcm { -+ struct snd_card *card; -+ struct list_head list; -+ unsigned int device; /* device number */ -+ unsigned int info_flags; -+ unsigned short dev_class; -+ unsigned short dev_subclass; -+ char id[64]; -+ char name[80]; -+ struct snd_pcm_str streams[2]; -+ struct mutex open_mutex; -+ wait_queue_head_t open_wait; -+ void *private_data; -+ void (*private_free) (struct snd_pcm *pcm); -+ struct device *dev; /* actual hw device this belongs to */ -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ struct snd_pcm_oss oss; -+#endif -+}; -+ -+struct snd_pcm_notify { -+ int (*n_register) (struct snd_pcm * pcm); -+ int (*n_disconnect) (struct snd_pcm * pcm); -+ int (*n_unregister) (struct snd_pcm * pcm); -+ struct list_head list; -+}; -+ -+/* -+ * Registering -+ */ -+ -+extern const struct file_operations snd_pcm_f_ops[2]; -+ -+int snd_pcm_new(struct snd_card *card, char *id, int device, -+ int playback_count, int capture_count, -+ struct snd_pcm **rpcm); -+int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count); -+ -+int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); -+ -+/* -+ * Native I/O -+ */ -+ -+extern rwlock_t snd_pcm_link_rwlock; -+ -+int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); -+int snd_pcm_info_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_info __user *info); -+int snd_pcm_status(struct snd_pcm_substream *substream, -+ struct snd_pcm_status *status); -+int snd_pcm_start(struct snd_pcm_substream *substream); -+int snd_pcm_stop(struct snd_pcm_substream *substream, int status); -+int snd_pcm_drain_done(struct snd_pcm_substream *substream); -+#ifdef CONFIG_PM -+int snd_pcm_suspend(struct snd_pcm_substream *substream); -+int snd_pcm_suspend_all(struct snd_pcm *pcm); -+#endif -+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); -+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file, -+ struct snd_pcm_substream **rsubstream); -+void snd_pcm_release_substream(struct snd_pcm_substream *substream); -+int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file, -+ struct snd_pcm_substream **rsubstream); -+void snd_pcm_detach_substream(struct snd_pcm_substream *substream); -+void snd_pcm_vma_notify_data(void *client, void *data); -+int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); -+ -+#if BITS_PER_LONG >= 64 -+ -+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -+{ -+ *rem = *n % div; -+ *n /= div; -+} -+ -+#elif defined(i386) -+ -+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -+{ -+ u_int32_t low, high; -+ low = *n & 0xffffffff; -+ high = *n >> 32; -+ if (high) { -+ u_int32_t high1 = high % div; -+ high /= div; -+ asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1)); -+ *n = (u_int64_t)high << 32 | low; -+ } else { -+ *n = low / div; -+ *rem = low % div; -+ } -+} -+#else -+ -+static inline void divl(u_int32_t high, u_int32_t low, -+ u_int32_t div, -+ u_int32_t *q, u_int32_t *r) -+{ -+ u_int64_t n = (u_int64_t)high << 32 | low; -+ u_int64_t d = (u_int64_t)div << 31; -+ u_int32_t q1 = 0; -+ int c = 32; -+ while (n > 0xffffffffU) { -+ q1 <<= 1; -+ if (n >= d) { -+ n -= d; -+ q1 |= 1; -+ } -+ d >>= 1; -+ c--; -+ } -+ q1 <<= c; -+ if (n) { -+ low = n; -+ *q = q1 | (low / div); -+ *r = low % div; -+ } else { -+ *r = 0; -+ *q = q1; -+ } -+ return; -+} -+ -+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem) -+{ -+ u_int32_t low, high; -+ low = *n & 0xffffffff; -+ high = *n >> 32; -+ if (high) { -+ u_int32_t high1 = high % div; -+ u_int32_t low1 = low; -+ high /= div; -+ divl(high1, low1, div, &low, rem); -+ *n = (u_int64_t)high << 32 | low; -+ } else { -+ *n = low / div; -+ *rem = low % div; -+ } -+} -+#endif -+ -+/* -+ * PCM library -+ */ -+ -+static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) -+{ -+ return substream->group != &substream->self_group; -+} -+ -+static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream) -+{ -+ read_lock(&snd_pcm_link_rwlock); -+ spin_lock(&substream->self_group.lock); -+} -+ -+static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) -+{ -+ spin_unlock(&substream->self_group.lock); -+ read_unlock(&snd_pcm_link_rwlock); -+} -+ -+static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) -+{ -+ read_lock_irq(&snd_pcm_link_rwlock); -+ spin_lock(&substream->self_group.lock); -+} -+ -+static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) -+{ -+ spin_unlock(&substream->self_group.lock); -+ read_unlock_irq(&snd_pcm_link_rwlock); -+} -+ -+#define snd_pcm_stream_lock_irqsave(substream, flags) \ -+do { \ -+ read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ -+ spin_lock(&substream->self_group.lock); \ -+} while (0) -+ -+#define snd_pcm_stream_unlock_irqrestore(substream, flags) \ -+do { \ -+ spin_unlock(&substream->self_group.lock); \ -+ read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ -+} while (0) -+ -+#define snd_pcm_group_for_each_entry(s, substream) \ -+ list_for_each_entry(s, &substream->group->substreams, link_list) -+ -+static inline int snd_pcm_running(struct snd_pcm_substream *substream) -+{ -+ return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING || -+ (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING && -+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)); -+} -+ -+static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size) -+{ -+ return size * 8 / runtime->sample_bits; -+} -+ -+static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size) -+{ -+ return size * 8 / runtime->frame_bits; -+} -+ -+static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size) -+{ -+ return size * runtime->sample_bits / 8; -+} -+ -+static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size) -+{ -+ return size * runtime->frame_bits / 8; -+} -+ -+static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes) -+{ -+ return bytes % runtime->byte_align == 0; -+} -+ -+static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return frames_to_bytes(runtime, runtime->buffer_size); -+} -+ -+static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return frames_to_bytes(runtime, runtime->period_size); -+} -+ -+/* -+ * result is: 0 ... (boundary - 1) -+ */ -+static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime) -+{ -+ snd_pcm_sframes_t avail = runtime->status->hw_ptr + runtime->buffer_size - runtime->control->appl_ptr; -+ if (avail < 0) -+ avail += runtime->boundary; -+ else if ((snd_pcm_uframes_t) avail >= runtime->boundary) -+ avail -= runtime->boundary; -+ return avail; -+} -+ -+/* -+ * result is: 0 ... (boundary - 1) -+ */ -+static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime) -+{ -+ snd_pcm_sframes_t avail = runtime->status->hw_ptr - runtime->control->appl_ptr; -+ if (avail < 0) -+ avail += runtime->boundary; -+ return avail; -+} -+ -+static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime) -+{ -+ return runtime->buffer_size - snd_pcm_playback_avail(runtime); -+} -+ -+static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime) -+{ -+ return runtime->buffer_size - snd_pcm_capture_avail(runtime); -+} -+ -+/** -+ * snd_pcm_playback_ready - check whether the playback buffer is available -+ * @substream: the pcm substream instance -+ * -+ * Checks whether enough free space is available on the playback buffer. -+ * -+ * Returns non-zero if available, or zero if not. -+ */ -+static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return snd_pcm_playback_avail(runtime) >= runtime->control->avail_min; -+} -+ -+/** -+ * snd_pcm_capture_ready - check whether the capture buffer is available -+ * @substream: the pcm substream instance -+ * -+ * Checks whether enough capture data is available on the capture buffer. -+ * -+ * Returns non-zero if available, or zero if not. -+ */ -+static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return snd_pcm_capture_avail(runtime) >= runtime->control->avail_min; -+} -+ -+/** -+ * snd_pcm_playback_data - check whether any data exists on the playback buffer -+ * @substream: the pcm substream instance -+ * -+ * Checks whether any data exists on the playback buffer. If stop_threshold -+ * is bigger or equal to boundary, then this function returns always non-zero. -+ * -+ * Returns non-zero if exists, or zero if not. -+ */ -+static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ if (runtime->stop_threshold >= runtime->boundary) -+ return 1; -+ return snd_pcm_playback_avail(runtime) < runtime->buffer_size; -+} -+ -+/** -+ * snd_pcm_playback_empty - check whether the playback buffer is empty -+ * @substream: the pcm substream instance -+ * -+ * Checks whether the playback buffer is empty. -+ * -+ * Returns non-zero if empty, or zero if not. -+ */ -+static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return snd_pcm_playback_avail(runtime) >= runtime->buffer_size; -+} -+ -+/** -+ * snd_pcm_capture_empty - check whether the capture buffer is empty -+ * @substream: the pcm substream instance -+ * -+ * Checks whether the capture buffer is empty. -+ * -+ * Returns non-zero if empty, or zero if not. -+ */ -+static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ return snd_pcm_capture_avail(runtime) == 0; -+} -+ -+static inline void snd_pcm_trigger_done(struct snd_pcm_substream *substream, -+ struct snd_pcm_substream *master) -+{ -+ substream->runtime->trigger_master = master; -+} -+ -+static inline int hw_is_mask(int var) -+{ -+ return var >= SNDRV_PCM_HW_PARAM_FIRST_MASK && -+ var <= SNDRV_PCM_HW_PARAM_LAST_MASK; -+} -+ -+static inline int hw_is_interval(int var) -+{ -+ return var >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL && -+ var <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; -+} -+ -+static inline struct snd_mask *hw_param_mask(struct snd_pcm_hw_params *params, -+ snd_pcm_hw_param_t var) -+{ -+ return ¶ms->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK]; -+} -+ -+static inline struct snd_interval *hw_param_interval(struct snd_pcm_hw_params *params, -+ snd_pcm_hw_param_t var) -+{ -+ return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; -+} -+ -+static inline const struct snd_mask *hw_param_mask_c(const struct snd_pcm_hw_params *params, -+ snd_pcm_hw_param_t var) -+{ -+ return ¶ms->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK]; -+} -+ -+static inline const struct snd_interval *hw_param_interval_c(const struct snd_pcm_hw_params *params, -+ snd_pcm_hw_param_t var) -+{ -+ return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; -+} -+ -+#define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)) -+#define params_format(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT)) -+#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) -+#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min -+#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min -+#define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min -+#define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8) -+#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min -+#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min -+#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min -+#define params_tick_time(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_TICK_TIME)->min -+ -+ -+int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); -+void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); -+void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); -+void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b, -+ unsigned int k, struct snd_interval *c); -+void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, -+ const struct snd_interval *b, struct snd_interval *c); -+int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask); -+int snd_interval_ratnum(struct snd_interval *i, -+ unsigned int rats_count, struct snd_ratnum *rats, -+ unsigned int *nump, unsigned int *denp); -+ -+void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); -+void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); -+int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); -+ -+int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); -+ -+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); -+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); -+ -+int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, -+ u_int32_t mask); -+int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, -+ u_int64_t mask); -+int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, -+ unsigned int min, unsigned int max); -+int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var); -+int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ snd_pcm_hw_param_t var, -+ struct snd_pcm_hw_constraint_list *l); -+int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ snd_pcm_hw_param_t var, -+ struct snd_pcm_hw_constraint_ratnums *r); -+int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ snd_pcm_hw_param_t var, -+ struct snd_pcm_hw_constraint_ratdens *r); -+int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ unsigned int width, -+ unsigned int msbits); -+int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ snd_pcm_hw_param_t var, -+ unsigned long step); -+int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ snd_pcm_hw_param_t var); -+int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, -+ unsigned int cond, -+ int var, -+ snd_pcm_hw_rule_func_t func, void *private, -+ int dep, ...); -+ -+int snd_pcm_format_signed(snd_pcm_format_t format); -+int snd_pcm_format_unsigned(snd_pcm_format_t format); -+int snd_pcm_format_linear(snd_pcm_format_t format); -+int snd_pcm_format_little_endian(snd_pcm_format_t format); -+int snd_pcm_format_big_endian(snd_pcm_format_t format); -+#if 0 /* just for DocBook */ -+/** -+ * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian -+ * @format: the format to check -+ * -+ * Returns 1 if the given PCM format is CPU-endian, 0 if -+ * opposite, or a negative error code if endian not specified. -+ */ -+int snd_pcm_format_cpu_endian(snd_pcm_format_t format); -+#endif /* DocBook */ -+#ifdef SNDRV_LITTLE_ENDIAN -+#define snd_pcm_format_cpu_endian(format) snd_pcm_format_little_endian(format) -+#else -+#define snd_pcm_format_cpu_endian(format) snd_pcm_format_big_endian(format) -+#endif -+int snd_pcm_format_width(snd_pcm_format_t format); /* in bits */ -+int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */ -+ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples); -+const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format); -+int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames); -+snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian); -+ -+void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, struct snd_pcm_ops *ops); -+void snd_pcm_set_sync(struct snd_pcm_substream *substream); -+int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); -+int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, -+ unsigned int cmd, void *arg); -+int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); -+int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); -+int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); -+int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream); -+int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream); -+void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr); -+void snd_pcm_tick_prepare(struct snd_pcm_substream *substream); -+void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks); -+void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream); -+void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); -+snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, -+ const void __user *buf, -+ snd_pcm_uframes_t frames); -+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, -+ void __user *buf, snd_pcm_uframes_t frames); -+snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, -+ void __user **bufs, snd_pcm_uframes_t frames); -+snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, -+ void __user **bufs, snd_pcm_uframes_t frames); -+ -+extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; -+ -+int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); -+unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); -+ -+static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream, -+ struct snd_dma_buffer *bufp) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (bufp) { -+ runtime->dma_buffer_p = bufp; -+ runtime->dma_area = bufp->area; -+ runtime->dma_addr = bufp->addr; -+ runtime->dma_bytes = bufp->bytes; -+ } else { -+ runtime->dma_buffer_p = NULL; -+ runtime->dma_area = NULL; -+ runtime->dma_addr = 0; -+ runtime->dma_bytes = 0; -+ } -+} -+ -+/* -+ * Timer interface -+ */ -+ -+void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); -+void snd_pcm_timer_init(struct snd_pcm_substream *substream); -+void snd_pcm_timer_done(struct snd_pcm_substream *substream); -+ -+/* -+ * Memory -+ */ -+ -+int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream); -+int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm); -+int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, -+ int type, struct device *data, -+ size_t size, size_t max); -+int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, -+ int type, void *data, -+ size_t size, size_t max); -+int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); -+int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); -+ -+#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data) -+#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size) -+#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs) -+struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset); -+ -+/* handle mmap counter - PCM mmap callback should handle this counter properly */ -+static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) -+{ -+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; -+ atomic_inc(&substream->mmap_count); -+} -+ -+static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) -+{ -+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; -+ atomic_dec(&substream->mmap_count); -+} -+ -+/* mmap for io-memory area */ -+#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) -+#define SNDRV_PCM_INFO_MMAP_IOMEM SNDRV_PCM_INFO_MMAP -+int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area); -+#else -+#define SNDRV_PCM_INFO_MMAP_IOMEM 0 -+#define snd_pcm_lib_mmap_iomem NULL -+#endif -+ -+static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) -+{ -+ *max = dma < 4 ? 64 * 1024 : 128 * 1024; -+} -+ -+/* -+ * Misc -+ */ -+ -+#define SNDRV_PCM_DEFAULT_CON_SPDIF (IEC958_AES0_CON_EMPHASIS_NONE|\ -+ (IEC958_AES1_CON_ORIGINAL<<8)|\ -+ (IEC958_AES1_CON_PCM_CODER<<8)|\ -+ (IEC958_AES3_CON_FS_48000<<24)) -+ -+#endif /* __SOUND_PCM_H */ -diff -urN linux-2.6.24.7.old/init/do_mounts.c linux-2.6.24.7/init/do_mounts.c ---- linux-2.6.24.7.old/init/do_mounts.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/init/do_mounts.c 2009-04-12 18:13:57.000000000 +0200 -@@ -440,7 +440,9 @@ - - if (saved_root_name[0]) { - root_device_name = saved_root_name; -- if (!strncmp(root_device_name, "mtd", 3)) { -+ if (!strncmp(root_device_name, "mtd", 3) || -+ !strncmp(root_device_name, "ubi", 3) || -+ !strncmp(root_device_name, "mmc", 3)) { - mount_block_root(root_device_name, root_mountflags); - goto out; - } -diff -urN linux-2.6.24.7.old/sound/core/pcm_native.c linux-2.6.24.7/sound/core/pcm_native.c ---- linux-2.6.24.7.old/sound/core/pcm_native.c 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/core/pcm_native.c 2009-04-12 18:13:57.000000000 +0200 -@@ -1780,12 +1780,13 @@ - return snd_interval_refine(hw_param_interval(params, rule->var), &t); - } - --#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 -+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 14 - #error "Change this table" - #endif - --static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, -- 48000, 64000, 88200, 96000, 176400, 192000 }; -+static unsigned int rates[] = { 5512, 8000, 11025, 12000, 16000, 22050, 24000, -+ 32000, 44100, 48000, 64000, 88200, 96000, -+ 176400, 192000 }; - - const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { - .count = ARRAY_SIZE(rates), -@@ -1796,9 +1797,17 @@ - struct snd_pcm_hw_rule *rule) - { - struct snd_pcm_hardware *hw = rule->private; -+#if 0 - return snd_interval_list(hw_param_interval(params, rule->var), - snd_pcm_known_rates.count, - snd_pcm_known_rates.list, hw->rates); -+#else -+ //printk("hw->rates=0x%08x\n",hw->rates);//0x3b6 -+ hw->rates = 0x3fe;//12KHz and 24KHz bits are all zero,you need set 1 -+ return snd_interval_list(hw_param_interval(params, rule->var), -+ snd_pcm_known_rates.count, -+ snd_pcm_known_rates.list, hw->rates); -+#endif - } - - static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, -diff -urN linux-2.6.24.7.old/sound/core/pcm_native.c.org linux-2.6.24.7/sound/core/pcm_native.c.org ---- linux-2.6.24.7.old/sound/core/pcm_native.c.org 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/core/pcm_native.c.org 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3451 @@ -+/* -+ * Digital Audio (PCM) abstract layer -+ * Copyright (c) by Jaroslav Kysela -+ * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Compatibility -+ */ -+ -+struct snd_pcm_hw_params_old { -+ unsigned int flags; -+ unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - -+ SNDRV_PCM_HW_PARAM_ACCESS + 1]; -+ struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; -+ unsigned int rmask; -+ unsigned int cmask; -+ unsigned int info; -+ unsigned int msbits; -+ unsigned int rate_num; -+ unsigned int rate_den; -+ snd_pcm_uframes_t fifo_size; -+ unsigned char reserved[64]; -+}; -+ -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old) -+#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old) -+ -+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams); -+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams); -+#endif -+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); -+ -+/* -+ * -+ */ -+ -+DEFINE_RWLOCK(snd_pcm_link_rwlock); -+EXPORT_SYMBOL(snd_pcm_link_rwlock); -+ -+static DECLARE_RWSEM(snd_pcm_link_rwsem); -+ -+static inline mm_segment_t snd_enter_user(void) -+{ -+ mm_segment_t fs = get_fs(); -+ set_fs(get_ds()); -+ return fs; -+} -+ -+static inline void snd_leave_user(mm_segment_t fs) -+{ -+ set_fs(fs); -+} -+ -+ -+ -+int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) -+{ -+ struct snd_pcm_runtime *runtime; -+ struct snd_pcm *pcm = substream->pcm; -+ struct snd_pcm_str *pstr = substream->pstr; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ memset(info, 0, sizeof(*info)); -+ info->card = pcm->card->number; -+ info->device = pcm->device; -+ info->stream = substream->stream; -+ info->subdevice = substream->number; -+ strlcpy(info->id, pcm->id, sizeof(info->id)); -+ strlcpy(info->name, pcm->name, sizeof(info->name)); -+ info->dev_class = pcm->dev_class; -+ info->dev_subclass = pcm->dev_subclass; -+ info->subdevices_count = pstr->substream_count; -+ info->subdevices_avail = pstr->substream_count - pstr->substream_opened; -+ strlcpy(info->subname, substream->name, sizeof(info->subname)); -+ runtime = substream->runtime; -+ /* AB: FIXME!!! This is definitely nonsense */ -+ if (runtime) { -+ info->sync = runtime->sync; -+ substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); -+ } -+ return 0; -+} -+ -+int snd_pcm_info_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_info __user * _info) -+{ -+ struct snd_pcm_info *info; -+ int err; -+ -+ info = kmalloc(sizeof(*info), GFP_KERNEL); -+ if (! info) -+ return -ENOMEM; -+ err = snd_pcm_info(substream, info); -+ if (err >= 0) { -+ if (copy_to_user(_info, info, sizeof(*info))) -+ err = -EFAULT; -+ } -+ kfree(info); -+ return err; -+} -+ -+#undef RULES_DEBUG -+ -+#ifdef RULES_DEBUG -+#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -+char *snd_pcm_hw_param_names[] = { -+ HW_PARAM(ACCESS), -+ HW_PARAM(FORMAT), -+ HW_PARAM(SUBFORMAT), -+ HW_PARAM(SAMPLE_BITS), -+ HW_PARAM(FRAME_BITS), -+ HW_PARAM(CHANNELS), -+ HW_PARAM(RATE), -+ HW_PARAM(PERIOD_TIME), -+ HW_PARAM(PERIOD_SIZE), -+ HW_PARAM(PERIOD_BYTES), -+ HW_PARAM(PERIODS), -+ HW_PARAM(BUFFER_TIME), -+ HW_PARAM(BUFFER_SIZE), -+ HW_PARAM(BUFFER_BYTES), -+ HW_PARAM(TICK_TIME), -+}; -+#endif -+ -+int snd_pcm_hw_refine(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int k; -+ struct snd_pcm_hardware *hw; -+ struct snd_interval *i = NULL; -+ struct snd_mask *m = NULL; -+ struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; -+ unsigned int rstamps[constrs->rules_num]; -+ unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; -+ unsigned int stamp = 2; -+ int changed, again; -+ -+ params->info = 0; -+ params->fifo_size = 0; -+ if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) -+ params->msbits = 0; -+ if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { -+ params->rate_num = 0; -+ params->rate_den = 0; -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { -+ m = hw_param_mask(params, k); -+ if (snd_mask_empty(m)) -+ return -EINVAL; -+ if (!(params->rmask & (1 << k))) -+ continue; -+#ifdef RULES_DEBUG -+ printk("%s = ", snd_pcm_hw_param_names[k]); -+ printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -+#endif -+ changed = snd_mask_refine(m, constrs_mask(constrs, k)); -+#ifdef RULES_DEBUG -+ printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); -+#endif -+ if (changed) -+ params->cmask |= 1 << k; -+ if (changed < 0) -+ return changed; -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { -+ i = hw_param_interval(params, k); -+ if (snd_interval_empty(i)) -+ return -EINVAL; -+ if (!(params->rmask & (1 << k))) -+ continue; -+#ifdef RULES_DEBUG -+ printk("%s = ", snd_pcm_hw_param_names[k]); -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ printk(" -> "); -+#endif -+ changed = snd_interval_refine(i, constrs_interval(constrs, k)); -+#ifdef RULES_DEBUG -+ if (i->empty) -+ printk("empty\n"); -+ else -+ printk("%c%u %u%c\n", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+#endif -+ if (changed) -+ params->cmask |= 1 << k; -+ if (changed < 0) -+ return changed; -+ } -+ -+ for (k = 0; k < constrs->rules_num; k++) -+ rstamps[k] = 0; -+ for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) -+ vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; -+ do { -+ again = 0; -+ for (k = 0; k < constrs->rules_num; k++) { -+ struct snd_pcm_hw_rule *r = &constrs->rules[k]; -+ unsigned int d; -+ int doit = 0; -+ if (r->cond && !(r->cond & params->flags)) -+ continue; -+ for (d = 0; r->deps[d] >= 0; d++) { -+ if (vstamps[r->deps[d]] > rstamps[k]) { -+ doit = 1; -+ break; -+ } -+ } -+ if (!doit) -+ continue; -+#ifdef RULES_DEBUG -+ printk("Rule %d [%p]: ", k, r->func); -+ if (r->var >= 0) { -+ printk("%s = ", snd_pcm_hw_param_names[r->var]); -+ if (hw_is_mask(r->var)) { -+ m = hw_param_mask(params, r->var); -+ printk("%x", *m->bits); -+ } else { -+ i = hw_param_interval(params, r->var); -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ } -+ } -+#endif -+ changed = r->func(params, r); -+#ifdef RULES_DEBUG -+ if (r->var >= 0) { -+ printk(" -> "); -+ if (hw_is_mask(r->var)) -+ printk("%x", *m->bits); -+ else { -+ if (i->empty) -+ printk("empty"); -+ else -+ printk("%c%u %u%c", -+ i->openmin ? '(' : '[', i->min, -+ i->max, i->openmax ? ')' : ']'); -+ } -+ } -+ printk("\n"); -+#endif -+ rstamps[k] = stamp; -+ if (changed && r->var >= 0) { -+ params->cmask |= (1 << r->var); -+ vstamps[r->var] = stamp; -+ again = 1; -+ } -+ if (changed < 0) -+ return changed; -+ stamp++; -+ } -+ } while (again); -+ if (!params->msbits) { -+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); -+ if (snd_interval_single(i)) -+ params->msbits = snd_interval_value(i); -+ } -+ -+ if (!params->rate_den) { -+ i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); -+ if (snd_interval_single(i)) { -+ params->rate_num = snd_interval_value(i); -+ params->rate_den = 1; -+ } -+ } -+ -+ hw = &substream->runtime->hw; -+ if (!params->info) -+ params->info = hw->info; -+ if (!params->fifo_size) -+ params->fifo_size = hw->fifo_size; -+ params->rmask = 0; -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_hw_refine); -+ -+static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params __user * _params) -+{ -+ struct snd_pcm_hw_params *params; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(params, _params, sizeof(*params))) { -+ err = -EFAULT; -+ goto out; -+ } -+ err = snd_pcm_hw_refine(substream, params); -+ if (copy_to_user(_params, params, sizeof(*params))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ return err; -+} -+ -+static int period_to_usecs(struct snd_pcm_runtime *runtime) -+{ -+ int usecs; -+ -+ if (! runtime->rate) -+ return -1; /* invalid */ -+ -+ /* take 75% of period time as the deadline */ -+ usecs = (750000 / runtime->rate) * runtime->period_size; -+ usecs += ((750000 % runtime->rate) * runtime->period_size) / -+ runtime->rate; -+ -+ return usecs; -+} -+ -+static int snd_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_pcm_runtime *runtime; -+ int err, usecs; -+ unsigned int bits; -+ snd_pcm_uframes_t frames; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_OPEN: -+ case SNDRV_PCM_STATE_SETUP: -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ default: -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) -+ if (!substream->oss.oss) -+#endif -+ if (atomic_read(&substream->mmap_count)) -+ return -EBADFD; -+ -+ params->rmask = ~0U; -+ err = snd_pcm_hw_refine(substream, params); -+ if (err < 0) -+ goto _error; -+ -+ err = snd_pcm_hw_params_choose(substream, params); -+ if (err < 0) -+ goto _error; -+ -+ if (substream->ops->hw_params != NULL) { -+ err = substream->ops->hw_params(substream, params); -+ if (err < 0) -+ goto _error; -+ } -+ -+ runtime->access = params_access(params); -+ runtime->format = params_format(params); -+ runtime->subformat = params_subformat(params); -+ runtime->channels = params_channels(params); -+ runtime->rate = params_rate(params); -+ runtime->period_size = params_period_size(params); -+ runtime->periods = params_periods(params); -+ runtime->buffer_size = params_buffer_size(params); -+ runtime->tick_time = params_tick_time(params); -+ runtime->info = params->info; -+ runtime->rate_num = params->rate_num; -+ runtime->rate_den = params->rate_den; -+ -+ bits = snd_pcm_format_physical_width(runtime->format); -+ runtime->sample_bits = bits; -+ bits *= runtime->channels; -+ runtime->frame_bits = bits; -+ frames = 1; -+ while (bits % 8 != 0) { -+ bits *= 2; -+ frames *= 2; -+ } -+ runtime->byte_align = bits / 8; -+ runtime->min_align = frames; -+ -+ /* Default sw params */ -+ runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; -+ runtime->period_step = 1; -+ runtime->sleep_min = 0; -+ runtime->control->avail_min = runtime->period_size; -+ runtime->xfer_align = runtime->period_size; -+ runtime->start_threshold = 1; -+ runtime->stop_threshold = runtime->buffer_size; -+ runtime->silence_threshold = 0; -+ runtime->silence_size = 0; -+ runtime->boundary = runtime->buffer_size; -+ while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) -+ runtime->boundary *= 2; -+ -+ snd_pcm_timer_resolution_change(substream); -+ runtime->status->state = SNDRV_PCM_STATE_SETUP; -+ -+ remove_acceptable_latency(substream->latency_id); -+ if ((usecs = period_to_usecs(runtime)) >= 0) -+ set_acceptable_latency(substream->latency_id, usecs); -+ return 0; -+ _error: -+ /* hardware might be unuseable from this time, -+ so we force application to retry to set -+ the correct hardware parameter settings */ -+ runtime->status->state = SNDRV_PCM_STATE_OPEN; -+ if (substream->ops->hw_free != NULL) -+ substream->ops->hw_free(substream); -+ return err; -+} -+ -+static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params __user * _params) -+{ -+ struct snd_pcm_hw_params *params; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(params, _params, sizeof(*params))) { -+ err = -EFAULT; -+ goto out; -+ } -+ err = snd_pcm_hw_params(substream, params); -+ if (copy_to_user(_params, params, sizeof(*params))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ return err; -+} -+ -+static int snd_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime; -+ int result = 0; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_SETUP: -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ default: -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (atomic_read(&substream->mmap_count)) -+ return -EBADFD; -+ if (substream->ops->hw_free) -+ result = substream->ops->hw_free(substream); -+ runtime->status->state = SNDRV_PCM_STATE_OPEN; -+ remove_acceptable_latency(substream->latency_id); -+ return result; -+} -+ -+static int snd_pcm_sw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_sw_params *params) -+{ -+ struct snd_pcm_runtime *runtime; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -ENXIO); -+ snd_pcm_stream_lock_irq(substream); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ -+ if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) -+ return -EINVAL; -+ if (params->avail_min == 0) -+ return -EINVAL; -+ if (params->xfer_align == 0 || -+ params->xfer_align % runtime->min_align != 0) -+ return -EINVAL; -+ if (params->silence_size >= runtime->boundary) { -+ if (params->silence_threshold != 0) -+ return -EINVAL; -+ } else { -+ if (params->silence_size > params->silence_threshold) -+ return -EINVAL; -+ if (params->silence_threshold > runtime->buffer_size) -+ return -EINVAL; -+ } -+ snd_pcm_stream_lock_irq(substream); -+ runtime->tstamp_mode = params->tstamp_mode; -+ runtime->sleep_min = params->sleep_min; -+ runtime->period_step = params->period_step; -+ runtime->control->avail_min = params->avail_min; -+ runtime->start_threshold = params->start_threshold; -+ runtime->stop_threshold = params->stop_threshold; -+ runtime->silence_threshold = params->silence_threshold; -+ runtime->silence_size = params->silence_size; -+ runtime->xfer_align = params->xfer_align; -+ params->boundary = runtime->boundary; -+ if (snd_pcm_running(substream)) { -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ else -+ snd_pcm_tick_set(substream, 0); -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+ wake_up(&runtime->sleep); -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return 0; -+} -+ -+static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_sw_params __user * _params) -+{ -+ struct snd_pcm_sw_params params; -+ int err; -+ if (copy_from_user(¶ms, _params, sizeof(params))) -+ return -EFAULT; -+ err = snd_pcm_sw_params(substream, ¶ms); -+ if (copy_to_user(_params, ¶ms, sizeof(params))) -+ return -EFAULT; -+ return err; -+} -+ -+int snd_pcm_status(struct snd_pcm_substream *substream, -+ struct snd_pcm_status *status) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ -+ snd_pcm_stream_lock_irq(substream); -+ status->state = runtime->status->state; -+ status->suspended_state = runtime->status->suspended_state; -+ if (status->state == SNDRV_PCM_STATE_OPEN) -+ goto _end; -+ status->trigger_tstamp = runtime->trigger_tstamp; -+ if (snd_pcm_running(substream)) { -+ snd_pcm_update_hw_ptr(substream); -+ if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) -+ status->tstamp = runtime->status->tstamp; -+ else -+ getnstimeofday(&status->tstamp); -+ } else -+ getnstimeofday(&status->tstamp); -+ status->appl_ptr = runtime->control->appl_ptr; -+ status->hw_ptr = runtime->status->hw_ptr; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ status->avail = snd_pcm_playback_avail(runtime); -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || -+ runtime->status->state == SNDRV_PCM_STATE_DRAINING) -+ status->delay = runtime->buffer_size - status->avail; -+ else -+ status->delay = 0; -+ } else { -+ status->avail = snd_pcm_capture_avail(runtime); -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) -+ status->delay = status->avail; -+ else -+ status->delay = 0; -+ } -+ status->avail_max = runtime->avail_max; -+ status->overrange = runtime->overrange; -+ runtime->avail_max = 0; -+ runtime->overrange = 0; -+ _end: -+ snd_pcm_stream_unlock_irq(substream); -+ return 0; -+} -+ -+static int snd_pcm_status_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_status __user * _status) -+{ -+ struct snd_pcm_status status; -+ struct snd_pcm_runtime *runtime; -+ int res; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ memset(&status, 0, sizeof(status)); -+ res = snd_pcm_status(substream, &status); -+ if (res < 0) -+ return res; -+ if (copy_to_user(_status, &status, sizeof(status))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int snd_pcm_channel_info(struct snd_pcm_substream *substream, -+ struct snd_pcm_channel_info * info) -+{ -+ struct snd_pcm_runtime *runtime; -+ unsigned int channel; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ channel = info->channel; -+ runtime = substream->runtime; -+ snd_pcm_stream_lock_irq(substream); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ snd_pcm_stream_unlock_irq(substream); -+ return -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (channel >= runtime->channels) -+ return -EINVAL; -+ memset(info, 0, sizeof(*info)); -+ info->channel = channel; -+ return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); -+} -+ -+static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_channel_info __user * _info) -+{ -+ struct snd_pcm_channel_info info; -+ int res; -+ -+ if (copy_from_user(&info, _info, sizeof(info))) -+ return -EFAULT; -+ res = snd_pcm_channel_info(substream, &info); -+ if (res < 0) -+ return res; -+ if (copy_to_user(_info, &info, sizeof(info))) -+ return -EFAULT; -+ return 0; -+} -+ -+static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master == NULL) -+ return; -+ if (runtime->trigger_master == substream) { -+ getnstimeofday(&runtime->trigger_tstamp); -+ } else { -+ snd_pcm_trigger_tstamp(runtime->trigger_master); -+ runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; -+ } -+ runtime->trigger_master = NULL; -+} -+ -+struct action_ops { -+ int (*pre_action)(struct snd_pcm_substream *substream, int state); -+ int (*do_action)(struct snd_pcm_substream *substream, int state); -+ void (*undo_action)(struct snd_pcm_substream *substream, int state); -+ void (*post_action)(struct snd_pcm_substream *substream, int state); -+}; -+ -+/* -+ * this functions is core for handling of linked stream -+ * Note: the stream state might be changed also on failure -+ * Note2: call with calling stream lock + link lock -+ */ -+static int snd_pcm_action_group(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state, int do_lock) -+{ -+ struct snd_pcm_substream *s = NULL; -+ struct snd_pcm_substream *s1; -+ int res = 0; -+ -+ snd_pcm_group_for_each_entry(s, substream) { -+ if (do_lock && s != substream) -+ spin_lock_nested(&s->self_group.lock, -+ SINGLE_DEPTH_NESTING); -+ res = ops->pre_action(s, state); -+ if (res < 0) -+ goto _unlock; -+ } -+ snd_pcm_group_for_each_entry(s, substream) { -+ res = ops->do_action(s, state); -+ if (res < 0) { -+ if (ops->undo_action) { -+ snd_pcm_group_for_each_entry(s1, substream) { -+ if (s1 == s) /* failed stream */ -+ break; -+ ops->undo_action(s1, state); -+ } -+ } -+ s = NULL; /* unlock all */ -+ goto _unlock; -+ } -+ } -+ snd_pcm_group_for_each_entry(s, substream) { -+ ops->post_action(s, state); -+ } -+ _unlock: -+ if (do_lock) { -+ /* unlock streams */ -+ snd_pcm_group_for_each_entry(s1, substream) { -+ if (s1 != substream) -+ spin_unlock(&s1->self_group.lock); -+ if (s1 == s) /* end */ -+ break; -+ } -+ } -+ return res; -+} -+ -+/* -+ * Note: call with stream lock -+ */ -+static int snd_pcm_action_single(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ res = ops->pre_action(substream, state); -+ if (res < 0) -+ return res; -+ res = ops->do_action(substream, state); -+ if (res == 0) -+ ops->post_action(substream, state); -+ else if (ops->undo_action) -+ ops->undo_action(substream, state); -+ return res; -+} -+ -+/* -+ * Note: call with stream lock -+ */ -+static int snd_pcm_action(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ if (snd_pcm_stream_linked(substream)) { -+ if (!spin_trylock(&substream->group->lock)) { -+ spin_unlock(&substream->self_group.lock); -+ spin_lock(&substream->group->lock); -+ spin_lock(&substream->self_group.lock); -+ } -+ res = snd_pcm_action_group(ops, substream, state, 1); -+ spin_unlock(&substream->group->lock); -+ } else { -+ res = snd_pcm_action_single(ops, substream, state); -+ } -+ return res; -+} -+ -+/* -+ * Note: don't use any locks before -+ */ -+static int snd_pcm_action_lock_irq(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ read_lock_irq(&snd_pcm_link_rwlock); -+ if (snd_pcm_stream_linked(substream)) { -+ spin_lock(&substream->group->lock); -+ spin_lock(&substream->self_group.lock); -+ res = snd_pcm_action_group(ops, substream, state, 1); -+ spin_unlock(&substream->self_group.lock); -+ spin_unlock(&substream->group->lock); -+ } else { -+ spin_lock(&substream->self_group.lock); -+ res = snd_pcm_action_single(ops, substream, state); -+ spin_unlock(&substream->self_group.lock); -+ } -+ read_unlock_irq(&snd_pcm_link_rwlock); -+ return res; -+} -+ -+/* -+ */ -+static int snd_pcm_action_nonatomic(struct action_ops *ops, -+ struct snd_pcm_substream *substream, -+ int state) -+{ -+ int res; -+ -+ down_read(&snd_pcm_link_rwsem); -+ if (snd_pcm_stream_linked(substream)) -+ res = snd_pcm_action_group(ops, substream, state, 0); -+ else -+ res = snd_pcm_action_single(ops, substream, state); -+ up_read(&snd_pcm_link_rwsem); -+ return res; -+} -+ -+/* -+ * start callbacks -+ */ -+static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) -+ return -EBADFD; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ !snd_pcm_playback_data(substream)) -+ return -EPIPE; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master != substream) -+ return 0; -+ return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); -+} -+ -+static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); -+} -+ -+static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ runtime->status->state = state; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, -+ &runtime->trigger_tstamp); -+} -+ -+static struct action_ops snd_pcm_action_start = { -+ .pre_action = snd_pcm_pre_start, -+ .do_action = snd_pcm_do_start, -+ .undo_action = snd_pcm_undo_start, -+ .post_action = snd_pcm_post_start -+}; -+ -+/** -+ * snd_pcm_start -+ * @substream: the PCM substream instance -+ * -+ * Start all linked streams. -+ */ -+int snd_pcm_start(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action(&snd_pcm_action_start, substream, -+ SNDRV_PCM_STATE_RUNNING); -+} -+ -+/* -+ * stop callbacks -+ */ -+static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream && -+ snd_pcm_running(substream)) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); -+ return 0; /* unconditonally stop all substreams */ -+} -+ -+static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state != state) { -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, -+ &runtime->trigger_tstamp); -+ runtime->status->state = state; -+ snd_pcm_tick_set(substream, 0); -+ } -+ wake_up(&runtime->sleep); -+} -+ -+static struct action_ops snd_pcm_action_stop = { -+ .pre_action = snd_pcm_pre_stop, -+ .do_action = snd_pcm_do_stop, -+ .post_action = snd_pcm_post_stop -+}; -+ -+/** -+ * snd_pcm_stop -+ * @substream: the PCM substream instance -+ * @state: PCM state after stopping the stream -+ * -+ * Try to stop all running streams in the substream group. -+ * The state of each stream is changed to the given value after that unconditionally. -+ */ -+int snd_pcm_stop(struct snd_pcm_substream *substream, int state) -+{ -+ return snd_pcm_action(&snd_pcm_action_stop, substream, state); -+} -+ -+EXPORT_SYMBOL(snd_pcm_stop); -+ -+/** -+ * snd_pcm_drain_done -+ * @substream: the PCM substream -+ * -+ * Stop the DMA only when the given stream is playback. -+ * The state is changed to SETUP. -+ * Unlike snd_pcm_stop(), this affects only the given stream. -+ */ -+int snd_pcm_drain_done(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action_single(&snd_pcm_action_stop, substream, -+ SNDRV_PCM_STATE_SETUP); -+} -+ -+/* -+ * pause callbacks -+ */ -+static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) -+ return -ENOSYS; -+ if (push) { -+ if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) -+ return -EBADFD; -+ } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) -+ return -EBADFD; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) -+{ -+ if (substream->runtime->trigger_master != substream) -+ return 0; -+ return substream->ops->trigger(substream, -+ push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : -+ SNDRV_PCM_TRIGGER_PAUSE_RELEASE); -+} -+ -+static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push) -+{ -+ if (substream->runtime->trigger_master == substream) -+ substream->ops->trigger(substream, -+ push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE : -+ SNDRV_PCM_TRIGGER_PAUSE_PUSH); -+} -+ -+static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (push) { -+ runtime->status->state = SNDRV_PCM_STATE_PAUSED; -+ if (substream->timer) -+ snd_timer_notify(substream->timer, -+ SNDRV_TIMER_EVENT_MPAUSE, -+ &runtime->trigger_tstamp); -+ snd_pcm_tick_set(substream, 0); -+ wake_up(&runtime->sleep); -+ } else { -+ runtime->status->state = SNDRV_PCM_STATE_RUNNING; -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, -+ SNDRV_TIMER_EVENT_MCONTINUE, -+ &runtime->trigger_tstamp); -+ } -+} -+ -+static struct action_ops snd_pcm_action_pause = { -+ .pre_action = snd_pcm_pre_pause, -+ .do_action = snd_pcm_do_pause, -+ .undo_action = snd_pcm_undo_pause, -+ .post_action = snd_pcm_post_pause -+}; -+ -+/* -+ * Push/release the pause for all linked streams. -+ */ -+static int snd_pcm_pause(struct snd_pcm_substream *substream, int push) -+{ -+ return snd_pcm_action(&snd_pcm_action_pause, substream, push); -+} -+ -+#ifdef CONFIG_PM -+/* suspend */ -+ -+static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) -+ return -EBUSY; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master != substream) -+ return 0; -+ if (! snd_pcm_running(substream)) -+ return 0; -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); -+ return 0; /* suspend unconditionally */ -+} -+ -+static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, -+ &runtime->trigger_tstamp); -+ runtime->status->suspended_state = runtime->status->state; -+ runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; -+ snd_pcm_tick_set(substream, 0); -+ wake_up(&runtime->sleep); -+} -+ -+static struct action_ops snd_pcm_action_suspend = { -+ .pre_action = snd_pcm_pre_suspend, -+ .do_action = snd_pcm_do_suspend, -+ .post_action = snd_pcm_post_suspend -+}; -+ -+/** -+ * snd_pcm_suspend -+ * @substream: the PCM substream -+ * -+ * Trigger SUSPEND to all linked streams. -+ * After this call, all streams are changed to SUSPENDED state. -+ */ -+int snd_pcm_suspend(struct snd_pcm_substream *substream) -+{ -+ int err; -+ unsigned long flags; -+ -+ if (! substream) -+ return 0; -+ -+ snd_pcm_stream_lock_irqsave(substream, flags); -+ err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); -+ snd_pcm_stream_unlock_irqrestore(substream, flags); -+ return err; -+} -+ -+EXPORT_SYMBOL(snd_pcm_suspend); -+ -+/** -+ * snd_pcm_suspend_all -+ * @pcm: the PCM instance -+ * -+ * Trigger SUSPEND to all substreams in the given pcm. -+ * After this call, all streams are changed to SUSPENDED state. -+ */ -+int snd_pcm_suspend_all(struct snd_pcm *pcm) -+{ -+ struct snd_pcm_substream *substream; -+ int stream, err = 0; -+ -+ if (! pcm) -+ return 0; -+ -+ for (stream = 0; stream < 2; stream++) { -+ for (substream = pcm->streams[stream].substream; -+ substream; substream = substream->next) { -+ /* FIXME: the open/close code should lock this as well */ -+ if (substream->runtime == NULL) -+ continue; -+ err = snd_pcm_suspend(substream); -+ if (err < 0 && err != -EBUSY) -+ return err; -+ } -+ } -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_suspend_all); -+ -+/* resume */ -+ -+static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (!(runtime->info & SNDRV_PCM_INFO_RESUME)) -+ return -ENOSYS; -+ runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->trigger_master != substream) -+ return 0; -+ /* DMA not running previously? */ -+ if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && -+ (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING || -+ substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) -+ return 0; -+ return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); -+} -+ -+static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->runtime->trigger_master == substream && -+ snd_pcm_running(substream)) -+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); -+} -+ -+static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_trigger_tstamp(substream); -+ if (substream->timer) -+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, -+ &runtime->trigger_tstamp); -+ runtime->status->state = runtime->status->suspended_state; -+ if (runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+} -+ -+static struct action_ops snd_pcm_action_resume = { -+ .pre_action = snd_pcm_pre_resume, -+ .do_action = snd_pcm_do_resume, -+ .undo_action = snd_pcm_undo_resume, -+ .post_action = snd_pcm_post_resume -+}; -+ -+static int snd_pcm_resume(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card = substream->pcm->card; -+ int res; -+ -+ snd_power_lock(card); -+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -+ res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); -+ snd_power_unlock(card); -+ return res; -+} -+ -+#else -+ -+static int snd_pcm_resume(struct snd_pcm_substream *substream) -+{ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+/* -+ * xrun ioctl -+ * -+ * Change the RUNNING stream(s) to XRUN state. -+ */ -+static int snd_pcm_xrun(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card = substream->pcm->card; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int result; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) -+ goto _unlock; -+ } -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_XRUN: -+ result = 0; /* already there */ -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); -+ break; -+ default: -+ result = -EBADFD; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ _unlock: -+ snd_power_unlock(card); -+ return result; -+} -+ -+/* -+ * reset ioctl -+ */ -+static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ return 0; -+ default: -+ return -EBADFD; -+ } -+} -+ -+static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); -+ if (err < 0) -+ return err; -+ // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, ); -+ runtime->hw_ptr_base = 0; -+ runtime->hw_ptr_interrupt = runtime->status->hw_ptr - -+ runtime->status->hw_ptr % runtime->period_size; -+ runtime->silence_start = runtime->status->hw_ptr; -+ runtime->silence_filled = 0; -+ return 0; -+} -+ -+static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ runtime->control->appl_ptr = runtime->status->hw_ptr; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && -+ runtime->silence_size > 0) -+ snd_pcm_playback_silence(substream, ULONG_MAX); -+} -+ -+static struct action_ops snd_pcm_action_reset = { -+ .pre_action = snd_pcm_pre_reset, -+ .do_action = snd_pcm_do_reset, -+ .post_action = snd_pcm_post_reset -+}; -+ -+static int snd_pcm_reset(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0); -+} -+ -+/* -+ * prepare ioctl -+ */ -+/* we use the second argument for updating f_flags */ -+static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, -+ int f_flags) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) -+ return -EBADFD; -+ if (snd_pcm_running(substream)) -+ return -EBUSY; -+ substream->f_flags = f_flags; -+ return 0; -+} -+ -+static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state) -+{ -+ int err; -+ err = substream->ops->prepare(substream); -+ if (err < 0) -+ return err; -+ return snd_pcm_do_reset(substream, 0); -+} -+ -+static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ runtime->control->appl_ptr = runtime->status->hw_ptr; -+ runtime->status->state = SNDRV_PCM_STATE_PREPARED; -+} -+ -+static struct action_ops snd_pcm_action_prepare = { -+ .pre_action = snd_pcm_pre_prepare, -+ .do_action = snd_pcm_do_prepare, -+ .post_action = snd_pcm_post_prepare -+}; -+ -+/** -+ * snd_pcm_prepare -+ * @substream: the PCM substream instance -+ * @file: file to refer f_flags -+ * -+ * Prepare the PCM substream to be triggerable. -+ */ -+static int snd_pcm_prepare(struct snd_pcm_substream *substream, -+ struct file *file) -+{ -+ int res; -+ struct snd_card *card = substream->pcm->card; -+ int f_flags; -+ -+ if (file) -+ f_flags = file->f_flags; -+ else -+ f_flags = substream->f_flags; -+ -+ snd_power_lock(card); -+ if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -+ res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, -+ substream, f_flags); -+ snd_power_unlock(card); -+ return res; -+} -+ -+/* -+ * drain ioctl -+ */ -+ -+static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+ if (substream->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ substream->runtime->trigger_master = substream; -+ return 0; -+} -+ -+static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ /* start playback stream if possible */ -+ if (! snd_pcm_playback_empty(substream)) { -+ snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); -+ snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); -+ } -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ runtime->status->state = SNDRV_PCM_STATE_DRAINING; -+ break; -+ default: -+ break; -+ } -+ } else { -+ /* stop running stream */ -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { -+ int state = snd_pcm_capture_avail(runtime) > 0 ? -+ SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; -+ snd_pcm_do_stop(substream, state); -+ snd_pcm_post_stop(substream, state); -+ } -+ } -+ return 0; -+} -+ -+static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state) -+{ -+} -+ -+static struct action_ops snd_pcm_action_drain_init = { -+ .pre_action = snd_pcm_pre_drain_init, -+ .do_action = snd_pcm_do_drain_init, -+ .post_action = snd_pcm_post_drain_init -+}; -+ -+struct drain_rec { -+ struct snd_pcm_substream *substream; -+ wait_queue_t wait; -+ snd_pcm_uframes_t stop_threshold; -+}; -+ -+static int snd_pcm_drop(struct snd_pcm_substream *substream); -+ -+/* -+ * Drain the stream(s). -+ * When the substream is linked, sync until the draining of all playback streams -+ * is finished. -+ * After this call, all streams are supposed to be either SETUP or DRAINING -+ * (capture only) state. -+ */ -+static int snd_pcm_drain(struct snd_pcm_substream *substream) -+{ -+ struct snd_card *card; -+ struct snd_pcm_runtime *runtime; -+ struct snd_pcm_substream *s; -+ int result = 0; -+ int i, num_drecs; -+ struct drain_rec *drec, drec_tmp, *d; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ card = substream->pcm->card; -+ runtime = substream->runtime; -+ -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) { -+ snd_power_unlock(card); -+ return result; -+ } -+ } -+ -+ /* allocate temporary record for drain sync */ -+ down_read(&snd_pcm_link_rwsem); -+ if (snd_pcm_stream_linked(substream)) { -+ drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); -+ if (! drec) { -+ up_read(&snd_pcm_link_rwsem); -+ snd_power_unlock(card); -+ return -ENOMEM; -+ } -+ } else -+ drec = &drec_tmp; -+ -+ /* count only playback streams */ -+ num_drecs = 0; -+ snd_pcm_group_for_each_entry(s, substream) { -+ runtime = s->runtime; -+ if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ d = &drec[num_drecs++]; -+ d->substream = s; -+ init_waitqueue_entry(&d->wait, current); -+ add_wait_queue(&runtime->sleep, &d->wait); -+ /* stop_threshold fixup to avoid endless loop when -+ * stop_threshold > buffer_size -+ */ -+ d->stop_threshold = runtime->stop_threshold; -+ if (runtime->stop_threshold > runtime->buffer_size) -+ runtime->stop_threshold = runtime->buffer_size; -+ } -+ } -+ up_read(&snd_pcm_link_rwsem); -+ -+ snd_pcm_stream_lock_irq(substream); -+ /* resume pause */ -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) -+ snd_pcm_pause(substream, 0); -+ -+ /* pre-start/stop - all running streams are changed to DRAINING state */ -+ result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); -+ if (result < 0) { -+ snd_pcm_stream_unlock_irq(substream); -+ goto _error; -+ } -+ -+ for (;;) { -+ long tout; -+ if (signal_pending(current)) { -+ result = -ERESTARTSYS; -+ break; -+ } -+ /* all finished? */ -+ for (i = 0; i < num_drecs; i++) { -+ runtime = drec[i].substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) -+ break; -+ } -+ if (i == num_drecs) -+ break; /* yes, all drained */ -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ snd_pcm_stream_unlock_irq(substream); -+ snd_power_unlock(card); -+ tout = schedule_timeout(10 * HZ); -+ snd_power_lock(card); -+ snd_pcm_stream_lock_irq(substream); -+ if (tout == 0) { -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) -+ result = -ESTRPIPE; -+ else { -+ snd_printd("playback drain error (DMA or IRQ trouble?)\n"); -+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); -+ result = -EIO; -+ } -+ break; -+ } -+ } -+ -+ snd_pcm_stream_unlock_irq(substream); -+ -+ _error: -+ for (i = 0; i < num_drecs; i++) { -+ d = &drec[i]; -+ runtime = d->substream->runtime; -+ remove_wait_queue(&runtime->sleep, &d->wait); -+ runtime->stop_threshold = d->stop_threshold; -+ } -+ -+ if (drec != &drec_tmp) -+ kfree(drec); -+ snd_power_unlock(card); -+ -+ return result; -+} -+ -+/* -+ * drop ioctl -+ * -+ * Immediately put all linked substreams into SETUP state. -+ */ -+static int snd_pcm_drop(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime; -+ struct snd_card *card; -+ int result = 0; -+ -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ card = substream->pcm->card; -+ -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) -+ return -EBADFD; -+ -+ snd_power_lock(card); -+ if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -+ result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -+ if (result < 0) -+ goto _unlock; -+ } -+ -+ snd_pcm_stream_lock_irq(substream); -+ /* resume pause */ -+ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) -+ snd_pcm_pause(substream, 0); -+ -+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); -+ /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ -+ snd_pcm_stream_unlock_irq(substream); -+ _unlock: -+ snd_power_unlock(card); -+ return result; -+} -+ -+ -+/* WARNING: Don't forget to fput back the file */ -+static struct file *snd_pcm_file_fd(int fd) -+{ -+ struct file *file; -+ struct inode *inode; -+ unsigned int minor; -+ -+ file = fget(fd); -+ if (!file) -+ return NULL; -+ inode = file->f_path.dentry->d_inode; -+ if (!S_ISCHR(inode->i_mode) || -+ imajor(inode) != snd_major) { -+ fput(file); -+ return NULL; -+ } -+ minor = iminor(inode); -+ if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) && -+ !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) { -+ fput(file); -+ return NULL; -+ } -+ return file; -+} -+ -+/* -+ * PCM link handling -+ */ -+static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) -+{ -+ int res = 0; -+ struct file *file; -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream1; -+ -+ file = snd_pcm_file_fd(fd); -+ if (!file) -+ return -EBADFD; -+ pcm_file = file->private_data; -+ substream1 = pcm_file->substream; -+ down_write(&snd_pcm_link_rwsem); -+ write_lock_irq(&snd_pcm_link_rwlock); -+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || -+ substream->runtime->status->state != substream1->runtime->status->state) { -+ res = -EBADFD; -+ goto _end; -+ } -+ if (snd_pcm_stream_linked(substream1)) { -+ res = -EALREADY; -+ goto _end; -+ } -+ if (!snd_pcm_stream_linked(substream)) { -+ substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); -+ if (substream->group == NULL) { -+ res = -ENOMEM; -+ goto _end; -+ } -+ spin_lock_init(&substream->group->lock); -+ INIT_LIST_HEAD(&substream->group->substreams); -+ list_add_tail(&substream->link_list, &substream->group->substreams); -+ substream->group->count = 1; -+ } -+ list_add_tail(&substream1->link_list, &substream->group->substreams); -+ substream->group->count++; -+ substream1->group = substream->group; -+ _end: -+ write_unlock_irq(&snd_pcm_link_rwlock); -+ up_write(&snd_pcm_link_rwsem); -+ fput(file); -+ return res; -+} -+ -+static void relink_to_local(struct snd_pcm_substream *substream) -+{ -+ substream->group = &substream->self_group; -+ INIT_LIST_HEAD(&substream->self_group.substreams); -+ list_add_tail(&substream->link_list, &substream->self_group.substreams); -+} -+ -+static int snd_pcm_unlink(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_substream *s; -+ int res = 0; -+ -+ down_write(&snd_pcm_link_rwsem); -+ write_lock_irq(&snd_pcm_link_rwlock); -+ if (!snd_pcm_stream_linked(substream)) { -+ res = -EALREADY; -+ goto _end; -+ } -+ list_del(&substream->link_list); -+ substream->group->count--; -+ if (substream->group->count == 1) { /* detach the last stream, too */ -+ snd_pcm_group_for_each_entry(s, substream) { -+ relink_to_local(s); -+ break; -+ } -+ kfree(substream->group); -+ } -+ relink_to_local(substream); -+ _end: -+ write_unlock_irq(&snd_pcm_link_rwlock); -+ up_write(&snd_pcm_link_rwsem); -+ return res; -+} -+ -+/* -+ * hw configurator -+ */ -+static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_mul(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_div(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]), -+ hw_param_interval_c(params, rule->deps[1]), -+ (unsigned long) rule->private, &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]), -+ (unsigned long) rule->private, -+ hw_param_interval_c(params, rule->deps[1]), &t); -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ unsigned int k; -+ struct snd_interval *i = hw_param_interval(params, rule->deps[0]); -+ struct snd_mask m; -+ struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); -+ snd_mask_any(&m); -+ for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { -+ int bits; -+ if (! snd_mask_test(mask, k)) -+ continue; -+ bits = snd_pcm_format_physical_width(k); -+ if (bits <= 0) -+ continue; /* ignore invalid formats */ -+ if ((unsigned)bits < i->min || (unsigned)bits > i->max) -+ snd_mask_reset(&m, k); -+ } -+ return snd_mask_refine(mask, &m); -+} -+ -+static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ unsigned int k; -+ t.min = UINT_MAX; -+ t.max = 0; -+ t.openmin = 0; -+ t.openmax = 0; -+ for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { -+ int bits; -+ if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) -+ continue; -+ bits = snd_pcm_format_physical_width(k); -+ if (bits <= 0) -+ continue; /* ignore invalid formats */ -+ if (t.min > (unsigned)bits) -+ t.min = bits; -+ if (t.max < (unsigned)bits) -+ t.max = bits; -+ } -+ t.integer = 1; -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 -+#error "Change this table" -+#endif -+ -+static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, -+ 48000, 64000, 88200, 96000, 176400, 192000 }; -+ -+const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { -+ .count = ARRAY_SIZE(rates), -+ .list = rates, -+}; -+ -+static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_pcm_hardware *hw = rule->private; -+ return snd_interval_list(hw_param_interval(params, rule->var), -+ snd_pcm_known_rates.count, -+ snd_pcm_known_rates.list, hw->rates); -+} -+ -+static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_rule *rule) -+{ -+ struct snd_interval t; -+ struct snd_pcm_substream *substream = rule->private; -+ t.min = 0; -+ t.max = substream->buffer_bytes_max; -+ t.openmin = 0; -+ t.openmax = 0; -+ t.integer = 1; -+ return snd_interval_refine(hw_param_interval(params, rule->var), &t); -+} -+ -+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; -+ int k, err; -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { -+ snd_mask_any(constrs_mask(constrs, k)); -+ } -+ -+ for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { -+ snd_interval_any(constrs_interval(constrs, k)); -+ } -+ -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)); -+ snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS)); -+ -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, -+ snd_pcm_hw_rule_format, NULL, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -+ snd_pcm_hw_rule_sample_bits, NULL, -+ SNDRV_PCM_HW_PARAM_FORMAT, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mul, NULL, -+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_div, NULL, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -+ snd_pcm_hw_rule_muldivk, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_mul, NULL, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_mulkdiv, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -+ snd_pcm_hw_rule_muldivk, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ snd_pcm_hw_rule_muldivk, (void*) 8, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ snd_pcm_hw_rule_muldivk, (void*) 8, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -+ snd_pcm_hw_rule_mulkdiv, (void*) 1000000, -+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_hardware *hw = &runtime->hw; -+ int err; -+ unsigned int mask = 0; -+ -+ if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_MMAP) { -+ if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; -+ if (hw->info & SNDRV_PCM_INFO_COMPLEX) -+ mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; -+ } -+ err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, -+ hw->channels_min, hw->channels_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, -+ hw->rate_min, hw->rate_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -+ hw->period_bytes_min, hw->period_bytes_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, -+ hw->periods_min, hw->periods_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ hw->period_bytes_min, hw->buffer_bytes_max); -+ snd_assert(err >= 0, return -EINVAL); -+ -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -+ snd_pcm_hw_rule_buffer_bytes_max, substream, -+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); -+ if (err < 0) -+ return err; -+ -+ /* FIXME: remove */ -+ if (runtime->dma_bytes) { -+ err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); -+ snd_assert(err >= 0, return -EINVAL); -+ } -+ -+ if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { -+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -+ snd_pcm_hw_rule_rate, hw, -+ SNDRV_PCM_HW_PARAM_RATE, -1); -+ if (err < 0) -+ return err; -+ } -+ -+ /* FIXME: this belong to lowlevel */ -+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, -+ 1000000 / HZ, 1000000 / HZ); -+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); -+ -+ return 0; -+} -+ -+static void pcm_release_private(struct snd_pcm_substream *substream) -+{ -+ snd_pcm_unlink(substream); -+} -+ -+void snd_pcm_release_substream(struct snd_pcm_substream *substream) -+{ -+ substream->ref_count--; -+ if (substream->ref_count > 0) -+ return; -+ -+ snd_pcm_drop(substream); -+ if (substream->hw_opened) { -+ if (substream->ops->hw_free != NULL) -+ substream->ops->hw_free(substream); -+ substream->ops->close(substream); -+ substream->hw_opened = 0; -+ } -+ if (substream->pcm_release) { -+ substream->pcm_release(substream); -+ substream->pcm_release = NULL; -+ } -+ snd_pcm_detach_substream(substream); -+} -+ -+EXPORT_SYMBOL(snd_pcm_release_substream); -+ -+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, -+ struct file *file, -+ struct snd_pcm_substream **rsubstream) -+{ -+ struct snd_pcm_substream *substream; -+ int err; -+ -+ err = snd_pcm_attach_substream(pcm, stream, file, &substream); -+ if (err < 0) -+ return err; -+ if (substream->ref_count > 1) { -+ *rsubstream = substream; -+ return 0; -+ } -+ -+ err = snd_pcm_hw_constraints_init(substream); -+ if (err < 0) { -+ snd_printd("snd_pcm_hw_constraints_init failed\n"); -+ goto error; -+ } -+ -+ if ((err = substream->ops->open(substream)) < 0) -+ goto error; -+ -+ substream->hw_opened = 1; -+ -+ err = snd_pcm_hw_constraints_complete(substream); -+ if (err < 0) { -+ snd_printd("snd_pcm_hw_constraints_complete failed\n"); -+ goto error; -+ } -+ -+ *rsubstream = substream; -+ return 0; -+ -+ error: -+ snd_pcm_release_substream(substream); -+ return err; -+} -+ -+EXPORT_SYMBOL(snd_pcm_open_substream); -+ -+static int snd_pcm_open_file(struct file *file, -+ struct snd_pcm *pcm, -+ int stream, -+ struct snd_pcm_file **rpcm_file) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_str *str; -+ int err; -+ -+ snd_assert(rpcm_file != NULL, return -EINVAL); -+ *rpcm_file = NULL; -+ -+ err = snd_pcm_open_substream(pcm, stream, file, &substream); -+ if (err < 0) -+ return err; -+ -+ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); -+ if (pcm_file == NULL) { -+ snd_pcm_release_substream(substream); -+ return -ENOMEM; -+ } -+ pcm_file->substream = substream; -+ if (substream->ref_count == 1) { -+ str = substream->pstr; -+ substream->file = pcm_file; -+ substream->pcm_release = pcm_release_private; -+ } -+ file->private_data = pcm_file; -+ *rpcm_file = pcm_file; -+ return 0; -+} -+ -+static int snd_pcm_playback_open(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ -+ pcm = snd_lookup_minor_data(iminor(inode), -+ SNDRV_DEVICE_TYPE_PCM_PLAYBACK); -+ return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); -+} -+ -+static int snd_pcm_capture_open(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ -+ pcm = snd_lookup_minor_data(iminor(inode), -+ SNDRV_DEVICE_TYPE_PCM_CAPTURE); -+ return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); -+} -+ -+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) -+{ -+ int err; -+ struct snd_pcm_file *pcm_file; -+ wait_queue_t wait; -+ -+ if (pcm == NULL) { -+ err = -ENODEV; -+ goto __error1; -+ } -+ err = snd_card_file_add(pcm->card, file); -+ if (err < 0) -+ goto __error1; -+ if (!try_module_get(pcm->card->module)) { -+ err = -EFAULT; -+ goto __error2; -+ } -+ init_waitqueue_entry(&wait, current); -+ add_wait_queue(&pcm->open_wait, &wait); -+ mutex_lock(&pcm->open_mutex); -+ while (1) { -+ err = snd_pcm_open_file(file, pcm, stream, &pcm_file); -+ if (err >= 0) -+ break; -+ if (err == -EAGAIN) { -+ if (file->f_flags & O_NONBLOCK) { -+ err = -EBUSY; -+ break; -+ } -+ } else -+ break; -+ set_current_state(TASK_INTERRUPTIBLE); -+ mutex_unlock(&pcm->open_mutex); -+ schedule(); -+ mutex_lock(&pcm->open_mutex); -+ if (signal_pending(current)) { -+ err = -ERESTARTSYS; -+ break; -+ } -+ } -+ remove_wait_queue(&pcm->open_wait, &wait); -+ mutex_unlock(&pcm->open_mutex); -+ if (err < 0) -+ goto __error; -+ return err; -+ -+ __error: -+ module_put(pcm->card->module); -+ __error2: -+ snd_card_file_remove(pcm->card, file); -+ __error1: -+ return err; -+} -+ -+static int snd_pcm_release(struct inode *inode, struct file *file) -+{ -+ struct snd_pcm *pcm; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ pcm = substream->pcm; -+ fasync_helper(-1, file, 0, &substream->runtime->fasync); -+ mutex_lock(&pcm->open_mutex); -+ snd_pcm_release_substream(substream); -+ kfree(pcm_file); -+ mutex_unlock(&pcm->open_mutex); -+ wake_up(&pcm->open_wait); -+ module_put(pcm->card->module); -+ snd_card_file_remove(pcm->card, file); -+ return 0; -+} -+ -+static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t hw_avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ hw_avail = snd_pcm_playback_hw_avail(runtime); -+ if (hw_avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)hw_avail) -+ frames = hw_avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr - frames; -+ if (appl_ptr < 0) -+ appl_ptr += runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t hw_avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_DRAINING: -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ hw_avail = snd_pcm_capture_hw_avail(runtime); -+ if (hw_avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)hw_avail) -+ frames = hw_avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr - frames; -+ if (appl_ptr < 0) -+ appl_ptr += runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ avail = snd_pcm_playback_avail(runtime); -+ if (avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)avail) -+ frames = avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr + frames; -+ if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -+ appl_ptr -= runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream, -+ snd_pcm_uframes_t frames) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t appl_ptr; -+ snd_pcm_sframes_t ret; -+ snd_pcm_sframes_t avail; -+ -+ if (frames == 0) -+ return 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_DRAINING: -+ case SNDRV_PCM_STATE_PAUSED: -+ break; -+ case SNDRV_PCM_STATE_RUNNING: -+ if (snd_pcm_update_hw_ptr(substream) >= 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_XRUN: -+ ret = -EPIPE; -+ goto __end; -+ default: -+ ret = -EBADFD; -+ goto __end; -+ } -+ -+ avail = snd_pcm_capture_avail(runtime); -+ if (avail <= 0) { -+ ret = 0; -+ goto __end; -+ } -+ if (frames > (snd_pcm_uframes_t)avail) -+ frames = avail; -+ else -+ frames -= frames % runtime->xfer_align; -+ appl_ptr = runtime->control->appl_ptr + frames; -+ if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -+ appl_ptr -= runtime->boundary; -+ runtime->control->appl_ptr = appl_ptr; -+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && -+ runtime->sleep_min) -+ snd_pcm_tick_prepare(substream); -+ ret = frames; -+ __end: -+ snd_pcm_stream_unlock_irq(substream); -+ return ret; -+} -+ -+static int snd_pcm_hwsync(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_DRAINING: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ goto __badfd; -+ case SNDRV_PCM_STATE_RUNNING: -+ if ((err = snd_pcm_update_hw_ptr(substream)) < 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ err = 0; -+ break; -+ case SNDRV_PCM_STATE_XRUN: -+ err = -EPIPE; -+ break; -+ default: -+ __badfd: -+ err = -EBADFD; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return err; -+} -+ -+static int snd_pcm_delay(struct snd_pcm_substream *substream, -+ snd_pcm_sframes_t __user *res) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ int err; -+ snd_pcm_sframes_t n = 0; -+ -+ snd_pcm_stream_lock_irq(substream); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_DRAINING: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ goto __badfd; -+ case SNDRV_PCM_STATE_RUNNING: -+ if ((err = snd_pcm_update_hw_ptr(substream)) < 0) -+ break; -+ /* Fall through */ -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_SUSPENDED: -+ err = 0; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ n = snd_pcm_playback_hw_avail(runtime); -+ else -+ n = snd_pcm_capture_avail(runtime); -+ break; -+ case SNDRV_PCM_STATE_XRUN: -+ err = -EPIPE; -+ break; -+ default: -+ __badfd: -+ err = -EBADFD; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ if (!err) -+ if (put_user(n, res)) -+ err = -EFAULT; -+ return err; -+} -+ -+static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, -+ struct snd_pcm_sync_ptr __user *_sync_ptr) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct snd_pcm_sync_ptr sync_ptr; -+ volatile struct snd_pcm_mmap_status *status; -+ volatile struct snd_pcm_mmap_control *control; -+ int err; -+ -+ memset(&sync_ptr, 0, sizeof(sync_ptr)); -+ if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) -+ return -EFAULT; -+ if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control))) -+ return -EFAULT; -+ status = runtime->status; -+ control = runtime->control; -+ if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { -+ err = snd_pcm_hwsync(substream); -+ if (err < 0) -+ return err; -+ } -+ snd_pcm_stream_lock_irq(substream); -+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) -+ control->appl_ptr = sync_ptr.c.control.appl_ptr; -+ else -+ sync_ptr.c.control.appl_ptr = control->appl_ptr; -+ if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) -+ control->avail_min = sync_ptr.c.control.avail_min; -+ else -+ sync_ptr.c.control.avail_min = control->avail_min; -+ sync_ptr.s.status.state = status->state; -+ sync_ptr.s.status.hw_ptr = status->hw_ptr; -+ sync_ptr.s.status.tstamp = status->tstamp; -+ sync_ptr.s.status.suspended_state = status->suspended_state; -+ snd_pcm_stream_unlock_irq(substream); -+ if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int snd_pcm_common_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_PVERSION: -+ return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; -+ case SNDRV_PCM_IOCTL_INFO: -+ return snd_pcm_info_user(substream, arg); -+ case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ -+ return 0; -+ case SNDRV_PCM_IOCTL_HW_REFINE: -+ return snd_pcm_hw_refine_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_PARAMS: -+ return snd_pcm_hw_params_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_FREE: -+ return snd_pcm_hw_free(substream); -+ case SNDRV_PCM_IOCTL_SW_PARAMS: -+ return snd_pcm_sw_params_user(substream, arg); -+ case SNDRV_PCM_IOCTL_STATUS: -+ return snd_pcm_status_user(substream, arg); -+ case SNDRV_PCM_IOCTL_CHANNEL_INFO: -+ return snd_pcm_channel_info_user(substream, arg); -+ case SNDRV_PCM_IOCTL_PREPARE: -+ return snd_pcm_prepare(substream, file); -+ case SNDRV_PCM_IOCTL_RESET: -+ return snd_pcm_reset(substream); -+ case SNDRV_PCM_IOCTL_START: -+ return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); -+ case SNDRV_PCM_IOCTL_LINK: -+ return snd_pcm_link(substream, (int)(unsigned long) arg); -+ case SNDRV_PCM_IOCTL_UNLINK: -+ return snd_pcm_unlink(substream); -+ case SNDRV_PCM_IOCTL_RESUME: -+ return snd_pcm_resume(substream); -+ case SNDRV_PCM_IOCTL_XRUN: -+ return snd_pcm_xrun(substream); -+ case SNDRV_PCM_IOCTL_HWSYNC: -+ return snd_pcm_hwsync(substream); -+ case SNDRV_PCM_IOCTL_DELAY: -+ return snd_pcm_delay(substream, arg); -+ case SNDRV_PCM_IOCTL_SYNC_PTR: -+ return snd_pcm_sync_ptr(substream, arg); -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+ case SNDRV_PCM_IOCTL_HW_REFINE_OLD: -+ return snd_pcm_hw_refine_old_user(substream, arg); -+ case SNDRV_PCM_IOCTL_HW_PARAMS_OLD: -+ return snd_pcm_hw_params_old_user(substream, arg); -+#endif -+ case SNDRV_PCM_IOCTL_DRAIN: -+ return snd_pcm_drain(substream); -+ case SNDRV_PCM_IOCTL_DROP: -+ return snd_pcm_drop(substream); -+ case SNDRV_PCM_IOCTL_PAUSE: -+ { -+ int res; -+ snd_pcm_stream_lock_irq(substream); -+ res = snd_pcm_pause(substream, (int)(unsigned long)arg); -+ snd_pcm_stream_unlock_irq(substream); -+ return res; -+ } -+ } -+ snd_printd("unknown ioctl = 0x%x\n", cmd); -+ return -ENOTTY; -+} -+ -+static int snd_pcm_playback_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL); -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_WRITEI_FRAMES: -+ { -+ struct snd_xferi xferi; -+ struct snd_xferi __user *_xferi = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (put_user(0, &_xferi->result)) -+ return -EFAULT; -+ if (copy_from_user(&xferi, _xferi, sizeof(xferi))) -+ return -EFAULT; -+ result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); -+ __put_user(result, &_xferi->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_WRITEN_FRAMES: -+ { -+ struct snd_xfern xfern; -+ struct snd_xfern __user *_xfern = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ void __user **bufs; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (runtime->channels > 128) -+ return -EINVAL; -+ if (put_user(0, &_xfern->result)) -+ return -EFAULT; -+ if (copy_from_user(&xfern, _xfern, sizeof(xfern))) -+ return -EFAULT; -+ bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { -+ kfree(bufs); -+ return -EFAULT; -+ } -+ result = snd_pcm_lib_writev(substream, bufs, xfern.frames); -+ kfree(bufs); -+ __put_user(result, &_xfern->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_REWIND: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_playback_rewind(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_FORWARD: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_playback_forward(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ } -+ return snd_pcm_common_ioctl1(file, substream, cmd, arg); -+} -+ -+static int snd_pcm_capture_ioctl1(struct file *file, -+ struct snd_pcm_substream *substream, -+ unsigned int cmd, void __user *arg) -+{ -+ snd_assert(substream != NULL, return -ENXIO); -+ snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL); -+ switch (cmd) { -+ case SNDRV_PCM_IOCTL_READI_FRAMES: -+ { -+ struct snd_xferi xferi; -+ struct snd_xferi __user *_xferi = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (put_user(0, &_xferi->result)) -+ return -EFAULT; -+ if (copy_from_user(&xferi, _xferi, sizeof(xferi))) -+ return -EFAULT; -+ result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); -+ __put_user(result, &_xferi->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_READN_FRAMES: -+ { -+ struct snd_xfern xfern; -+ struct snd_xfern __user *_xfern = arg; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ void *bufs; -+ snd_pcm_sframes_t result; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (runtime->channels > 128) -+ return -EINVAL; -+ if (put_user(0, &_xfern->result)) -+ return -EFAULT; -+ if (copy_from_user(&xfern, _xfern, sizeof(xfern))) -+ return -EFAULT; -+ bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { -+ kfree(bufs); -+ return -EFAULT; -+ } -+ result = snd_pcm_lib_readv(substream, bufs, xfern.frames); -+ kfree(bufs); -+ __put_user(result, &_xfern->result); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_REWIND: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_capture_rewind(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ case SNDRV_PCM_IOCTL_FORWARD: -+ { -+ snd_pcm_uframes_t frames; -+ snd_pcm_uframes_t __user *_frames = arg; -+ snd_pcm_sframes_t result; -+ if (get_user(frames, _frames)) -+ return -EFAULT; -+ if (put_user(0, _frames)) -+ return -EFAULT; -+ result = snd_pcm_capture_forward(substream, frames); -+ __put_user(result, _frames); -+ return result < 0 ? result : 0; -+ } -+ } -+ return snd_pcm_common_ioctl1(file, substream, cmd, arg); -+} -+ -+static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ -+ if (((cmd >> 8) & 0xff) != 'A') -+ return -ENOTTY; -+ -+ return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, -+ (void __user *)arg); -+} -+ -+static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct snd_pcm_file *pcm_file; -+ -+ pcm_file = file->private_data; -+ -+ if (((cmd >> 8) & 0xff) != 'A') -+ return -ENOTTY; -+ -+ return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, -+ (void __user *)arg); -+} -+ -+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, -+ unsigned int cmd, void *arg) -+{ -+ mm_segment_t fs; -+ int result; -+ -+ fs = snd_enter_user(); -+ switch (substream->stream) { -+ case SNDRV_PCM_STREAM_PLAYBACK: -+ result = snd_pcm_playback_ioctl1(NULL, substream, cmd, -+ (void __user *)arg); -+ break; -+ case SNDRV_PCM_STREAM_CAPTURE: -+ result = snd_pcm_capture_ioctl1(NULL, substream, cmd, -+ (void __user *)arg); -+ break; -+ default: -+ result = -EINVAL; -+ break; -+ } -+ snd_leave_user(fs); -+ return result; -+} -+ -+EXPORT_SYMBOL(snd_pcm_kernel_ioctl); -+ -+static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, -+ loff_t * offset) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (!frame_aligned(runtime, count)) -+ return -EINVAL; -+ count = bytes_to_frames(runtime, count); -+ result = snd_pcm_lib_read(substream, buf, count); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ return result; -+} -+ -+static ssize_t snd_pcm_write(struct file *file, const char __user *buf, -+ size_t count, loff_t * offset) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, result = -ENXIO; goto end); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ result = -EBADFD; -+ goto end; -+ } -+ if (!frame_aligned(runtime, count)) { -+ result = -EINVAL; -+ goto end; -+ } -+ count = bytes_to_frames(runtime, count); -+ result = snd_pcm_lib_write(substream, buf, count); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ end: -+ return result; -+} -+ -+static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, -+ unsigned long nr_segs, loff_t pos) -+ -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ unsigned long i; -+ void __user **bufs; -+ snd_pcm_uframes_t frames; -+ -+ pcm_file = iocb->ki_filp->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (nr_segs > 1024 || nr_segs != runtime->channels) -+ return -EINVAL; -+ if (!frame_aligned(runtime, iov->iov_len)) -+ return -EINVAL; -+ frames = bytes_to_samples(runtime, iov->iov_len); -+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ for (i = 0; i < nr_segs; ++i) -+ bufs[i] = iov[i].iov_base; -+ result = snd_pcm_lib_readv(substream, bufs, frames); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ kfree(bufs); -+ return result; -+} -+ -+static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, -+ unsigned long nr_segs, loff_t pos) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ snd_pcm_sframes_t result; -+ unsigned long i; -+ void __user **bufs; -+ snd_pcm_uframes_t frames; -+ -+ pcm_file = iocb->ki_filp->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, result = -ENXIO; goto end); -+ runtime = substream->runtime; -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { -+ result = -EBADFD; -+ goto end; -+ } -+ if (nr_segs > 128 || nr_segs != runtime->channels || -+ !frame_aligned(runtime, iov->iov_len)) { -+ result = -EINVAL; -+ goto end; -+ } -+ frames = bytes_to_samples(runtime, iov->iov_len); -+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); -+ if (bufs == NULL) -+ return -ENOMEM; -+ for (i = 0; i < nr_segs; ++i) -+ bufs[i] = iov[i].iov_base; -+ result = snd_pcm_lib_writev(substream, bufs, frames); -+ if (result > 0) -+ result = frames_to_bytes(runtime, result); -+ kfree(bufs); -+ end: -+ return result; -+} -+ -+static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ unsigned int mask; -+ snd_pcm_uframes_t avail; -+ -+ pcm_file = file->private_data; -+ -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ poll_wait(file, &runtime->sleep, wait); -+ -+ snd_pcm_stream_lock_irq(substream); -+ avail = snd_pcm_playback_avail(runtime); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ if (avail >= runtime->control->avail_min) { -+ mask = POLLOUT | POLLWRNORM; -+ break; -+ } -+ /* Fall through */ -+ case SNDRV_PCM_STATE_DRAINING: -+ mask = 0; -+ break; -+ default: -+ mask = POLLOUT | POLLWRNORM | POLLERR; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return mask; -+} -+ -+static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) -+{ -+ struct snd_pcm_file *pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ unsigned int mask; -+ snd_pcm_uframes_t avail; -+ -+ pcm_file = file->private_data; -+ -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ poll_wait(file, &runtime->sleep, wait); -+ -+ snd_pcm_stream_lock_irq(substream); -+ avail = snd_pcm_capture_avail(runtime); -+ switch (runtime->status->state) { -+ case SNDRV_PCM_STATE_RUNNING: -+ case SNDRV_PCM_STATE_PREPARED: -+ case SNDRV_PCM_STATE_PAUSED: -+ if (avail >= runtime->control->avail_min) { -+ mask = POLLIN | POLLRDNORM; -+ break; -+ } -+ mask = 0; -+ break; -+ case SNDRV_PCM_STATE_DRAINING: -+ if (avail > 0) { -+ mask = POLLIN | POLLRDNORM; -+ break; -+ } -+ /* Fall through */ -+ default: -+ mask = POLLIN | POLLRDNORM | POLLERR; -+ break; -+ } -+ snd_pcm_stream_unlock_irq(substream); -+ return mask; -+} -+ -+/* -+ * mmap support -+ */ -+ -+/* -+ * Only on coherent architectures, we can mmap the status and the control records -+ * for effcient data transfer. On others, we have to use HWSYNC ioctl... -+ */ -+#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) -+/* -+ * mmap status record -+ */ -+static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ struct page * page; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ page = virt_to_page(runtime->status); -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_status = -+{ -+ .nopage = snd_pcm_mmap_status_nopage, -+}; -+ -+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ size = area->vm_end - area->vm_start; -+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) -+ return -EINVAL; -+ area->vm_ops = &snd_pcm_vm_ops_status; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ return 0; -+} -+ -+/* -+ * mmap control record -+ */ -+static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ struct page * page; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ page = virt_to_page(runtime->control); -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_control = -+{ -+ .nopage = snd_pcm_mmap_control_nopage, -+}; -+ -+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ size = area->vm_end - area->vm_start; -+ if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) -+ return -EINVAL; -+ area->vm_ops = &snd_pcm_vm_ops_control; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ return 0; -+} -+#else /* ! coherent mmap */ -+/* -+ * don't support mmap for status and control records. -+ */ -+static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ return -ENXIO; -+} -+static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ return -ENXIO; -+} -+#endif /* coherent mmap */ -+ -+/* -+ * nopage callback for mmapping a RAM page -+ */ -+static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, -+ unsigned long address, int *type) -+{ -+ struct snd_pcm_substream *substream = area->vm_private_data; -+ struct snd_pcm_runtime *runtime; -+ unsigned long offset; -+ struct page * page; -+ void *vaddr; -+ size_t dma_bytes; -+ -+ if (substream == NULL) -+ return NOPAGE_SIGBUS; -+ runtime = substream->runtime; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ offset += address - area->vm_start; -+ snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); -+ dma_bytes = PAGE_ALIGN(runtime->dma_bytes); -+ if (offset > dma_bytes - PAGE_SIZE) -+ return NOPAGE_SIGBUS; -+ if (substream->ops->page) { -+ page = substream->ops->page(substream, offset); -+ if (! page) -+ return NOPAGE_OOM; /* XXX: is this really due to OOM? */ -+ } else { -+ vaddr = runtime->dma_area + offset; -+ page = virt_to_page(vaddr); -+ } -+ get_page(page); -+ if (type) -+ *type = VM_FAULT_MINOR; -+ return page; -+} -+ -+static struct vm_operations_struct snd_pcm_vm_ops_data = -+{ -+ .open = snd_pcm_mmap_data_open, -+ .close = snd_pcm_mmap_data_close, -+ .nopage = snd_pcm_mmap_data_nopage, -+}; -+ -+/* -+ * mmap the DMA buffer on RAM -+ */ -+static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, -+ struct vm_area_struct *area) -+{ -+ area->vm_ops = &snd_pcm_vm_ops_data; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_RESERVED; -+ atomic_inc(&substream->mmap_count); -+ return 0; -+} -+ -+/* -+ * mmap the DMA buffer on I/O memory area -+ */ -+#if SNDRV_PCM_INFO_MMAP_IOMEM -+static struct vm_operations_struct snd_pcm_vm_ops_data_mmio = -+{ -+ .open = snd_pcm_mmap_data_open, -+ .close = snd_pcm_mmap_data_close, -+}; -+ -+int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, -+ struct vm_area_struct *area) -+{ -+ long size; -+ unsigned long offset; -+ -+#ifdef pgprot_noncached -+ area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -+#endif -+ area->vm_ops = &snd_pcm_vm_ops_data_mmio; -+ area->vm_private_data = substream; -+ area->vm_flags |= VM_IO; -+ size = area->vm_end - area->vm_start; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ if (io_remap_pfn_range(area, area->vm_start, -+ (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, -+ size, area->vm_page_prot)) -+ return -EAGAIN; -+ atomic_inc(&substream->mmap_count); -+ return 0; -+} -+ -+EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); -+#endif /* SNDRV_PCM_INFO_MMAP */ -+ -+/* -+ * mmap DMA buffer -+ */ -+int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, -+ struct vm_area_struct *area) -+{ -+ struct snd_pcm_runtime *runtime; -+ long size; -+ unsigned long offset; -+ size_t dma_bytes; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if (!(area->vm_flags & (VM_WRITE|VM_READ))) -+ return -EINVAL; -+ } else { -+ if (!(area->vm_flags & VM_READ)) -+ return -EINVAL; -+ } -+ runtime = substream->runtime; -+ snd_assert(runtime != NULL, return -EAGAIN); -+ if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -+ return -EBADFD; -+ if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) -+ return -ENXIO; -+ if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || -+ runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) -+ return -EINVAL; -+ size = area->vm_end - area->vm_start; -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ dma_bytes = PAGE_ALIGN(runtime->dma_bytes); -+ if ((size_t)size > dma_bytes) -+ return -EINVAL; -+ if (offset > dma_bytes - size) -+ return -EINVAL; -+ -+ if (substream->ops->mmap) -+ return substream->ops->mmap(substream, area); -+ else -+ return snd_pcm_default_mmap(substream, area); -+} -+ -+EXPORT_SYMBOL(snd_pcm_mmap_data); -+ -+static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) -+{ -+ struct snd_pcm_file * pcm_file; -+ struct snd_pcm_substream *substream; -+ unsigned long offset; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ -+ offset = area->vm_pgoff << PAGE_SHIFT; -+ switch (offset) { -+ case SNDRV_PCM_MMAP_OFFSET_STATUS: -+ if (pcm_file->no_compat_mmap) -+ return -ENXIO; -+ return snd_pcm_mmap_status(substream, file, area); -+ case SNDRV_PCM_MMAP_OFFSET_CONTROL: -+ if (pcm_file->no_compat_mmap) -+ return -ENXIO; -+ return snd_pcm_mmap_control(substream, file, area); -+ default: -+ return snd_pcm_mmap_data(substream, file, area); -+ } -+ return 0; -+} -+ -+static int snd_pcm_fasync(int fd, struct file * file, int on) -+{ -+ struct snd_pcm_file * pcm_file; -+ struct snd_pcm_substream *substream; -+ struct snd_pcm_runtime *runtime; -+ int err; -+ -+ pcm_file = file->private_data; -+ substream = pcm_file->substream; -+ snd_assert(substream != NULL, return -ENXIO); -+ runtime = substream->runtime; -+ -+ err = fasync_helper(fd, file, on, &runtime->fasync); -+ if (err < 0) -+ return err; -+ return 0; -+} -+ -+/* -+ * ioctl32 compat -+ */ -+#ifdef CONFIG_COMPAT -+#include "pcm_compat.c" -+#else -+#define snd_pcm_ioctl_compat NULL -+#endif -+ -+/* -+ * To be removed helpers to keep binary compatibility -+ */ -+ -+#ifdef CONFIG_SND_SUPPORT_OLD_API -+#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) -+#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) -+ -+static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params, -+ struct snd_pcm_hw_params_old *oparams) -+{ -+ unsigned int i; -+ -+ memset(params, 0, sizeof(*params)); -+ params->flags = oparams->flags; -+ for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) -+ params->masks[i].bits[0] = oparams->masks[i]; -+ memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); -+ params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); -+ params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); -+ params->info = oparams->info; -+ params->msbits = oparams->msbits; -+ params->rate_num = oparams->rate_num; -+ params->rate_den = oparams->rate_den; -+ params->fifo_size = oparams->fifo_size; -+} -+ -+static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *oparams, -+ struct snd_pcm_hw_params *params) -+{ -+ unsigned int i; -+ -+ memset(oparams, 0, sizeof(*oparams)); -+ oparams->flags = params->flags; -+ for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) -+ oparams->masks[i] = params->masks[i].bits[0]; -+ memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); -+ oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); -+ oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); -+ oparams->info = params->info; -+ oparams->msbits = params->msbits; -+ oparams->rate_num = params->rate_num; -+ oparams->rate_den = params->rate_den; -+ oparams->fifo_size = params->fifo_size; -+} -+ -+static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams) -+{ -+ struct snd_pcm_hw_params *params; -+ struct snd_pcm_hw_params_old *oparams = NULL; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); -+ if (!oparams) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { -+ err = -EFAULT; -+ goto out; -+ } -+ snd_pcm_hw_convert_from_old_params(params, oparams); -+ err = snd_pcm_hw_refine(substream, params); -+ snd_pcm_hw_convert_to_old_params(oparams, params); -+ if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ kfree(oparams); -+ return err; -+} -+ -+static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params_old __user * _oparams) -+{ -+ struct snd_pcm_hw_params *params; -+ struct snd_pcm_hw_params_old *oparams = NULL; -+ int err; -+ -+ params = kmalloc(sizeof(*params), GFP_KERNEL); -+ if (!params) { -+ err = -ENOMEM; -+ goto out; -+ } -+ oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); -+ if (!oparams) { -+ err = -ENOMEM; -+ goto out; -+ } -+ if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { -+ err = -EFAULT; -+ goto out; -+ } -+ snd_pcm_hw_convert_from_old_params(params, oparams); -+ err = snd_pcm_hw_params(substream, params); -+ snd_pcm_hw_convert_to_old_params(oparams, params); -+ if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -+ if (!err) -+ err = -EFAULT; -+ } -+out: -+ kfree(params); -+ kfree(oparams); -+ return err; -+} -+#endif /* CONFIG_SND_SUPPORT_OLD_API */ -+ -+/* -+ * Register section -+ */ -+ -+const struct file_operations snd_pcm_f_ops[2] = { -+ { -+ .owner = THIS_MODULE, -+ .write = snd_pcm_write, -+ .aio_write = snd_pcm_aio_write, -+ .open = snd_pcm_playback_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_playback_poll, -+ .unlocked_ioctl = snd_pcm_playback_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ }, -+ { -+ .owner = THIS_MODULE, -+ .read = snd_pcm_read, -+ .aio_read = snd_pcm_aio_read, -+ .open = snd_pcm_capture_open, -+ .release = snd_pcm_release, -+ .poll = snd_pcm_capture_poll, -+ .unlocked_ioctl = snd_pcm_capture_ioctl, -+ .compat_ioctl = snd_pcm_ioctl_compat, -+ .mmap = snd_pcm_mmap, -+ .fasync = snd_pcm_fasync, -+ } -+}; -diff -urN linux-2.6.24.7.old/sound/oss/Kconfig linux-2.6.24.7/sound/oss/Kconfig ---- linux-2.6.24.7.old/sound/oss/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/oss/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -5,6 +5,91 @@ - # - # Prompt user for primary drivers. - -+config OSS_OBSOLETE -+ bool "Obsolete OSS drivers" -+ depends on SOUND_PRIME -+ help -+ This option enables support for obsolete OSS drivers that -+ are scheduled for removal in the near future. -+ -+ Please contact Adrian Bunk if you had to -+ say Y here because your hardware is not properly supported -+ by ALSA. -+ -+ If unsure, say N. -+ -+config SOUND_JZ_AC97 -+ bool "Jz On-Chip AC97 driver" -+ depends on OSS_OBSOLETE -+ help -+ Say Y here if you have want to select the on-chip AC97 driver -+ on Jz4730/Jz4740/Jz5730. -+ -+config SOUND_JZ_I2S -+ bool "Jz On-Chip I2S driver" -+ depends on OSS_OBSOLETE -+ help -+ Say Y here if you have want to select the on-chip I2S driver -+ on Jz4730/Jz4740/Jz5730. -+ -+config SOUND_JZ_PCM -+ bool "Jz On-Chip PCM driver" -+ depends on SOC_JZ4750 -+ help -+ Say Y here if you have want to select the on-chip PCM driver -+ on Jz4750. -+ -+choice -+ prompt "I2S codec type" -+ depends on SOUND_JZ_I2S -+ -+config I2S_AK4642EN -+ bool "AK4642EN" -+ depends on SOC_JZ4730 -+ help -+ Answer Y if you have an external AK4642EN codec. -+ -+config I2S_ICODEC -+ bool "Internal On-Chip codec" -+ depends on SOC_JZ4740 -+ help -+ Answer Y if you have an internal I2S codec. -+ -+config I2S_DLV -+ bool "Internal On-Chip codec on Jz4750 or Jz4750d" -+ depends on SOC_JZ4750 || SOC_JZ4750D -+ help -+ Answer Y if you have an internal I2S codec on Jz4750 or Jz4750d. -+ -+endchoice -+ -+choice -+ prompt "PCM codec type" -+ depends on SOUND_JZ_PCM -+ -+config PCM_TLV320AIC1106 -+ bool "TLV320AIC1106" -+ help -+ Answer Y if you have an TI tlv320aic 1106 codec. -+ -+endchoice -+ -+config SOUND_BT878 -+ tristate "BT878 audio dma" -+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE -+ ---help--- -+ Audio DMA support for bt878 based grabber boards. As you might have -+ already noticed, bt878 is listed with two functions in /proc/pci. -+ Function 0 does the video stuff (bt848 compatible), function 1 does -+ the same for audio data. This is a driver for the audio part of -+ the chip. If you say 'Y' here you get a oss-compatible dsp device -+ where you can record from. If you want just watch TV you probably -+ don't need this driver as most TV cards handle sound with a short -+ cable from the TV card to your sound card's line-in. -+ -+ To compile this driver as a module, choose M here: the module will -+ be called btaudio. -+ - config SOUND_BCM_CS4297A - tristate "Crystal Sound CS4297a (for Swarm)" - depends on SOUND_PRIME && SIBYTE_SWARM -@@ -15,6 +100,13 @@ - note that CONFIG_KGDB should not be enabled at the same - time, since it also attempts to use this UART port. - -+config SOUND_ICH -+ tristate "Intel ICH (i8xx) audio support" -+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE -+ help -+ Support for integral audio in Intel's I/O Controller Hub (ICH) -+ chipset, as used on the 810/820/840 motherboards. -+ - config SOUND_VWSND - tristate "SGI Visual Workstation Sound" - depends on SOUND_PRIME && X86_VISWS -@@ -31,6 +123,14 @@ - Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to - use its on-board A2 audio system. - -+config SOUND_VRC5477 -+ tristate "NEC Vrc5477 AC97 sound" -+ depends on SOUND_PRIME && DDB5477 -+ help -+ Say Y here to enable sound support for the NEC Vrc5477 chip, an -+ integrated, multi-function controller chip for MIPS CPUs. Works -+ with the AC97 codec. -+ - config SOUND_AU1550_AC97 - tristate "Au1550/Au1200 AC97 Sound" - select SND_AC97_CODEC -@@ -75,7 +175,7 @@ - - - This driver differs slightly from OSS/Free, so PLEASE READ the -- comments at the top of . -+ comments at the top of . - - config SOUND_MSNDCLAS - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" -@@ -302,9 +402,29 @@ - and Pinnacle). Larger values reduce the chance of data overruns at - the expense of overall latency. If unsure, use the default. - -+config SOUND_VIA82CXXX -+ tristate "VIA 82C686 Audio Codec" -+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE -+ help -+ Say Y here to include support for the audio codec found on VIA -+ 82Cxxx-based chips. Typically these are built into a motherboard. -+ -+ DO NOT select Sound Blaster or Adlib with this driver, unless -+ you have a Sound Blaster or Adlib card in addition to your VIA -+ audio chip. -+ -+config MIDI_VIA82CXXX -+ bool "VIA 82C686 MIDI" -+ depends on SOUND_VIA82CXXX && ISA_DMA_API -+ help -+ Answer Y to use the MIDI interface of the Via686. You may need to -+ enable this in the BIOS before it will work. This is for connection -+ to external MIDI hardware, and is not required for software playback -+ of MIDI files. -+ - config SOUND_OSS - tristate "OSS sound modules" -- depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS -+ depends on SOUND_PRIME && ISA_DMA_API - help - OSS is the Open Sound System suite of sound card drivers. They make - sound programming easier since they provide a common API. Say Y or -@@ -336,10 +456,23 @@ - - Say Y unless you have 16MB or more RAM or a PCI sound card. - -+config SOUND_CS4232 -+ tristate "Crystal CS4232 based (PnP) cards" -+ depends on SOUND_OSS && OSS_OBSOLETE -+ help -+ Say Y here if you have a card based on the Crystal CS4232 chip set, -+ which uses its own Plug and Play protocol. -+ -+ If you compile the driver into the kernel, you have to add -+ "cs4232=,,,,," to the kernel -+ command line. -+ -+ See for more information on -+ configuring this card. -+ - config SOUND_SSCAPE - tristate "Ensoniq SoundScape support" - depends on SOUND_OSS -- depends on VIRT_TO_BUS - help - Answer Y if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, Spea -@@ -564,7 +697,7 @@ - questions. - - Read the file and the head of -- as well as -+ as well as - to get more information - about this driver and its configuration. - -@@ -642,6 +775,13 @@ - Say Y here to include support for the Rockwell WaveArtist sound - system. This driver is mainly for the NetWinder. - -+config SOUND_TVMIXER -+ tristate "TV card (bt848) mixer support" -+ depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE -+ help -+ Support for audio mixer facilities on the BT848 TV frame-grabber -+ card. -+ - config SOUND_KAHLUA - tristate "XpressAudio Sound Blaster emulation" - depends on SOUND_SB -diff -urN linux-2.6.24.7.old/sound/oss/Makefile linux-2.6.24.7/sound/oss/Makefile ---- linux-2.6.24.7.old/sound/oss/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/oss/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -10,6 +10,12 @@ - - # Please leave it as is, cause the link order is significant ! - -+obj-$(CONFIG_SOUND_JZ_AC97) += jz_ac97.o ac97_codec.o -+obj-$(CONFIG_I2S_AK4642EN) += ak4642en.o -+obj-$(CONFIG_I2S_ICODEC) += jzcodec.o jz_i2s.o -+obj-$(CONFIG_I2S_DLV) += jzdlv.o jz_i2s.o -+obj-$(CONFIG_SOUND_JZ_PCM) += jz_pcm_tlv320aic1106_dma.o -+ - obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o - obj-$(CONFIG_SOUND_HAL2) += hal2.o - obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o -diff -urN linux-2.6.24.7.old/sound/oss/ak4642en.c linux-2.6.24.7/sound/oss/ak4642en.c ---- linux-2.6.24.7.old/sound/oss/ak4642en.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/ak4642en.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,712 @@ -+/* -+ * linux/sound/oss/ak4642en.c -+ * -+ * AKM ak4642en codec chip driver to I2S interface -+ * -+ * Copyright (c) 2005-2007 Ingenic Semiconductor Inc. -+ * Author: -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int abnormal_data_count; -+ -+extern void (*clear_codec_mode)(void); -+extern void (*set_codec_gpio_pin)(void); -+extern void (*each_time_init_codec)(void); -+extern void (*set_codec_record)(void); -+extern void (*set_codec_replay)(void); -+extern void (*clear_codec_record)(void); -+extern void (*clear_codec_replay)(void); -+extern void (*set_codec_speed)(int range); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(int wr,int rd); -+extern void (*set_replay_hp_or_speaker)(void); -+ -+#define I2S_PDN 68 -+#define JACK_PLUG_PIN 83 -+#define JACK_PLUG_IRQ (IRQ_GPIO_0 + JACK_PLUG_PIN) -+ -+static int jack_plug_level, old_level; -+static unsigned int i2c_addr = 0x26; //AK4642EN device address at I2C bus -+static unsigned int i2c_clk = 100000;//AK4642EN 400kHz max,but 100kHz here -+static unsigned int spk_hp = 0; -+static int codec_volume; -+ -+void set_ak4642en_gpio_pin(void); -+void each_time_init_ak4642en(void); -+void set_ak4642en_replay(void); -+void set_ak4642en_record(void); -+void turn_on_ak4642en(void); -+void turn_off_ak4642en(void); -+void set_ak4642en_speed(int rate); -+void reset_ak4642en(void); -+void ak4642en_mixer_old_info_id_name(void); -+void ak4642en_mixer_info_id_name(void); -+void set_ak4642en_bass(int val); -+void set_ak4642en_volume(int val); -+void set_ak4642en_mic(int val); -+void resume_ak4642en(void); -+void suspend_ak4642en(int wr,int rd); -+ -+static void write_reg(u8 reg, u8 val) -+{ -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_write((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+} -+ -+#if 0 -+static u8 read_reg(u8 reg) -+{ -+ u8 val; -+ i2c_open(); -+ i2c_setclk(i2c_clk); -+ i2c_read((i2c_addr >> 1), &val, reg, 1); -+ i2c_close(); -+ return val; -+} -+ -+static u16 i2s_codec_read(u8 reg) -+{ -+ u16 value; -+ value = read_reg(reg); -+ return value; -+} -+#endif -+ -+static void i2s_codec_write(u8 reg, u16 data) -+{ -+ u8 val = data & 0xff; -+ write_reg(reg, val); -+} -+ -+void set_ak4642en_gpio_pin(void) -+{ -+ //set AIC pin to I2S slave mode,only GPIO70,71,77,78 -+ __gpio_as_output(68); -+ __gpio_clear_pin(68); -+ __gpio_as_output(69); -+ __gpio_clear_pin(69); -+ __gpio_as_output(70); -+ __gpio_clear_pin(70); -+ __gpio_as_input(71); -+ __gpio_clear_pin(71); -+ __gpio_as_input(77); -+ __gpio_clear_pin(77); -+ __gpio_as_input(78); -+ __gpio_clear_pin(78); -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; -+ REG_GPIO_GPALR(2) |= 0x14005000; -+ //set SCC clock initialization -+ REG_SCC1_CR(SCC1_BASE) = 0x00000000; -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; -+ udelay(2); -+ -+ __gpio_as_output(I2S_PDN); -+ __gpio_set_pin(I2S_PDN); -+ udelay(5); -+ __gpio_clear_pin(I2S_PDN); -+ ndelay(300);//>150ns -+ __gpio_set_pin(I2S_PDN); -+ mdelay(1); -+ //set PLL Master mode -+ i2s_codec_write(0x01, 0x0008);//master -+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli -+ i2s_codec_write(0x05, 0x000b);//sync:48KHz; -+ i2s_codec_write(0x00, 0x0040);//PMVCM -+ i2s_codec_write(0x01, 0x0009);//master,PLL enable -+ mdelay(40); -+ jack_plug_level = 10; -+ old_level = 100; -+ spk_hp = 0; -+ __gpio_disable_pull(JACK_PLUG_PIN); -+ udelay(10); -+ __gpio_as_input(JACK_PLUG_PIN); -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ //i suppose jack_plug_lvel is 1 indicate with HPO -+ if (jack_plug_level > 1 || jack_plug_level <0) -+ printk("Audio ak4642en codec Jack plug level is wrong!\n"); -+ if (jack_plug_level) -+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); -+ else -+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); -+} -+ -+void clear_ak4642en_mode(void) -+{ -+ spk_hp = 0; -+ i2s_codec_write(0x01, 0x0008);//master,PLL disable -+ //free_irq(JACK_PLUG_IRQ, i2s_controller); -+ __gpio_clear_pin(I2S_PDN); -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; -+ udelay(2); -+} -+ -+void set_ak4642en_replay(void) -+{ -+ //for poll -+ /*jack_plug_level is H for SPK,is L for HP*/ -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ if(old_level == jack_plug_level) -+ return; -+ old_level = jack_plug_level; -+ if(spk_hp == 1) -+ { -+ if(jack_plug_level == 1) -+ { -+ //now HeadPhone output,so clear SPK -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ } -+ else -+ { -+ //now Speaker output,so clear HP -+ i2s_codec_write(0x01, 0x0039); -+ i2s_codec_write(0x01, 0x0009); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0e, 0x0000); -+ i2s_codec_write(0x0f, 0x0008); -+ } -+ } -+ spk_hp = 1; -+ if(jack_plug_level == 1) -+ { -+ //for HeadPhone output -+ i2s_codec_write(0x00, 0x0060); // -+ i2s_codec_write(0x0f, 0x0009); //5-10 -+ -+ i2s_codec_write(0x00, 0x0064); // -+ i2s_codec_write(0x09, 0x0091);// volume control 0dB -+ i2s_codec_write(0x0c, 0x0091);// 0dB(right) -+ //eq off -+ i2s_codec_write(0x11, 0x0000);//5-10 -+ i2s_codec_write(0x01, 0x0039); // -+ -+ i2s_codec_write(0x01, 0x0079); // -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x02, 0x0020); -+ -+ i2s_codec_write(0x03, 0x0018);//5-10 -+ i2s_codec_write(0x06, 0x003c); -+ -+ i2s_codec_write(0x08, 0x00A1);//5-10 -+ -+ i2s_codec_write(0x0b, 0x0040); //5-10 -+ -+ i2s_codec_write(0x07, 0x002d); //5-10 -+ i2s_codec_write(0x09, 0x0091); -+ i2s_codec_write(0x0c, 0x0091); -+ //HP volume output value -+ -+ i2s_codec_write(0x0a, codec_volume);//5-10 -+ i2s_codec_write(0x0d, codec_volume);//5-10 -+ -+ i2s_codec_write(0x00, 0x0074); -+ i2s_codec_write(0x02, 0x00a0); -+ } -+} -+ -+void set_ak4642en_record(void) -+{ -+ abnormal_data_count = 0; -+ i2s_codec_write(0x02, 0x0004); -+ i2s_codec_write(0x03, 0x0038);// recording volume add -+ i2s_codec_write(0x06, 0x0000);//for ALC short waiting time -+ i2s_codec_write(0x08, 0x00e1); -+ i2s_codec_write(0x0b, 0x0000); -+ i2s_codec_write(0x07, 0x0021); // ALC on -+ -+ i2s_codec_write(0x10, 0x0000);//0x0001 -+ //i2s_codec_write(0x10, 0x0001);//0x0001 -+ i2s_codec_write(0x01, 0x0039); //for open pop noise -+ i2s_codec_write(0x01, 0x0079); -+ i2s_codec_write(0x00, 0x0065); -+ mdelay(300); -+} -+ -+void clear_ak4642en_replay(void) -+{ -+ //for poll -+ old_level = 100; -+ spk_hp = 0; -+ if(jack_plug_level == 1) -+ { -+ //for HeadPhone output -+ i2s_codec_write(0x01, 0x0039); // for close pop noise -+ mdelay(300); -+ i2s_codec_write(0x01, 0x0009); //PLL on I2S -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0f, 0x0008); // for open pop noise -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); // for close pop noise -+ } -+} -+ -+void clear_ak4642en_record(void) -+{ -+ //for Mic input(Stereo) -+ i2s_codec_write(0x02, 0x0001); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+} -+ -+void each_time_init_ak4642en(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __i2s_set_sample_size(16); -+} -+ -+void set_ak4642en_speed(int rate) -+{ -+ //codec work at frequency -+ unsigned short speed = 0; -+ unsigned short val = 0; -+ switch (rate) -+ { -+ case 8000: -+ speed = 0x00; -+ if(jack_plug_level == 1) //speaker -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0027);//800hz -+ i2s_codec_write(0x1D, 0x0018); -+ i2s_codec_write(0x1E, 0x00b2); -+ i2s_codec_write(0x1F, 0x002f); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 12000: -+ speed = 0x01; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0064); -+ i2s_codec_write(0x1D, 0x001a); -+ i2s_codec_write(0x1E, 0x0038); -+ i2s_codec_write(0x1F, 0x002b); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 16000: -+ speed = 0x02; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x00af); -+ i2s_codec_write(0x17, 0x0020); -+ i2s_codec_write(0x18, 0x0043); -+ i2s_codec_write(0x19, 0x001a); -+ i2s_codec_write(0x1A, 0x00af); -+ i2s_codec_write(0x1B, 0x0020); -+ i2s_codec_write(0x1C, 0x00a0); -+ i2s_codec_write(0x1D, 0x001b); -+ i2s_codec_write(0x1E, 0x00c0); -+ i2s_codec_write(0x1F, 0x0028); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 24000: -+ speed = 0x03; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0086); -+ i2s_codec_write(0x17, 0x0015); -+ i2s_codec_write(0x18, 0x005d); -+ i2s_codec_write(0x19, 0x0006); -+ i2s_codec_write(0x1A, 0x0086); -+ i2s_codec_write(0x1B, 0x0015); -+ i2s_codec_write(0x1C, 0x00f5); -+ i2s_codec_write(0x1D, 0x001c); -+ i2s_codec_write(0x1E, 0x0016); -+ i2s_codec_write(0x1F, 0x0026); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 7350: -+ speed = 0x04; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x0027); -+ i2s_codec_write(0x1D, 0x0018); -+ i2s_codec_write(0x1E, 0x00b2); -+ i2s_codec_write(0x1F, 0x002f); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 11025: -+ speed = 0x05; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0059); -+ i2s_codec_write(0x17, 0x000d); -+ i2s_codec_write(0x18, 0x00cb); -+ i2s_codec_write(0x19, 0x0037); -+ i2s_codec_write(0x1A, 0x0059); -+ i2s_codec_write(0x1B, 0x000d); -+ i2s_codec_write(0x1C, 0x0046); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0074); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 14700: -+ speed = 0x06; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0000); -+ i2s_codec_write(0x17, 0x0000); -+ i2s_codec_write(0x18, 0x0000); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x0000); -+ i2s_codec_write(0x1B, 0x0000); -+ i2s_codec_write(0x1C, 0x004a); -+ i2s_codec_write(0x1D, 0x001b); -+ i2s_codec_write(0x1E, 0x006c); -+ i2s_codec_write(0x1F, 0x0029); -+ i2s_codec_write(0x11, 0x0010); //eq on -+ } -+ break; -+ case 22050: -+ speed = 0x07; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x002d); -+ i2s_codec_write(0x17, 0x0017); -+ i2s_codec_write(0x18, 0x0050); -+ i2s_codec_write(0x19, 0x0009); -+ i2s_codec_write(0x1A, 0x002d); -+ i2s_codec_write(0x1B, 0x0017); -+ i2s_codec_write(0x1C, 0x00d7); -+ i2s_codec_write(0x1D, 0x001c); -+ i2s_codec_write(0x1E, 0x0093); -+ i2s_codec_write(0x1F, 0x0026); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 32000: -+ speed = 0x0a; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0012); -+ i2s_codec_write(0x17, 0x0011); -+ i2s_codec_write(0x18, 0x006e); -+ i2s_codec_write(0x19, 0x003e); -+ i2s_codec_write(0x1A, 0x0012); -+ i2s_codec_write(0x1B, 0x0011); -+ i2s_codec_write(0x1C, 0x00aa); -+ i2s_codec_write(0x1D, 0x001d); -+ i2s_codec_write(0x1E, 0x00ab); -+ i2s_codec_write(0x1F, 0x0024); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 48000: -+ speed = 0x0b; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0082); -+ i2s_codec_write(0x17, 0x000c); -+ i2s_codec_write(0x18, 0x004b); -+ i2s_codec_write(0x19, 0x0036); -+ i2s_codec_write(0x1A, 0x0082); -+ i2s_codec_write(0x1B, 0x000c); -+ i2s_codec_write(0x1C, 0x0068); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0030); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 29400: -+ speed = 0x0e; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x003d); -+ i2s_codec_write(0x17, 0x0012); -+ i2s_codec_write(0x18, 0x0083); -+ i2s_codec_write(0x19, 0x0000); -+ i2s_codec_write(0x1A, 0x003d); -+ i2s_codec_write(0x1B, 0x0012); -+ i2s_codec_write(0x1C, 0x0079); -+ i2s_codec_write(0x1D, 0x001d); -+ i2s_codec_write(0x1E, 0x000d); -+ i2s_codec_write(0x1F, 0x0025); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ case 44100: -+ speed = 0x0f; -+ if(jack_plug_level == 1) -+ { -+ i2s_codec_write(0x16, 0x0059); -+ i2s_codec_write(0x17, 0x000d); -+ i2s_codec_write(0x18, 0x00cb); -+ i2s_codec_write(0x19, 0x0037); -+ i2s_codec_write(0x1A, 0x0059); -+ i2s_codec_write(0x1B, 0x000d); -+ i2s_codec_write(0x1C, 0x0046); -+ i2s_codec_write(0x1D, 0x001e); -+ i2s_codec_write(0x1E, 0x0074); -+ i2s_codec_write(0x1F, 0x0023); -+ i2s_codec_write(0x11, 0x0018); //eq on -+ } -+ break; -+ default: -+ break; -+ } -+ val = speed & 0x08; -+ val = val << 2; -+ speed = speed & 0x07; -+ val = val | speed; -+ i2s_codec_write(0x05, val); -+} -+ -+void ak4642en_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "AK4642EN", sizeof(info.id)); -+ strncpy(info.name,"AKM AK4642en codec", sizeof(info.name)); -+} -+ -+void ak4642en_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "AK4642EN", sizeof(old_info.id)); -+ strncpy(old_info.name,"AKM AK4642en codec", sizeof(old_info.name)); -+} -+ -+void set_ak4642en_volume(int val) -+{ -+ if ( val == 0 ) -+ codec_volume = 255; -+ else if ( val > 1 && val <= 10) -+ codec_volume = 92; -+ else if ( val > 10 && val <= 20 ) -+ codec_volume = 67; -+ else if ( val > 20 && val <= 30 ) -+ codec_volume = 50; -+ else if ( val > 30 && val <= 40 ) -+ codec_volume = 40; -+ else if ( val > 40 && val <= 50 ) -+ codec_volume = 30; -+ else if ( val > 50 && val <= 60 ) -+ codec_volume = 22; -+ else if ( val > 60&& val <= 70 ) -+ codec_volume = 15; -+ else if ( val > 70 && val <= 80 ) -+ codec_volume = 8; -+ else if ( val > 80 && val <= 90 ) -+ codec_volume = 4; -+ else if ( val > 90 && val <= 100 ) -+ codec_volume = 2; -+ -+ i2s_codec_write(0x0a, codec_volume); -+ i2s_codec_write(0x0d, codec_volume); -+} -+ -+void set_ak4642en_mic(int val) -+{ -+ int mic_gain; -+ mic_gain = 241 * val /100; -+ i2s_codec_write(0x09, mic_gain); -+ i2s_codec_write(0x0c, mic_gain); -+} -+ -+void resume_ak4642en(void) -+{ -+ __gpio_as_output(17); -+ __gpio_set_pin(17); //enable ak4642 -+ __gpio_as_output(68); -+ __gpio_clear_pin(68); -+ __gpio_as_output(69); -+ __gpio_clear_pin(69); -+ __gpio_as_output(70); -+ __gpio_clear_pin(70); -+ __gpio_as_input(71); -+ __gpio_clear_pin(71); -+ __gpio_as_input(77); -+ __gpio_clear_pin(77); -+ __gpio_as_input(78); -+ __gpio_clear_pin(78); -+ REG_GPIO_GPALR(2) &= 0xC3FF0CFF; -+ REG_GPIO_GPALR(2) |= 0x14005000; -+ //set SCC clock initialization -+ REG_SCC1_CR(SCC1_BASE) = 0x00000000; -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) |= 1 << 31; -+ udelay(2); -+ __gpio_as_output(I2S_PDN); -+ __gpio_set_pin(I2S_PDN); -+ udelay(5); -+ __gpio_clear_pin(I2S_PDN); -+ ndelay(300);//>150ns -+ __gpio_set_pin(I2S_PDN); -+ mdelay(1); -+ //set PLL Master mode -+ i2s_codec_write(0x01, 0x0008);//master -+ i2s_codec_write(0x04, 0x006b);//ref:12MHz;BITCLK:64fs;I2S compli -+ i2s_codec_write(0x05, 0x000b);//sync:48KHz; -+ i2s_codec_write(0x00, 0x0040);//PMVCM -+ i2s_codec_write(0x01, 0x0009);//master,PLL enable -+ jack_plug_level = 10; -+ old_level = 100; -+ spk_hp = 0; -+ __gpio_as_input(JACK_PLUG_PIN); -+ jack_plug_level = __gpio_get_pin(JACK_PLUG_PIN); -+ //i suppose jack_plug_lvel is 1 indicate with HPO -+ if(jack_plug_level > 1 || jack_plug_level <0) -+ printk("Audio ak4642en codec Jack plug level is wrong!\n"); -+ if(jack_plug_level) -+ __gpio_as_irq_fall_edge(JACK_PLUG_PIN); -+ else -+ __gpio_as_irq_rise_edge(JACK_PLUG_PIN); -+ -+ i2s_codec_write(0x00, 0x0065); //for resume power -+ i2s_codec_write(0x01, 0x0039); //for open pop noise -+ i2s_codec_write(0x01, 0x0079); -+ i2s_codec_write(0x0a, codec_volume); -+ i2s_codec_write(0x0d, codec_volume); -+} -+ -+void suspend_ak4642en(int wr,int rd) -+{ -+ if(wr) //playing -+ { -+ if(jack_plug_level == 0) -+ { -+ i2s_codec_write(0x01, 0x0039); // for close pop noise -+ mdelay(500); -+ i2s_codec_write(0x01, 0x0009); //PLL on I2S -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x00, 0x0040); -+ i2s_codec_write(0x0f, 0x0008); // for open pop noise -+ -+ } -+ else -+ { -+ //for Speaker output -+ i2s_codec_write(0x02, 0x0020); -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ i2s_codec_write(0x02, 0x0000); -+ i2s_codec_write(0x00, 0x0040); // for close pop noise -+ } -+ } -+ -+ if(rd) // recording -+ { -+ i2s_codec_write(0x02, 0x0001); // 5-11 a1 -+ i2s_codec_write(0x07, 0x0001); -+ i2s_codec_write(0x11, 0x0000); -+ mdelay(300); -+ } -+ __gpio_as_output(17); -+ __gpio_clear_pin(17);//disable ak4642 -+ __i2s_disable(); -+} -+ -+static int __init init_ak4642en(void) -+{ -+ set_codec_gpio_pin = set_ak4642en_gpio_pin; -+ each_time_init_codec = each_time_init_ak4642en; -+ clear_codec_mode = clear_ak4642en_mode; -+ -+ set_codec_record = set_ak4642en_record; -+ set_codec_replay = set_ak4642en_replay; -+ set_replay_hp_or_speaker = set_ak4642en_replay; -+ -+ set_codec_speed = set_ak4642en_speed; -+ clear_codec_record = clear_ak4642en_record; -+ clear_codec_replay = clear_ak4642en_replay; -+ -+ codec_mixer_old_info_id_name = ak4642en_mixer_old_info_id_name; -+ codec_mixer_info_id_name = ak4642en_mixer_info_id_name; -+ -+ set_codec_volume = set_ak4642en_volume; -+ -+ set_codec_mic = set_ak4642en_mic; -+ -+ i2s_resume_codec = resume_ak4642en; -+ i2s_suspend_codec = suspend_ak4642en; -+ printk("---> ak4642en initialization!\n"); -+ return 0; -+} -+ -+static void __exit cleanup_ak4642en(void) -+{ -+ spk_hp = 0; -+ i2s_codec_write(0x01, 0x0008);//master,PLL disable -+ //free_irq(JACK_PLUG_IRQ, i2s_controller); -+ __gpio_clear_pin(I2S_PDN); -+ udelay(2); -+ REG_SCC1_CR(SCC1_BASE) &= 0 << 31; -+ udelay(2); -+} -+ -+module_init(init_ak4642en); -+module_exit(cleanup_ak4642en); -diff -urN linux-2.6.24.7.old/sound/oss/jz_ac97.c linux-2.6.24.7/sound/oss/jz_ac97.c ---- linux-2.6.24.7.old/sound/oss/jz_ac97.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_ac97.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2252 @@ -+/* -+ * linux/drivers/sound/jz_ac97.c -+ * -+ * Jz On-Chip AC97 audio driver. -+ * -+ * Copyright (C) 2005 - 2007, Ingenic Semiconductor Inc. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#define __NO_VERSION__ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+//#include -+#include "sound_config.h" -+ -+#define DMA_ID_AC97_TX DMA_ID_AIC_TX -+#define DMA_ID_AC97_RX DMA_ID_AIC_RX -+ -+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ -+#define NR_AC97 2 -+ -+#define STANDARD_SPEED 48000 -+#define MAX_RETRY 100 -+ -+static unsigned int k_8000[] = { -+ 0, 42, 85, 128, 170, 213, -+}; -+ -+static unsigned int reload_8000[] = { -+ 1, 0, 0, 0, 0, 0, -+}; -+ -+static unsigned int k_11025[] = { -+ 0, 58, 117, 176, 234, 37, 96, 154, -+ 213, 16, 74, 133, 192, 250, 53, 112, -+ 170, 229, 32, 90, 149, 208, 10, 69, -+ 128, 186, 245, 48, 106, 165, 224, 26, -+ 85, 144, 202, 5, 64, 122, 181, 240, -+ 42, 101, 160, 218, 21, 80, 138, 197, -+}; -+ -+static unsigned int reload_11025[] = { -+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, -+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, -+}; -+ -+static unsigned int k_16000[] = { -+ 0, 85, 170, -+}; -+ -+static unsigned int reload_16000[] = { -+ 1, 0, 0, -+}; -+ -+static unsigned int k_22050[] = { -+ 0, 117, 234, 96, 213, 74, 192, 53, -+ 170, 32, 149, 10, 128, 245, 106, 224, -+ 85, 202, 64, 181, 42, 160, 21, 138, -+}; -+ -+static unsigned int reload_22050[] = { -+ 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, -+ 1, 0, 1, 0, 1, 0, 1, 0, -+}; -+ -+static unsigned int k_24000[] = { -+ 0, 128, -+}; -+ -+static unsigned int reload_24000[] = { -+ 1, 0, -+}; -+ -+static unsigned int k_32000[] = { -+ 0, 170, 85, -+}; -+ -+static unsigned int reload_32000[] = { -+ 1, 0, 1, -+}; -+ -+static unsigned int k_44100[] = { -+ 0, 234, 213, 192, 170, 149, 128, 106, -+ 85, 64, 42, 21, -+}; -+ -+static unsigned int reload_44100[] = { -+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+}; -+ -+static unsigned int k_48000[] = { -+ 0, -+}; -+ -+static unsigned int reload_48000[] = { -+ 1, -+}; -+ -+ -+static unsigned int f_scale_counts[8] = { -+ 6, 48, 3, 24, 2, 3, 12, 1, -+}; -+ -+static int jz_audio_rate; -+static char jz_audio_format; -+static char jz_audio_channels; -+static int jz_audio_k; /* rate expand multiple */ -+static int jz_audio_q; /* rate expand compensate */ -+static int jz_audio_count; /* total count of voice data */ -+static int last_jz_audio_count; -+ -+static int jz_audio_fragments;//unused fragment amount -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer -+ -+static unsigned int f_scale_count; -+static unsigned int *f_scale_array; -+static unsigned int *f_scale_reload; -+static unsigned int f_scale_idx; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+extern void jz_set_dma_block_size(int dmanr, int nbyte); -+extern void jz_set_dma_dest_width(int dmanr, int nbit); -+extern void jz_set_dma_src_width(int dmanr, int nbit); -+ -+static void jz_update_filler(int bits, int channels); -+ -+static void Init_In_Out_queue(int fragstotal,int fragsize); -+static void Free_In_Out_queue(int fragstotal,int fragsize); -+ -+static irqreturn_t -+jz_ac97_replay_dma_irq(int irqnr, void *dev_id); -+static irqreturn_t -+jz_ac97_record_dma_irq(int irqnr, void *dev_id); -+ -+static void -+(*replay_filler)(unsigned long src_start, int count, int id); -+static int -+(*record_filler)(unsigned long dst_start, int count, int id); -+ -+static struct file_operations jz_ac97_audio_fops; -+ -+DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+ -+struct jz_ac97_controller_info -+{ -+ int io_base; -+ int dma1; /* play */ -+ int dma2; /* record */ -+ -+ char *name; -+ -+ int dev_audio; -+ struct ac97_codec *ac97_codec[NR_AC97]; -+ -+ unsigned short ac97_features; -+ -+ int opened1; -+ int opened2; -+ -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ -+ int nextIn; // byte index to next-in to DMA buffer -+ int nextOut; // byte index to next-out from DMA buffer -+ int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer -+ unsigned total_bytes; // total bytes written or read -+ unsigned blocks; -+ unsigned error; // over/underrun -+ -+ /* We use two devices, because we can do simultaneous play and record. -+ This keeps track of which device is being used for what purpose; -+ these are the actual device numbers. */ -+ int dev_for_play; -+ int dev_for_record; -+ -+ int playing; -+ int recording; -+ int patched; -+ unsigned long rec_buf_size; -+ unsigned long playback_buf_size; -+ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+static struct jz_ac97_controller_info *ac97_controller = NULL; -+ -+static int jz_readAC97Reg(struct ac97_codec *dev, u8 reg); -+static int jz_writeAC97Reg(struct ac97_codec *dev, u8 reg, u16 data); -+static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg); -+static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data); -+ -+#define QUEUE_MAX 2 -+ -+typedef struct buffer_queue_s { -+ int count; -+ int *id; -+ spinlock_t lock; -+} buffer_queue_t; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+ -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+ -+static int first_record_call = 0; -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r, i; -+ unsigned long flags; -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ return r; -+} -+ -+/**************************************************************************** -+ * Architecture related routines -+ ****************************************************************************/ -+static inline -+void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_ac97_controller_info * controller = -+ (struct jz_ac97_controller_info *) dev_id; -+ //for DSP_GETOPTR -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ set_dma_mode(chan, mode); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk(KERN_DEBUG "%s: JzSOC DMA controller can't set dma count zero!\n", -+ __FUNCTION__); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t -+jz_ac97_record_dma_irq (int irq, void *dev_id) -+{ -+ struct jz_ac97_controller_info * controller = -+ (struct jz_ac97_controller_info *) dev_id; -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ //for DSP_GETIPTR -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else { -+ in_busy_queue.count = 0; -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t -+jz_ac97_replay_dma_irq (int irq, void *dev_id) -+{ -+ struct jz_ac97_controller_info * controller = -+ (struct jz_ac97_controller_info *) dev_id; -+ int dma = controller->dma1, id; -+ unsigned long flags; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ //for DSP_GETOPTR -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) { -+ printk(KERN_DEBUG "Strange DMA finish interrupt for AC97 module\n"); -+ } -+ -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ } -+ } else { -+ out_busy_queue.count = 0; -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+/* -+ * Initialize the onchip AC97 controller -+ */ -+static void jz_ac97_initHw(struct jz_ac97_controller_info *controller) -+{ -+ __ac97_disable(); -+ __ac97_reset(); -+ __ac97_enable(); -+ -+ __ac97_cold_reset_codec(); -+ /* wait for a long time to let ac97 controller reset completely, -+ * otherwise, registers except ACFR will be clear by reset, can't be -+ * set correctly. -+ */ -+ udelay(160); -+ -+ __ac97_disable_record(); -+ __ac97_disable_replay(); -+ __ac97_disable_loopback(); -+ -+ /* Check the trigger threshold reset value to detect version */ -+ if (((REG_AIC_FR & AIC_FR_TFTH_MASK) >> AIC_FR_TFTH_BIT) == 8) { -+ printk("JzAC97: patched controller detected.\n"); -+ controller->patched = 1; -+ } else { -+ printk("JzAC97: standard controller detected.\n"); -+ controller->patched = 0; -+ } -+ -+ /* Set FIFO data size. Which shows valid data bits. -+ * -+ */ -+ __ac97_set_oass(8); -+ __ac97_set_iass(8); -+ -+ __ac97_set_xs_stereo(); -+ __ac97_set_rs_stereo(); -+} -+ -+/* -+ * Initialize all of in(out)_empty_queue value -+ */ -+static void Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ if(out_dma_buf || in_dma_buf) -+ return; -+ in_empty_queue.count = fragstotal; -+ out_empty_queue.count = fragstotal; -+ -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) { -+ *(in_empty_queue.id + i) = i; -+ *(out_empty_queue.id + i) = i; -+ } -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /*alloc DMA buffer*/ -+ for (i = 0; i < jz_audio_fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ for (i = 0; i < jz_audio_fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(IN) buffers.\n"); -+ goto mem_failed_in; -+ } -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), 4096*8);//fragsize -+ *(in_dma_buf + i) = KSEG1ADDR(*(in_dma_buf + i)); -+ } -+ return ; -+ -+ all_mem_err: -+ printk("error:allocate memory occur error!\n"); -+ return ; -+ -+mem_failed_out: -+ -+ for (i = 0; i < jz_audio_fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ return ; -+ -+mem_failed_in: -+ -+ for (i = 0; i < jz_audio_fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return ; -+ -+} -+static void Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ if(out_dma_buf != NULL) -+ { -+ for (i = 0; i < jz_audio_fragstotal; i++) -+ { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) -+ { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) -+ { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(in_dma_buf) -+ { -+ for (i = 0; i < jz_audio_fragstotal; i++) -+ { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) -+ { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) -+ { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) -+ { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) -+ { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) -+ { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ if(out_empty_queue.id) -+ { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) -+ { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) -+ { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ out_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ return ; -+} -+ -+/* -+ * Reset everything -+ */ -+static void -+jz_ac97_full_reset(struct jz_ac97_controller_info *controller) -+{ -+ jz_ac97_initHw(controller); -+} -+ -+ -+static void -+jz_ac97_mksound(unsigned int hz, unsigned int ticks) -+{ -+// printk("BEEP - %d %d!\n", hz, ticks); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ u32 dacp; -+ struct ac97_codec *codec=ac97_controller->ac97_codec[0]; -+ -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ -+ -+ /* Power down the DAC */ -+ dacp=ac97_codec_read(codec, AC97_POWER_CONTROL); -+ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200); -+ /* Load the rate; only 48Khz playback available, read always zero */ -+ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) -+ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate); -+ else -+ ac97_codec_write(codec, AC97_PCM_FRONT_DAC_RATE, 48000); -+ -+ /* Power it back up */ -+ ac97_codec_write(codec, AC97_POWER_CONTROL, dacp); -+ -+ jz_audio_rate = rate; -+ jz_audio_k = STANDARD_SPEED / rate; -+ if (rate * jz_audio_k != STANDARD_SPEED) -+ jz_audio_q = rate / ((STANDARD_SPEED / jz_audio_k) - rate ); -+ else -+ jz_audio_q = 0x1fffffff; /* a very big value, don't compensate */ -+ -+ switch (rate) { -+ case 8000: -+ f_scale_count = f_scale_counts[0]; -+ f_scale_array = k_8000; -+ f_scale_reload = reload_8000; -+ break; -+ case 11025: -+ f_scale_count = f_scale_counts[1]; -+ f_scale_array = k_11025; -+ f_scale_reload = reload_11025; -+ break; -+ case 16000: -+ f_scale_count = f_scale_counts[2]; -+ f_scale_array = k_16000; -+ f_scale_reload = reload_16000; -+ break; -+ case 22050: -+ f_scale_count = f_scale_counts[3]; -+ f_scale_array = k_22050; -+ f_scale_reload = reload_22050; -+ break; -+ case 24000: -+ f_scale_count = f_scale_counts[4]; -+ f_scale_array = k_24000; -+ f_scale_reload = reload_24000; -+ break; -+ case 32000: -+ f_scale_count = f_scale_counts[5]; -+ f_scale_array = k_32000; -+ f_scale_reload = reload_32000; -+ break; -+ case 44100: -+ f_scale_count = f_scale_counts[6]; -+ f_scale_array = k_44100; -+ f_scale_reload = reload_44100; -+ break; -+ case 48000: -+ f_scale_count = f_scale_counts[7]; -+ f_scale_array = k_48000; -+ f_scale_reload = reload_48000; -+ break; -+ } -+ f_scale_idx = 0; -+ -+ return jz_audio_rate; -+} -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ if ((jz_audio_count++ % jz_audio_k) == 0) { -+ cnt++; -+ data = *(s++); -+ *(dp ++) = data + 0x80; -+ s++; /* skip the other channel */ -+ } else { -+ s += 2; /* skip the redundancy */ -+ } -+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q) { -+ jz_audio_count++; -+ last_jz_audio_count = jz_audio_count; -+ count -= 2; -+ s += 2; -+ } -+ } -+ return cnt; -+} -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1, d2; -+ volatile unsigned char *s = (unsigned char *)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ if ((jz_audio_count++ % jz_audio_k) == 0) { -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = d1 + 0x80; -+ d2 = *(s++); -+ *(dp ++) = d2 + 0x80; -+ } else { -+ s += 2; /* skip the redundancy */ -+ } -+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { -+ jz_audio_count += 2; -+ last_jz_audio_count = jz_audio_count; -+ count -= 2; -+ s += 2; -+ } -+ } -+ return cnt; -+} -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short d1; -+ unsigned short *s = (unsigned short *)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ if ((jz_audio_count++ % jz_audio_k) == 0) { -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = d1; -+ s++; /* skip the other channel */ -+ } else { -+ s += 2; /* skip the redundancy */ -+ } -+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 2) { -+ jz_audio_count += 2; -+ last_jz_audio_count = jz_audio_count; -+ count -= 2; -+ s += 2; -+ } -+ } -+ return cnt; -+} -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short d1, d2; -+ unsigned short *s = (unsigned short *)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ if ((jz_audio_count++ % jz_audio_k) == 0) { -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = d1; -+ d2 = *(s++); -+ *(dp ++) = d2; -+ } else -+ s += 2; /* skip the redundancy */ -+ -+ if (jz_audio_count - last_jz_audio_count >= jz_audio_q * 4) { -+ jz_audio_count += 4; -+ last_jz_audio_count = jz_audio_count; -+ count -= 2; -+ s += 2; -+ } -+ } -+ return cnt; -+} -+ -+ -+static void replay_fill_1x8_u(unsigned long src_start, int count, int id) -+{ -+ int i, cnt = 0; -+ unsigned char data; -+ unsigned char *s = (unsigned char *)src_start; -+ unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ jz_audio_count++; -+ cnt += jz_audio_k; -+ data = *(s++) - 0x80; -+ for (i=0;i 0) { -+ count -= 2; -+ jz_audio_count += 2; -+ cnt += 2 * jz_audio_k; -+ d1 = *(s++) - 0x80; -+ d2 = *(s++) - 0x80; -+ for (i=0;i= jz_audio_q * 2) { -+ cnt += 2 * jz_audio_k; -+ last_jz_audio_count = jz_audio_count; -+ for (i=0;i= 0) { -+ if (f_scale_reload[f_scale_idx]) { -+ d1 = d2; -+ d2 = *s++; -+ if (!count) -+ break; -+ count -= 2; -+ } -+ d = d1 + (((d2 - d1) * f_scale_array[f_scale_idx]) >> 8); -+ *dp++ = d; -+ *dp++ = d; -+ cnt += 4; -+ f_scale_idx ++; -+ if (f_scale_idx >= f_scale_count) -+ f_scale_idx = 0; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x16_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ static short d11, d12, d21, d22, d1, d2; -+ short *s = (short *)src_start; -+ short *dp = (short *)(*(out_dma_buf + id)); -+ -+ d12 = *s++; -+ d22 = *s++; -+ count -= 4; -+ while (count >= 0) { -+ register unsigned int kvalue; -+ kvalue = f_scale_array[f_scale_idx]; -+ if (f_scale_reload[f_scale_idx]) { -+ d11 = d12; -+ d12 = *s++; -+ d21 = d22; -+ d22 = *s++; -+ if (!count) -+ break; -+ count -= 4; -+ } -+ d1 = d11 + (((d12 - d11)*kvalue) >> 8); -+ d2 = d21 + (((d22 - d21)*kvalue) >> 8); -+ *dp++ = d1; -+ *dp++ = d2; -+ cnt += 4; -+ f_scale_idx ++; -+ if (f_scale_idx >= f_scale_count) -+ f_scale_idx = 0; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ case AFMT_S16_LE: -+ jz_audio_format = fmt; -+ jz_update_filler(fmt, jz_audio_channels); -+ case AFMT_QUERY: -+ break; -+ } -+ return jz_audio_format; -+} -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ __ac97_set_xs_stereo(); // always stereo when recording -+ __ac97_set_rs_stereo(); // always stereo when recording -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case 2: -+ __ac97_set_xs_stereo(); -+ __ac97_set_rs_stereo(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case 0: -+ break; -+ } -+ return jz_audio_channels; -+} -+ -+ -+static void jz_audio_reset(void) -+{ -+ __ac97_disable_replay(); -+ __ac97_disable_receive_dma(); -+ __ac97_disable_record(); -+ __ac97_disable_transmit_dma(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file, -+ struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer, -+ size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer, -+ size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_ac97_audio_fops */ -+static struct file_operations jz_ac97_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+/* Read / Write AC97 codec registers */ -+static inline int jz_out_command_ready(void) -+{ -+ int t2 = 1000; -+ int done = 0; -+ -+ while (! done && t2-- > 0) { -+ if (REG32(AC97_ACSR) & AIC_ACSR_CADT) { -+ REG32(AC97_ACSR) &= ~AIC_ACSR_CADT; -+ done = 1; -+ } -+ else -+ udelay (1); -+ } -+ return done; -+} -+ -+static inline int jz_in_status_ready(void) -+{ -+ int t2 = 1000; -+ int done = 0; -+ -+ while (! done && t2-- > 0) { -+ if (REG32(AC97_ACSR) & AIC_ACSR_SADR) { -+ REG32(AC97_ACSR) &= ~AIC_ACSR_SADR; -+ done = 1; -+ } -+ else { -+ if (REG32(AC97_ACSR) & AIC_ACSR_RSTO) { -+ REG32(AC97_ACSR) &= ~AIC_ACSR_RSTO; -+ printk(KERN_DEBUG "%s: RSTO receive status timeout.\n", -+ __FUNCTION__); -+ done = 0; -+ break; -+ } -+ udelay (1); -+ } -+ } -+ return done; -+} -+ -+static int jz_readAC97Reg (struct ac97_codec *dev, u8 reg) -+{ -+ u16 value; -+ -+ if (reg < 128) { -+ u8 ret_reg; -+ __ac97_out_rcmd_addr(reg);//output read addr -+ if (jz_out_command_ready())//judge if send completely? -+ while (jz_in_status_ready()) {//judge if receive completely? -+ ret_reg = __ac97_in_status_addr();//slot1:send addr -+ value = __ac97_in_data(); -+ if (ret_reg == reg) -+ return value; -+ else { -+// printk(KERN_DEBUG "%s: index (0x%02x)->(0x%02x) 0x%x\n", __FUNCTION__, reg, ret_reg, value); -+ return -EINVAL; -+ } -+ } -+ } -+ value = __ac97_in_data(); -+ printk (KERN_DEBUG "timeout while reading AC97 codec (0x%x)\n", reg); -+ return -EINVAL; -+} -+ -+static u16 ac97_codec_read(struct ac97_codec *codec, u8 reg) -+{ -+ int res = jz_readAC97Reg(codec, reg); -+ int count = 0; -+ while (res == -EINVAL) { -+ udelay(1000); -+ __ac97_warm_reset_codec(); -+ udelay(1000); -+ res = jz_readAC97Reg(codec, reg); -+ count ++; -+ if (count > MAX_RETRY){ -+ printk(KERN_WARNING"After try %d when read AC97 codec 0x%x, can't success, give up operate!!\n", -+ MAX_RETRY, reg); -+ break; -+ } -+ } -+ return (u16)res; -+} -+ -+static int jz_writeAC97Reg (struct ac97_codec *dev, u8 reg, u16 value) -+{ -+ //unsigned long flags; -+ int done = 0; -+ -+ //save_and_cli(flags); -+ -+ __ac97_out_wcmd_addr(reg); -+ __ac97_out_data(value); -+ if (jz_out_command_ready()) -+ done = 1; -+ else -+ printk (KERN_DEBUG "Tiemout AC97 codec write (0x%X<==0x%X)\n", reg, value); -+ //restore_flags(flags); -+ return done; -+} -+static void ac97_codec_write(struct ac97_codec *codec, u8 reg, u16 data) -+{ -+ int done = jz_writeAC97Reg(codec, reg, data); -+ int count = 0; -+ while (done == 0) { -+ count ++; -+ udelay (2000); -+ __ac97_warm_reset_codec(); -+ udelay(2000); -+ done = jz_writeAC97Reg(codec, reg, data); -+ if ( count > MAX_RETRY ){ -+ printk (KERN_DEBUG " After try %d when write AC97 codec (0x%x), can't sucess, give up!! \n", -+ MAX_RETRY, reg); -+ break; -+ } -+ } -+} -+ -+/* OSS /dev/mixer file operation methods */ -+ -+static int jz_ac97_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_ac97_controller_info *controller = ac97_controller; -+ -+ for (i = 0; i < NR_AC97; i++) -+ if (controller->ac97_codec[i] != NULL && -+ controller->ac97_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+ -+ match: -+ file->private_data = controller->ac97_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_ac97_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct ac97_codec *codec = (struct ac97_codec *)file->private_data; -+ -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_ac97_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static /*const*/ struct file_operations jz_ac97_mixer_fops = { -+ owner: THIS_MODULE, -+ llseek: jz_ac97_llseek, -+ ioctl: jz_ac97_ioctl_mixdev, -+ open: jz_ac97_open_mixdev, -+}; -+ -+/* AC97 codec initialisation. */ -+static int __init jz_ac97_codec_init(struct jz_ac97_controller_info *controller) -+{ -+ int num_ac97 = 0; -+ int ready_2nd = 0; -+ struct ac97_codec *codec; -+ unsigned short eid; -+ int i = 0; -+ -+ if (__ac97_codec_is_low_power_mode()) { -+ printk(KERN_DEBUG "AC97 codec is low power mode, warm reset ...\n"); -+ __ac97_warm_reset_codec(); -+ udelay(10); -+ } -+ i = 0; -+ while (!__ac97_codec_is_ready()) { -+ i++; -+ if ( i > 100 ) { -+ printk(KERN_WARNING "AC97 codec not ready, failed init ..\n"); -+ return -ENODEV; -+ } -+ udelay(10); -+ } -+ i = 0; -+ -+ /* Reset the mixer. */ -+ for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { -+ if ((codec = kmalloc(sizeof(struct ac97_codec), -+ GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct ac97_codec)); -+ -+ /* initialize some basic codec information, -+ other fields will be filled -+ in ac97_probe_codec */ -+ codec->private_data = controller; -+ codec->id = num_ac97; -+ -+ codec->codec_read = ac97_codec_read; -+ codec->codec_write = ac97_codec_write; -+ -+ if (ac97_probe_codec(codec) == 0) -+ break; -+ -+ eid = ac97_codec_read(codec, AC97_EXTENDED_ID); -+ if (eid == 0xFFFF) { -+ printk(KERN_WARNING "Jz AC97: no codec attached?\n"); -+ kfree(codec); -+ break; -+ } -+ -+ controller->ac97_features = eid; -+ -+ if (!(eid & 0x0001)) -+ printk(KERN_WARNING "AC97 codec: only 48Khz playback available.\n"); -+ else { -+ printk(KERN_WARNING "AC97 codec: supports variable sample rate.\n"); -+ /* Enable HPEN: UCB1400 only */ -+ ac97_codec_write(codec, 0x6a, -+ ac97_codec_read(codec, 0x6a) | 0x40); -+ -+ /* Enable variable rate mode */ -+ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9); -+ ac97_codec_write(codec, -+ AC97_EXTENDED_STATUS, -+ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800); -+ /* power up everything, modify this -+ when implementing power saving */ -+ ac97_codec_write(codec, -+ AC97_POWER_CONTROL, -+ ac97_codec_read(codec, AC97_POWER_CONTROL) & ~0x7f00); -+ /* wait for analog ready */ -+ for (i=10; i && ((ac97_codec_read(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) { -+// current->state = TASK_UNINTERRUPTIBLE; -+// schedule_timeout(HZ/20); -+ } -+ -+ if (!(ac97_codec_read(codec, AC97_EXTENDED_STATUS) & 1)) { -+ printk(KERN_WARNING "Jz AC97: Codec refused to allow VRA, using 48Khz only.\n"); -+ controller->ac97_features &= ~1; -+ } -+ } -+ -+ if ((codec->dev_mixer = -+ register_sound_mixer(&jz_ac97_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz AC97: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ -+ controller->ac97_codec[num_ac97] = codec; -+ -+ /* if there is no secondary codec at all, don't probe any more */ -+ if (!ready_2nd) -+ return num_ac97+1; -+ } -+ return num_ac97; -+} -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<3) | ((ch)&7)) /* up to 8 chans supported. */ -+ -+ -+ switch (TYPE(format, channels)) { -+ default: -+ -+ case TYPE(AFMT_U8, 1): -+ if ((ac97_controller->patched) && -+ (ac97_controller->ac97_features & 1)) { -+ __aic_enable_mono2stereo(); -+ __aic_enable_unsignadj(); -+ jz_set_dma_block_size(ac97_controller->dma1, 16); -+ jz_set_dma_block_size(ac97_controller->dma2, 16); -+ } else { -+ __aic_disable_mono2stereo(); -+ __aic_disable_unsignadj(); -+ jz_set_dma_block_size(ac97_controller->dma1, 4); -+ jz_set_dma_block_size(ac97_controller->dma2, 4); -+ } -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ __ac97_set_oass(8); -+ __ac97_set_iass(8); -+ jz_set_dma_dest_width(ac97_controller->dma1, 8); -+ jz_set_dma_src_width(ac97_controller->dma2, 8); -+ break; -+ case TYPE(AFMT_U8, 2): -+ if ((ac97_controller->patched) && -+ (ac97_controller->ac97_features & 1)) { -+ __aic_enable_mono2stereo(); -+ __aic_enable_unsignadj(); -+ jz_set_dma_block_size(ac97_controller->dma1, 16); -+ jz_set_dma_block_size(ac97_controller->dma2, 16); -+ } else { -+ __aic_disable_mono2stereo(); -+ __aic_disable_unsignadj(); -+ jz_set_dma_block_size(ac97_controller->dma1, 4); -+ jz_set_dma_block_size(ac97_controller->dma2, 4); -+ } -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ __ac97_set_oass(8); -+ __ac97_set_iass(8); -+ jz_set_dma_dest_width(ac97_controller->dma1, 8); -+ jz_set_dma_src_width(ac97_controller->dma2, 8); -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ if ((ac97_controller->patched) && -+ (ac97_controller->ac97_features & 1)) { -+ __aic_enable_mono2stereo(); -+ jz_set_dma_block_size(ac97_controller->dma1, 16); -+ jz_set_dma_block_size(ac97_controller->dma2, 16); -+ } else { -+ __aic_disable_mono2stereo(); -+ jz_set_dma_block_size(ac97_controller->dma1, 4); -+ jz_set_dma_block_size(ac97_controller->dma2, 4); -+ } -+ __aic_disable_unsignadj(); -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ __ac97_set_oass(16); -+ __ac97_set_iass(16); -+ -+ jz_set_dma_dest_width(ac97_controller->dma1, 16); -+ jz_set_dma_src_width(ac97_controller->dma2, 16); -+ -+ break; -+ -+ case TYPE(AFMT_S16_LE, 2): -+ if ((ac97_controller->patched) && -+ (ac97_controller->ac97_features & 1)) { -+ jz_set_dma_block_size(ac97_controller->dma1, 16); -+ jz_set_dma_block_size(ac97_controller->dma2, 16); -+ } else { -+ jz_set_dma_block_size(ac97_controller->dma1, 4); -+ jz_set_dma_block_size(ac97_controller->dma2, 4); -+ } -+ __aic_disable_mono2stereo(); -+ __aic_disable_unsignadj(); -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ __ac97_set_oass(16); -+ __ac97_set_iass(16); -+ jz_set_dma_dest_width(ac97_controller->dma1, 16); -+ jz_set_dma_src_width(ac97_controller->dma2, 16); -+ break; -+ } -+} -+ -+#ifdef CONFIG_PROC_FS -+ -+extern struct proc_dir_entry *proc_jz_root; -+ -+static int jz_ac97_init_proc(struct jz_ac97_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("ac97", 0, proc_jz_root, -+ ac97_read_proc, controller->ac97_codec[0])) -+ return -EIO; -+ -+ return 0; -+} -+ -+static void jz_ac97_cleanup_proc(struct jz_ac97_controller_info *controller) -+{ -+} -+ -+#endif -+ -+static void __init attach_jz_ac97(struct jz_ac97_controller_info *controller) -+{ -+ char *name; -+ int adev; -+ -+ name = controller->name; -+ jz_ac97_initHw(controller); -+ -+ /* register /dev/audio ? */ -+ adev = register_sound_dsp(&jz_ac97_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ -+ /* initialize AC97 codec and register /dev/mixer */ -+ if (jz_ac97_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_ac97_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create AC97 proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8);//4 -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8);//4 -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ -+ if ((controller->dma1 = jz_request_dma(DMA_ID_AC97_TX, "audio dac", -+ jz_ac97_replay_dma_irq, -+ IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_AC97_RX, "audio adc", -+ jz_ac97_record_dma_irq, -+ IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ -+ printk("Jz On-Chip AC97 controller registered (DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d)\n", -+ controller->dma1, get_dma_done_irq(controller->dma1), -+ controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ old_mksound = kd_mksound; /* see vt.c */ -+ kd_mksound = jz_ac97_mksound; -+ controller->dev_audio = adev; -+ return; -+ -+ dma2_failed: -+ jz_free_dma(controller->dma1); -+ dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8);//4 -+ tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8);//4 -+ tmp1_failed: -+#ifdef CONFIG_PROC_FS -+ jz_ac97_cleanup_proc(controller); -+#endif -+ proc_failed: -+ /* unregister mixer dev */ -+ mixer_failed: -+ unregister_sound_dsp(adev); -+ audio_failed: -+ return; -+} -+ -+static int __init probe_jz_ac97(struct jz_ac97_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_ac97_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz AC97 Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ memset( *controller, 0, sizeof(struct jz_ac97_controller_info) ); -+ (*controller)->name = "Jz AC97 controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_ac97(struct jz_ac97_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_ac97_full_reset (controller); -+ -+ controller->dev_audio = -1; -+ -+ if (old_mksound) -+ kd_mksound = old_mksound; /* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_ac97_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ -+ free_pages((unsigned long)controller->tmp1, 8);//4 -+ free_pages((unsigned long)controller->tmp2, 8);//4 -+ -+ if (adev >= 0) { -+ //unregister_sound_mixer(audio_devs[adev]->mixer_dev); -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+ -+static int reserve_mastervol, reserve_micvol; -+static int reserve_power1, reserve_power2; -+static int reserve_power3, reserve_power4; -+static int reserve_power5, reserve_power6; -+ -+static int jz_ac97_suspend(struct jz_ac97_controller_info *controller, int state) -+{ -+ struct ac97_codec *codec = controller->ac97_codec[0]; -+ -+ /* save codec states */ -+ reserve_mastervol = ac97_codec_read(codec, 0x0002); -+ reserve_micvol = ac97_codec_read(codec, 0x000e); -+ -+ reserve_power1 = ac97_codec_read(codec, 0x0026); -+ reserve_power2 = ac97_codec_read(codec, 0x006c); -+ reserve_power3 = ac97_codec_read(codec, 0x005c); -+ reserve_power4 = ac97_codec_read(codec, 0x0064); -+ reserve_power5 = ac97_codec_read(codec, 0x0066); -+ reserve_power6 = ac97_codec_read(codec, 0x006a); -+ -+ /* put codec into power-saving mode */ -+ ac97_codec_write(codec, 0x5c, 0xffff); -+ ac97_codec_write(codec, 0x64, 0x0000); -+ ac97_codec_write(codec, 0x66, 0x0000); -+ ac97_codec_write(codec, 0x6a, 0x0000); -+ -+ ac97_codec_write(codec, 0x6c, 0x0030); -+ ac97_codec_write(codec, 0x26, 0x3b00); -+ -+ ac97_save_state(codec); -+ __ac97_disable(); -+ -+ return 0; -+} -+ -+static int jz_ac97_resume(struct jz_ac97_controller_info *controller) -+{ -+ struct ac97_codec *codec = controller->ac97_codec[0]; -+ -+ jz_ac97_full_reset(controller); -+ ac97_probe_codec(codec); -+ ac97_restore_state(codec); -+ -+ ac97_codec_write(codec, 0x0026, reserve_power1); -+ ac97_codec_write(codec, 0x006c, reserve_power2); -+ ac97_codec_write(codec, 0x005c, reserve_power3); -+ ac97_codec_write(codec, 0x0064, reserve_power4); -+ ac97_codec_write(codec, 0x0066, reserve_power5); -+ ac97_codec_write(codec, 0x006a, reserve_power6); -+ -+ ac97_codec_write(codec, 0x0002, reserve_mastervol); -+ ac97_codec_write(codec, 0x000e, reserve_micvol); -+ -+ /* Enable variable rate mode */ -+ ac97_codec_write(codec, AC97_EXTENDED_STATUS, 9); -+ ac97_codec_write(codec, -+ AC97_EXTENDED_STATUS, -+ ac97_codec_read(codec, AC97_EXTENDED_STATUS) | 0xE800); -+ -+ return 0; -+} -+ -+static int jz_ac97_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_ac97_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_ac97_suspend(controller, (int)data); -+ break; -+ -+ case PM_RESUME: -+ ret = jz_ac97_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+ -+static int __init init_jz_ac97(void) -+{ -+ int errno; -+ -+ if ((errno = probe_jz_ac97(&ac97_controller)) < 0) -+ return errno; -+ attach_jz_ac97(ac97_controller); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+#ifdef CONFIG_PM -+ ac97_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_ac97_pm_callback); -+ if (ac97_controller->pm) -+ ac97_controller->pm->data = ac97_controller; -+#endif -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_ac97(void) -+{ -+ unload_jz_ac97(ac97_controller); -+} -+ -+module_init(init_jz_ac97); -+module_exit(cleanup_jz_ac97); -+ -+ -+static int drain_adc(struct jz_ac97_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ unsigned tmo; -+ -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ -+ if (signal_pending(current)) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED; -+ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4; -+ tmo /= jz_audio_channels; -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ return 0; -+} -+ -+static int drain_dac(struct jz_ac97_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ unsigned tmo; -+ -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0 && elements_in_queue(&out_full_queue) <= 0) -+ break; -+ if (signal_pending(current)) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ tmo = (PAGE_SIZE * HZ) / STANDARD_SPEED; -+ tmo *= jz_audio_k * (jz_audio_format == AFMT_S16_LE) ? 2 : 4; -+ tmo /= jz_audio_channels; -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ return 0; -+} -+ -+/* -+ * Audio operation routines implementation -+ */ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ struct jz_ac97_controller_info *controller = -+ (struct jz_ac97_controller_info *) file->private_data; -+ unsigned long flags; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ controller->opened1 = 0; -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __ac97_disable_transmit_dma(); -+ __ac97_disable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ } -+ if (file->f_mode & FMODE_READ) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __ac97_disable_receive_dma(); -+ __ac97_disable_record(); -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ } -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ struct jz_ac97_controller_info *controller= ac97_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ jz_audio_set_channels(controller->dev_audio, 1); -+ jz_audio_set_format(controller->dev_audio, AFMT_U8); -+ jz_audio_set_speed(controller->dev_audio, 8000); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ controller->opened2 = 1; -+ first_record_call = 1; -+ printk(KERN_DEBUG "You'd better apply 48000Hz 16-bit Stereo for record.\n"); -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ jz_audio_set_channels(controller->dev_audio, 2); -+ jz_audio_set_format(controller->dev_audio, AFMT_S16_LE); -+ jz_audio_set_speed(controller->dev_audio, 48000); -+ } -+ -+ last_jz_audio_count = jz_audio_count = 0; -+ file->private_data = controller; -+ -+ jz_audio_fragsize = 8 * PAGE_SIZE; -+ jz_audio_fragstotal = 4; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ return 0; -+} -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct jz_ac97_controller_info *controller = -+ (struct jz_ac97_controller_info *) file->private_data; -+ int val=0,fullc,busyc,unfinish; -+ unsigned int flags; -+ count_info cinfo; -+ -+ switch (cmd) -+ { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ -+ case SNDCTL_DSP_RESET: -+ jz_audio_reset(); -+ return 0; -+ -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ -+ case SNDCTL_DSP_SPEED: /* set smaple rate */ -+ { -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ } -+ -+ case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ return 0; -+ -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(4*PAGE_SIZE, (int *)arg); -+ return put_user(jz_audio_fragsize , (int *)arg); -+ -+ case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ -+ case SNDCTL_DSP_SETFMT: /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ -+ if (val != AFMT_QUERY) { -+ jz_audio_set_format(controller->dev_audio,val); -+ } else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? -+ AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? -+ AFMT_S16_LE : AFMT_U8; -+ } -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ -+ case SNDCTL_DSP_SETFRAGMENT: -+ if(out_dma_buf || in_dma_buf) -+ return -EBUSY; -+ get_user(val, (long *) arg); -+ jz_audio_fragsize = 1 << (val & 0xFFFF);//16 least bits -+ -+ if (jz_audio_fragsize < 4 * PAGE_SIZE) -+ jz_audio_fragsize = 4 * PAGE_SIZE; -+ if (jz_audio_fragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE -+ jz_audio_fragsize = 16 * PAGE_SIZE; -+ jz_audio_fragstotal = (val >> 16) & 0x7FFF; -+ if (jz_audio_fragstotal < 2) -+ jz_audio_fragstotal = 2; -+ if (jz_audio_fragstotal > 32) -+ jz_audio_fragstotal = 32; -+ -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ return 0; -+ -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ audio_buf_info abinfo; -+ int i, bytes = 0; -+ -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ //unused fragment amount -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ bytes /= jz_audio_k; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ //bytes /= jz_audio_b; -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ -+ case SNDCTL_DSP_GETISPACE: -+ { -+ audio_buf_info abinfo; -+ int i, bytes = 0; -+ -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ //unused fragment amount -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) //record is at working -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) //playback is at working -+ val |= PCM_ENABLE_OUTPUT; -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ /*if (file->f_mode & FMODE_READ) { -+ if (val & PCM_ENABLE_INPUT) { -+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) -+ return ret; -+ start_adc(state); -+ } else -+ stop_adc(state); -+ } -+ if (file->f_mode & FMODE_WRITE) { -+ if (val & PCM_ENABLE_OUTPUT) { -+ if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) -+ return ret; -+ start_dac(state); -+ } else -+ stop_dac(state); -+ }*/ -+ return 0; -+ -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //controller->total_bytes += get_dma_residue(controller->dma2); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //controller->total_bytes += get_dma_residue(controller->dma1); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ -+ case SNDCTL_DSP_GETODELAY: -+ { -+ int id, i; -+ -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ -+ for(i = 0;i < fullc ;i ++) -+ { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) -+ { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ unfinish /= jz_audio_k;//jz_audio_k is jz_audio_b -+ return put_user(val, (int *)arg); -+ } -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+static unsigned int jz_audio_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ struct jz_ac97_controller_info *controller = -+ (struct jz_ac97_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } -+ else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct jz_ac97_controller_info *controller = -+ (struct jz_ac97_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+ if (count < 2*PAGE_SIZE / jz_audio_k) { -+ copy_count = count * 16 / (jz_audio_channels * jz_audio_format); -+ } else -+ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4; -+ left_count = count; -+ -+ if (first_record_call) { -+ first_record_call = 0; -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8); -+ __ac97_enable_receive_dma(); -+ __ac97_enable_record(); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ interruptible_sleep_on(&rx_wait_queue); -+ } else -+ BUG(); -+ } -+ -+ while (left_count > 0) { -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ interruptible_sleep_on(&rx_wait_queue); -+ } -+ if (signal_pending(current)) -+ return ret ? ret: -ERESTARTSYS; -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ BUG(); -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ *(in_dma_buf_data_count + id) = copy_count * (jz_audio_format/8); -+ __ac97_enable_receive_dma(); -+ __ac97_enable_record(); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ -+ if (ret + cnt > count) -+ cnt = count - ret; -+ -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ ret += cnt; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ left_count -= cnt; -+ } -+ if (ret != count) -+ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n", -+ __FUNCTION__, count, ret, jz_audio_count); -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, -+ size_t count, loff_t *ppos) -+{ -+ struct jz_ac97_controller_info *controller = -+ (struct jz_ac97_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count; -+ unsigned int flags; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+ /* The data buffer size of the user space is always a PAGE_SIZE -+ * scale, so the process can be simplified. -+ */ -+ -+ if ((ac97_controller->patched) && (ac97_controller->ac97_features & 1)) -+ copy_count = count; -+ else { -+ if (count < 2*PAGE_SIZE / jz_audio_k) -+ copy_count = count; -+ else -+ copy_count = ((2*PAGE_SIZE / jz_audio_k + 3) / 4) * 4; -+ } -+ left_count = count; -+ -+ if (!(ac97_controller->patched) || !(ac97_controller->ac97_features & 1)) { -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__); -+ return ret ? ret : -EFAULT; -+ } -+ } -+ -+ while (left_count > 0) { -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ interruptible_sleep_on(&tx_wait_queue); -+ } -+ -+ if (signal_pending(current)) -+ return ret ? ret : -ERESTARTSYS; -+ -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ if ((ac97_controller->patched) && -+ (ac97_controller->ac97_features & 1)) { -+ if (copy_from_user((char *)(*(out_dma_buf + id)), buffer+ret, copy_count)) { -+ printk(KERN_DEBUG "%s: copy_from_user failed.\n", __FUNCTION__); -+ return ret ? ret : -EFAULT; -+ } -+ *(out_dma_buf_data_count + id) = copy_count; -+ } else -+ replay_filler( -+ (unsigned long)controller->tmp1 + ret, -+ copy_count, id); -+ //when 0,kernel will panic -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); -+ } else {//when 0,i need refill in empty queue -+ put_buffer_id(&out_empty_queue, id); -+ } -+ } else -+ BUG(); -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ __ac97_enable_transmit_dma(); -+ __ac97_enable_replay(); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1,file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ } -+ } -+ } -+ } -+ -+ if (ret != count) -+ printk(KERN_DEBUG "%s: count=%d ret=%d jz_audio_count=%d\n", -+ __FUNCTION__, count, ret, jz_audio_count); -+ return ret; -+} -+ -+/* this function for the other codec function */ -+struct ac97_codec * find_ac97_codec(void) -+{ -+ if ( ac97_controller ) -+ return ac97_controller->ac97_codec[0]; -+ return 0; -+ -+} -+ -diff -urN linux-2.6.24.7.old/sound/oss/jz_i2s.c linux-2.6.24.7/sound/oss/jz_i2s.c ---- linux-2.6.24.7.old/sound/oss/jz_i2s.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_i2s.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2894 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#if defined(CONFIG_I2S_DLV) -+#include "jzdlv.h" -+#endif -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define JZCODEC_RW_BUFFER_SIZE 5 -+#define JZCODEC_RW_BUFFER_TOTAL 4 -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(int mode) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(int mode) = NULL; -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*set_codec_line)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+void (*set_codec_linein2hp)(void) = NULL; -+void (*clear_codec_linein2hp)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+#if defined(CONFIG_I2S_DLV) -+int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+#endif -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+static int use_mic_line_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+#if 1 -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+#else -+ set_dma_mode(chan, mode); -+#endif -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+#if defined(CONFIG_I2S_DLV) -+ if (rate > 96000) -+ rate = 96000; -+#else -+ if (rate > 48000) -+ rate = 48000; -+#endif -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+#if defined(CONFIG_I2S_ICODEC) -+ l1 >>= codec_volue_shift; -+#endif -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICODEC) -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x18_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed long d1; -+ signed long l1; -+ volatile signed long *s = (signed long *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 4; -+ cnt += 4; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ } -+ -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ case 18: -+ __i2s_set_oss_sample_size(18); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ -+ jz_audio_volume = val; -+ if(set_codec_volume) -+ set_codec_volume(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ use_mic_line_flag = USE_MIC; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ -+ case SOUND_MIXER_WRITE_LINE: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ use_mic_line_flag = USE_LINEIN; -+ codec_mic_gain = val; -+ if(set_codec_line) -+ set_codec_line(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_LINE: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ case TYPE(18, 2): -+ jz_audio_b = 1; -+ replay_filler = replay_fill_2x18_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(use_mic_line_flag); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+ -+#if defined(CONFIG_I2S_DLV) -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+#endif -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno; -+#if defined(CONFIG_I2S_DLV) -+ int retval; -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ use_mic_line_flag = USE_NONE; -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ int tfl; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ /* wait for TX fifo */ -+ while (1) { -+ tfl = __aic_get_transmit_resident(); -+ if (tfl == 0) -+ break; -+ udelay(2); -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) -+#define MAXDELAY 50000 -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+#if defined(CONFIG_I2S_DLV) -+ unsigned long tfl; -+#endif -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+#endif -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ /*while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ }*/ -+ mdelay(100); -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_replay) -+ clear_codec_replay(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_record) -+ clear_codec_record(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ if (use_mic_line_flag == USE_LINEIN) { -+ unset_record_line_input_audio_with_audio_data_replay(); -+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ unset_record_mic_input_audio_with_audio_data_replay(); -+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ -+#if 0 -+ unset_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } else if (controller->opened1 == 1) { -+ //controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_ICODEC) -+ //write_mute_to_dma_buffer(save_last_samples[last_dma_buffer_id].left,save_last_samples[last_dma_buffer_id].right); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_replay) -+ clear_codec_replay(); -+#endif -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(turn_off_codec) -+ turn_off_codec(); -+#endif -+ } else if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(clear_codec_record) -+ clear_codec_record(); -+#endif -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* unset Record MIC input audio with direct playback */ -+ unset_record_mic_input_audio_with_direct_playback(); -+#endif -+#if 1 -+ /* unset Record MIC input audio without playback */ -+ unset_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* unset Record LINE input audio without playback */ -+ unset_record_line_input_audio_without_playback(); -+#endif -+#endif -+ __i2s_disable(); -+#if defined(CONFIG_I2S_ICODEC) -+ if(turn_off_codec) -+ turn_off_codec(); -+#endif -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+/* __cpm_stop_idct(); -+ __cpm_stop_db(); -+ __cpm_stop_me(); -+ __cpm_stop_mc(); -+ __cpm_stop_ipu();*/ -+#endif -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ controller->opened1 = 0; -+ controller->opened2 = 0; -+ //print_pop_duration(); -+ //__dmac_disable_module(0); -+ } else if ( controller->opened1 == 1 ) { -+ controller->opened1 = 0; -+ //print_pop_duration(); -+ } else if ( controller->opened2 == 1 ) { -+ controller->opened2 = 0; -+ } -+ -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+#endif -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+#if defined(CONFIG_I2S_DLV) -+ REG_DMAC_DMACKE(0) = 0x3f; -+#endif -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } else if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } else if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_ICODEC) -+ if (set_codec_replay_record) -+ set_codec_replay_record(use_mic_line_flag); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ if (use_mic_line_flag == USE_NONE) { -+ printk("you select mic or line recording please.or use mic recording!\n"); -+ use_mic_line_flag = USE_MIC; -+ } -+ if (use_mic_line_flag == USE_LINEIN) { -+ /* Record LINE input audio with Audio data replay (full duplex for linein) */ -+ /* codec_test_line */ -+ set_record_line_input_audio_with_audio_data_replay(); -+ -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ /* Record MIC input audio with Audio data replay (full duplex) */ -+ /* codec_test_mic */ -+ set_record_mic_input_audio_with_audio_data_replay(); -+ } -+#if 0 -+ /* Record playing audio mixed with MIC input audio */ -+ set_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+ -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_ICODEC) -+ if(set_codec_replay) -+ set_codec_replay(); -+#endif -+#if defined(CONFIG_I2S_DLV) -+ //mdelay(10); -+ /* Audio data replay */ -+ set_audio_data_replay(); -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_ICODEC) -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(use_mic_line_flag); -+#endif -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* Record MIC input audio with direct playback */ -+ set_record_mic_input_audio_with_direct_playback(); -+#endif -+ -+#if 1 -+ /* set Record MIC input audio without playback */ -+ set_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* set Record LINE input audio without playback */ -+ set_record_line_input_audio_without_playback(); -+#endif -+ mdelay(1); -+#endif -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ ndelay(100); -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_DLV) -+ //set SB_ADC or SB_DAC -+ __dmac_enable_module(0); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_DLV) -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+#endif -+ } -+#endif -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i; -+ unsigned long bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = (int)bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i; -+ unsigned long bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = (int)bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ if (file->f_flags & O_NONBLOCK) -+ udelay(2); -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+#if defined(CONFIG_I2S_DLV) -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+#endif -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif -diff -urN linux-2.6.24.7.old/sound/oss/jz_i2s_4750.c linux-2.6.24.7/sound/oss/jz_i2s_4750.c ---- linux-2.6.24.7.old/sound/oss/jz_i2s_4750.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_i2s_4750.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,3010 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 2 -+#define JZCODEC_RW_BUFFER_TOTAL 6 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(void) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(void); -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+static int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+static int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+#if 0 /* mask warning */ -+static void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+#endif -+ -+static void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+static int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+ -+#if 0 /* mask warning */ -+/* set Audio data replay */ -+static void set_audio_data_replay(void) -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+#endif -+ -+/* unset Audio data replay */ -+static void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio without playback */ -+static void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio without playback */ -+static void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio without playback */ -+static void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio without playback */ -+static void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Playback LINE input audio direct only */ -+static void set_playback_line_input_audio_direct_only(void) -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Playback LINE input audio direct only */ -+static void unset_playback_line_input_audio_direct_only(void) -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with direct playback */ -+static void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with direct playback */ -+static void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record playing audio mixed with MIC input audio */ -+static void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record playing audio mixed with MIC input audio */ -+static void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+static void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ //set_dma_mode(chan, mode); -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+#if 0 -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICDC) -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+#else -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ -+#if 0 -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); -+ memcpy((char*)dp, (char*)s, count); -+ *(out_dma_buf_data_count + id) = count; -+#else -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+#endif -+ -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ /* print all files */ -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ if (val > 31) -+ val = 31; -+ jz_audio_volume = val; -+ -+ if(set_codec_volume) -+ set_codec_volume(val); -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno, retval; -+#if defined(CONFIG_I2S_DLV) -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+ -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long tfl; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ __aic_flush_fifo(); -+ if(clear_codec_replay) -+ clear_codec_replay(); -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ } -+ -+ if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ -+ if(clear_codec_record) -+ clear_codec_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+#endif -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+ REG_DMAC_DMACKE(0) = 0x3f; -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ jz_codec_config = 0; -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(); -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ if (file->f_mode & FMODE_WRITE) { -+ -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ } else if (file->f_mode & FMODE_READ) { -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+ } -+ -+#endif -+ -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ /*if (file->f_flags & O_NONBLOCK) -+ udelay(2);*/ -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), -+ *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif -diff -urN linux-2.6.24.7.old/sound/oss/jz_i2s_dlv_dma_test.c linux-2.6.24.7/sound/oss/jz_i2s_dlv_dma_test.c ---- linux-2.6.24.7.old/sound/oss/jz_i2s_dlv_dma_test.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_i2s_dlv_dma_test.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2808 @@ -+/* -+ * linux/drivers/sound/jz_i2s_dlv.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+ -+#define NR_I2S 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 3 -+#define JZCODEC_RW_BUFFER_TOTAL 3 -+#define JZCODEC_USER_BUFFER 6 -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+static int jz_audio_rate; -+static char jz_audio_format; -+static char jz_audio_volume; -+static char jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments;//unused fragment amount -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+static int audio_mix_modcnt; -+static int codec_volue_shift; -+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer -+static int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static int use_mic_line_flag; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+ -+ -+static void jz_update_filler(int bits, int channels); -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+static void jz_audio_reset(void); -+ -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* play */ -+ int dma2; /* record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; // byte index to next-in to DMA buffer -+ int nextOut; // byte index to next-out from DMA buffer -+ int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer -+ unsigned total_bytes; // total bytes written or read -+ unsigned blocks; -+ unsigned error; // over/underrun -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs fcj add -+ void (*codec_write) (u8 reg, u16 val);//to AK4642EN,val is 8bit -+ /* Wait for codec-ready. Ok to sleep here. */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+static void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+ -+static void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+static int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+ -+/* set Audio data replay */ -+static void set_audio_data_replay() -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+ -+/* unset Audio data replay */ -+static void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio without playback */ -+static void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio without playback */ -+static void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record LINE input audio without playback */ -+static void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record LINE input audio without playback */ -+static void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Playback LINE input audio direct only */ -+static void set_playback_line_input_audio_direct_only() -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+ -+/* unset Playback LINE input audio direct only */ -+static void unset_playback_line_input_audio_direct_only() -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with direct playback */ -+static void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio with direct playback */ -+static void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record playing audio mixed with MIC input audio */ -+static void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record playing audio mixed with MIC input audio */ -+static void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+static void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+///////// -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+///////// -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ spin_lock_irqsave(&q->lock, flags); -+ //spin_lock(&q->lock); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ //spin_unlock(&q->lock); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ //spin_unlock(&q->lock); -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&q->lock, flags); -+ //spin_lock(&q->lock); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+ //spin_unlock(&q->lock); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ spin_lock_irqsave(&q->lock, flags); -+ //spin_lock(&q->lock); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ //spin_unlock(&q->lock); -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ //for DSP_GETOPTR -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ jz_audio_dma_tran_count = count; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ flags = claim_dma_lock(); -+ //__dmac_disable_module(0); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ -+ set_dma_mode(chan, mode); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) -+ { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ //__dmac_enable_module(0); -+ release_dma_lock(flags); -+ //dump_jz_dma_channel(chan); -+ -+ //printk_codec_files(); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ //for DSP_GETIPTR -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ //write back -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } -+ else -+ in_busy_queue.count = 0; -+ } -+ return IRQ_HANDLED; -+ -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ disable_dma(dma); -+ -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ -+ //for DSP_GETOPTR -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //spin_lock(&controller->ioctllock); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ //spin_unlock(&controller->ioctllock); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); //very busy -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+ __i2s_disable(); -+ //schedule_timeout(5); -+ -+#if defined(CONFIG_I2S_DLV) -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __aic_internal_codec(); -+ //__i2s_set_oss_sample_size(16); -+ //__i2s_set_iss_sample_size(16); -+ -+#endif -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(7); -+ __i2s_set_receive_trigger(8); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ // recording -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ //playing -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /*alloc DMA buffer*/ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ //playing -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; //release page error -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ // recording -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; //release page error -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ int speed = 0, val; -+ -+ jz_audio_speed = rate; -+ if (rate > 96000) -+ rate = 96000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+#if defined(CONFIG_I2S_DLV) -+ speed = 0; -+ switch (rate) { -+ case 8000: -+ speed = 10; -+ break; -+ case 9600: -+ speed = 9; -+ break; -+ case 11025: -+ speed = 8; -+ break; -+ case 12000: -+ speed = 7; -+ break; -+ case 16000: -+ speed = 6; -+ break; -+ case 22050: -+ speed = 5; -+ break; -+ case 24000: -+ speed = 4; -+ break; -+ case 32000: -+ speed = 3; -+ break; -+ case 44100: -+ speed = 2; -+ break; -+ case 48000: -+ speed = 1; -+ break; -+ case 96000: -+ speed = 0; -+ break; -+ default: -+ break; -+ } -+ -+ val = read_codec_file(4); -+ val = (speed << 4) | speed; -+ write_codec_file(4, val); -+ -+#if 0 -+ for (i = 0; i <= 27 ; i++) { -+ printk(" ( CCC %d : 0x%x ) ",i ,read_codec_file(i)); -+ } -+#endif -+ -+#endif -+ return jz_audio_rate; -+} -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ return cnt; -+} -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ return cnt; -+} -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ d2 = *(s++); -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ return cnt; -+} -+ -+static int record_fill_2x24_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 4; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 24) >> 24; -+ d2 = *(s++); -+ *(dp ++) = (d2 << 24) >> 24; -+ } -+ //printk("--- rec 24 ---\n"); -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x8_u(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (unsigned long)d1; -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+ -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+ -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ -+ /* print all files */ -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ case 18: -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x28); -+ //write_codec_file(2, 0x60); -+ __i2s_set_oss_sample_size(18); -+ __i2s_set_iss_sample_size(16); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case 24: -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x78); -+ //write_codec_file(2, 0x60); -+ __i2s_set_oss_sample_size(24); -+ __i2s_set_iss_sample_size(24); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ break; -+ case AFMT_QUERY: -+ break; -+ } -+ return jz_audio_format; -+} -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ /* print all files */ -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+ break; -+ case 2: -+ /* print all files */ -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+ break; -+ case 0: -+ break; -+ } -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+#if defined(CONFIG_I2S_DLV) -+ /* reset DLV codec. from hibernate mode to sleep mode */ -+ write_codec_file(0, 0xf); -+ write_codec_file_bit(6, 0, 0); -+ write_codec_file_bit(6, 0, 1); -+ mdelay(200); -+ //write_codec_file(0, 0xf); -+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 -+ mdelay(10);//wait for stability -+#endif -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+ REG_AIC_I2SCR = 0x10; -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ u8 cur_vol; -+ long val = 0; -+ -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ { -+ mixer_info info; -+#if defined(CONFIG_I2S_DLV) -+ strncpy(info.id, "DLV", sizeof(info.id)); -+ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name)); -+#endif -+ -+ info.modify_counter = audio_mix_modcnt; -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ } -+ case SOUND_OLD_MIXER_INFO: -+ { -+ _old_mixer_info info; -+#if defined(CONFIG_I2S_DLV) -+ strncpy(info.id, "DLV", sizeof(info.id)); -+ strncpy(info.name,"Jz4750 internal codec", sizeof(info.name)); -+#endif -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ } -+ case SOUND_MIXER_READ_STEREODEVS: -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ -+ REG_CPM_I2SCDR = val; -+ printk_codec_files(); -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+#if defined(CONFIG_I2S_DLV) -+#endif -+ return 0; -+ -+ case SOUND_MIXER_READ_BASS: -+#if defined(CONFIG_I2S_DLV) -+#endif -+ return put_user(val, (long *) arg); -+ -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val == 100) { -+ //REG_CPM_CLKGR |= 0x60; -+ printk("gate clock : 0x%08x\n", REG_CPM_CLKGR); -+ return 100; -+ } -+ if(val == 99) { -+ REG_CPM_CLKGR &= ~0x60; -+ return 99; -+ } -+ if(val == 98) { -+ REG_CPM_CPCCR |= 0x80400000; -+ return 98; -+ } -+ if(val == 97) { -+ REG_CPM_CPCCR &= ~0x8000000; -+ REG_CPM_CPCCR |= 0x0040000; -+ return 97; -+ } -+ if(val > 31) -+ val = 31; -+ -+ jz_audio_volume = val; -+ //printk("\njz_audio_volume=%d\n",jz_audio_volume); -+#if defined(CONFIG_I2S_DLV) -+ cur_vol = val; -+ write_codec_file(17, cur_vol | 0xc0); -+ write_codec_file(18, cur_vol); -+#endif -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+#if defined(CONFIG_I2S_DLV) -+ val = jz_audio_volume | jz_audio_volume << 8; -+#endif -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_LINE: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if (val == 100) { -+ printk("Playback LINE input audio direct only is starting...\n"); -+ printk_codec_files(); -+ set_playback_line_input_audio_direct_only(); -+ printk_codec_files(); -+ return 100; -+ } -+ if (val == 99) { -+ printk("Playback LINE input audio direct only is end\n"); -+ unset_playback_line_input_audio_direct_only(); -+ printk_codec_files(); -+ return 99; -+ } -+ -+ if(val > 31) -+ val = 31; -+#if defined(CONFIG_I2S_DLV) -+ use_mic_line_flag = USE_LINEIN; -+ /* set gain */ -+ cur_vol = val; -+ cur_vol &= 0x1f; -+ write_codec_file(11, cur_vol);//GO1L -+ write_codec_file(12, cur_vol);//GO1R -+#endif -+ return 0; -+ break; -+ case SOUND_MIXER_WRITE_MIC: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ -+ if(val > 0xf) -+ val = 0xf; -+#if defined(CONFIG_I2S_DLV) -+ use_mic_line_flag = USE_MIC; -+ /* set gain */ -+ //write_codec_file_bit(6, 1, 3);//GIM -+ cur_vol = val; -+ cur_vol |= cur_vol << 4; -+ write_codec_file(19, cur_vol);//GIL,GIR -+#endif -+ return 0; -+ -+ case SOUND_MIXER_READ_MIC: -+#if defined(CONFIG_I2S_DLV) -+#endif -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ -+ return 0; -+} -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+static void replay_fill_2x18_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed long d1; -+ signed long l1; -+ volatile signed long *s = (signed long *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 4; -+ cnt += 4; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ } -+ -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x24_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed long d1; -+ signed long l1; -+ volatile signed long *s = (signed long *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 4; -+ cnt += 4; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ } -+ -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+ //printk("--- play 24 ---\n"); -+} -+ -+static void jz_update_filler(int format, int channels) -+{ -+ #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ default: -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4;//4bytes * 8bits =32bits -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ //2bytes * 16bits =32bits -+ jz_audio_b = 2; -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ case TYPE(18, 2): -+ jz_audio_b = 1; -+ replay_filler = replay_fill_2x18_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ case TYPE(24, 2): -+ jz_audio_b = 1; -+ replay_filler = replay_fill_2x24_s; -+ record_filler = record_fill_2x24_s; -+ //printk("--- 24 ---\n"); -+ break; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+ -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+ ; -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev;//No of Audio device. -+ name = controller->name; -+ jz_i2s_initHw(1);//initialize AIC controller and reset it -+ /* register /dev/audio */ -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma2); -+dma1_failed: -+ jz_free_dma(controller->dma1); -+ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); -+tmp2_failed: -+tmp1_failed: -+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ jz_i2s_full_reset (controller); -+ controller->dev_audio = -1; -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ free_pages((unsigned long)controller->tmp2, JZCODEC_USER_BUFFER); -+ if (adev >= 0) { -+ //unregister_sound_mixer(audio_devs[adev]->mixer_dev); -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+ -+ -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno, retval; -+ -+#if defined(CONFIG_I2S_DLV) -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ -+ //REG_CPM_CPCCR &= ~(1 << 31); -+ //REG_CPM_CPCCR &= ~(1 << 30); -+ use_mic_line_flag = USE_NONE; -+ write_codec_file(0, 0xf); -+ -+ REG_AIC_I2SCR = 0x10; -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ __aic_reset(); -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ -+ /* power on DLV */ -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+#endif -+ -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ attach_jz_i2s(i2s_controller); -+#if defined(CONFIG_I2S_DLV) -+ __i2s_disable_transmit_intr(); -+ __i2s_disable_receive_intr(); -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+ -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+ unload_jz_i2s(i2s_controller); -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static void print_pop_duration(void) -+{ -+ long diff; -+#if 0 -+ printk(" ramp_up_start=0x%x\n",ramp_up_start); -+ printk(" ramp_up_end =0x%x\n",ramp_up_end); -+ printk(" gain_up_start=0x%x\n",gain_up_start); -+ printk(" gain_up_end =0x%x\n",gain_up_end); -+ -+ printk("ramp_down_start=0x%x\n",ramp_down_start); -+ printk("ramp_down_end =0x%x\n",ramp_down_end); -+ printk("gain_down_start=0x%x\n",gain_down_start); -+ printk("gain_down_end =0x%x\n",gain_down_end); -+#endif -+ -+ diff = (long)ramp_up_end - (long)ramp_up_start; -+ printk("ramp up duration: %d ms\n",diff * 1000 / HZ); -+ diff = (long)gain_up_end - (long)gain_up_start; -+ printk("gain up duration: %d ms\n",diff * 1000 / HZ); -+ diff = (long)gain_down_end - (long)gain_down_start; -+ printk("gain down duration: %d ms\n",diff); -+ diff = (long)ramp_down_end - (long)ramp_down_start; -+ printk("ramp down duration: %d ms\n",diff * 1000 / HZ); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long tfl; -+ -+ jz_codec_config = 0; -+ if (controller == NULL) -+ return -ENODEV; -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ /*while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ }*/ -+ mdelay(100); -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ -+ ///////////////////////// -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ //__aic_flush_fifo(); -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ if (use_mic_line_flag == USE_LINEIN) { -+ unset_record_line_input_audio_with_audio_data_replay(); -+ //printk("3 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ unset_record_mic_input_audio_with_audio_data_replay(); -+ //printk("4 use_mic_line_flag=%d\n",use_mic_line_flag); -+ } -+ -+#if 0 -+ unset_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+ __i2s_disable(); -+#endif -+ } else if ( controller->opened1 == 1 ) { -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ -+ __aic_flush_fifo(); -+ -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+ } else if ( controller->opened2 == 1 ) { -+ //controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* unset Record MIC input audio with direct playback */ -+ unset_record_mic_input_audio_with_direct_playback(); -+#endif -+#if 1 -+ /* unset Record MIC input audio without playback */ -+ unset_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* unset Record LINE input audio without playback */ -+ unset_record_line_input_audio_without_playback(); -+#endif -+#endif -+ __i2s_disable(); -+ } -+ -+ if (controller->opened1 == 1 && controller->opened2 == 1) { -+ controller->opened1 = 0; -+ controller->opened2 = 0; -+ print_pop_duration(); -+ //__dmac_disable_module(0); -+ } else if ( controller->opened1 == 1 ) { -+ controller->opened1 = 0; -+ print_pop_duration(); -+ } else if ( controller->opened2 == 1 ) { -+ controller->opened2 = 0; -+ } -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ -+/* __cpm_stop_idct(); -+ __cpm_stop_db(); -+ __cpm_stop_me(); -+ __cpm_stop_mc(); -+ __cpm_stop_ipu();*/ -+ printk("close audio and clear ipu gate : 0x%08x\n", REG_CPM_CLKGR); -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ if (controller == NULL) -+ return -ENODEV; -+ mdelay(2); -+ REG_DMAC_DMACKE(0) = 0x3f; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ jz_codec_config = 0; -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } else if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ } else if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset();//11.2 -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_DLV) -+ -+ if (use_mic_line_flag == USE_LINEIN) { -+ /* Record LINE input audio with Audio data replay (full duplex for linein) */ -+ /* codec_test_line */ -+ set_record_line_input_audio_with_audio_data_replay(); -+ -+ } -+ if (use_mic_line_flag == USE_MIC) { -+ /* Record MIC input audio with Audio data replay (full duplex) */ -+ /* codec_test_mic */ -+ set_record_mic_input_audio_with_audio_data_replay(); -+ } -+#if 0 -+ /* Record playing audio mixed with MIC input audio */ -+ set_record_playing_audio_mixed_with_mic_input_audio(); -+#endif -+ -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_DLV) -+ //mdelay(10); -+ /* Audio data replay */ -+ set_audio_data_replay(); -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_DLV) -+#if 0 -+ /* Record MIC input audio with direct playback */ -+ set_record_mic_input_audio_with_direct_playback(); -+#endif -+ -+#if 1 -+ /* set Record MIC input audio without playback */ -+ set_record_mic_input_audio_without_playback(); -+#endif -+#if 0 -+ /* tested */ -+ /* set Record LINE input audio without playback */ -+ set_record_line_input_audio_without_playback(); -+#endif -+ mdelay(1); -+#endif -+ } -+ -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+ __i2s_enable(); -+ ndelay(100); -+ -+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) { -+#if defined(CONFIG_I2S_DLV) -+ //set SB_ADC or SB_DAC -+ __dmac_enable_module(0); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+#endif -+ } else if (file->f_mode & FMODE_WRITE) { -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+#endif -+ } else if (file->f_mode & FMODE_READ) { -+#if defined(CONFIG_I2S_DLV) -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+#endif -+ } -+ -+ -+ printk("open audio and set ipu gate : 0x%08x\n", REG_CPM_CLKGR); -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ audio_buf_info abinfo; -+ int i, bytes, id; -+ count_info cinfo; -+ val = 0; -+ bytes = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ { -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ } -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ return 0; -+ -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(4*PAGE_SIZE, (int *)arg); -+ return put_user(jz_audio_fragsize , (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ { -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) { -+ jz_audio_set_format(controller->dev_audio,val); -+ } else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ -+ } -+ return put_user(val, (int *)arg); -+ } -+ -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF);//16 least bits -+ -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ //unused fragment amount -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ bytes /= jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ bytes = 0; -+ //unused fragment amount -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ bytes /= jz_audio_b; -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //controller->total_bytes += get_dma_residue(controller->dma2); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //controller->total_bytes += get_dma_residue(controller->dma1); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ unfinish /= jz_audio_b; -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, -+ (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->nextIn = 0; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ -+ spin_lock(&controller->lock); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ spin_unlock(&controller->lock); -+ -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ //write back -+ dma_cache_wback_inv(*(in_dma_buf + id), -+ *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ //interruptible_sleep_on(&rx_wait_queue); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ /*if (signal_pending(current)) -+ return ret ? ret: -ERESTARTSYS; */ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, -+ copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ //write back -+ dma_cache_wback_inv(*(in_dma_buf + id), -+ *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->nextIn += ret; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ }//while (left_count > 0) -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0, val; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ //spin_lock(&controller->ioctllock); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ //spin_unlock(&controller->ioctllock); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ if (file->f_flags & O_NONBLOCK) -+ udelay(2); -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ // all are full -+ if (file->f_flags & O_NONBLOCK) -+ return ret;//no waiting,no block -+ else { -+ sleep_on(&tx_wait_queue);//blocked -+ } -+ } -+ /*if (signal_pending(current)) -+ return ret ? ret : -ERESTARTSYS;*/ -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ //replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id); -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); //busy in -+ dma_cache_wback_inv(*(out_dma_buf + id), -+ *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); //spare -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ controller->nextOut += ret; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); //first once,next spare -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+ } -+ } -+ } -+ } -+ return ret; -+} -diff -urN linux-2.6.24.7.old/sound/oss/jz_i2s_for_4750.c linux-2.6.24.7/sound/oss/jz_i2s_for_4750.c ---- linux-2.6.24.7.old/sound/oss/jz_i2s_for_4750.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_i2s_for_4750.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,2981 @@ -+/* -+ * linux/drivers/sound/Jz_i2s.c -+ * -+ * JzSOC On-Chip I2S audio driver. -+ * -+ * Copyright (C) 2005 by Junzheng Corp. -+ * Modified by cjfeng on Aug 9,2007,and not any bug on Jz4730 using -+ * dma channel 4&3,noah is tested. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define DPRINTK(args...) printk(args) -+#define DMA_ID_I2S_TX DMA_ID_AIC_TX -+#define DMA_ID_I2S_RX DMA_ID_AIC_RX -+#define NR_I2S 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 2 -+#define JZCODEC_RW_BUFFER_TOTAL 6 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+mixer_info info; -+_old_mixer_info old_info; -+int codec_volue_shift; -+hpvol_shift_t hpvol_shift_table[72]; -+int abnormal_data_count; -+unsigned long i2s_clk; -+ -+void (*set_codec_mode)(void) = NULL; -+void (*clear_codec_mode)(void) = NULL; -+void (*set_codec_gpio_pin)(void) = NULL; -+void (*each_time_init_codec)(void) = NULL; -+int (*set_codec_startup_param)(void) = NULL; -+void (*set_codec_volume_table)(void) = NULL; -+void (*set_codec_record)(void) = NULL; -+void (*set_codec_replay)(void) = NULL; -+void (*set_codec_replay_record)(void); -+void (*turn_on_codec)(void) = NULL; -+void (*turn_off_codec)(void) = NULL; -+void (*set_codec_speed)(int rate) = NULL; -+void (*reset_codec)(void) = NULL; -+void (*codec_mixer_old_info_id_name)(void) = NULL; -+void (*codec_mixer_info_id_name)(void) = NULL; -+void (*set_codec_bass)(int val) = NULL; -+void (*set_codec_volume)(int val) = NULL; -+void (*set_codec_mic)(int val) = NULL; -+void (*i2s_resume_codec)(void) = NULL; -+void (*i2s_suspend_codec)(int wr,int rd) = NULL; -+void (*init_codec_pin)(void) = NULL; -+void (*set_codec_some_func)(void) = NULL; -+void (*clear_codec_record)(void) = NULL; -+void (*clear_codec_replay)(void) = NULL; -+void (*set_replay_hp_or_speaker)(void) = NULL; -+void (*set_codec_direct_mode)(void) = NULL; -+void (*clear_codec_direct_mode)(void) = NULL; -+ -+static int jz_audio_rate; -+static int jz_audio_format; -+static int jz_audio_volume; -+static int jz_audio_channels; -+static int jz_audio_b; /* bits expand multiple */ -+static int jz_audio_fragments; /* unused fragment amount */ -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+ -+static int codec_bass_gain; -+static int audio_mix_modcnt; -+static int jz_audio_dma_tran_count; /* bytes count of one DMA transfer */ -+static int jz_mic_only = 1; -+static int jz_codec_config = 0; -+static unsigned long ramp_up_start; -+static unsigned long ramp_up_end; -+static unsigned long gain_up_start; -+static unsigned long gain_up_end; -+static unsigned long ramp_down_start; -+static unsigned long ramp_down_end; -+static unsigned long gain_down_start; -+static unsigned long gain_down_end; -+ -+static int codec_mic_gain; -+static int pop_dma_flag; -+static int last_dma_buffer_id; -+static int drain_flag; -+ -+static void (*old_mksound)(unsigned int hz, unsigned int ticks); -+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); -+static void jz_update_filler(int bits, int channels); -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_i2s_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_i2s_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(signed long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample); -+#endif -+static void jz_audio_reset(void); -+static struct file_operations jz_i2s_audio_fops; -+ -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (drain_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (pop_wait_queue); -+ -+struct jz_i2s_controller_info -+{ -+ int io_base; -+ int dma1; /* for play */ -+ int dma2; /* for record */ -+ char *name; -+ int dev_audio; -+ struct i2s_codec *i2s_codec[NR_I2S]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; /* byte index to next-in to DMA buffer */ -+ int nextOut; /* byte index to next-out from DMA buffer */ -+ int count; /* current byte count in DMA buffer */ -+ int finish; /* current transfered byte count in DMA buffer */ -+ unsigned total_bytes; /* total bytes written or read */ -+ unsigned blocks; -+ unsigned error; /* over/underrun */ -+#ifdef CONFIG_PM -+ struct pm_dev *pm; -+#endif -+}; -+ -+ -+static struct jz_i2s_controller_info *i2s_controller = NULL; -+struct i2s_codec -+{ -+ /* I2S controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl i2s accessing routines */ -+ u16 (*codec_read) (u8 reg); /* the function accessing Codec REGs */ -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready */ -+ void (*codec_wait) (struct i2s_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct i2s_codec *codec, int oss_channel); -+ void (*write_mixer)(struct i2s_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct i2s_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct i2s_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+ -+typedef struct buffer_queue_s -+{ -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+typedef struct left_right_sample_s -+{ -+ signed long left; -+ signed long right; -+} left_right_sample_t; -+ -+static unsigned long pop_turn_onoff_buf; -+static unsigned long pop_turn_onoff_pbuf; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static left_right_sample_t save_last_samples[64]; -+static int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+static void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+ -+static void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+static int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+ -+/* set Audio data replay */ -+static void set_audio_data_replay() -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+ -+/* unset Audio data replay */ -+static void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio without playback */ -+static void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio without playback */ -+static void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record LINE input audio without playback */ -+static void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+ -+/* unset Record LINE input audio without playback */ -+static void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Playback LINE input audio direct only */ -+static void set_playback_line_input_audio_direct_only() -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+ -+/* unset Playback LINE input audio direct only */ -+static void unset_playback_line_input_audio_direct_only() -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with direct playback */ -+static void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+ -+/* unset Record MIC input audio with direct playback */ -+static void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record playing audio mixed with MIC input audio */ -+static void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record playing audio mixed with MIC input audio */ -+static void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+static void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+static void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+ -+///////// -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+static void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+///////// -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_dma_tran_count = count / jz_audio_b; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ //set_dma_mode(chan, mode); -+ jz_set_oss_dma(chan, mode, jz_audio_format); -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+} -+ -+static irqreturn_t jz_i2s_record_dma_irq (int irq, void *dev_id) -+{ -+ int id1, id2; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(drain_flag == 1) -+ wake_up(&drain_wait_queue); -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_i2s_replay_dma_irq (int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_i2s_controller_info * controller = (struct jz_i2s_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ -+ if(pop_dma_flag == 1) { -+ pop_dma_flag = 0; -+ wake_up(&pop_wait_queue); -+ } else { -+ if(drain_flag == 1) { -+ /* Is replay dma buffer over ? */ -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ drain_flag = 0; -+ wake_up(&drain_wait_queue); -+ } -+ } -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for I2S module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static void jz_i2s_initHw(int set) -+{ -+#if defined(CONFIG_MIPS_JZ_URANUS) -+ i2s_clk = 48000000; -+#else -+ i2s_clk = __cpm_get_i2sclk(); -+#endif -+ __i2s_disable(); -+ if(set) -+ __i2s_reset(); -+ schedule_timeout(5); -+ if(each_time_init_codec) -+ each_time_init_codec(); -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ -+ /* recording */ -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ /* playing */ -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* alloc DMA buffer */ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ /* playing */ -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ /* recording */ -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static void jz_i2s_full_reset(struct jz_i2s_controller_info *controller) -+{ -+ jz_i2s_initHw(0); -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999 ? */ -+ jz_audio_speed = rate; -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ if(set_codec_speed) -+ set_codec_speed(rate); -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long data; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt++; -+ data = *(s++); -+ *(dp ++) = ((data << 16) >> 24) + 0x80; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ volatile unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ *(dp ++) = ((d1 << 16) >> 24) + 0x80; -+ d2 = *(s++); -+ *(dp ++) = ((d2 << 16) >> 24) + 0x80; -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 2; /* count in byte */ -+ d1 = *(s++); -+ *(dp ++) = (d1 << 16) >> 16; -+ s++; /* skip the other channel */ -+ } -+ -+ return cnt; -+} -+ -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned long d1, d2; -+ unsigned long *s = (unsigned long*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ while (count > 0) { -+ count -= 2; /* count in dword */ -+ cnt += 4; /* count in byte */ -+ d1 = *(s++); -+ d2 = *(s++); -+ if(abnormal_data_count > 0) { -+ d1 = d2 = 0; -+ abnormal_data_count --; -+ } -+ *(dp ++) = (d1 << 16) >> 16; -+ *(dp ++) = (d2 << 16) >> 16; -+ } -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char data; -+ unsigned long ddata; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count--; -+ cnt += 1; -+ data = *(s++) - 0x80; -+ ddata = (unsigned long) data << 8; -+ *(dp ++) = ddata; -+ *(dp ++) = ddata; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = ddata; -+ save_last_samples[id].right = ddata; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_2x8_u(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned char d1; -+ unsigned long dd1; -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned long *dp = (unsigned long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 1; -+ cnt += 1 ; -+ d1 = *(s++) - 0x80; -+ dd1 = (unsigned long) d1 << 8; -+ *(dp ++) = dd1; -+ /* save last left */ -+ if(count == 2) -+ save_last_samples[id].left = dd1; -+ /* save last right */ -+ if(count == 1) -+ save_last_samples[id].right = dd1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+ -+static void replay_fill_1x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ count -= 2; -+ cnt += 2 ; -+ d1 = *(s++); -+ l1 = (signed long)d1; -+ *(dp ++) = l1; -+ *(dp ++) = l1; -+ -+ /* save last left and right */ -+ if(count == 1) { -+ save_last_samples[id].left = l1; -+ save_last_samples[id].right = l1; -+ } -+ } -+ cnt = cnt * 2 * jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+#if 0 -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+#if defined(CONFIG_I2S_ICDC) -+ volatile signed long *before_dp; -+ int sam_rate = jz_audio_rate / 20; -+ -+ tmp1 = tmp2 = 0; -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ l1 >>= codec_volue_shift; -+ -+ if(l1 == 0) { -+ mute_cnt ++; -+ if(mute_cnt >= sam_rate) { -+ before_dp = dp - 10; -+ *(before_dp) = (signed long)1; -+ before_dp = dp - 11; -+ *(before_dp) = (signed long)1; -+ mute_cnt = 0; -+ } -+ } else -+ mute_cnt = 0; -+ -+ *(dp ++) = l1; -+ -+ tmp1 = tmp2; -+ tmp2 = l1; -+ } -+ -+ /* save last left */ -+ save_last_samples[id].left = tmp1; -+ /* save last right */ -+ save_last_samples[id].right = tmp2; -+#endif -+#if defined(CONFIG_I2S_DLV) -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+#endif -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+} -+#else -+static void replay_fill_2x16_s(signed long src_start, int count, int id) -+{ -+ int cnt = 0; -+ signed short d1; -+ signed long l1; -+ int mute_cnt = 0; -+ signed long tmp1,tmp2; -+ -+#if 0 -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed short *dp = (signed short*)(*(out_dma_buf + id)); -+ memcpy((char*)dp, (char*)s, count); -+ *(out_dma_buf_data_count + id) = count; -+#else -+ volatile signed short *s = (signed short *)src_start; -+ volatile signed long *dp = (signed long*)(*(out_dma_buf + id)); -+ while (count > 0) { -+ count -= 2; -+ cnt += 2; -+ d1 = *(s++); -+ -+ l1 = (signed long)d1; -+ -+ *(dp ++) = l1; -+ } -+ cnt *= jz_audio_b; -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+#endif -+ -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ case AFMT_S16_LE: -+#if defined(CONFIG_I2S_DLV) -+ /* DAC path and ADC path */ -+ write_codec_file(2, 0x00); -+ //write_codec_file(2, 0x60); -+#endif -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format,jz_audio_channels); -+ /* print all files */ -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ if(set_codec_some_func) -+ set_codec_some_func(); -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 1, 6);//CR1.MONO->1 for Mono -+#endif -+ break; -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(1, 0, 6);//CR1.MONO->0 for Stereo -+#endif -+ break; -+ case 0: -+ break; -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ /* inititalize internal I2S codec */ -+ if(init_codec_pin) -+ init_codec_pin(); -+ -+#if defined(CONFIG_I2S_ICDC) -+ /* initialize AIC but not reset it */ -+ jz_i2s_initHw(0); -+#endif -+ if(reset_codec) -+ reset_codec(); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#if defined(CONFIG_I2S_DLV) -+ REG_AIC_I2SCR = 0x10; -+#endif -+ init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_i2s_audio_fops */ -+static struct file_operations jz_i2s_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_i2s_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ for (i = 0; i < NR_I2S; i++) -+ if (controller->i2s_codec[i] != NULL && controller->i2s_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->i2s_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_i2s_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct i2s_codec *codec = (struct i2s_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_i2s_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_i2s_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_i2s_llseek, -+ ioctl: jz_i2s_ioctl_mixdev, -+ open: jz_i2s_open_mixdev, -+}; -+ -+static int i2s_mixer_ioctl(struct i2s_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ switch (cmd) { -+ case SOUND_MIXER_INFO: -+ -+ if(codec_mixer_info_id_name) -+ codec_mixer_info_id_name(); -+ info.modify_counter = audio_mix_modcnt; -+ -+ return copy_to_user((void *)arg, &info, sizeof(info)); -+ case SOUND_OLD_MIXER_INFO: -+ -+ if(codec_mixer_old_info_id_name) -+ codec_mixer_old_info_id_name(); -+ -+ return copy_to_user((void *)arg, &old_info, sizeof(info)); -+ case SOUND_MIXER_READ_STEREODEVS: -+ -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_SPEAKER: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ switch(val) { -+ case 100: -+ if(set_codec_direct_mode) -+ set_codec_direct_mode(); -+ break; -+ case 0: -+ if(clear_codec_direct_mode) -+ clear_codec_direct_mode(); -+ break; -+ } -+ break; -+ case SOUND_MIXER_WRITE_BASS: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_bass_gain = val; -+ if(set_codec_bass) -+ set_codec_bass(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_BASS: -+ -+ val = codec_bass_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ if (val > 31) -+ val = 31; -+ jz_audio_volume = val; -+ -+ if(set_codec_volume) -+ set_codec_volume(val); -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_MIC: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ codec_mic_gain = val; -+ if(set_codec_mic) -+ set_codec_mic(val); -+ -+ return 0; -+ case SOUND_MIXER_READ_MIC: -+ -+ val = codec_mic_gain; -+ ret = val << 8; -+ val = val | ret; -+ -+ return put_user(val, (long *) arg); -+ default: -+ return -ENOSYS; -+ } -+ audio_mix_modcnt ++; -+ return 0; -+} -+ -+ -+int i2s_probe_codec(struct i2s_codec *codec) -+{ -+ /* generic OSS to I2S wrapper */ -+ codec->mixer_ioctl = i2s_mixer_ioctl; -+ return 1; -+} -+ -+ -+/* I2S codec initialisation. */ -+static int __init jz_i2s_codec_init(struct jz_i2s_controller_info *controller) -+{ -+ int num_i2s = 0; -+ struct i2s_codec *codec; -+ -+ for (num_i2s = 0; num_i2s < NR_I2S; num_i2s++) { -+ if ((codec = kmalloc(sizeof(struct i2s_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct i2s_codec)); -+ codec->private_data = controller; -+ codec->id = num_i2s; -+ -+ if (i2s_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_i2s_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz I2S: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->i2s_codec[num_i2s] = codec; -+ } -+ return num_i2s; -+} -+ -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) -+ { -+ -+ case TYPE(AFMT_U8, 1): -+ jz_audio_b = 4; /* 4bytes * 8bits =32bits */ -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ jz_audio_b = 4; -+ replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u; -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ jz_audio_b = 2; /* 2bytes * 16bits =32bits */ -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ jz_audio_b = 2; -+ replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s; -+ break; -+ default: -+ ; -+ } -+} -+ -+ -+#ifdef CONFIG_PROC_FS -+extern struct proc_dir_entry *proc_jz_root; -+int i2s_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ return 0; -+} -+ -+static int jz_i2s_init_proc(struct jz_i2s_controller_info *controller) -+{ -+ if (!create_proc_read_entry ("i2s", 0, proc_jz_root, i2s_read_proc, controller->i2s_codec[0])) -+ return -EIO; -+ return 0; -+} -+ -+static void jz_i2s_cleanup_proc(struct jz_i2s_controller_info *controller) -+{ -+} -+#endif -+ -+static void __init attach_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ char *name; -+ int adev; /* No of Audio device. */ -+ -+ name = controller->name; -+ /* initialize AIC controller and reset it */ -+ jz_i2s_initHw(1); -+ adev = register_sound_dsp(&jz_i2s_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize I2S codec and register /dev/mixer */ -+ if (jz_i2s_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+#ifdef CONFIG_PROC_FS -+ if (jz_i2s_init_proc(controller) < 0) { -+ printk(KERN_ERR "%s: can't create I2S proc filesystem.\n", name); -+ goto proc_failed; -+ } -+#endif -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ controller->tmp2 = (void *)__get_free_pages(GFP_KERNEL, 8); -+ if (!controller->tmp2) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp2_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_I2S_RX, "audio adc", jz_i2s_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ if ((controller->dma1 = jz_request_dma(DMA_ID_I2S_TX, "audio dac", jz_i2s_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ printk("JzSOC On-Chip I2S controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ controller->dev_audio = adev; -+ pop_turn_onoff_buf = __get_free_pages(GFP_KERNEL | GFP_DMA, 8); -+ if(!pop_turn_onoff_buf) -+ printk("pop_turn_onoff_buf alloc is wrong!\n"); -+ pop_turn_onoff_pbuf = virt_to_phys((void *)pop_turn_onoff_buf); -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma1); -+dma1_failed: -+ free_pages((unsigned long)controller->tmp2, 8); -+tmp2_failed: -+ free_pages((unsigned long)controller->tmp1, 8); -+tmp1_failed: -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+proc_failed: -+ /* unregister mixer dev */ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+static int __init probe_jz_i2s(struct jz_i2s_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_i2s_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz I2S Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ (*controller)->name = "Jz I2S controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ init_waitqueue_head(&pop_wait_queue); -+ init_waitqueue_head(&drain_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_i2s(struct jz_i2s_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ jz_i2s_full_reset(controller); -+ controller->dev_audio = -1; -+ if (old_mksound) -+ kd_mksound = old_mksound;/* Our driver support bell for kb, see vt.c */ -+ -+#ifdef CONFIG_PROC_FS -+ jz_i2s_cleanup_proc(controller); -+#endif -+ -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, 8); -+ free_pages((unsigned long)controller->tmp2, 8); -+ free_pages((unsigned long)pop_turn_onoff_buf, 8); -+ -+ if (adev >= 0) { -+ /* unregister_sound_mixer(audio_devs[adev]->mixer_dev); */ -+ unregister_sound_dsp(controller->dev_audio); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int jz_i2s_suspend(struct jz_i2s_controller_info *controller, int state) -+{ -+ if(i2s_suspend_codec) -+ i2s_suspend_codec(controller->opened1,controller->opened2); -+ printk("Aic and codec are suspended!\n"); -+ return 0; -+} -+ -+static int jz_i2s_resume(struct jz_i2s_controller_info *controller) -+{ -+ if(i2s_resume_codec) -+ i2s_resume_codec(); -+ -+#if defined(CONFIG_I2S_AK4642EN) -+ jz_i2s_initHw(0); -+ jz_audio_reset(); -+ __i2s_enable(); -+ jz_audio_set_speed(controller->dev_audio,jz_audio_speed); -+ /* playing */ -+ if(controller->opened1) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ int dma = controller->dma1; -+ int id; -+ unsigned long flags; -+ disable_dma(dma); -+ if(__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if(__dmac_channel_transmit_end_detected(dma)) -+ __dmac_channel_clear_transmit_end(dma); -+ -+ /* for DSP_GETOPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ while((id = get_buffer_id(&out_busy_queue)) >= 0) -+ put_buffer_id(&out_empty_queue, id); -+ -+ out_busy_queue.count=0; -+ if((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_empty_queue, id); -+ } -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } else -+ printk("pm out_empty_queue empty"); -+ } -+ -+ /* recording */ -+ if(controller->opened2) { -+ if(set_codec_record) -+ set_codec_record(); -+ int dma = controller->dma2; -+ int id1, id2; -+ unsigned long flags; -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ } -+ /* for DSP_GETIPTR */ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_full_queue, id2); -+ } -+ in_busy_queue.count = 0; -+ } -+#endif -+ -+ return 0; -+} -+ -+static int jz_i2s_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ int ret; -+ struct jz_i2s_controller_info *controller = pm_dev->data; -+ -+ if (!controller) return -EINVAL; -+ -+ switch (req) { -+ case PM_SUSPEND: -+ ret = jz_i2s_suspend(controller, (int)data); -+ break; -+ case PM_RESUME: -+ ret = jz_i2s_resume(controller); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+#endif /* CONFIG_PM */ -+static irqreturn_t aic_codec_irq(int irq, void *dev_id) -+{ -+ u8 file_9 = read_codec_file(9); -+ u8 file_8 = read_codec_file(8); -+ -+ //printk("--- 8:0x%x 9:0x%x ---\n",file_8,file_9); -+ if ((file_9 & 0x1f) == 0x10) { -+ -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x4) != 0x4); -+ while ((read_codec_file(9) & 0x10) == 0x10) { -+ write_codec_file(9, 0x10); -+ } -+ write_codec_file_bit(5, 0, 6);//SB_OUT->0 -+ mdelay(300); -+ while ((read_codec_file(9) & 0x8) != 0x8); -+ write_codec_file(9, file_9); -+ write_codec_file(8, file_8); -+ -+ return IRQ_HANDLED; -+ } -+ -+ if (file_9 & 0x8) -+ ramp_up_end = jiffies; -+ else if (file_9 & 0x4) -+ ramp_down_end = jiffies; -+ else if (file_9 & 0x2) -+ gain_up_end = jiffies; -+ else if (file_9 & 0x1) -+ gain_down_end = jiffies; -+ -+ write_codec_file(9, file_9); -+ if (file_9 & 0xf) -+ wake_up(&pop_wait_queue); -+ while (REG_ICDC_RGDATA & 0x100); -+ -+ return IRQ_HANDLED; -+} -+ -+static int __init init_jz_i2s(void) -+{ -+ int errno, retval; -+#if defined(CONFIG_I2S_DLV) -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+#endif -+ -+ abnormal_data_count = 0; -+ if(set_codec_mode) -+ set_codec_mode(); -+ -+ drain_flag = 0; -+ if ((errno = probe_jz_i2s(&i2s_controller)) < 0) -+ return errno; -+ if(set_codec_gpio_pin) -+ set_codec_gpio_pin(); -+ -+ attach_jz_i2s(i2s_controller); -+ if(set_codec_startup_param) -+ set_codec_startup_param(); -+#if defined(CONFIG_I2S_DLV) -+ jz_codec_config = 0; -+ retval = request_irq(IRQ_AIC, aic_codec_irq, IRQF_DISABLED, "aic_codec_irq", NULL); -+ if (retval) { -+ printk("Could not get aic codec irq %d\n", IRQ_AIC); -+ return retval; -+ } -+#endif -+ if(set_codec_volume_table) -+ set_codec_volume_table(); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+#ifdef CONFIG_PM -+ i2s_controller->pm = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, -+ jz_i2s_pm_callback); -+ if (i2s_controller->pm) -+ i2s_controller->pm->data = i2s_controller; -+#endif -+ -+#if defined(CONFIG_I2S_DLV) -+ __cpm_start_idct(); -+ __cpm_start_db(); -+ __cpm_start_me(); -+ __cpm_start_mc(); -+ __cpm_start_ipu(); -+#endif -+ -+ printk("JZ I2S OSS audio driver initialized\n"); -+ -+ return 0; -+} -+ -+static void __exit cleanup_jz_i2s(void) -+{ -+#ifdef CONFIG_PM -+ /* pm_unregister(i2s_controller->pm); */ -+#endif -+#if defined(CONFIG_I2S_DLV) -+ free_irq(IRQ_AIC, NULL); -+#endif -+ unload_jz_i2s(i2s_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ if(clear_codec_mode) -+ clear_codec_mode(); -+} -+ -+module_init(init_jz_i2s); -+module_exit(cleanup_jz_i2s); -+ -+#if defined(CONFIG_SOC_JZ4730) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,con; -+ -+ if(elements_in_queue(&in_busy_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&ctrl->adc_wait, &wait); -+ for (con = 0; con < 1000; con ++) { -+ udelay(1); -+ set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ if (nonblock) { -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->adc_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ return 0; -+} -+ -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count; -+ -+ if(elements_in_queue(&out_full_queue) > 0) { -+ if (nonblock) -+ return -EBUSY; -+ -+ drain_flag = 1; -+ sleep_on(&drain_wait_queue); -+ drain_flag = 0; -+ } else { -+ add_wait_queue(&(ctrl->dac_wait), &wait); -+ for (;;) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if(elements_in_queue(&out_full_queue) <= 0) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if(count <= 0) -+ break; -+ } -+ if (nonblock) { -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ remove_wait_queue(&ctrl->dac_wait, &wait); -+ current->state = TASK_RUNNING; -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4750) -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ //DECLARE_WAITQUEUE(wait, current); -+ unsigned long flags; -+ int count,i=0; -+ -+ //add_wait_queue(&ctrl->adc_wait, &wait); -+ for (;;) { -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ //set_current_state(TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ //spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ //spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ /*if (signal_pending(current)) -+ break;*/ -+ if (nonblock) { -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ return -EBUSY; -+ } -+ } -+ //remove_wait_queue(&ctrl->adc_wait, &wait); -+ //current->state = TASK_RUNNING; -+ /*if (signal_pending(current)) -+ return -ERESTARTSYS;*/ -+ return 0; -+} -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count,ele,busyele,emptyele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if (i < MAXDELAY) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(200); -+ -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } else {//non-blocked -+ //mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ //mdelay(100); -+ busyele = elements_in_queue(&out_busy_queue); -+ emptyele = elements_in_queue(&out_empty_queue); -+ -+ if (busyele <= 0 && emptyele >= jz_audio_fragstotal) { -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+#if defined(CONFIG_SOC_JZ4740) -+#define MAXDELAY 50000 -+static int drain_dac(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,ele,i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int drain_adc(struct jz_i2s_controller_info *ctrl, int nonblock) -+{ -+ int count,i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) -+ { -+ udelay(10); -+ i++; -+ } -+ else -+ break; -+ spin_lock(&ctrl->lock); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock(&ctrl->lock); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) { -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+#endif -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ unsigned long flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long tfl; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1) { -+ controller->opened1 = 0; -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ /* add some mute to anti-pop */ -+#if defined(CONFIG_I2S_DLV) -+ /* wait for fifo empty */ -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ gain_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_down_end = jiffies; -+ while (1) { -+ tfl = REG_AIC_SR & 0x00003f00; -+ if (tfl == 0) { -+ udelay(500); -+ break; -+ } -+ mdelay(2); -+ } -+#endif -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable_replay(); -+ __aic_flush_fifo(); -+ if(clear_codec_replay) -+ clear_codec_replay(); -+ __aic_flush_fifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ ramp_down_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //ramp_down_end = jiffies; -+ unset_audio_data_replay(); -+#endif -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ } -+ -+ if (controller->opened2 == 1) { -+ controller->opened2 = 0; -+ first_record_call = 1; -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ -+ if(clear_codec_record) -+ clear_codec_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ __i2s_disable(); -+ if(turn_off_codec) -+ turn_off_codec(); -+ abnormal_data_count = 0; -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+#endif -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ mdelay(2); -+ REG_DMAC_DMACKE(0) = 0x3f; -+ pop_dma_flag = 0; -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ jz_codec_config = 0; -+ -+ ramp_up_start = 0; -+ ramp_up_end = 0; -+ gain_up_start = 0; -+ gain_up_end = 0; -+ ramp_down_start = 0; -+ ramp_down_end = 0; -+ gain_down_start = 0; -+ gain_down_end = 0; -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ -+ controller->opened1 = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ for(i=0;i < 64;i++) { -+ save_last_samples[i].left = 0; -+ save_last_samples[i].right = 0; -+ } -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ last_dma_buffer_id = 0; -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ -+ controller->opened2 = 1; -+ first_record_call = 1; -+ /* for ioctl */ -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ REG_AIC_FR |= (1 << 6); -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if(set_codec_replay) -+ set_codec_replay(); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ abnormal_data_count = 0; -+ if(set_codec_record) -+ set_codec_record(); -+ } -+ -+#if defined(CONFIG_I2S_DLV) -+ __aic_reset(); -+ -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ __aic_flush_fifo(); -+#endif -+ -+ __i2s_enable(); -+ -+#if defined(CONFIG_I2S_DLV) -+ if (file->f_mode & FMODE_WRITE) { -+ -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ ramp_up_start = jiffies; -+ /*while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RCR = 0x1; -+ while (!(REG_RTC_RCR & RTC_RCR_WRDY)); -+ REG_RTC_RGR = 1;*/ -+ sleep_on(&pop_wait_queue); -+ //ramp_up_end = jiffies; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ } else if (file->f_mode & FMODE_READ) { -+ if (jz_mic_only) -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ else -+ write_codec_file_bit(5, 0, 7);//SB_DAC->0 -+ mdelay(500); -+ } -+ -+#endif -+ -+ return 0; -+} -+ -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ count_info cinfo; -+ audio_buf_info abinfo; -+ int id, i; -+ -+ val = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+#if 0 -+ jz_audio_reset(); -+ __i2s_disable_replay(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_record(); -+ __i2s_disable_transmit_dma(); -+#endif -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ return drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ /* set smaple rate */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ -+ return 0; -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(jz_audio_fragsize / jz_audio_b, (int *)arg); -+ return put_user(jz_audio_fragsize, (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ case SNDCTL_DSP_SETFMT: -+ /* Select sample format */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else { -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ } -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ jz_audio_set_channels(controller->dev_audio, val); -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF); -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 1!\n"); -+ -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ /* unused fragment amount */ -+ abinfo.fragments = jz_audio_fragments; -+ /* amount of fragments */ -+ abinfo.fragstotal = jz_audio_fragstotal; -+ /* fragment size in bytes */ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETOSPACE : channels is wrong 2!\n"); -+ -+ /* write size count without blocking in bytes */ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ { -+ int i, bytes = 0; -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ if (jz_audio_channels == 2) -+ bytes /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ bytes /= 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 1!\n"); -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ -+ if (jz_audio_channels == 2) -+ abinfo.fragsize = jz_audio_fragsize / jz_audio_b; -+ else if (jz_audio_channels == 1) -+ abinfo.fragsize = jz_audio_fragsize / 4; -+ else -+ printk("SNDCTL_DSP_GETISPACE : channels is wrong 2!\n"); -+ -+ abinfo.bytes = bytes; -+ -+ return copy_to_user((void *)arg, &abinfo, -+ sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ -+ return put_user(val, (int *)arg); -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (jz_audio_channels == 2) -+ unfinish /= jz_audio_b; -+ else if (jz_audio_channels == 1) -+ unfinish /= 4; -+ else -+ printk("SNDCTL_DSP_GETODELAY : channels is wrong !\n"); -+ -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ unsigned long flags; -+ unsigned int mask = 0; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ unsigned long flags; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ copy_count = jz_audio_fragsize / 4; -+ -+ left_count = count; -+ if (first_record_call) { -+ first_record_call = 0; -+ audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ -+ spin_unlock(&controller->lock); -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+ audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp2+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count * 4; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp2+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextIn += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count = 0; -+ unsigned int flags; -+ struct jz_i2s_controller_info *controller = (struct jz_i2s_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ if(set_replay_hp_or_speaker) -+ set_replay_hp_or_speaker(); -+ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if (jz_audio_channels == 2) -+ copy_count = jz_audio_fragsize / jz_audio_b; -+ else if(jz_audio_channels == 1) -+ copy_count = jz_audio_fragsize / 4; -+ left_count = count; -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+ audio_write_back: -+ /*if (file->f_flags & O_NONBLOCK) -+ udelay(2);*/ -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((signed long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); -+ dma_cache_wback_inv(*(out_dma_buf + id), -+ *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut += ret; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ last_dma_buffer_id = id; -+ if (jz_codec_config == 0) { -+ write_codec_file_bit(1, 0, 5); -+ gain_up_start = jiffies; -+ sleep_on(&pop_wait_queue); -+ //gain_up_end = jiffies; -+ jz_codec_config = 1; -+ //SB_ADC->1 -+ //write_codec_file_bit(5, 1, 4); -+ //while(1); -+ } -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+#if defined(CONFIG_I2S_ICODEC) -+static void write_mute_to_dma_buffer(signed long l_sample, signed long r_sample) -+{ -+ int i,step_len; -+ unsigned long *pop_buf = (unsigned long*)pop_turn_onoff_buf; -+ unsigned int sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ unsigned long l_sample_count,r_sample_count,sample_count; -+ struct jz_i2s_controller_info *controller = i2s_controller; -+ signed int left_sam=0,right_sam=0,l_val,r_val; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ left_sam = (signed int)l_sample; -+ right_sam = (signed int)r_sample; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+ -+ if(left_sam == 0 && right_sam == 0) -+ return; -+ -+ switch (sample_oss) { -+ case 0x0: -+ break; -+ case 0x1: -+ step_len = jz_audio_speed / 10 * 3; -+ step_len = step_len / 2; -+ step_len = 0x7fff / step_len + 1; -+ -+ l_sample_count = 0; -+ l_val = left_sam; -+ -+ while(1) { -+ if(l_val > 0) { -+ if(l_val >= step_len) { -+ l_val -= step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val < 0) { -+ if(l_val <= -step_len) { -+ l_val += step_len; -+ l_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(l_val == 0) -+ break; -+ } -+ -+ r_sample_count = 0; -+ r_val = right_sam; -+ while(1) { -+ if(r_val > 0) { -+ if(r_val >= step_len) { -+ r_val -= step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val < 0) { -+ if(r_val <= -step_len) { -+ r_val += step_len; -+ r_sample_count ++; -+ } else -+ break; -+ } -+ -+ if(r_val == 0) -+ break; -+ } -+ /* fill up */ -+ if(l_sample_count > r_sample_count) -+ sample_count = l_sample_count; -+ else -+ sample_count = r_sample_count; -+ -+ l_val = left_sam; -+ r_val = right_sam; -+ for(i=0;i <= sample_count;i++) { -+ -+ *pop_buf = (unsigned long)l_val; -+ pop_buf ++; -+ -+ if(l_val > step_len) -+ l_val -= step_len; -+ else if(l_val < -step_len) -+ l_val += step_len; -+ else if(l_val >= -step_len && l_val <= step_len) -+ l_val = 0; -+ -+ *pop_buf = (unsigned long)r_val; -+ pop_buf ++; -+ if(r_val > step_len) -+ r_val -= step_len; -+ else if(r_val < -step_len) -+ r_val += step_len; -+ else if(r_val >= -step_len && r_val <= step_len) -+ r_val = 0; -+ } -+ -+ *pop_buf = 0; -+ pop_buf ++; -+ *pop_buf = 0; -+ -+ pop_buf ++; -+ sample_count += 2; -+ dma_cache_wback_inv(pop_turn_onoff_buf, sample_count*8); -+ -+ pop_dma_flag = 1; -+ audio_start_dma(controller->dma1,controller,pop_turn_onoff_pbuf,sample_count*8,DMA_MODE_WRITE); -+ sleep_on(&pop_wait_queue); -+ pop_dma_flag = 0; -+ break; -+ case 0x2: -+ break; -+ case 0x3: -+ break; -+ case 0x4: -+ break; -+ } -+} -+#endif -diff -urN linux-2.6.24.7.old/sound/oss/jz_pcm_tlv320aic1106_dma.c linux-2.6.24.7/sound/oss/jz_pcm_tlv320aic1106_dma.c ---- linux-2.6.24.7.old/sound/oss/jz_pcm_tlv320aic1106_dma.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jz_pcm_tlv320aic1106_dma.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,1839 @@ -+/* -+ * linux/drivers/sound/jz_pcm_tlv320aic1106.c -+ * -+ * JzSOC On-Chip PCM audio driver. -+ * -+ * Copyright (C) 2005 by Ingenic Corp. -+ * -+ * 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. -+ * -+ * Because the normal application of AUDIO devices are focused on Little_endian, -+ * then we only perform the little endian data format in driver. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "sound_config.h" -+ -+#define NR_PCM 2 -+#define MAXDELAY 50000 -+#define JZCODEC_RW_BUFFER_SIZE 4 -+#define JZCODEC_RW_BUFFER_TOTAL 3 -+#define JZCODEC_USER_BUFFER 6 -+ -+#define MODE_is_8 0 // 1 is 8 bits, and 0 is 16 bits -+ -+static int jz_audio_rate; -+static char jz_audio_format; -+static char jz_audio_volume; -+static char jz_audio_channels; -+static int jz_audio_fragments;//unused fragment amount -+static int jz_audio_fragstotal; -+static int jz_audio_fragsize; -+static int jz_audio_speed; -+static int jz_audio_dma_tran_count;//bytes count of one DMA transfer -+ -+static void jz_update_filler(int bits, int channels); -+static int Init_In_Out_queue(int fragstotal,int fragsize); -+static int Free_In_Out_queue(int fragstotal,int fragsize); -+static irqreturn_t jz_pcm_irq(int irqnr, void *ref); -+static irqreturn_t jz_pcm_replay_dma_irq(int irqnr, void *ref); -+static irqreturn_t jz_pcm_record_dma_irq(int irqnr, void *ref); -+static void (*replay_filler)(unsigned long src_start, int count, int id); -+static int (*record_filler)(unsigned long dst_start, int count, int id); -+static void dump_pcmc_reg(void); -+ -+static struct file_operations jz_pcm_audio_fops; -+static DECLARE_WAIT_QUEUE_HEAD (rx_wait_queue); -+static DECLARE_WAIT_QUEUE_HEAD (tx_wait_queue); -+ -+struct jz_pcm_controller_info { -+ int io_base; -+ int dma1; /* play */ -+ int dma2; /* record */ -+ char *name; -+ int dev_audio; -+ struct pcm_codec *pcm_codec[NR_PCM]; -+ int opened1; -+ int opened2; -+ unsigned char *tmp1; /* tmp buffer for sample conversions */ -+ unsigned char *tmp2; -+ spinlock_t lock; -+ spinlock_t ioctllock; -+ -+ wait_queue_head_t dac_wait; -+ wait_queue_head_t adc_wait; -+ int nextIn; // byte index to next-in to DMA buffer -+ int nextOut; // byte index to next-out from DMA buffer -+ int count; // current byte count in DMA buffer -+ int finish; // current transfered byte count in DMA buffer -+ unsigned long total_bytes; // total bytes written or read -+ unsigned long blocks; -+ unsigned long error; // over/underrun -+}; -+static struct jz_pcm_controller_info *pcm_controller = NULL; -+ -+struct pcm_codec { -+ /* PCM controller connected with */ -+ void *private_data; -+ char *name; -+ int id; -+ int dev_mixer; -+ /* controller specific lower leverl pcm accessing routines */ -+ u16 (*codec_read) (u8 reg);//the function accessing Codec REGs -+ void (*codec_write) (u8 reg, u16 val); -+ /* Wait for codec-ready. Ok to sleep here. */ -+ void (*codec_wait) (struct pcm_codec *codec); -+ /* OSS mixer masks */ -+ int modcnt; -+ int supported_mixers; -+ int stereo_mixers; -+ int record_sources; -+ int bit_resolution; -+ /* OSS mixer interface */ -+ int (*read_mixer) (struct pcm_codec *codec, int oss_channel); -+ void (*write_mixer)(struct pcm_codec *codec, int oss_channel, -+ unsigned int left, unsigned int right); -+ int (*recmask_io) (struct pcm_codec *codec, int rw, int mask); -+ int (*mixer_ioctl)(struct pcm_codec *codec, unsigned int cmd, unsigned long arg); -+ /* saved OSS mixer states */ -+ unsigned int mixer_state[SOUND_MIXER_NRDEVICES]; -+}; -+ -+typedef struct buffer_queue_s { -+ int count; -+ int *id; -+ int lock; -+} buffer_queue_t; -+ -+static unsigned long *out_dma_buf = NULL; -+static unsigned long *out_dma_pbuf = NULL; -+static unsigned long *out_dma_buf_data_count = NULL; -+static unsigned long *in_dma_buf = NULL; -+static unsigned long *in_dma_pbuf = NULL; -+static unsigned long *in_dma_buf_data_count = NULL; -+ -+static buffer_queue_t out_empty_queue; -+static buffer_queue_t out_full_queue; -+static buffer_queue_t out_busy_queue; -+static buffer_queue_t in_empty_queue; -+static buffer_queue_t in_full_queue; -+static buffer_queue_t in_busy_queue; -+static int first_record_call = 0; -+ -+static inline int get_buffer_id(struct buffer_queue_s *q) -+{ -+ int r, i; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ if (q->count == 0) { -+ spin_unlock_irqrestore(&q->lock, flags); -+ return -1; -+ } -+ r = *(q->id + 0); -+ for (i=0;i < q->count-1;i++) -+ *(q->id + i) = *(q->id + (i+1)); -+ q->count --; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void put_buffer_id(struct buffer_queue_s *q, int id) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ *(q->id + q->count) = id; -+ q->count ++; -+ spin_unlock_irqrestore(&q->lock, flags); -+} -+ -+static inline int elements_in_queue(struct buffer_queue_s *q) -+{ -+ int r; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&q->lock, flags); -+ r = q->count; -+ spin_unlock_irqrestore(&q->lock, flags); -+ -+ return r; -+} -+ -+static inline void audio_start_dma(int chan, void *dev_id, unsigned long phyaddr,int count, int mode) -+{ -+ unsigned long flags; -+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; -+ -+ //for DSP_GETOPTR -+ //spin_lock_irqsave(&controller->ioctllock, flags); -+ spin_lock(&controller->ioctllock); -+ jz_audio_dma_tran_count = count; -+ //spin_unlock_irqrestore(&controller->ioctllock, flags); -+ spin_unlock(&controller->ioctllock); -+ flags = claim_dma_lock(); -+ __dmac_disable_module(0);//!!!!!!!!! -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ set_dma_mode(chan, mode); -+#if MODE_is_8 -+ __dmac_channel_set_src_port_width(chan, 8); -+ __dmac_channel_set_dest_port_width(chan, 8); -+ __dmac_channel_set_transfer_unit_8bit(chan); -+#else -+ __dmac_channel_set_src_port_width(chan, 16); -+ __dmac_channel_set_dest_port_width(chan, 16); -+ __dmac_channel_set_transfer_unit_16bit(chan); -+#endif -+ -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ __dmac_enable_module(0); -+ release_dma_lock(flags); -+#if 0 -+ //for DSP_GETOPTR on FPGA -+ struct jz_dma_chan *tmpchan = &jz_dma_table[1]; -+ -+ spin_lock(&controller->ioctllock); -+ jz_audio_dma_tran_count = count; -+ spin_unlock(&controller->ioctllock); -+ flags = claim_dma_lock(); -+ disable_dma(chan); -+ clear_dma_ff(chan); -+ set_dma_mode(chan, mode); -+#if MODE_is_8 -+ __dmac_channel_set_src_port_width(chan, 8); -+ __dmac_channel_set_dest_port_width(chan, 8); -+ __dmac_channel_set_transfer_unit_8bit(chan); -+#else -+ __dmac_channel_set_src_port_width(chan, 16); -+ __dmac_channel_set_dest_port_width(chan, 16); -+ __dmac_channel_set_transfer_unit_16bit(chan); -+#endif -+ set_dma_addr(chan, phyaddr); -+ if (count == 0) { -+ count++; -+ printk("JzSOC DMA controller can't set dma 0 count!\n"); -+ } -+ set_dma_count(chan, count); -+ enable_dma(chan); -+ release_dma_lock(flags); -+#if 0 -+ __pcm_enable_tfs_intr(); -+ __pcm_enable_tur_intr(); -+ __pcm_enable_rfs_intr(); -+ __pcm_enable_ror_intr(); -+#endif -+#endif -+} -+ -+static irqreturn_t jz_pcm_record_dma_irq(int irq, void *dev_id) -+{ -+ int id1, id2; -+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; -+ int dma = controller->dma2; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ //for DSP_GETIPTR -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock(&controller->ioctllock); -+ id1 = get_buffer_id(&in_busy_queue); -+ put_buffer_id(&in_full_queue, id1); -+ -+ wake_up(&rx_wait_queue); -+ wake_up(&controller->adc_wait); -+ if ((id2 = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id2); -+ *(in_dma_buf_data_count + id2) = *(in_dma_buf_data_count + id1); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id2), *(in_dma_buf_data_count + id2)); -+ audio_start_dma(dma,dev_id, -+ *(in_dma_pbuf + id2), -+ *(in_dma_buf_data_count + id2), -+ DMA_MODE_READ); -+ } else -+ in_busy_queue.count = 0; -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_pcm_irq(int irq, void *dev_id) -+{ -+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; -+ printk("pcm interrupt REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t jz_pcm_replay_dma_irq(int irq, void *dev_id) -+{ -+ int id; -+ unsigned long flags; -+ struct jz_pcm_controller_info * controller = (struct jz_pcm_controller_info *) dev_id; -+ int dma = controller->dma1; -+ -+ disable_dma(dma); -+ if (__dmac_channel_address_error_detected(dma)) { -+ printk(KERN_DEBUG "%s: DMAC address error.\n", __FUNCTION__); -+ __dmac_channel_clear_address_error(dma); -+ } -+ if (__dmac_channel_transmit_end_detected(dma)) { -+ __dmac_channel_clear_transmit_end(dma); -+ //for DSP_GETOPTR -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->total_bytes += jz_audio_dma_tran_count; -+ controller->blocks ++; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ if ((id = get_buffer_id(&out_busy_queue)) < 0) -+ printk(KERN_DEBUG "Strange DMA finish interrupt for PCM module\n"); -+ put_buffer_id(&out_empty_queue, id); -+ if ((id = get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); //very busy -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(dma, dev_id, *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ } -+ } else -+ out_busy_queue.count = 0; -+ -+ if (elements_in_queue(&out_empty_queue) > 0) { -+ wake_up(&tx_wait_queue); -+ wake_up(&controller->dac_wait); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int Init_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ // recording -+ in_empty_queue.count = fragstotal; -+ in_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf) -+ goto all_mem_err; -+ in_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_pbuf) -+ goto all_mem_err; -+ in_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!in_dma_buf_data_count) -+ goto all_mem_err; -+ in_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_empty_queue.id) -+ goto all_mem_err; -+ in_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_full_queue.id) -+ goto all_mem_err; -+ in_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!in_busy_queue.id) -+ goto all_mem_err; -+ -+ for (i=0;i < fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ for (i = 0; i < fragstotal; i++) { -+ *(in_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(in_dma_buf + i) == 0) -+ goto mem_failed_in; -+ *(in_dma_pbuf + i) = virt_to_phys((void *)(*(in_dma_buf + i))); -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ } -+ -+ //playing -+ out_empty_queue.count = fragstotal; -+ out_dma_buf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_buf) -+ goto all_mem_err; -+ out_dma_pbuf = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ if (!out_dma_pbuf) -+ goto all_mem_err; -+ out_dma_buf_data_count = (unsigned long *)kmalloc(sizeof(unsigned long) * fragstotal, GFP_KERNEL); -+ -+ if (!out_dma_buf_data_count) -+ goto all_mem_err; -+ out_empty_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_empty_queue.id) -+ goto all_mem_err; -+ out_full_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_full_queue.id) -+ goto all_mem_err; -+ out_busy_queue.id = (int *)kmalloc(sizeof(int) * fragstotal, GFP_KERNEL); -+ if (!out_busy_queue.id) -+ goto all_mem_err; -+ for (i=0;i < fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /*alloc DMA buffer*/ -+ for (i = 0; i < fragstotal; i++) { -+ *(out_dma_buf + i) = __get_free_pages(GFP_KERNEL | GFP_DMA, get_order(fragsize)); -+ if (*(out_dma_buf + i) == 0) { -+ printk(" can't allocate required DMA(OUT) buffers.\n"); -+ goto mem_failed_out; -+ } -+ *(out_dma_pbuf + i) = virt_to_phys((void *)(*(out_dma_buf + i))); -+ } -+ -+ return 1; -+all_mem_err: -+ printk("error:allocate memory occur error 1!\n"); -+ return 0; -+mem_failed_out: -+ printk("error:allocate memory occur error 2!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ } -+ -+ return 0; -+mem_failed_in: -+ printk("error:allocate memory occur error 3!\n"); -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ return 0; -+} -+ -+static int Free_In_Out_queue(int fragstotal,int fragsize) -+{ -+ int i; -+ //playing -+ if(out_dma_buf != NULL) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(out_dma_buf + i)) -+ free_pages(*(out_dma_buf + i), get_order(fragsize)); -+ *(out_dma_buf + i) = 0; //release page error -+ } -+ kfree(out_dma_buf); -+ out_dma_buf = NULL; -+ } -+ if(out_dma_pbuf) { -+ kfree(out_dma_pbuf); -+ out_dma_pbuf = NULL; -+ } -+ if(out_dma_buf_data_count) { -+ kfree(out_dma_buf_data_count); -+ out_dma_buf_data_count = NULL; -+ } -+ if(out_empty_queue.id) { -+ kfree(out_empty_queue.id); -+ out_empty_queue.id = NULL; -+ } -+ if(out_full_queue.id) { -+ kfree(out_full_queue.id); -+ out_full_queue.id = NULL; -+ } -+ if(out_busy_queue.id) { -+ kfree(out_busy_queue.id); -+ out_busy_queue.id = NULL; -+ } -+ out_empty_queue.count = fragstotal; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ -+ // recording -+ if(in_dma_buf) { -+ for (i = 0; i < fragstotal; i++) { -+ if(*(in_dma_buf + i)) { -+ dma_cache_wback_inv(*(in_dma_buf + i), fragsize); -+ free_pages(*(in_dma_buf + i), get_order(fragsize)); -+ } -+ *(in_dma_buf + i) = 0; //release page error -+ } -+ kfree(in_dma_buf); -+ in_dma_buf = NULL; -+ } -+ if(in_dma_pbuf) { -+ kfree(in_dma_pbuf); -+ in_dma_pbuf = NULL; -+ } -+ if(in_dma_buf_data_count) { -+ kfree(in_dma_buf_data_count); -+ in_dma_buf_data_count = NULL; -+ } -+ if(in_empty_queue.id) { -+ kfree(in_empty_queue.id); -+ in_empty_queue.id = NULL; -+ } -+ if(in_full_queue.id) { -+ kfree(in_full_queue.id); -+ in_full_queue.id = NULL; -+ } -+ if(in_busy_queue.id) { -+ kfree(in_busy_queue.id); -+ in_busy_queue.id = NULL; -+ } -+ -+ in_empty_queue.count = fragstotal; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ -+ return 1; -+} -+ -+static int jz_audio_set_speed(int dev, int rate) -+{ -+ /* 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 */ -+ long codec_speed; -+ long speed = 0; -+ -+ jz_audio_speed = rate; -+ if (rate > 48000) -+ rate = 48000; -+ if (rate < 8000) -+ rate = 8000; -+ jz_audio_rate = rate; -+ -+ /*switch (rate) { -+ case 8000: -+ speed = 0; -+ break; -+ case 11025: -+ speed = 1; -+ break; -+ case 12000: -+ speed = 2; -+ break; -+ case 16000: -+ speed = 3; -+ break; -+ case 22050: -+ speed = 4; -+ break; -+ case 24000: -+ speed = 5; -+ break; -+ case 32000: -+ speed = 6; -+ break; -+ case 44100: -+ speed = 7; -+ break; -+ case 48000: -+ speed = 8; -+ break; -+ default: -+ break; -+ } -+ printk("set PCMIN or PCMOUT speed.\n"); -+ __pcm_set_clk_rate(speed); -+ __pcm_set_sync_rate(256);*/ -+ -+ return jz_audio_rate; -+} -+ -+ -+static int record_fill_1x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+ while (count > 0) { -+ *dp = *s; -+ dp ++; -+ s++; -+ count --; -+ cnt ++; -+ } -+ -+ return cnt; -+} -+ -+static int record_fill_2x8_u(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ volatile unsigned char *s = (unsigned char*)(*(in_dma_buf + id)); -+ volatile unsigned char *dp = (unsigned char*)dst_start; -+ -+#if 1 -+ while (count > 0) { -+ *dp = *s; -+ s ++; -+ dp ++; -+ count --; -+ cnt ++; -+ } -+#else -+ while (count > 0) { -+ *dp = *s; -+ s += 2; //skip right sample -+ dp ++; -+ count -= 2; -+ cnt ++; -+ } -+#endif -+ return cnt; -+} -+ -+static int record_fill_1x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short d1; -+ unsigned short *s = (unsigned short*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+ while (count > 0) { -+ *dp = *s; -+ s ++; -+ dp ++; -+ count -= 2; -+ cnt += 2; -+ } -+ -+ return cnt; -+} -+ -+static int record_fill_2x16_s(unsigned long dst_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short *s = (unsigned short*)(*(in_dma_buf + id)); -+ unsigned short *dp = (unsigned short *)dst_start; -+ -+#if 1 -+ while (count > 0) { -+ *dp = *s; -+ s ++; -+ dp ++; -+ count -= 2; -+ cnt += 2; -+ } -+#else -+ while (count > 0) { -+ *dp = *s; -+ s += 2; //skip right sample -+ dp ++; -+ count -= 4; -+ cnt += 2;/* count in byte */ -+ } -+#endif -+ -+ return cnt; -+} -+ -+static void replay_fill_1x8_u(unsigned long src_start, int count, int id) -+{ -+#if 0 -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); -+ -+ *(out_dma_buf_data_count + id) = count; -+ while (count > 0) { -+ *dp = *s; -+ dp ++; -+ s ++; -+ count --; -+ } -+#else -+ volatile u8 *s = (u8 *)src_start; -+ volatile u8 *dp = (u8 *)(*(out_dma_buf + id)); -+ -+ *(out_dma_buf_data_count + id) = count; -+ while (count > 0) { -+ *dp = *s; -+ dp ++; -+ s ++; -+ count --; -+ } -+#endif -+} -+ -+static void replay_fill_2x8_u(unsigned long src_start, int count, int id) -+{ -+ volatile unsigned char *s = (unsigned char *)src_start; -+ volatile unsigned char *dp = (unsigned char *)(*(out_dma_buf + id)); -+ -+#if 1 -+ *(out_dma_buf_data_count + id) = count; -+ while (count > 0) { -+ *dp = *s; -+ dp ++; -+ s ++; -+ count --; -+ } -+#else -+ while (count > 0) { -+ *dp = *s; -+ s += 2; //skip right sample -+ dp ++; -+ count -= 2; -+ cnt ++; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+ -+ -+static void replay_fill_1x16_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short d1, l1; -+ signed short sam_to; -+ volatile unsigned short *s = (unsigned short *)src_start; -+ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id)); -+ -+ while (count > 0) { -+ d1 = *s; -+ -+ sam_to = (signed short)d1; -+ if (sam_to >= 0) { -+ sam_to = 0xfff * sam_to / 0x7fff; -+ } else { -+ sam_to = 0 - sam_to; -+ sam_to = 0xfff * sam_to / 0x7fff; -+ sam_to = 0 - sam_to; -+ } -+ d1 = (unsigned short)sam_to; -+ d1 = d1 << 3; -+ l1 = d1 | jz_audio_volume; -+ -+ *dp = l1; -+ s ++; -+ dp ++; -+ count -= 2; -+ cnt += 2 ; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+} -+ -+static void replay_fill_2x16_s(unsigned long src_start, int count, int id) -+{ -+ int cnt = 0; -+ unsigned short d1, l1; -+ volatile unsigned short *s = (unsigned short *)src_start; -+ volatile unsigned short *dp = (unsigned short*)(*(out_dma_buf + id)); -+ -+#if 1 -+ while (count > 0) { -+ d1 = *s; -+ l1 = (d1 & 0xfff8) | jz_audio_volume; -+ *dp = l1; -+ s ++; -+ dp ++; -+ count -= 2; -+ cnt += 2 ; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+#else -+ while (count > 0) { -+ d1 = *s; -+ l1 = (d1 & 0xfff8) | jz_audio_volume; -+ *dp = l1; -+ s += 2; //skip right sample -+ dp ++; -+ count -= 4; -+ cnt += 2; -+ } -+ *(out_dma_buf_data_count + id) = cnt; -+#endif -+} -+ -+static unsigned int jz_audio_set_format(int dev, unsigned int fmt) -+{ -+ switch (fmt) { -+ case AFMT_U8: -+ case AFMT_S16_LE: -+ jz_audio_format = fmt; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ case AFMT_QUERY: -+ break; -+ } -+ -+ return jz_audio_format; -+} -+ -+static short jz_audio_set_channels(int dev, short channels) -+{ -+ switch (channels) { -+ case 1: -+ case 2: -+ jz_audio_channels = channels; -+ jz_update_filler(jz_audio_format, jz_audio_channels); -+ break; -+ default: -+ printk("channel number is wrong. %d\n",__LINE__); -+ } -+ -+ return jz_audio_channels; -+} -+ -+static void init_codec(void) -+{ -+ printk("set PCM codec RESET pin on LOW, while MCLK occur.\n"); -+ printk("set LINSEL on LOW(8bits) or HIGH(13bits+3bits for PCMOUT gain).\n"); -+} -+ -+static void jz_audio_reset(void) -+{ -+ __pcm_flush_fifo(); -+ __pcm_disable_txfifo(); -+ __pcm_disable_rxfifo(); -+ __pcm_set_transmit_trigger(7); -+ __pcm_set_receive_trigger(7); -+ __pcm_omsb_next_sync(); -+ __pcm_imsb_next_sync(); -+#if MODE_is_8 -+ __pcm_set_iss(8);//8bits decided by LINSEL -+ __pcm_set_oss(8);//8bits decided by LINSEL -+#else -+ __pcm_set_iss(16);//16bits decided by LINSEL -+ __pcm_set_oss(16); -+#endif -+ __pcm_disable_tfs_intr(); -+ __pcm_disable_tur_intr(); -+ __pcm_disable_rfs_intr(); -+ __pcm_disable_ror_intr(); -+ -+ __pcm_disable_receive_dma(); -+ __pcm_disable_transmit_dma(); -+ -+ //init_codec(); -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file); -+static int jz_audio_open(struct inode *inode, struct file *file); -+static int jz_audio_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg); -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait); -+static ssize_t jz_audio_write(struct file *file, const char *buffer,size_t count, loff_t *ppos); -+static ssize_t jz_audio_read(struct file *file, char *buffer,size_t count, loff_t *ppos); -+ -+/* static struct file_operations jz_pcm_audio_fops */ -+static struct file_operations jz_pcm_audio_fops = -+{ -+ owner: THIS_MODULE, -+ open: jz_audio_open, -+ release: jz_audio_release, -+ write: jz_audio_write, -+ read: jz_audio_read, -+ poll: jz_audio_poll, -+ ioctl: jz_audio_ioctl -+}; -+ -+static int jz_pcm_open_mixdev(struct inode *inode, struct file *file) -+{ -+ int i; -+ int minor = MINOR(inode->i_rdev); -+ struct jz_pcm_controller_info *controller = pcm_controller; -+ -+ for (i = 0; i < NR_PCM; i++) -+ if (controller->pcm_codec[i] != NULL && controller->pcm_codec[i]->dev_mixer == minor) -+ goto match; -+ -+ if (!controller) -+ return -ENODEV; -+match: -+ file->private_data = controller->pcm_codec[i]; -+ -+ return 0; -+} -+ -+static int jz_pcm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ struct pcm_codec *codec = (struct pcm_codec *)file->private_data; -+ return codec->mixer_ioctl(codec, cmd, arg); -+} -+ -+static loff_t jz_pcm_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+static struct file_operations jz_pcm_mixer_fops = -+{ -+ owner: THIS_MODULE, -+ llseek: jz_pcm_llseek, -+ ioctl: jz_pcm_ioctl_mixdev, -+ open: jz_pcm_open_mixdev, -+}; -+ -+static int pcm_mixer_ioctl(struct pcm_codec *codec, unsigned int cmd, unsigned long arg) -+{ -+ int ret; -+ long val = 0; -+ -+ switch (cmd) { -+ case SOUND_MIXER_READ_STEREODEVS: -+ return put_user(0, (long *) arg); -+ case SOUND_MIXER_READ_CAPS: -+ val = SOUND_CAP_EXCL_INPUT; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_READ_DEVMASK: -+ break; -+ case SOUND_MIXER_READ_RECMASK: -+ break; -+ case SOUND_MIXER_READ_RECSRC: -+ break; -+ case SOUND_MIXER_WRITE_VOLUME: -+ ret = get_user(val, (long *) arg); -+ if (ret) -+ return ret; -+ val = val & 0xff; -+ if(val < 0) -+ val = 0; -+ if(val > 100) -+ val = 100; -+ if (val == 100) { -+ dump_pcmc_reg(); -+ return 100; -+ } -+ val = val / 10; -+ switch (val) { -+ case 0: -+ case 1: -+ jz_audio_volume = 7; -+ break; -+ case 2: -+ jz_audio_volume = 6; -+ break; -+ case 3: -+ jz_audio_volume = 5; -+ break; -+ case 4: -+ jz_audio_volume = 4; -+ break; -+ case 5: -+ jz_audio_volume = 3; -+ break; -+ case 6: -+ jz_audio_volume = 2; -+ break; -+ case 7: -+ case 8: -+ jz_audio_volume = 1; -+ break; -+ case 9: -+ case 10: -+ jz_audio_volume = 0; -+ break; -+ } -+ return 0; -+ case SOUND_MIXER_READ_VOLUME: -+ val = jz_audio_volume; -+ ret = val << 8; -+ val = val | ret; -+ return put_user(val, (long *) arg); -+ case SOUND_MIXER_WRITE_MIC: -+ printk("Can not justify Mic gain to the PCM codec.!\n"); -+ return -ENOSYS; -+ -+ case SOUND_MIXER_READ_MIC: -+ printk("Can not justify Mic gain to the PCM codec.!\n"); -+ return -ENOSYS; -+ default: -+ return -ENOSYS; -+ } -+ -+ return 0; -+} -+ -+ -+int pcm_probe_codec(struct pcm_codec *codec) -+{ -+ /* generic OSS to PCM wrapper */ -+ codec->mixer_ioctl = pcm_mixer_ioctl; -+ return 1; -+} -+ -+/* PCM codec initialisation. */ -+static int __init jz_pcm_codec_init(struct jz_pcm_controller_info *controller) -+{ -+ int num_pcm = 0; -+ struct pcm_codec *codec; -+ -+ for (num_pcm = 0; num_pcm < NR_PCM; num_pcm++) { -+ if ((codec = kmalloc(sizeof(struct pcm_codec),GFP_KERNEL)) == NULL) -+ return -ENOMEM; -+ memset(codec, 0, sizeof(struct pcm_codec)); -+ codec->private_data = controller; -+ codec->id = num_pcm; -+ -+ if (pcm_probe_codec(codec) == 0) -+ break; -+ if ((codec->dev_mixer = register_sound_mixer(&jz_pcm_mixer_fops, -1)) < 0) { -+ printk(KERN_ERR "Jz PCM: couldn't register mixer!\n"); -+ kfree(codec); -+ break; -+ } -+ controller->pcm_codec[num_pcm] = codec; -+ } -+ -+ return num_pcm; -+} -+ -+static void jz_update_filler(int format, int channels) -+{ -+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) -+ -+ switch (TYPE(format, channels)) { -+ default: -+ case TYPE(AFMT_U8, 1): -+ replay_filler = replay_fill_1x8_u; -+ record_filler = record_fill_1x8_u; -+ break; -+ case TYPE(AFMT_U8, 2): -+ /*replay_filler = replay_fill_2x8_u; -+ record_filler = record_fill_2x8_u;*/ -+ printk("channel is 2. Line:%d\n",__LINE__); -+ break; -+ case TYPE(AFMT_S16_LE, 1): -+ replay_filler = replay_fill_1x16_s; -+ record_filler = record_fill_1x16_s; -+ break; -+ case TYPE(AFMT_S16_LE, 2): -+ /*replay_filler = replay_fill_2x16_s; -+ record_filler = record_fill_2x16_s;*/ -+ printk("channel is 2. Line:%d\n",__LINE__); -+ break; -+ } -+} -+ -+static void __init attach_jz_pcm(struct jz_pcm_controller_info *controller) -+{ -+ char *name; -+ int adev;//No of Audio device. -+ int err; -+ -+ name = controller->name; -+ /* register /dev/audio */ -+ adev = register_sound_dsp(&jz_pcm_audio_fops, -1); -+ if (adev < 0) -+ goto audio_failed; -+ /* initialize PCM codec and register /dev/mixer */ -+ if (jz_pcm_codec_init(controller) <= 0) -+ goto mixer_failed; -+ -+ controller->tmp1 = (void *)__get_free_pages(GFP_KERNEL, JZCODEC_USER_BUFFER); -+ if (!controller->tmp1) { -+ printk(KERN_ERR "%s: can't allocate tmp buffers.\n", controller->name); -+ goto tmp1_failed; -+ } -+ printk("DMA_ID_PCM_TX=0x%08x DMA_ID_PCM_RX=0x%08x\n",DMA_ID_PCM_TX ,DMA_ID_PCM_RX); -+ if ((controller->dma1 = jz_request_dma(DMA_ID_PCM_TX, "audio dac", jz_pcm_replay_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA DAC channel.\n", name); -+ goto dma1_failed; -+ } -+ if ((controller->dma2 = jz_request_dma(DMA_ID_PCM_RX, "audio adc", jz_pcm_record_dma_irq, IRQF_DISABLED, controller)) < 0) { -+ printk(KERN_ERR "%s: can't reqeust DMA ADC channel.\n", name); -+ goto dma2_failed; -+ } -+ printk("JzSOC On-Chip PCM controller registered (DAC: DMA(play):%d/IRQ%d,\n ADC: DMA(record):%d/IRQ%d)\n", controller->dma1, get_dma_done_irq(controller->dma1), controller->dma2, get_dma_done_irq(controller->dma2)); -+ -+ err = request_irq(IRQ_PCM, jz_pcm_irq, IRQF_DISABLED, "pcm irq", controller); -+ if (err < 0) -+ printk("can't allocate pcm irq.\n"); -+ controller->dev_audio = adev; -+ -+ return; -+dma2_failed: -+ jz_free_dma(controller->dma2); -+dma1_failed: -+ jz_free_dma(controller->dma1); -+tmp1_failed: -+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ -+mixer_failed: -+ unregister_sound_dsp(adev); -+audio_failed: -+ return; -+} -+ -+ -+static int __init probe_jz_pcm(struct jz_pcm_controller_info **controller) -+{ -+ if ((*controller = kmalloc(sizeof(struct jz_pcm_controller_info), -+ GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "Jz PCM Controller: out of memory.\n"); -+ return -ENOMEM; -+ } -+ -+ (*controller)->name = "Jz PCM controller"; -+ (*controller)->opened1 = 0; -+ (*controller)->opened2 = 0; -+ init_waitqueue_head(&(*controller)->adc_wait); -+ init_waitqueue_head(&(*controller)->dac_wait); -+ spin_lock_init(&(*controller)->lock); -+ init_waitqueue_head(&rx_wait_queue); -+ init_waitqueue_head(&tx_wait_queue); -+ -+ return 0; -+} -+ -+static void __exit unload_jz_pcm(struct jz_pcm_controller_info *controller) -+{ -+ int adev = controller->dev_audio; -+ -+ __pcm_reset(); -+ schedule_timeout(5); -+ __pcm_disable(); -+ __pcm_clk_disable(); -+ __pcm_flush_fifo(); -+ -+ controller->dev_audio = -1; -+ jz_free_dma(controller->dma1); -+ jz_free_dma(controller->dma2); -+ free_pages((unsigned long)controller->tmp1, JZCODEC_USER_BUFFER); -+ -+ if (adev >= 0) -+ unregister_sound_dsp(controller->dev_audio); -+} -+ -+static int __init init_jz_pcm(void) -+{ -+ int errno; -+ /* 24M OSC ---> CPCCR.ECS ---> PCMCDR.PCMS ---> cpm_pcm_sysclk(X) */ -+ long X = 12000000; //in Hz /* 6.144 MHz <= X <= 264.192 MHz */ -+ -+#if 0 -+ /* pcm_sys_clk is from PLL divsion */ -+ REG_CPM_PCMCDR = 0x8000001b; -+ REG_CPM_CPCCR |= 0x00400000; -+#endif -+ /* pcm_sys_clk is from external clock */ -+ /* reset codec GPF4 */ -+ __gpio_as_output(32 * 5 + 4); -+ __gpio_set_pin(32 * 5 + 4); -+ mdelay(1); -+ -+ __pcm_reset(); -+ schedule_timeout(5); -+ __pcm_clk_disable(); -+ -+ /* set CPM to output cpm-pcm-sysclk ,assume cpm-pcm-sysclk is X Hz */ -+ /* PCMCLK must be 2048000 Hz, it is 256 mutil of PCMSYNC */ -+ //__pcm_set_clk_rate(X, 2048000); -+ __pcm_set_clk_rate(X, 2000000); -+ /* PCMSYNC must be 8000 Hz. 2048000 / 256 = 8000 */ -+ __pcm_set_sync_rate(2048000, 8000); -+ //__pcm_set_sync_rate(2000000, 8000); -+ __pcm_set_sync_len(0); -+ -+ __pcm_flush_fifo(); -+ __pcm_disable_txfifo(); -+ __pcm_disable_rxfifo(); -+ __pcm_set_transmit_trigger(7); -+ __pcm_set_receive_trigger(7); -+ __pcm_omsb_next_sync(); -+ __pcm_imsb_next_sync(); -+ -+#if MODE_is_8 -+ __pcm_set_iss(8);//8bits decided by LINSEL -+ __pcm_set_oss(8); -+#else -+ __pcm_set_iss(16);//16bits decided by LINSEL -+ __pcm_set_oss(16); -+#endif -+ __pcm_set_valid_slot(1); -+ -+ __pcm_disable_tfs_intr(); -+ __pcm_disable_tur_intr(); -+ __pcm_disable_rfs_intr(); -+ __pcm_disable_ror_intr(); -+ -+ __pcm_disable_receive_dma(); -+ __pcm_disable_transmit_dma(); -+ -+ __pcm_last_sample(); -+ __pcm_as_master(); -+ -+ __pcm_enable(); -+ __pcm_clk_enable(); -+ -+ if ((errno = probe_jz_pcm(&pcm_controller)) < 0) -+ return errno; -+ attach_jz_pcm(pcm_controller); -+ -+ out_empty_queue.id = NULL; -+ out_full_queue.id = NULL; -+ out_busy_queue.id = NULL; -+ in_empty_queue.id = NULL; -+ in_full_queue.id = NULL; -+ in_busy_queue.id = NULL; -+ -+ jz_audio_fragsize = JZCODEC_RW_BUFFER_SIZE * PAGE_SIZE; -+ jz_audio_fragstotal = JZCODEC_RW_BUFFER_TOTAL ; -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ -+ __gpio_clear_pin(32 * 5 + 4); -+ udelay(100); -+ -+ __gpio_set_pin(32 * 5 + 4); -+ dump_pcmc_reg(); -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_jz_pcm(void) -+{ -+ unload_jz_pcm(pcm_controller); -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+} -+ -+module_init(init_jz_pcm); -+module_exit(cleanup_jz_pcm); -+ -+static int drain_adc(struct jz_pcm_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count, i=0; -+ -+ for (;;) { -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma2); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ -+ if (nonblock) -+ return -EBUSY; -+ } -+ -+ return 0; -+} -+static int drain_dac(struct jz_pcm_controller_info *ctrl, int nonblock) -+{ -+ unsigned long flags; -+ int count, ele, i=0; -+ -+ for (;;) { -+ if(!nonblock) {//blocked -+ if ( i < MAXDELAY ) { -+ udelay(10); -+ i++; -+ } else -+ break; -+ -+ ele = elements_in_queue(&out_full_queue); -+ if(ele <= 0) { -+ udelay(10); -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } else {//non-blocked -+ mdelay(100); -+ ele = elements_in_queue(&out_full_queue); -+ -+ if(ele <= 0) { -+ mdelay(100); -+ -+ spin_lock_irqsave(&ctrl->lock, flags); -+ count = get_dma_residue(ctrl->dma1); -+ spin_unlock_irqrestore(&ctrl->lock, flags); -+ if (count <= 0) -+ break; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static int jz_audio_release(struct inode *inode, struct file *file) -+{ -+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ if ( controller->opened1 == 1 ) { -+ __pcm_enable_transmit_dma(); -+ __pcm_enable_txfifo(); -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma1); -+ set_dma_count(controller->dma1, 0); -+ -+ __pcm_disable_transmit_dma(); -+ __pcm_disable_txfifo(); -+ -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ spin_unlock(&controller->ioctllock); -+ //__pcm_disable(); -+ controller->opened1 = 0; -+ } -+ -+ if ( controller->opened2 == 1 ) { -+ first_record_call = 1; -+ __pcm_enable_receive_dma(); -+ __pcm_enable_rxfifo(); -+ drain_adc(controller, file->f_flags & O_NONBLOCK); -+ disable_dma(controller->dma2); -+ set_dma_count(controller->dma2, 0); -+ __pcm_disable_receive_dma(); -+ __pcm_disable_rxfifo(); -+ -+ spin_lock(&controller->ioctllock); -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ spin_unlock(&controller->ioctllock); -+ //__pcm_disable(); -+ controller->opened2 = 0; -+ } -+ __pcm_disable_tfs_intr(); -+ __pcm_disable_tur_intr(); -+ __pcm_disable_rfs_intr(); -+ __pcm_disable_ror_intr(); -+ -+ return 0; -+} -+ -+static int jz_audio_open(struct inode *inode, struct file *file) -+{ -+ int i; -+ struct jz_pcm_controller_info *controller = pcm_controller; -+ -+ if (controller == NULL) -+ return -ENODEV; -+ -+ if (controller->opened1 == 1 || controller->opened2 == 1 ) { -+ printk("\naudio is busy!\n"); -+ return -EBUSY; -+ } -+ REG_DMAC_DMACKE(0) = 0x3f; -+ REG_DMAC_DMACKE(1) = 0x3f; -+ if (file->f_mode & FMODE_WRITE) { -+ if (controller->opened1 == 1) -+ return -EBUSY; -+ controller->opened1 = 1; -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextOut = 0; -+ -+ out_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(out_empty_queue.id + i) = i; -+ out_busy_queue.count = 0; -+ out_full_queue.count = 0; -+ /* set PCMOUT params */ -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (controller->opened2 == 1) -+ return -EBUSY; -+ controller->opened2 = 1; -+ first_record_call = 1; -+ //for ioctl -+ controller->total_bytes = 0; -+ jz_audio_dma_tran_count = 0; -+ controller->count = 0; -+ controller->finish = 0; -+ controller->blocks = 0; -+ controller->nextIn = 0; -+ in_empty_queue.count = jz_audio_fragstotal; -+ for (i=0;i < jz_audio_fragstotal;i++) -+ *(in_empty_queue.id + i) = i; -+ in_full_queue.count = 0; -+ in_busy_queue.count = 0; -+ /* set PCMIN params */ -+ } -+ -+ file->private_data = controller; -+ jz_audio_reset(); -+ __pcm_enable(); -+ -+ return 0; -+} -+ -+static int jz_audio_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int val,fullc,busyc,unfinish,newfragstotal,newfragsize; -+ unsigned int flags; -+ audio_buf_info abinfo; -+ int i, bytes, id; -+ count_info cinfo; -+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ -+ val = 0; -+ bytes = 0; -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ case SNDCTL_DSP_RESET: -+ return 0; -+ case SNDCTL_DSP_SYNC: -+ if (file->f_mode & FMODE_WRITE) -+ drain_dac(controller, file->f_flags & O_NONBLOCK); -+ return 0; -+ case SNDCTL_DSP_SPEED: -+ { -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ /* set smaple rate */ -+ if (val >= 0) -+ jz_audio_set_speed(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ } -+ case SNDCTL_DSP_STEREO: -+ /* set stereo or mono channel */ -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ -+ jz_audio_set_channels(controller->dev_audio, val ? 2 : 1); -+ return 0; -+ -+ case SNDCTL_DSP_GETBLKSIZE: -+ //return put_user(4*PAGE_SIZE, (int *)arg); -+ return put_user(jz_audio_fragsize , (int *)arg); -+ case SNDCTL_DSP_GETFMTS: -+ /* Returns a mask of supported sample format*/ -+ return put_user(AFMT_U8 | AFMT_S16_LE, (int *)arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ { -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ /* Select sample format */ -+ if (val != AFMT_QUERY) -+ jz_audio_set_format(controller->dev_audio,val); -+ else -+ if (file->f_mode & FMODE_READ) -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ else -+ val = (jz_audio_format == 16) ? AFMT_S16_LE : AFMT_U8; -+ return put_user(val, (int *)arg); -+ } -+ -+ case SNDCTL_DSP_CHANNELS: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ printk("%s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__); -+ jz_audio_set_channels(controller->dev_audio, val); -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_POST: -+ /* FIXME: the same as RESET ?? */ -+ return 0; -+ -+ case SNDCTL_DSP_SUBDIVIDE: -+ return 0; -+ -+ case SNDCTL_DSP_SETFRAGMENT: -+ get_user(val, (long *) arg); -+ newfragsize = 1 << (val & 0xFFFF);//16 least bits -+ -+ if (newfragsize < 4 * PAGE_SIZE) -+ newfragsize = 4 * PAGE_SIZE; -+ if (newfragsize > (16 * PAGE_SIZE)) //16 PAGE_SIZE -+ newfragsize = 16 * PAGE_SIZE; -+ -+ newfragstotal = (val >> 16) & 0x7FFF; -+ if (newfragstotal < 2) -+ newfragstotal = 2; -+ if (newfragstotal > 32) -+ newfragstotal = 32; -+ if((jz_audio_fragstotal == newfragstotal) && (jz_audio_fragsize == newfragsize)) -+ return 0; -+ Free_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(500); -+ jz_audio_fragstotal = newfragstotal; -+ jz_audio_fragsize = newfragsize; -+ -+ Init_In_Out_queue(jz_audio_fragstotal,jz_audio_fragsize); -+ mdelay(10); -+ -+ return 0; -+ case SNDCTL_DSP_GETCAPS: -+ return put_user(DSP_CAP_REALTIME|DSP_CAP_BATCH, (int *)arg); -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ case SNDCTL_DSP_SETDUPLEX: -+ return -EINVAL; -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ //unused fragment amount -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ jz_audio_fragments = elements_in_queue(&out_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -+ } -+ case SNDCTL_DSP_GETISPACE: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ bytes = 0; -+ //unused fragment amount -+ jz_audio_fragments = elements_in_queue(&in_empty_queue); -+ for (i = 0; i < jz_audio_fragments; i++) -+ bytes += jz_audio_fragsize; -+ -+ abinfo.fragments = jz_audio_fragments; -+ abinfo.fragstotal = jz_audio_fragstotal; -+ abinfo.fragsize = jz_audio_fragsize; -+ abinfo.bytes = bytes; -+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && in_dma_buf) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && out_dma_buf) -+ val |= PCM_ENABLE_OUTPUT; -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ return 0; -+ case SNDCTL_DSP_GETIPTR: -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextIn; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETOPTR: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ cinfo.bytes = controller->total_bytes; -+ cinfo.blocks = controller->blocks; -+ cinfo.ptr = controller->nextOut; -+ controller->blocks = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)); -+ case SNDCTL_DSP_GETODELAY: -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ unfinish = 0; -+ fullc = elements_in_queue(&out_full_queue); -+ busyc = elements_in_queue(&out_busy_queue); -+ for(i = 0;i < fullc ;i ++) { -+ id = *(out_full_queue.id + i); -+ unfinish += *(out_dma_buf_data_count + id); -+ } -+ for(i = 0;i < busyc ;i ++) { -+ id = *(out_busy_queue.id + i); -+ unfinish += get_dma_residue(controller->dma1); -+ } -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ return put_user(unfinish, (int *) arg); -+ case SOUND_PCM_READ_RATE: -+ return put_user(jz_audio_rate, (int *)arg); -+ case SOUND_PCM_READ_CHANNELS: -+ return put_user(jz_audio_channels, (int *)arg); -+ case SOUND_PCM_READ_BITS: -+ return put_user((jz_audio_format & (AFMT_S8 | AFMT_U8)) ? 8 : 16, (int *)arg); -+ case SNDCTL_DSP_MAPINBUF: -+ case SNDCTL_DSP_MAPOUTBUF: -+ case SNDCTL_DSP_SETSYNCRO: -+ case SOUND_PCM_WRITE_FILTER: -+ case SOUND_PCM_READ_FILTER: -+ return -EINVAL; -+ } -+ return -EINVAL; -+} -+ -+static unsigned int jz_audio_poll(struct file *file,struct poll_table_struct *wait) -+{ -+ unsigned long flags; -+ unsigned int mask = 0; -+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ return POLLOUT | POLLWRNORM; -+ poll_wait(file, &controller->dac_wait, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ return POLLIN | POLLRDNORM; -+ poll_wait(file, &controller->adc_wait, wait); -+ } -+ -+ spin_lock_irqsave(&controller->lock, flags); -+ if (file->f_mode & FMODE_WRITE) { -+ if (elements_in_queue(&out_empty_queue) > 0) -+ mask |= POLLOUT | POLLWRNORM; -+ } else if (file->f_mode & FMODE_READ) { -+ if (elements_in_queue(&in_full_queue) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ } -+ spin_unlock_irqrestore(&controller->lock, flags); -+ -+ return mask; -+} -+ -+static ssize_t jz_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret = 0, left_count, copy_count, cnt = 0; -+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ -+ if (count < 0) -+ return -EINVAL; -+ -+ __pcm_enable_receive_dma(); -+ __pcm_enable_rxfifo(); -+ -+ spin_lock(&controller->ioctllock); -+ controller->nextIn = 0; -+ spin_unlock(&controller->ioctllock); -+ -+ spin_lock(&controller->lock); -+ -+#if 0 -+ if (count < 2 * PAGE_SIZE ) -+ copy_count = count * 16 / (jz_audio_channels * jz_audio_format); -+ else -+ copy_count = 2 * PAGE_SIZE ; -+#else -+ if (count <= jz_audio_fragsize) -+ copy_count = count; -+ else -+ copy_count = jz_audio_fragsize; -+#endif -+ -+ left_count = count; -+ spin_unlock(&controller->lock); -+ -+ if (first_record_call) { -+ first_record_call = 0; -+audio_read_back_first: -+ if ((id = get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ -+ sleep_on(&rx_wait_queue); -+ } else -+ goto audio_read_back_first; -+ } -+ -+ while (left_count > 0) { -+audio_read_back_second: -+ if (elements_in_queue(&in_full_queue) <= 0) { -+ if (file->f_flags & O_NONBLOCK) -+ return ret ? ret : -EAGAIN; -+ else -+ sleep_on(&rx_wait_queue); -+ } -+ -+ if ((id = get_buffer_id(&in_full_queue)) >= 0) { -+ spin_lock(&controller->lock); -+ cnt = record_filler((unsigned long)controller->tmp1+ret, copy_count, id); -+ spin_unlock(&controller->lock); -+ put_buffer_id(&in_empty_queue, id); -+ } else -+ goto audio_read_back_second; -+ -+ if (elements_in_queue(&in_busy_queue) == 0) { -+ if ((id=get_buffer_id(&in_empty_queue)) >= 0) { -+ put_buffer_id(&in_busy_queue, id); -+ spin_lock(&controller->lock); -+ *(in_dma_buf_data_count + id) = copy_count; -+ spin_unlock(&controller->lock); -+ -+ dma_cache_wback_inv(*(in_dma_buf + id), *(in_dma_buf_data_count + id)); -+ audio_start_dma(controller->dma2,file->private_data, -+ *(in_dma_pbuf + id), -+ *(in_dma_buf_data_count + id), -+ DMA_MODE_READ); -+ } -+ } -+ if (ret + cnt > count) { -+ spin_lock(&controller->lock); -+ cnt = count - ret; -+ spin_unlock(&controller->lock); -+ } -+ if (copy_to_user(buffer+ret, controller->tmp1+ret, cnt)) -+ return ret ? ret : -EFAULT; -+ spin_lock(&controller->lock); -+ ret += cnt; -+ spin_unlock(&controller->lock); -+ -+ spin_lock(&controller->ioctllock); -+ controller->nextIn += ret; -+ spin_unlock(&controller->ioctllock); -+ -+ spin_lock(&controller->lock); -+ left_count -= cnt; -+ spin_unlock(&controller->lock); -+ } -+ -+ return ret; -+} -+ -+static ssize_t jz_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) -+{ -+ int id, ret, left_count, copy_count; -+ unsigned int flags; -+ struct jz_pcm_controller_info *controller = (struct jz_pcm_controller_info *) file->private_data; -+ -+ if (count <= 0) -+ return -EINVAL; -+ -+ __pcm_enable_transmit_dma(); -+ __pcm_enable_txfifo(); -+ -+ spin_lock_irqsave(&controller->ioctllock, flags); -+ controller->nextOut = 0; -+ spin_unlock_irqrestore(&controller->ioctllock, flags); -+ -+#if 0 -+ if (count < 2 * PAGE_SIZE ) -+ copy_count = count; -+ else -+ copy_count = 2 * PAGE_SIZE; -+#else -+ if (count <= jz_audio_fragsize) -+ copy_count = count; -+ else -+ copy_count = jz_audio_fragsize; -+#endif -+ -+ left_count = count; -+ ret = 0; -+ -+ if (copy_from_user(controller->tmp1, buffer, count)) { -+ printk("copy_from_user failed:%d",ret); -+ return ret ? ret : -EFAULT; -+ } -+ -+ while (left_count > 0) { -+audio_write_back: -+ if (elements_in_queue(&out_empty_queue) == 0) { -+ // all are full -+ if (file->f_flags & O_NONBLOCK) -+ return ret; -+ else -+ sleep_on(&tx_wait_queue); -+ } -+ /* the end fragment size in this write */ -+ if (ret + copy_count > count) -+ copy_count = count - ret; -+ if ((id = get_buffer_id(&out_empty_queue)) >= 0) { -+ replay_filler((unsigned long)controller->tmp1 + ret, copy_count, id); -+ if(*(out_dma_buf_data_count + id) > 0) { -+ put_buffer_id(&out_full_queue, id); //busy in -+ dma_cache_wback_inv(*(out_dma_buf + id), *(out_dma_buf_data_count + id)); -+ } else -+ put_buffer_id(&out_empty_queue, id); //spare -+ } else -+ goto audio_write_back; -+ -+ left_count = left_count - copy_count; -+ ret += copy_count;//all is in byte -+ -+ spin_lock(&controller->ioctllock); -+ controller->nextOut += ret; -+ spin_unlock(&controller->ioctllock); -+ -+ if (elements_in_queue(&out_busy_queue) == 0) { -+ if ((id=get_buffer_id(&out_full_queue)) >= 0) { -+ put_buffer_id(&out_busy_queue, id); -+ -+ if(*(out_dma_buf_data_count + id) > 0) { -+ audio_start_dma(controller->dma1, -+ file->private_data, -+ *(out_dma_pbuf + id), -+ *(out_dma_buf_data_count + id), -+ DMA_MODE_WRITE); -+ -+ } -+ } -+ } -+ } -+ -+ return ret; -+} -+ -+static void dump_pcmc_reg(void) -+{ -+ printk("REG_DMAC_DMACKE(0) : 0x%08x\n",REG_DMAC_DMACKE(0)); -+ printk("REG_DMAC_DMACKE(1) : 0x%08x\n",REG_DMAC_DMACKE(1)); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR : 0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_CPM_PCMCDR : 0x%08x\n",REG_CPM_PCMCDR); -+ printk("REG_PCM_CLT : 0x%08x\n",REG_PCM_CTL); -+ printk("REG_PCM_CFG : 0x%08x\n",REG_PCM_CFG); -+ printk("REG_PCM_INTC : 0x%08x\n",REG_PCM_INTC); -+ printk("REG_PCM_INTS : 0x%08x\n",REG_PCM_INTS); -+ printk("REG_PCM_DIV : 0x%08x\n",REG_PCM_DIV); -+} -diff -urN linux-2.6.24.7.old/sound/oss/jzcodec.c linux-2.6.24.7/sound/oss/jzcodec.c ---- linux-2.6.24.7.old/sound/oss/jzcodec.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jzcodec.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,443 @@ -+/* -+ * linux/drivers/sound/jzcodec.c -+ * -+ * JzSOC internal audio driver. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+typedef struct hpvol_shift_s -+{ -+ int hpvol; -+ int shift; -+} hpvol_shift_t; -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int codec_volue_shift; -+extern hpvol_shift_t hpvol_shift_table[72]; -+extern int abnormal_data_count; -+ -+extern void (*set_codec_mode)(void); -+extern void (*each_time_init_codec)(void); -+extern int (*set_codec_startup_param)(void); -+extern void (*set_codec_volume_table)(void); -+extern void (*set_codec_record)(int mode); -+extern void (*set_codec_replay)(void); -+extern void (*set_codec_replay_record)(int mode); -+extern void (*turn_on_codec)(void); -+extern void (*turn_off_codec)(void); -+extern void (*set_codec_speed)(int rate); -+extern void (*reset_codec)(void); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_bass)(int val); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*set_codec_line)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(void); -+extern void (*set_codec_direct_mode)(void); -+extern void (*clear_codec_direct_mode)(void); -+ -+static int jzcodec_reg[2]; -+ -+void set_jzcodec_mode(void); -+void each_time_init_jzcodec(void); -+int set_jzcodec_startup_param(void); -+void set_jzcodec_volume_table(void); -+void set_jzcodec_replay(void); -+void set_jzcodec_record(int mode); -+void turn_on_jzcodec(void); -+void turn_off_jzcodec(void); -+void set_jzcodec_speed(int rate); -+void reset_jzcodec(void); -+void jzcodec_mixer_old_info_id_name(void); -+void jzcodec_mixer_info_id_name(void); -+void set_jzcodec_bass(int val); -+void set_jzcodec_volume(int val); -+void set_jzcodec_mic(int val); -+void set_jzcodec_line(int val); -+void in_codec_app1(void); -+void in_codec_app12(void); -+void HP_turn_on(void); -+void HP_turn_off(void); -+void resume_jzcodec(void); -+void suspend_jzcodec(void); -+void set_jzcodec_replay_record(int mode); -+ -+void set_jzcodec_mode(void) -+{ -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ -+ REG_ICDC_CDCCR1 = 0x001b2303; -+ schedule_timeout(1); -+ REG_ICDC_CDCCR1 = 0x001b2302; -+} -+ -+void each_time_init_jzcodec(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+} -+ -+int set_jzcodec_startup_param(void) -+{ -+ REG_ICDC_CDCCR1 = 0x001b2300; -+ schedule_timeout(50); -+ REG_ICDC_CDCCR1 = 0x00033300; -+ schedule_timeout(5); -+ REG_ICDC_CDCCR1 = 0x17026300; -+ -+ return 1; -+} -+void set_jzcodec_volume_table(void) -+{ -+ int errno,hpvol_step,sample_shift; -+ -+ codec_volue_shift = 0; -+ hpvol_step = 3; -+ sample_shift = 0; -+ for(errno = 0;errno < 72;errno++) { -+ hpvol_shift_table[errno].hpvol = hpvol_step; -+ hpvol_shift_table[errno].shift = sample_shift; -+ hpvol_step --; -+ if(hpvol_step <= 0) { -+ hpvol_step = 3; -+ sample_shift ++; -+ } -+ } -+} -+ -+void set_jzcodec_replay(void) -+{ -+ in_codec_app1(); -+} -+ -+void set_jzcodec_record(int mode) -+{ -+ switch (mode) { -+ case USE_NONE: -+ case USE_MIC: -+ in_codec_app12(); -+ abnormal_data_count = 0; -+ break; -+ case USE_LINEIN: -+ REG_ICDC_CDCCR1 = 0x27022000;//for linein -+ mdelay(300); -+ break; -+ } -+} -+ -+void set_jzcodec_replay_record(int mode) -+{ -+ long val = 0; -+ REG_ICDC_CDCCR1 = 0x00037302; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03006000; -+ mdelay(2); -+ -+ switch (mode) { -+ case USE_NONE: -+ case USE_MIC: -+ REG_ICDC_CDCCR1 = 0x17022000;//for mic -+ break; -+ case USE_LINEIN: -+ REG_ICDC_CDCCR1 = 0x27022000;//for linein -+ break; -+ } -+ -+ val = REG_ICDC_CDCCR2; -+ val &= 0x0000ff00; -+ val |= 0x00170030; -+ REG_ICDC_CDCCR2 = val; -+} -+ -+void turn_on_jzcodec(void) -+{ -+ HP_turn_on(); -+} -+ -+void set_jzcodec_direct_mode(void) -+{ -+ long val = 0; -+ REG_ICDC_CDCCR1 = 0x14000000; -+ val &= 0x0000ff00; -+ val |= 0x001f0033; -+ REG_ICDC_CDCCR2 = val; -+ mdelay(300); -+} -+ -+void clear_jzcodec_direct_mode(void) -+{ -+ HP_turn_off(); -+} -+ -+void turn_off_jzcodec(void) -+{ -+ HP_turn_off(); -+} -+ -+void set_jzcodec_speed(int rate) -+{ -+ long codec_speed,speed = 0; -+ switch (rate) { -+ case 8000: -+ speed = 0; -+ break; -+ case 11025: -+ speed = 1; -+ break; -+ case 12000: -+ speed = 2; -+ break; -+ case 16000: -+ speed = 3; -+ break; -+ case 22050: -+ speed = 4; -+ break; -+ case 24000: -+ speed = 5; -+ break; -+ case 32000: -+ speed = 6; -+ break; -+ case 44100: -+ speed = 7; -+ break; -+ case 48000: -+ speed = 8; -+ break; -+ default: -+ break; -+ } -+ -+ codec_speed = REG_ICDC_CDCCR2; -+ codec_speed |= 0x00000f00; -+ -+ speed = speed << 8; -+ speed |= 0xfffff0ff; -+ codec_speed &= speed; -+ REG_ICDC_CDCCR2 = codec_speed; -+} -+ -+void reset_jzcodec(void) -+{ -+ REG_ICDC_CDCCR1 |= 1; -+ mdelay(1); -+ REG_ICDC_CDCCR1 &= 0xfffffffe; -+} -+ -+void jzcodec_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "JZCODEC", sizeof(info.id)); -+ strncpy(info.name,"Jz internal codec", sizeof(info.name)); -+} -+ -+void jzcodec_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "JZCODEC", sizeof(old_info.id)); -+ strncpy(old_info.name,"Jz internal codec", sizeof(old_info.name)); -+} -+ -+void set_jzcodec_bass(int val) -+{ -+ int bass_gain = 0; -+ if(val < 25) -+ bass_gain = 0; -+ if(val >= 25 && val < 50) -+ bass_gain = 1; -+ if(val >= 50 && val < 75) -+ bass_gain = 2; -+ if(val >= 75 && val <= 100 ) -+ bass_gain = 3; -+ -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3 << 4)) | (bass_gain << 4)); -+} -+ -+void set_jzcodec_volume(int val) -+{ -+ unsigned int sample_oss; -+ int index,shift_max,vol_scale,vol_step,codec_volume; -+ shift_max = 0; -+ sample_oss = (REG_AIC_CR & 0x00380000) >> 19; -+ -+ switch(sample_oss) -+ { -+ case 0x0: -+ shift_max = 4; /* 8 bits */ -+ break; -+ case 0x1: -+ shift_max = 10; /* 16 bits */ -+ break; -+ case 0x2: -+ shift_max = 12; /* 18 bits */ -+ break; -+ case 0x3: -+ shift_max = 15; /* 20 bits */ -+ break; -+ case 0x4: -+ shift_max = 19; /* 24 bits */ -+ break; -+ } -+ -+ vol_scale = 3 * (shift_max + 1); -+ vol_step = 100 / vol_scale; -+ -+ for(index = 0;index <= 100;index += vol_step) -+ if( val <= index ) -+ break; -+ -+ if(index == 0) -+ index = vol_step; -+ index = index / vol_step; -+ if(index > vol_scale) -+ index = vol_scale; -+ -+ index = vol_scale - index; -+ codec_volume = hpvol_shift_table[index].hpvol; -+ codec_volue_shift = hpvol_shift_table[index].shift; -+ codec_volume = 3; -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x3)) | codec_volume); -+} -+ -+void set_jzcodec_mic(int val) -+{ -+ long mic_gain; -+ -+ mic_gain = 31 * val /100; -+ REG_ICDC_CDCCR2 = (REG_ICDC_CDCCR2 | (0x3 << 4)); -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (mic_gain << 16)); -+} -+ -+void set_jzcodec_line(int val) -+{ -+ long line_gain; -+ -+ line_gain = 31 * val /100; -+ REG_ICDC_CDCCR2 = ((REG_ICDC_CDCCR2 & ~(0x1f << 16)) | (line_gain << 16)); -+} -+ -+void HP_turn_on(void) -+{ -+ long val = 0; -+ /* simple and slow anti-pop */ -+ REG_ICDC_CDCCR1 = 0x00037302; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03006000; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x03002000; -+ -+ val = REG_ICDC_CDCCR2; -+ val &= 0x0000ff00; -+ val |= 0x001f0033; -+ REG_ICDC_CDCCR2 = val; -+} -+ -+void HP_turn_off(void) -+{ -+ mdelay(20); -+ REG_ICDC_CDCCR1 = 0x00033300; -+} -+ -+void in_codec_app1(void) -+{ -+ /* test is OK */ -+ HP_turn_on(); -+} -+ -+void in_codec_app12(void) -+{ -+ REG_ICDC_CDCCR1 = 0x14024300; -+ mdelay(300); -+} -+ -+void resume_jzcodec(void) -+{ -+ REG_ICDC_CDCCR2 = 0x00170800; -+ mdelay(2); -+ REG_ICDC_CDCCR1 = 0x001f2102; -+ mdelay(5); -+ REG_ICDC_CDCCR1 = 0x00033302; -+ mdelay(550); -+ REG_ICDC_CDCCR1 = 0x00033300; -+ REG_ICDC_CDCCR1 = jzcodec_reg[0]; -+ REG_ICDC_CDCCR2 = jzcodec_reg[1]; -+} -+ -+void suspend_jzcodec(void) -+{ -+ -+ jzcodec_reg[0] = REG_ICDC_CDCCR1; -+ jzcodec_reg[1] = REG_ICDC_CDCCR2; -+ -+ REG_ICDC_CDCCR1 = 0x001b2302; -+ mdelay(1); -+ REG_ICDC_CDCCR1 = 0x001b2102; -+} -+ -+static int __init init_jzcodec(void) -+{ -+ set_codec_mode = set_jzcodec_mode; -+ each_time_init_codec = each_time_init_jzcodec; -+ -+ set_codec_startup_param = set_jzcodec_startup_param; -+ set_codec_volume_table = set_jzcodec_volume_table; -+ set_codec_record = set_jzcodec_record; -+ set_codec_replay = set_jzcodec_replay; -+ set_codec_replay_record = set_jzcodec_replay_record; -+ turn_on_codec = turn_on_jzcodec; -+ turn_off_codec = turn_off_jzcodec; -+ set_codec_speed = set_jzcodec_speed; -+ reset_codec = reset_jzcodec; -+ codec_mixer_old_info_id_name = jzcodec_mixer_old_info_id_name; -+ codec_mixer_info_id_name = jzcodec_mixer_info_id_name; -+ set_codec_bass = set_jzcodec_bass; -+ set_codec_volume = set_jzcodec_volume; -+ set_codec_mic = set_jzcodec_mic; -+ set_codec_line = set_jzcodec_line; -+ i2s_resume_codec = resume_jzcodec; -+ i2s_suspend_codec = suspend_jzcodec; -+ set_codec_direct_mode = set_jzcodec_direct_mode; -+ clear_codec_direct_mode = clear_jzcodec_direct_mode; -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_jzcodec(void) -+{ -+ REG_ICDC_CDCCR1 = 0x001b2302; -+ -+} -+ -+module_init(init_jzcodec); -+module_exit(cleanup_jzcodec); -diff -urN linux-2.6.24.7.old/sound/oss/jzdlv.c linux-2.6.24.7/sound/oss/jzdlv.c ---- linux-2.6.24.7.old/sound/oss/jzdlv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jzdlv.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,644 @@ -+/* -+ * linux/drivers/sound/jzcodec.c -+ * -+ * JzSOC internal audio driver. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sound_config.h" -+#include "jzdlv.h" -+ -+#define USE_NONE 1 -+#define USE_MIC 2 -+#define USE_LINEIN 3 -+ -+extern mixer_info info; -+extern _old_mixer_info old_info; -+extern int codec_volue_shift; -+ -+extern void (*set_codec_mode)(void); -+extern void (*each_time_init_codec)(void); -+extern int (*set_codec_startup_param)(void); -+extern void (*set_codec_record)(void); -+extern void (*set_codec_replay)(void); -+extern void (*set_codec_replay_record)(void); -+extern void (*turn_on_codec)(void); -+extern void (*turn_off_codec)(void); -+extern void (*set_codec_speed)(int rate); -+extern void (*reset_codec)(void); -+extern void (*codec_mixer_old_info_id_name)(void); -+extern void (*codec_mixer_info_id_name)(void); -+extern void (*set_codec_bass)(int val); -+extern void (*set_codec_volume)(int val); -+extern void (*set_codec_mic)(int val); -+extern void (*set_codec_line)(int val); -+extern void (*i2s_resume_codec)(void); -+extern void (*i2s_suspend_codec)(void); -+extern void (*set_codec_direct_mode)(void); -+extern void (*clear_codec_direct_mode)(void); -+ -+ -+void set_dlv_mode(void); -+void each_time_init_jzcodec(void); -+int set_dlv_startup_param(void); -+void set_dlvjzcodec_volume_table(void); -+void set_dlv_replay(void); -+void set_dlv_record(void); -+void set_dlv_speed(int rate); -+void reset_dlv(void); -+void jzcodec_mixer_old_info_id_name(void); -+void jzcodec_mixer_info_id_name(void); -+void set_dlv_volume(int val); -+void set_dlv_mic(int val); -+ -+extern int jz_mic_only; -+int read_codec_file(int addr) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ return(__icdc_get_value()); -+} -+ -+#if 0 -+void printk_codec_files(void) -+{ -+ int cnt; -+ -+ printk("\n"); -+ -+ printk("REG_CPM_I2SCDR=0x%08x\n",REG_CPM_I2SCDR); -+ printk("REG_CPM_CLKGR=0x%08x\n",REG_CPM_CLKGR); -+ printk("REG_CPM_CPCCR=0x%08x\n",REG_CPM_CPCCR); -+ printk("REG_AIC_FR=0x%08x\n",REG_AIC_FR); -+ printk("REG_AIC_CR=0x%08x\n",REG_AIC_CR); -+ printk("REG_AIC_I2SCR=0x%08x\n",REG_AIC_I2SCR); -+ printk("REG_AIC_SR=0x%08x\n",REG_AIC_SR); -+ printk("REG_ICDC_RGDATA=0x%08x\n",REG_ICDC_RGDATA); -+ -+ for (cnt = 0; cnt <= 27 ; cnt++) { -+ printk(" ( %d : 0x%x ) ",cnt ,read_codec_file(cnt)); -+ } -+ printk("\n"); -+} -+#endif -+ -+void write_codec_file(int addr, int val) -+{ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+} -+ -+int write_codec_file_bit(int addr, int bitval, int mask_bit) -+{ -+ int val; -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ mdelay(1); -+ val = __icdc_get_value(); /* read */ -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val &= ~(1 << mask_bit); -+ if (bitval == 1) -+ val |= 1 << mask_bit; -+ -+ __icdc_set_cmd(val); /* write */ -+ mdelay(1); -+ __icdc_set_rgwr(); -+ mdelay(1); -+ -+ while (__icdc_rgwr_ready()); -+ __icdc_set_addr(addr); -+ val = __icdc_get_value(); /* read */ -+ -+ if (((val >> mask_bit) & bitval) == bitval) -+ return 1; -+ else -+ return 0; -+} -+void set_dlv_mode(void) -+{ -+ /*REG_CPM_CPCCR &= ~(1 << 31); -+ REG_CPM_CPCCR &= ~(1 << 30);*/ -+ write_codec_file(0, 0xf); -+ -+ REG_AIC_I2SCR = 0x10; -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ __aic_reset(); -+ mdelay(10); -+ REG_AIC_I2SCR = 0x10; -+ mdelay(20); -+ -+ /* power on DLV */ -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+} -+void reset_dlv_codec(void) -+{ -+ /* reset DLV codec. from hibernate mode to sleep mode */ -+ write_codec_file(0, 0xf); -+ write_codec_file_bit(6, 0, 0); -+ write_codec_file_bit(6, 0, 1); -+ mdelay(200); -+ //write_codec_file(0, 0xf); -+ write_codec_file_bit(5, 0, 7);//PMR1.SB_DAC->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_ADC->0 -+ mdelay(10);//wait for stability -+} -+ -+void each_time_init_dlv(void) -+{ -+ __i2s_disable(); -+ __i2s_as_slave(); -+ __aic_internal_codec(); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+} -+ -+int set_dlv_startup_param(void) -+{ -+ __i2s_disable_transmit_intr(); -+ __i2s_disable_receive_intr(); -+ -+ return 1; -+} -+/* set Audio data replay */ -+void set_audio_data_replay(void) -+{ -+ /* DAC path */ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ //mdelay(100); -+ //write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //mdelay(300); -+} -+ -+#if 1 /* mask warning */ -+/* set Record MIC input audio without playback */ -+void set_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2); -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ -+ write_codec_file(22, 0x40);//mic 1 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ //write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record MIC input audio without playback */ -+void unset_record_mic_input_audio_without_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record LINE input audio without playback */ -+void set_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ jz_mic_only = 1; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(3, 1, 7);//CR1.HP_DIS->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ mdelay(10); -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record LINE input audio without playback */ -+void unset_record_line_input_audio_without_playback(void) -+{ -+ /* ADC path for LINE IN */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(5, 1, 3);//ONR1.SB_LIN->1 -+ -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Playback LINE input audio direct only */ -+void set_playback_line_input_audio_direct_only(void) -+{ -+ jz_audio_reset();//or init_codec() -+ REG_AIC_I2SCR = 0x10; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ write_codec_file(22, 0xf6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ mdelay(10); -+ write_codec_file_bit(1, 1, 2);//CR1.HP_BYPASS->1 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file_bit(5, 1, 7);//PMR1.SB_DAC->1 -+ //write_codec_file_bit(5, 1, 4);//PMR1.SB_ADC->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Playback LINE input audio direct only */ -+void unset_playback_line_input_audio_direct_only(void) -+{ -+ write_codec_file_bit(6, 0, 3);//GIM->0 -+ write_codec_file_bit(1, 0, 2);//PMR1.BYPASS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LINE->1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ mdelay(100); -+ write_codec_file_bit(5, 1, 5);//PMR1.SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record MIC input audio with direct playback */ -+void set_record_mic_input_audio_with_direct_playback(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ jz_mic_only = 0; -+ write_codec_file(9, 0xff); -+ write_codec_file(8, 0x3f); -+ mdelay(10); -+ -+ write_codec_file(22, 0x60);//mic 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(1, 0, 3);//CR1.DACSEL->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ mdelay(100); -+ write_codec_file_bit(5, 0, 6);//PMR1.SB_OUT->0 -+ //write_codec_file(1, 0x4); -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record MIC input audio with direct playback */ -+void unset_record_mic_input_audio_with_direct_playback(void) -+{ -+ /* ADC path for MIC IN */ -+ jz_mic_only = 0; -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1 -+ write_codec_file_bit(5, 1, 6);//PMR1.SB_OUT->1 -+ write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* set Record playing audio mixed with MIC input audio */ -+void set_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ mdelay(10); -+ -+ write_codec_file(22, 0x63);//mic 1 -+ -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(6, 1, 3);// gain set -+ -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ write_codec_file_bit(5, 0, 4);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 0 /* mask warning */ -+/* unset Record playing audio mixed with MIC input audio */ -+void unset_record_playing_audio_mixed_with_mic_input_audio(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* set Record MIC input audio with Audio data replay (full duplex) */ -+void set_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 1, 3);//PMR1.SB_LIN->1 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ -+ write_codec_file_bit(22, 0, 7);//CR3.SB_MIC->0 -+ write_codec_file_bit(1, 0, 7);//CR1.SB_MICBIAS->0 -+ -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record MIC input audio with Audio data replay (full duplex) */ -+void unset_record_mic_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* set Record LINE input audio with Audio data replay (full duplex for linein) */ -+void set_record_line_input_audio_with_audio_data_replay(void) -+{ -+ write_codec_file(9, 0xff); -+ //write_codec_file(8, 0x30); -+ write_codec_file(8, 0x20); -+ write_codec_file_bit(1, 0, 4);//CR1.HP_DIS->0 -+ write_codec_file_bit(5, 0, 3);//PMR1.SB_LIN->0 -+ write_codec_file_bit(5, 1, 0);//PMR1.SB_IND->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(22, 1, 7);//CR3.SB_MIC->1 -+ write_codec_file_bit(1, 1, 3);//CR1.DACSEL->1 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+ -+ -+ //jz_mic_only = 1; -+ write_codec_file(22, 0xc6);//line in 1 -+ write_codec_file_bit(23, 0, 7);//AGC1.AGC_EN->0 -+ write_codec_file_bit(1, 0, 2);//CR1.BYPASS->0 -+ write_codec_file_bit(5, 0, 5);//PMR1.SB_MIX->0 -+} -+#endif -+ -+#if 1 /* mask warning */ -+/* unset Record LINE input audio with Audio data replay (full duplex for linein) */ -+void unset_record_line_input_audio_with_audio_data_replay(void) -+{ -+ /* ADC path */ -+ write_codec_file_bit(5, 1, 4);//SB_ADC->1 -+ write_codec_file_bit(1, 1, 7);//CR1.SB_MICBIAS->1 -+ //write_codec_file_bit(1, 1, 6);//CR1.MONO->1 -+ write_codec_file(22, 0xc0);//CR3.SB_MIC1->1 -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 5);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+#if 1 -+/* unset Audio data replay */ -+void unset_audio_data_replay(void) -+{ -+ //write_codec_file_bit(1, 1, 5);//DAC_MUTE->1 -+ //mdelay(800); -+ //write_codec_file_bit(5, 1, 6);//SB_OUT->1 -+ //mdelay(800); -+ write_codec_file_bit(5, 1, 7);//SB_DAC->1 -+ write_codec_file_bit(5, 1, 4);//SB_MIX->1 -+ write_codec_file_bit(6, 1, 0);//SB_SLEEP->1 -+ write_codec_file_bit(6, 1, 1);//SB->1 -+} -+#endif -+ -+void set_dlv_replay(void) -+{ -+ set_audio_data_replay(); -+} -+ -+void set_dlv_speed(int rate) -+{ -+ int speed = 0, val; -+ speed = 0; -+ switch (rate) { -+ case 8000: -+ speed = 10; -+ break; -+ case 9600: -+ speed = 9; -+ break; -+ case 11025: -+ speed = 8; -+ break; -+ case 12000: -+ speed = 7; -+ break; -+ case 16000: -+ speed = 6; -+ break; -+ case 22050: -+ speed = 5; -+ break; -+ case 24000: -+ speed = 4; -+ break; -+ case 32000: -+ speed = 3; -+ break; -+ case 44100: -+ speed = 2; -+ break; -+ case 48000: -+ speed = 1; -+ break; -+ case 96000: -+ speed = 0; -+ break; -+ default: -+ break; -+ } -+ -+ val = read_codec_file(4); -+ val = (speed << 4) | speed; -+ write_codec_file(4, val); -+} -+ -+void reset_jzcodec(void) -+{ -+ -+} -+ -+void dlv_mixer_old_info_id_name(void) -+{ -+ strncpy(info.id, "JZDLV", sizeof(info.id)); -+ strncpy(info.name,"Jz internal codec dlv on jz4750", sizeof(info.name)); -+} -+ -+void dlv_mixer_info_id_name(void) -+{ -+ strncpy(old_info.id, "JZDLV", sizeof(old_info.id)); -+ strncpy(old_info.name,"Jz internal codec dlv on jz4750", sizeof(old_info.name)); -+} -+ -+void set_dlv_mic(int val) -+{ -+ int cur_vol ; -+ /* set gain */ -+ //write_codec_file_bit(6, 1, 3);//GIM -+ cur_vol = 31 * val / 100; -+ cur_vol |= cur_vol << 4; -+ write_codec_file(19, cur_vol);//GIL,GIR -+} -+ -+void set_dlv_line(int val) -+{ -+ int cur_vol; -+ /* set gain */ -+ cur_vol = 31 * val / 100; -+ cur_vol &= 0x1f; -+ write_codec_file(11, cur_vol);//GO1L -+ write_codec_file(12, cur_vol);//GO1R -+} -+ -+void set_dlv_volume(int val) -+{ -+ unsigned long cur_vol; -+ cur_vol = 31 * (100 - val) / 100; -+ write_codec_file(17, cur_vol | 0xc0); -+ write_codec_file(18, cur_vol); -+} -+ -+static int __init init_dlv(void) -+{ -+ set_codec_mode = set_dlv_mode; -+ each_time_init_codec = each_time_init_dlv; -+ reset_codec = reset_dlv_codec; -+ set_codec_startup_param = set_dlv_startup_param; -+ -+ set_codec_replay = set_dlv_replay; -+ -+ set_codec_speed = set_dlv_speed; -+ -+ codec_mixer_old_info_id_name = dlv_mixer_old_info_id_name; -+ codec_mixer_info_id_name = dlv_mixer_info_id_name; -+ -+ set_codec_volume = set_dlv_volume; -+ set_codec_mic = set_dlv_mic; -+ set_codec_line = set_dlv_line; -+ -+ return 0; -+} -+ -+ -+static void __exit cleanup_dlv(void) -+{ -+ -+} -+ -+module_init(init_dlv); -+module_exit(cleanup_dlv); -diff -urN linux-2.6.24.7.old/sound/oss/jzdlv.h linux-2.6.24.7/sound/oss/jzdlv.h ---- linux-2.6.24.7.old/sound/oss/jzdlv.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/oss/jzdlv.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+/* header file for dlv */ -+void write_codec_file(int addr, int val); -+int read_codec_file(int addr); -+void printk_codec_files(void); -+int write_codec_file_bit(int addr, int bitval, int mask_bit); -+void set_audio_data_replay(void); -+void unset_audio_data_replay(void); -+void set_record_mic_input_audio_without_playback(void); -+void unset_record_mic_input_audio_without_playback(void); -+void set_record_line_input_audio_without_playback(void); -+void unset_record_line_input_audio_without_playback(void); -+void set_playback_line_input_audio_direct_only(void); -+void unset_playback_line_input_audio_direct_only(void); -+void set_record_mic_input_audio_with_direct_playback(void); -+void unset_record_mic_input_audio_with_direct_playback(void); -+void set_record_playing_audio_mixed_with_mic_input_audio(void); -+void unset_record_playing_audio_mixed_with_mic_input_audio(void); -+void set_record_mic_input_audio_with_audio_data_replay(void); -+void unset_record_mic_input_audio_with_audio_data_replay(void); -+void set_record_line_input_audio_with_audio_data_replay(void); -+void unset_record_line_input_audio_with_audio_data_replay(void); -diff -urN linux-2.6.24.7.old/sound/oss/os.h linux-2.6.24.7/sound/oss/os.h ---- linux-2.6.24.7.old/sound/oss/os.h 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/oss/os.h 2009-04-12 18:13:57.000000000 +0200 -@@ -9,7 +9,6 @@ - #ifdef __KERNEL__ - #include - #include --#include - #include - #include - #include -diff -urN linux-2.6.24.7.old/sound/soc/Kconfig linux-2.6.24.7/sound/soc/Kconfig ---- linux-2.6.24.7.old/sound/soc/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/soc/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -28,6 +28,7 @@ - source "sound/soc/pxa/Kconfig" - source "sound/soc/s3c24xx/Kconfig" - source "sound/soc/sh/Kconfig" -+source "sound/soc/jz4740/Kconfig" - - # Supported codecs - source "sound/soc/codecs/Kconfig" -diff -urN linux-2.6.24.7.old/sound/soc/Makefile linux-2.6.24.7/sound/soc/Makefile ---- linux-2.6.24.7.old/sound/soc/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/soc/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -1,4 +1,4 @@ - snd-soc-core-objs := soc-core.o soc-dapm.o - - obj-$(CONFIG_SND_SOC) += snd-soc-core.o --obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ -+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ jz4740/ -diff -urN linux-2.6.24.7.old/sound/soc/codecs/Kconfig linux-2.6.24.7/sound/soc/codecs/Kconfig ---- linux-2.6.24.7.old/sound/soc/codecs/Kconfig 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/soc/codecs/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -37,3 +37,8 @@ - bool - depends on SND_SOC_CS4270 - -+config SND_SOC_ICODEC -+ tristate "Jz4740 internal codec" -+ depends on SND_SOC && SND_JZ4740_SOC_PAVO && SND_JZ4740_SOC_I2S -+ help -+ Say Y if you want to use internal codec on Ingenic Jz4740 PAVO board. -diff -urN linux-2.6.24.7.old/sound/soc/codecs/Makefile linux-2.6.24.7/sound/soc/codecs/Makefile ---- linux-2.6.24.7.old/sound/soc/codecs/Makefile 2008-05-07 01:22:34.000000000 +0200 -+++ linux-2.6.24.7/sound/soc/codecs/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -4,6 +4,7 @@ - snd-soc-wm8753-objs := wm8753.o - snd-soc-wm9712-objs := wm9712.o - snd-soc-cs4270-objs := cs4270.o -+snd-soc-jzcodec-objs := jzcodec.o - - obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o - obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o -@@ -11,3 +12,4 @@ - obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o - obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o - obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o -+obj-$(CONFIG_SND_SOC_ICODEC) += snd-soc-jzcodec.o -diff -urN linux-2.6.24.7.old/sound/soc/codecs/jzcodec.c linux-2.6.24.7/sound/soc/codecs/jzcodec.c ---- linux-2.6.24.7.old/sound/soc/codecs/jzcodec.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/codecs/jzcodec.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,725 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../jz4740/jz4740-pcm.h" -+#include "jzcodec.h" -+ -+#define AUDIO_NAME "jzcodec" -+#define JZCODEC_VERSION "1.0" -+ -+/* -+ * Debug -+ */ -+ -+#define JZCODEC_DEBUG 0 -+ -+#ifdef JZCODEC_DEBUG -+#define dbg(format, arg...) \ -+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) -+#else -+#define dbg(format, arg...) do {} while (0) -+#endif -+#define err(format, arg...) \ -+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) -+#define info(format, arg...) \ -+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) -+#define warn(format, arg...) \ -+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) -+ -+struct snd_soc_codec_device soc_codec_dev_jzcodec; -+ -+/* codec private data */ -+struct jzcodec_priv { -+ unsigned int sysclk; -+}; -+ -+/* -+ * jzcodec register cache -+ */ -+static u32 jzcodec_reg[JZCODEC_CACHEREGNUM / 2]; -+ -+/* -+ * codec register is 16 bits width in ALSA, so we define array to store 16 bits configure paras -+ */ -+static u16 jzcodec_reg_LH[JZCODEC_CACHEREGNUM]; -+ -+/* -+ * read jzcodec register cache -+ */ -+static inline unsigned int jzcodec_read_reg_cache(struct snd_soc_codec *codec, -+ unsigned int reg) -+{ -+ u16 *cache = codec->reg_cache; -+ -+ if (reg >= JZCODEC_CACHEREGNUM) -+ return -1; -+ return cache[reg]; -+} -+ -+/* -+ * write jzcodec register cache -+ */ -+static inline void jzcodec_write_reg_cache(struct snd_soc_codec *codec, -+ unsigned int reg, u16 value) -+{ -+ u16 *cache = codec->reg_cache; -+ u32 reg_val; -+ -+ if (reg >= JZCODEC_CACHEREGNUM) { -+ return; -+ } -+ -+ cache[reg] = value; -+ /* update internal codec register value */ -+ switch (reg) { -+ case 0: -+ case 1: -+ reg_val = cache[0] & 0xffff; -+ reg_val = reg_val | (cache[1] << 16); -+ jzcodec_reg[0] = reg_val; -+ break; -+ case 2: -+ case 3: -+ reg_val = cache[2] & 0xffff; -+ reg_val = reg_val | (cache[3] << 16); -+ jzcodec_reg[1] = reg_val; -+ break; -+ } -+} -+ -+/* -+ * write to the jzcodec register space -+ */ -+static int jzcodec_write(struct snd_soc_codec *codec, unsigned int reg, -+ unsigned int value) -+{ -+ jzcodec_write_reg_cache(codec, reg, value); -+ if(codec->hw_write) -+ codec->hw_write(&value, NULL, reg); -+ return 0; -+} -+ -+static int jzcodec_reset(struct snd_soc_codec *codec) -+{ -+ u16 val; -+ -+ val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); -+ val = val | 0x1; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ mdelay(1); -+ -+ val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); -+ val = val & ~0x1; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ mdelay(1); -+ -+ return 0; -+} -+ -+static const struct snd_kcontrol_new jzcodec_snd_controls[] = { -+ -+ //SOC_DOUBLE_R("Master Playback Volume", 1, 1, 0, 3, 0), -+ SOC_DOUBLE_R("Master Playback Volume", ICODEC_2_LOW, ICODEC_2_LOW, 0, 3, 0), -+ //SOC_DOUBLE_R("MICBG", ICODEC_2_LOW, ICODEC_2_LOW, 4, 3, 0), -+ //SOC_DOUBLE_R("Line", 2, 2, 0, 31, 0), -+ SOC_DOUBLE_R("Line", ICODEC_2_HIGH, ICODEC_2_HIGH, 0, 31, 0), -+}; -+ -+/* add non dapm controls */ -+static int jzcodec_add_controls(struct snd_soc_codec *codec) -+{ -+ int err, i; -+ -+ for (i = 0; i < ARRAY_SIZE(jzcodec_snd_controls); i++) { -+ if ((err = snd_ctl_add(codec->card, -+ snd_soc_cnew(&jzcodec_snd_controls[i], codec, NULL))) < 0) -+ return err; -+ } -+ -+ return 0; -+} -+ -+static const struct snd_soc_dapm_widget jzcodec_dapm_widgets[] = { -+ SND_SOC_DAPM_OUTPUT("LOUT"), -+ SND_SOC_DAPM_OUTPUT("LHPOUT"), -+ SND_SOC_DAPM_OUTPUT("ROUT"), -+ SND_SOC_DAPM_OUTPUT("RHPOUT"), -+ SND_SOC_DAPM_INPUT("MICIN"), -+ SND_SOC_DAPM_INPUT("RLINEIN"), -+ SND_SOC_DAPM_INPUT("LLINEIN"), -+}; -+ -+static const char *intercon[][3] = { -+ /* output mixer */ -+ {"Output Mixer", "Line Bypass Switch", "Line Input"}, -+ {"Output Mixer", "HiFi Playback Switch", "DAC"}, -+ {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, -+ -+ /* outputs */ -+ {"RHPOUT", NULL, "Output Mixer"}, -+ {"ROUT", NULL, "Output Mixer"}, -+ {"LHPOUT", NULL, "Output Mixer"}, -+ {"LOUT", NULL, "Output Mixer"}, -+ -+ /* input mux */ -+ {"Input Mux", "Line In", "Line Input"}, -+ {"Input Mux", "Mic", "Mic Bias"}, -+ {"ADC", NULL, "Input Mux"}, -+ -+ /* inputs */ -+ {"Line Input", NULL, "LLINEIN"}, -+ {"Line Input", NULL, "RLINEIN"}, -+ {"Mic Bias", NULL, "MICIN"}, -+ -+ /* terminator */ -+ {NULL, NULL, NULL}, -+}; -+ -+static int jzcodec_add_widgets(struct snd_soc_codec *codec) -+{ -+ int i,cnt; -+ -+ cnt = ARRAY_SIZE(jzcodec_dapm_widgets); -+ for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) { -+ snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]); -+ } -+ -+ /* set up audio path interconnects */ -+ for(i = 0; intercon[i][0] != NULL; i++) { -+ snd_soc_dapm_connect_input(codec, intercon[i][0], -+ intercon[i][1], intercon[i][2]); -+ } -+ -+ snd_soc_dapm_new_widgets(codec); -+ return 0; -+} -+ -+static int jzcodec_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; -+ u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); -+ -+ /* bit size. codec side */ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ break; -+ } -+ /* sample rate */ -+ reg_val = reg_val & ~(0xf << 8); -+ -+ switch (params_rate(params)) { -+ case 8000: -+ reg_val |= (0x0 << 8); -+ break; -+ case 11025: -+ reg_val |= (0x1 << 8); -+ break; -+ case 12000: -+ reg_val |= (0x2 << 8); -+ break; -+ case 16000: -+ reg_val |= (0x3 << 8); -+ break; -+ case 22050: -+ reg_val |= (0x4 << 8); -+ break; -+ case 24000: -+ reg_val |= (0x5 << 8); -+ break; -+ case 32000: -+ reg_val |= (0x6 << 8); -+ break; -+ case 44100: -+ reg_val |= (0x7 << 8); -+ break; -+ case 48000: -+ reg_val |= (0x8 << 8); -+ break; -+ default: -+ printk(" invalid rate :0x%08x\n",params_rate(params)); -+ } -+ -+ jzcodec_write(codec, ICODEC_2_LOW, reg_val); -+ return 0; -+} -+ -+static int jzcodec_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ int ret = 0; -+ u16 val; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ //case SNDRV_PCM_TRIGGER_RESUME: -+ //case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ val = 0x7302; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x0003; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ mdelay(2); -+ val = 0x6000; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x0300; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ mdelay(2); -+ val = 0x2000; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x0300; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ } else { -+ val = 0x4300; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x1402; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ } -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ //case SNDRV_PCM_TRIGGER_SUSPEND: -+ //case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { -+ val = 0x3300; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x0003; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ } else { -+ val = 0x3300; -+ jzcodec_write(codec, ICODEC_1_LOW, val); -+ val = 0x0003; -+ jzcodec_write(codec, ICODEC_1_HIGH, val); -+ } -+ break; -+ -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static int jzcodec_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; */ -+ -+ return 0; -+} -+ -+static void jzcodec_shutdown(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_device *socdev = rtd->socdev; -+ struct snd_soc_codec *codec = socdev->codec; -+ -+ /* deactivate */ -+ if (!codec->active) { -+ udelay(50); -+ } -+} -+ -+static int jzcodec_mute(struct snd_soc_codec_dai *dai, int mute) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); -+ -+ if (mute != 0) -+ mute = 1; -+ if (mute) -+ reg_val = reg_val | (0x1 << 14); -+ else -+ reg_val = reg_val & ~(0x1 << 14); -+ -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ return 0; -+} -+ -+static int jzcodec_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, -+ int clk_id, unsigned int freq, int dir) -+{ -+ struct snd_soc_codec *codec = codec_dai->codec; -+ struct jzcodec_priv *jzcodec = codec->private_data; -+ -+ jzcodec->sysclk = freq; -+ return 0; -+} -+/* -+ * Set's ADC and Voice DAC format. called by pavo_hw_params() in pavo.c -+ */ -+static int jzcodec_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, -+ unsigned int fmt) -+{ -+ /* struct snd_soc_codec *codec = codec_dai->codec; */ -+ -+ /* set master/slave audio interface. codec side */ -+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBM_CFM: -+ /* set master mode for codec */ -+ break; -+ case SND_SOC_DAIFMT_CBS_CFS: -+ /* set slave mode for codec */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* interface format . set some parameter for codec side */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ /* set I2S mode for codec */ -+ break; -+ case SND_SOC_DAIFMT_RIGHT_J: -+ /* set right J mode */ -+ break; -+ case SND_SOC_DAIFMT_LEFT_J: -+ /* set left J mode */ -+ break; -+ case SND_SOC_DAIFMT_DSP_A: -+ /* set dsp A mode */ -+ break; -+ case SND_SOC_DAIFMT_DSP_B: -+ /* set dsp B mode */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* clock inversion. codec side */ -+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_NB_NF: -+ break; -+ case SND_SOC_DAIFMT_IB_IF: -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ break; -+ case SND_SOC_DAIFMT_NB_IF: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* jzcodec_write(codec, 0, val); */ -+ return 0; -+} -+ -+static int jzcodec_dapm_event(struct snd_soc_codec *codec, int event) -+{ -+/* u16 reg_val; */ -+ -+ switch (event) { -+ case SNDRV_CTL_POWER_D0: /* full On */ -+ /* vref/mid, osc on, dac unmute */ -+ /* u16 reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); */ -+ /* jzcodec_write(codec, 0, val); */ -+ break; -+ case SNDRV_CTL_POWER_D1: /* partial On */ -+ case SNDRV_CTL_POWER_D2: /* partial On */ -+ break; -+ case SNDRV_CTL_POWER_D3hot: /* Off, with power */ -+ /* everything off except vref/vmid, */ -+ /*reg_val = 0x0800; -+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x0017; -+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); -+ REG_ICDC_CDCCR1 = jzcodec_reg[0]; -+ mdelay(2); -+ reg_val = 0x2102; -+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x001f; -+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); -+ REG_ICDC_CDCCR1 = jzcodec_reg[0]; -+ mdelay(2); -+ reg_val = 0x3302; -+ jzcodec_write_reg_cache(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x0003; -+ jzcodec_write_reg_cache(codec, ICODEC_1_HIGH, reg_val); -+ REG_ICDC_CDCCR1 = jzcodec_reg[0];*/ -+ break; -+ case SNDRV_CTL_POWER_D3cold: /* Off, without power */ -+ /* everything off, dac mute, inactive */ -+ /*reg_val = 0x2302; -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x001b; -+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); -+ mdelay(1); -+ reg_val = 0x2102; -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x001b; -+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val);*/ -+ break; -+ } -+ codec->dapm_state = event; -+ return 0; -+} -+ -+#define JZCODEC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ -+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ -+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ -+ SNDRV_PCM_RATE_48000) -+ -+#define JZCODEC_FORMATS (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FMTBIT_S16_LE) -+ -+struct snd_soc_codec_dai jzcodec_dai = { -+ .name = "JZCODEC", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = JZCODEC_RATES, -+ .formats = JZCODEC_FORMATS,}, -+ .capture = { -+ .stream_name = "Capture", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = JZCODEC_RATES, -+ .formats = JZCODEC_FORMATS,}, -+ .ops = { -+ .trigger = jzcodec_pcm_trigger, -+ .prepare = jzcodec_pcm_prepare, -+ .hw_params = jzcodec_hw_params, -+ .shutdown = jzcodec_shutdown, -+ }, -+ .dai_ops = { -+ .digital_mute = jzcodec_mute, -+ .set_sysclk = jzcodec_set_dai_sysclk, -+ .set_fmt = jzcodec_set_dai_fmt, -+ } -+}; -+EXPORT_SYMBOL_GPL(jzcodec_dai); -+ -+#ifdef CONFIG_PM -+static u16 jzcodec_reg_pm[JZCODEC_CACHEREGNUM]; -+static int jzcodec_suspend(struct platform_device *pdev, pm_message_t state) -+{ -+ struct snd_soc_device *socdev = platform_get_drvdata(pdev); -+ struct snd_soc_codec *codec = socdev->codec; -+ -+ jzcodec_reg_pm[ICODEC_1_LOW] = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); -+ jzcodec_reg_pm[ICODEC_1_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_1_HIGH); -+ jzcodec_reg_pm[ICODEC_2_LOW] = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); -+ jzcodec_reg_pm[ICODEC_2_HIGH] = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH); -+ -+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold); -+ return 0; -+} -+ -+static int jzcodec_resume(struct platform_device *pdev) -+{ -+ struct snd_soc_device *socdev = platform_get_drvdata(pdev); -+ struct snd_soc_codec *codec = socdev->codec; -+ u16 reg_val; -+ -+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); -+ reg_val = jzcodec_reg_pm[ICODEC_1_LOW]; -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ reg_val = jzcodec_reg_pm[ICODEC_1_HIGH]; -+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); -+ reg_val = jzcodec_reg_pm[ICODEC_2_LOW]; -+ jzcodec_write(codec, ICODEC_2_LOW, reg_val); -+ reg_val = jzcodec_reg_pm[ICODEC_2_HIGH]; -+ jzcodec_write(codec, ICODEC_2_HIGH, reg_val); -+ -+ jzcodec_dapm_event(codec, codec->suspend_dapm_state); -+ return 0; -+} -+#else -+#define jzcodec_suspend NULL -+#define jzcodec_resume NULL -+#endif -+/* -+ * initialise the JZCODEC driver -+ * register the mixer and dsp interfaces with the kernel -+ */ -+static int jzcodec_init(struct snd_soc_device *socdev) -+{ -+ struct snd_soc_codec *codec = socdev->codec; -+ int reg, ret = 0; -+ u16 reg_val; -+ -+ for (reg = 0; reg < JZCODEC_CACHEREGNUM / 2; reg++) { -+ switch (reg) { -+ case 0: -+ jzcodec_reg[reg] = REG_ICDC_CDCCR1; -+ jzcodec_reg_LH[ICODEC_1_LOW] = jzcodec_reg[reg] & 0xffff; -+ jzcodec_reg_LH[ICODEC_1_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16; -+ break; -+ case 1: -+ jzcodec_reg[reg] = REG_ICDC_CDCCR2; -+ jzcodec_reg_LH[ICODEC_2_LOW] = jzcodec_reg[reg] & 0xffff; -+ jzcodec_reg_LH[ICODEC_2_HIGH] = (jzcodec_reg[reg] & 0xffff0000) >> 16; -+ break; -+ } -+ } -+ -+ codec->name = "JZCODEC"; -+ codec->owner = THIS_MODULE; -+ codec->read = jzcodec_read_reg_cache; -+ codec->write = jzcodec_write; -+ codec->dapm_event = jzcodec_dapm_event; -+ codec->dai = &jzcodec_dai; -+ codec->num_dai = 1; -+ codec->reg_cache_size = sizeof(jzcodec_reg_LH); -+ codec->reg_cache = kmemdup(jzcodec_reg_LH, sizeof(jzcodec_reg_LH), GFP_KERNEL); -+ if (codec->reg_cache == NULL) -+ return -ENOMEM; -+ -+ jzcodec_reset(codec); -+ /* register pcms */ -+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); -+ if (ret < 0) { -+ printk(KERN_ERR "jzcodec: failed to create pcms\n"); -+ goto pcm_err; -+ } -+ -+ /* power on device */ -+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3hot); -+ -+ /* clear suspend bit of jz4740 internal codec */ -+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_1_LOW); -+ reg_val = reg_val & ~(0x2); -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ /* set vol bits */ -+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); -+ reg_val = reg_val | 0x3; -+ jzcodec_write(codec, ICODEC_2_LOW, reg_val); -+ /* set line in capture gain bits */ -+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_HIGH); -+ reg_val = reg_val | 0x1f; -+ jzcodec_write(codec, ICODEC_2_HIGH, reg_val); -+ /* set mic boost gain bits */ -+ reg_val = jzcodec_read_reg_cache(codec, ICODEC_2_LOW); -+ reg_val = reg_val | (0x3 << 4); -+ jzcodec_write(codec, ICODEC_2_LOW, reg_val); -+ mdelay(5); -+ reg_val = 0x3300; -+ jzcodec_write(codec, ICODEC_1_LOW, reg_val); -+ reg_val = 0x0003; -+ jzcodec_write(codec, ICODEC_1_HIGH, reg_val); -+ jzcodec_add_controls(codec); -+ jzcodec_add_widgets(codec); -+ -+ ret = snd_soc_register_card(socdev); -+ if (ret < 0) { -+ printk(KERN_ERR "jzcodec: failed to register card\n"); -+ goto card_err; -+ } -+ return ret; -+ -+card_err: -+ snd_soc_free_pcms(socdev); -+ snd_soc_dapm_free(socdev); -+pcm_err: -+ kfree(codec->reg_cache); -+ return ret; -+} -+ -+static struct snd_soc_device *jzcodec_socdev; -+ -+static int write_codec_reg(u16 * add, char * name, int reg) -+{ -+ switch (reg) { -+ case 0: -+ case 1: -+ REG_ICDC_CDCCR1 = jzcodec_reg[0]; -+ break; -+ case 2: -+ case 3: -+ REG_ICDC_CDCCR2 = jzcodec_reg[1]; -+ break; -+ } -+ return 0; -+} -+ -+static int jzcodec_probe(struct platform_device *pdev) -+{ -+ struct snd_soc_device *socdev = platform_get_drvdata(pdev); -+ struct snd_soc_codec *codec; -+ struct jzcodec_priv *jzcodec; -+ int ret = 0; -+ -+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); -+ if (codec == NULL) -+ return -ENOMEM; -+ -+ jzcodec = kzalloc(sizeof(struct jzcodec_priv), GFP_KERNEL); -+ if (jzcodec == NULL) { -+ kfree(codec); -+ return -ENOMEM; -+ } -+ -+ codec->private_data = jzcodec; -+ socdev->codec = codec; -+ mutex_init(&codec->mutex); -+ INIT_LIST_HEAD(&codec->dapm_widgets); -+ INIT_LIST_HEAD(&codec->dapm_paths); -+ -+ jzcodec_socdev = socdev; -+ -+ /* Add other interfaces here ,no I2C connection */ -+ codec->hw_write = (hw_write_t)write_codec_reg; -+ ret = jzcodec_init(jzcodec_socdev); -+ -+ if (ret < 0) { -+ codec = jzcodec_socdev->codec; -+ err("failed to initialise jzcodec\n"); -+ kfree(codec); -+ } -+ -+ return ret; -+} -+ -+/* power down chip */ -+static int jzcodec_remove(struct platform_device *pdev) -+{ -+ struct snd_soc_device *socdev = platform_get_drvdata(pdev); -+ struct snd_soc_codec *codec = socdev->codec; -+ -+ if (codec->control_data) -+ jzcodec_dapm_event(codec, SNDRV_CTL_POWER_D3cold); -+ -+ snd_soc_free_pcms(socdev); -+ snd_soc_dapm_free(socdev); -+ kfree(codec->private_data); -+ kfree(codec); -+ -+ return 0; -+} -+ -+struct snd_soc_codec_device soc_codec_dev_jzcodec = { -+ .probe = jzcodec_probe, -+ .remove = jzcodec_remove, -+ .suspend = jzcodec_suspend, -+ .resume = jzcodec_resume, -+}; -+ -+EXPORT_SYMBOL_GPL(soc_codec_dev_jzcodec); -+ -+MODULE_DESCRIPTION("ASoC JZCODEC driver"); -+MODULE_AUTHOR("Richard"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/sound/soc/codecs/jzcodec.h linux-2.6.24.7/sound/soc/codecs/jzcodec.h ---- linux-2.6.24.7.old/sound/soc/codecs/jzcodec.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/codecs/jzcodec.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,22 @@ -+/* -+ * 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 _ICODEC_H -+#define _ICODEC_H -+ -+/* jzcodec register space */ -+#define ICODEC_1_LOW 0x00 /* bit0 -- bit15 in CDCCR1 */ -+#define ICODEC_1_HIGH 0x01 /* bit16 -- bit31 in CDCCR1 */ -+#define ICODEC_2_LOW 0x02 /* bit0 -- bit16 in CDCCR2 */ -+#define ICODEC_2_HIGH 0x03 /* bit16 -- bit31 in CDCCR2 */ -+ -+#define JZCODEC_CACHEREGNUM 4 -+#define JZCODEC_SYSCLK 0 -+ -+extern struct snd_soc_codec_dai jzcodec_dai; -+extern struct snd_soc_codec_device soc_codec_dev_jzcodec; -+ -+#endif -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/Kconfig linux-2.6.24.7/sound/soc/jz4740/Kconfig ---- linux-2.6.24.7.old/sound/soc/jz4740/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/Kconfig 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,34 @@ -+config SND_JZ4740_SOC -+ tristate "SoC Audio for Ingenic jz4740 chip" -+ depends on (JZ4740_PAVO || JZ4725_DIPPER || JZ4720_VIRGO) && SND_SOC -+ help -+ Say Y or M if you want to add support for codecs attached to -+ the Jz4740 AC97, I2S or SSP interface. You will also need -+ to select the audio interfaces to support below. -+ -+config SND_JZ4740_SOC_PAVO -+ tristate "SoC Audio support for Ingenic Jz4740 PAVO board" -+ depends on SND_JZ4740_SOC -+ help -+ Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 PAVO board. -+ -+config SND_JZ4740_AC97 -+ tristate "select AC97 protocol and AC97 codec pcm core support" -+ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO -+ select SND_AC97_CODEC -+ help -+ Say Y if you want to add AC97 protocol support for pcm core. -+ -+config SND_JZ4740_SOC_AC97 -+ tristate "SoC Audio (AC97 protocol) for Ingenic jz4740 chip" -+ depends on SND_JZ4740_SOC && SND_JZ4740_AC97 && SND_JZ4740_SOC_PAVO -+ select AC97_BUS -+ select SND_SOC_AC97_BUS -+ help -+ Say Y if you want to use AC97 protocol and ac97 codec on Ingenic Jz4740 PAVO board. -+ -+config SND_JZ4740_SOC_I2S -+ depends on SND_JZ4740_SOC && SND_JZ4740_SOC_PAVO -+ tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip" -+ help -+ Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 PAVO board. -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/Makefile linux-2.6.24.7/sound/soc/jz4740/Makefile ---- linux-2.6.24.7.old/sound/soc/jz4740/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/Makefile 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,15 @@ -+# -+# Jz4740 Platform Support -+# -+snd-soc-jz4740-objs := jz4740-pcm.o -+snd-soc-jz4740-ac97-objs := jz4740-ac97.o -+snd-soc-jz4740-i2s-objs := jz4740-i2s.o -+ -+obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o -+obj-$(CONFIG_SND_JZ4740_SOC_AC97) += snd-soc-jz4740-ac97.o -+obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o -+ -+# Jz4740 Machine Support -+snd-soc-pavo-objs := pavo.o -+ -+obj-$(CONFIG_SND_JZ4740_SOC_PAVO) += snd-soc-pavo.o -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-ac97.c linux-2.6.24.7/sound/soc/jz4740/jz4740-ac97.c ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-ac97.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-ac97.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,261 @@ -+/* -+ * linux/sound/jz4740-ac97.c -- AC97 support for the Ingenic jz4740 chip. -+ * -+ * Author: Richard -+ * Created: Dec 02, 2007 -+ * Copyright: Ingenic Semiconductor Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "jz4740-pcm.h" -+#include "jz4740-ac97.h" -+ -+static DEFINE_MUTEX(car_mutex); -+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); -+static volatile long gsr_bits; -+ -+static unsigned short jz4740_ac97_read(struct snd_ac97 *ac97, -+ unsigned short reg) -+{ -+ unsigned short val = -1; -+ volatile u32 *reg_addr; -+ -+ mutex_lock(&car_mutex); -+ -+out: mutex_unlock(&car_mutex); -+ return val; -+} -+ -+static void jz4740_ac97_write(struct snd_ac97 *ac97, unsigned short reg, -+ unsigned short val) -+{ -+ volatile u32 *reg_addr; -+ -+ mutex_lock(&car_mutex); -+ -+ mutex_unlock(&car_mutex); -+} -+ -+static void jz4740_ac97_warm_reset(struct snd_ac97 *ac97) -+{ -+ gsr_bits = 0; -+} -+ -+static void jz4740_ac97_cold_reset(struct snd_ac97 *ac97) -+{ -+} -+ -+static irqreturn_t jz4740_ac97_irq(int irq, void *dev_id) -+{ -+ long status; -+ return IRQ_NONE; -+} -+ -+struct snd_ac97_bus_ops soc_ac97_ops = { -+ .read = jz4740_ac97_read, -+ .write = jz4740_ac97_write, -+ .warm_reset = jz4740_ac97_warm_reset, -+ .reset = jz4740_ac97_cold_reset, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_out = { -+ .name = "AC97 PCM Stereo out", -+ .dev_addr = __PREG(PCDR), -+ .drcmr = &DRCMRTXPCDR, -+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | -+ DCMD_BURST32 | DCMD_WIDTH4, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_stereo_in = { -+ .name = "AC97 PCM Stereo in", -+ .dev_addr = __PREG(PCDR), -+ .drcmr = &DRCMRRXPCDR, -+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | -+ DCMD_BURST32 | DCMD_WIDTH4, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_out = { -+ .name = "AC97 Aux PCM (Slot 5) Mono out", -+ .dev_addr = __PREG(MODR), -+ .drcmr = &DRCMRTXMODR, -+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | -+ DCMD_BURST16 | DCMD_WIDTH2, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_aux_mono_in = { -+ .name = "AC97 Aux PCM (Slot 5) Mono in", -+ .dev_addr = __PREG(MODR), -+ .drcmr = &DRCMRRXMODR, -+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | -+ DCMD_BURST16 | DCMD_WIDTH2, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_ac97_pcm_mic_mono_in = { -+ .name = "AC97 Mic PCM (Slot 6) Mono in", -+ .dev_addr = __PREG(MCDR), -+ .drcmr = &DRCMRRXMCDR, -+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | -+ DCMD_BURST16 | DCMD_WIDTH2, -+}; -+ -+#ifdef CONFIG_PM -+static int jz4740_ac97_suspend(struct platform_device *pdev, -+ struct snd_soc_cpu_dai *dai) -+{ -+ return 0; -+} -+ -+static int jz4740_ac97_resume(struct platform_device *pdev, -+ struct snd_soc_cpu_dai *dai) -+{ -+ return 0; -+} -+ -+#else -+#define jz4740_ac97_suspend NULL -+#define jz4740_ac97_resume NULL -+#endif -+ -+static int jz4740_ac97_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ return 0; -+} -+ -+static void jz4740_ac97_remove(struct platform_device *pdev) -+{ -+} -+ -+static int jz4740_ac97_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_out; -+ else -+ cpu_dai->dma_data = &jz4740_ac97_pcm_stereo_in; -+ -+ return 0; -+} -+ -+static int jz4740_ac97_hw_aux_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_out; -+ else -+ cpu_dai->dma_data = &jz4740_ac97_pcm_aux_mono_in; -+ -+ return 0; -+} -+ -+static int jz4740_ac97_hw_mic_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ return -ENODEV; -+ else -+ cpu_dai->dma_data = &jz4740_ac97_pcm_mic_mono_in; -+ -+ return 0; -+} -+ -+#define JZ4740_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ -+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ -+ SNDRV_PCM_RATE_48000) -+ -+struct snd_soc_cpu_dai jz4740_ac97_dai[] = { -+{ -+ .name = "jz4740-ac97", -+ .id = 0, -+ .type = SND_SOC_DAI_AC97, -+ .probe = jz4740_ac97_probe, -+ .remove = jz4740_ac97_remove, -+ .suspend = jz4740_ac97_suspend, -+ .resume = jz4740_ac97_resume, -+ .playback = { -+ .stream_name = "AC97 Playback", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = JZ4740_AC97_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -+ .capture = { -+ .stream_name = "AC97 Capture", -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = JZ4740_AC97_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -+ .ops = { -+ .hw_params = jz4740_ac97_hw_params,}, -+}, -+{ -+ .name = "jz4740-ac97-aux", -+ .id = 1, -+ .type = SND_SOC_DAI_AC97, -+ .playback = { -+ .stream_name = "AC97 Aux Playback", -+ .channels_min = 1, -+ .channels_max = 1, -+ .rates = JZ4740_AC97_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -+ .capture = { -+ .stream_name = "AC97 Aux Capture", -+ .channels_min = 1, -+ .channels_max = 1, -+ .rates = JZ4740_AC97_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -+ .ops = { -+ .hw_params = jz4740_ac97_hw_aux_params,}, -+}, -+{ -+ .name = "jz4740-ac97-mic", -+ .id = 2, -+ .type = SND_SOC_DAI_AC97, -+ .capture = { -+ .stream_name = "AC97 Mic Capture", -+ .channels_min = 1, -+ .channels_max = 1, -+ .rates = JZ4740_AC97_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE,}, -+ .ops = { -+ .hw_params = jz4740_ac97_hw_mic_params,}, -+}, -+}; -+ -+EXPORT_SYMBOL_GPL(jz4740_ac97_dai); -+EXPORT_SYMBOL_GPL(soc_ac97_ops); -+ -+MODULE_AUTHOR("Richard"); -+MODULE_DESCRIPTION("AC97 driver for the Ingenic jz4740 chip"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-ac97.h linux-2.6.24.7/sound/soc/jz4740/jz4740-ac97.h ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-ac97.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-ac97.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,21 @@ -+/* -+ * linux/sound/soc/jz4740/jz4740-ac97.h -+ * -+ * 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 _JZ4740_AC97_H -+#define _JZ4740_AC97_H -+ -+#define JZ4740_DAI_AC97_HIFI 0 -+#define JZ4740_DAI_AC97_AUX 1 -+#define JZ4740_DAI_AC97_MIC 2 -+ -+extern struct snd_soc_cpu_dai jz4740_ac97_dai[3]; -+ -+/* platform data */ -+extern struct snd_ac97_bus_ops jz4740_ac97_ops; -+ -+#endif -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-i2s.c linux-2.6.24.7/sound/soc/jz4740/jz4740-i2s.c ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-i2s.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-i2s.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,296 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "jz4740-pcm.h" -+#include "jz4740-i2s.h" -+ -+static struct jz4740_dma_client jz4740_dma_client_out = { -+ .name = "I2S PCM Stereo out" -+}; -+ -+static struct jz4740_dma_client jz4740_dma_client_in = { -+ .name = "I2S PCM Stereo in" -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = { -+ .client = &jz4740_dma_client_out, -+ .channel = DMA_ID_AIC_TX, -+ .dma_addr = AIC_DR, -+ .dma_size = 2, -+}; -+ -+static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = { -+ .client = &jz4740_dma_client_in, -+ .channel = DMA_ID_AIC_RX, -+ .dma_addr = AIC_DR, -+ .dma_size = 2, -+}; -+ -+static int jz4740_i2s_startup(struct snd_pcm_substream *substream) -+{ -+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/ -+ -+ return 0; -+} -+ -+static int jz4740_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, -+ unsigned int fmt) -+{ -+ /* interface format */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ /* 1 : ac97 , 0 : i2s */ -+ break; -+ case SND_SOC_DAIFMT_LEFT_J: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ /* 0 : slave */ -+ break; -+ case SND_SOC_DAIFMT_CBM_CFS: -+ /* 1 : master */ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+/* -+* Set Jz4740 Clock source -+*/ -+static int jz4740_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, -+ int clk_id, unsigned int freq, int dir) -+{ -+ return 0; -+} -+ -+static void jz4740_snd_tx_ctrl(int on) -+{ -+ if (on) { -+ /* enable replay */ -+ __i2s_enable_transmit_dma(); -+ __i2s_enable_replay(); -+ __i2s_enable(); -+ -+ } else { -+ /* disable replay & capture */ -+ __i2s_disable_replay(); -+ __i2s_disable_record(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable(); -+ } -+} -+ -+static void jz4740_snd_rx_ctrl(int on) -+{ -+ if (on) { -+ /* enable capture */ -+ __i2s_enable_receive_dma(); -+ __i2s_enable_record(); -+ __i2s_enable(); -+ -+ } else { -+ /* disable replay & capture */ -+ __i2s_disable_replay(); -+ __i2s_disable_record(); -+ __i2s_disable_receive_dma(); -+ __i2s_disable_transmit_dma(); -+ __i2s_disable(); -+ } -+} -+ -+static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ int channels = params_channels(params); -+ -+ jz4740_snd_rx_ctrl(0); -+ jz4740_snd_rx_ctrl(0); -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out; -+ if (channels == 1) -+ __aic_enable_mono2stereo(); -+ else -+ __aic_disable_mono2stereo(); -+ } else -+ cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in; -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S8: -+ __i2s_set_transmit_trigger(4); -+ __i2s_set_receive_trigger(3); -+ __i2s_set_oss_sample_size(8); -+ __i2s_set_iss_sample_size(8); -+ break; -+ case SNDRV_PCM_FORMAT_S16_LE: -+ /* playback sample:16 bits, burst:16 bytes */ -+ __i2s_set_transmit_trigger(4); -+ /* capture sample:16 bits, burst:16 bytes */ -+ __i2s_set_receive_trigger(3); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ break; -+ } -+ -+ return 0; -+} -+ -+static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ int ret = 0; -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ jz4740_snd_rx_ctrl(1); -+ else -+ jz4740_snd_tx_ctrl(1); -+ break; -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ jz4740_snd_rx_ctrl(0); -+ else -+ jz4740_snd_tx_ctrl(0); -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream) -+{ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ } else { -+ } -+ -+ return; -+} -+ -+static int jz4740_i2s_probe(struct platform_device *pdev) -+{ -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ mdelay(2); -+ -+ __i2s_disable(); -+ __i2s_reset(); -+ mdelay(2); -+ -+ __i2s_disable(); -+ __i2s_internal_codec(); -+ __i2s_as_slave(); -+ __i2s_select_i2s(); -+ __aic_select_i2s(); -+ __i2s_set_oss_sample_size(16); -+ __i2s_set_iss_sample_size(16); -+ __aic_play_lastsample(); -+ -+ __i2s_disable_record(); -+ __i2s_disable_replay(); -+ __i2s_disable_loopback(); -+ __i2s_set_transmit_trigger(7); -+ __i2s_set_receive_trigger(7); -+ -+ jz4740_snd_tx_ctrl(0); -+ jz4740_snd_rx_ctrl(0); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int jz4740_i2s_suspend(struct platform_device *dev, -+ struct snd_soc_cpu_dai *dai) -+{ -+ if (!dai->active) -+ return 0; -+ -+ return 0; -+} -+ -+static int jz4740_i2s_resume(struct platform_device *pdev, -+ struct snd_soc_cpu_dai *dai) -+{ -+ if (!dai->active) -+ return 0; -+ -+ return 0; -+} -+ -+#else -+#define jz4740_i2s_suspend NULL -+#define jz4740_i2s_resume NULL -+#endif -+ -+#define JZ4740_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ -+ SNDRV_PCM_RATE_12000 | SNDRV_PCM_RATE_16000 |\ -+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_24000 |\ -+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ -+ SNDRV_PCM_RATE_48000) -+ -+struct snd_soc_cpu_dai jz4740_i2s_dai = { -+ .name = "jz4740-i2s", -+ .id = 0, -+ .type = SND_SOC_DAI_I2S, -+ .probe = jz4740_i2s_probe, -+ .suspend = jz4740_i2s_suspend, -+ .resume = jz4740_i2s_resume, -+ .playback = { -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = JZ4740_I2S_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, -+ .capture = { -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = JZ4740_I2S_RATES, -+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, -+ .ops = { -+ .startup = jz4740_i2s_startup, -+ .shutdown = jz4740_i2s_shutdown, -+ .trigger = jz4740_i2s_trigger, -+ .hw_params = jz4740_i2s_hw_params,}, -+ .dai_ops = { -+ .set_fmt = jz4740_i2s_set_dai_fmt, -+ .set_sysclk = jz4740_i2s_set_dai_sysclk, -+ }, -+}; -+ -+EXPORT_SYMBOL_GPL(jz4740_i2s_dai); -+ -+/* Module information */ -+MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); -+MODULE_DESCRIPTION("jz4740 I2S SoC Interface"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-i2s.h linux-2.6.24.7/sound/soc/jz4740/jz4740-i2s.h ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-i2s.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-i2s.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,18 @@ -+/* -+ * 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 _JZ4740_I2S_H -+#define _JZ4740_I2S_H -+ -+/* jz4740 DAI ID's */ -+#define JZ4740_DAI_I2S 0 -+ -+/* I2S clock */ -+#define JZ4740_I2S_SYSCLK 0 -+ -+extern struct snd_soc_cpu_dai jz4740_i2s_dai; -+ -+#endif -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-pcm.c linux-2.6.24.7/sound/soc/jz4740/jz4740-pcm.c ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-pcm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-pcm.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,689 @@ -+/* -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "jz4740-pcm.h" -+ -+static long sum_bytes = 0; -+static int first_transfer = 0; -+static int printk_flag = 0; -+static int tran_bit = 0; -+#ifdef CONFIG_SND_OSSEMUL -+static int hw_params_cnt = 0; -+#endif -+ -+struct jz4740_dma_buf_aic { -+ struct jz4740_dma_buf_aic *next; -+ int size; /* buffer size in bytes */ -+ dma_addr_t data; /* start of DMA data */ -+ dma_addr_t ptr; /* where the DMA got to [1] */ -+ void *id; /* client's id */ -+}; -+ -+struct jz4740_runtime_data { -+ spinlock_t lock; -+ int state; -+ int aic_dma_flag; /* start dma transfer or not */ -+ unsigned int dma_loaded; -+ unsigned int dma_limit; -+ unsigned int dma_period; -+ dma_addr_t dma_start; -+ dma_addr_t dma_pos; -+ dma_addr_t dma_end; -+ struct jz4740_pcm_dma_params *params; -+ -+ dma_addr_t user_cur_addr; /* user current write buffer start address */ -+ unsigned int user_cur_len; /* user current write buffer length */ -+ -+ /* buffer list and information */ -+ struct jz4740_dma_buf_aic *curr; /* current dma buffer */ -+ struct jz4740_dma_buf_aic *next; /* next buffer to load */ -+ struct jz4740_dma_buf_aic *end; /* end of queue */ -+ -+}; -+ -+/* identify hardware playback capabilities */ -+static const struct snd_pcm_hardware jz4740_pcm_hardware = { -+ .info = SNDRV_PCM_INFO_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_BLOCK_TRANSFER, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_U16_LE | -+ SNDRV_PCM_FMTBIT_U8 | -+ SNDRV_PCM_FMTBIT_S8, -+ .rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/, -+ .rate_min = 8000, -+ .rate_min = 48000, -+ .channels_min = 1,//2 -+ .channels_max = 2, -+ .buffer_bytes_max = 128 * 1024,//16 * 1024 -+ .period_bytes_min = PAGE_SIZE, -+ .period_bytes_max = PAGE_SIZE * 2, -+ .periods_min = 2, -+ .periods_max = 128,//16, -+ .fifo_size = 32, -+}; -+ -+/* jz4740__dma_buf_enqueue -+ * -+ * queue an given buffer for dma transfer. -+ * -+ * data the physical address of the buffer data -+ * size the size of the buffer in bytes -+ * -+*/ -+static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size) -+{ -+ struct jz4740_dma_buf_aic *aic_buf; -+ -+ aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL); -+ if (aic_buf == NULL) { -+ printk("aic buffer allocate failed,no memory!\n"); -+ return -ENOMEM; -+ } -+ aic_buf->next = NULL; -+ aic_buf->data = aic_buf->ptr = data; -+ aic_buf->size = size; -+ if( prtd->curr == NULL) { -+ prtd->curr = aic_buf; -+ prtd->end = aic_buf; -+ prtd->next = NULL; -+ } else { -+ if (prtd->end == NULL) -+ printk("prtd->end is NULL\n"); -+ prtd->end->next = aic_buf; -+ prtd->end = aic_buf; -+ } -+ -+ /* if necessary, update the next buffer field */ -+ if (prtd->next == NULL) -+ prtd->next = aic_buf; -+ -+ return 0; -+} -+ -+ -+void audio_start_dma(struct jz4740_runtime_data *prtd, int mode) -+{ -+ unsigned long flags; -+ struct jz4740_dma_buf_aic *aic_buf; -+ int channel; -+ -+ switch (mode) { -+ case DMA_MODE_WRITE: -+ /* free cur aic_buf */ -+ if (first_transfer == 1) { -+ first_transfer = 0; -+ } else { -+ aic_buf = prtd->curr; -+ if (aic_buf != NULL) { -+ prtd->curr = aic_buf->next; -+ prtd->next = aic_buf->next; -+ aic_buf->next = NULL; -+ kfree(aic_buf); -+ aic_buf = NULL; -+ } -+ } -+ -+ aic_buf = prtd->next; -+ channel = prtd->params->channel; -+ if (aic_buf) { -+ flags = claim_dma_lock(); -+ disable_dma(channel); -+ jz_set_alsa_dma(channel, mode, tran_bit); -+ set_dma_addr(channel, aic_buf->data); -+ set_dma_count(channel, aic_buf->size); -+ enable_dma(channel); -+ release_dma_lock(flags); -+ prtd->aic_dma_flag |= AIC_START_DMA; -+ } else { -+ printk("next buffer is NULL for playback\n"); -+ prtd->aic_dma_flag &= ~AIC_START_DMA; -+ return; -+ } -+ break; -+ case DMA_MODE_READ: -+ /* free cur aic_buf */ -+ if (first_transfer == 1) { -+ first_transfer = 0; -+ } else { -+ aic_buf = prtd->curr; -+ if (aic_buf != NULL) { -+ prtd->curr = aic_buf->next; -+ prtd->next = aic_buf->next; -+ aic_buf->next = NULL; -+ kfree(aic_buf); -+ aic_buf = NULL; -+ } -+ } -+ -+ aic_buf = prtd->next; -+ channel = prtd->params->channel; -+ -+ if (aic_buf) { -+ flags = claim_dma_lock(); -+ disable_dma(channel); -+ jz_set_alsa_dma(channel, mode, tran_bit); -+ set_dma_addr(channel, aic_buf->data); -+ set_dma_count(channel, aic_buf->size); -+ enable_dma(channel); -+ release_dma_lock(flags); -+ prtd->aic_dma_flag |= AIC_START_DMA; -+ } else { -+ printk("next buffer is NULL for capture\n"); -+ prtd->aic_dma_flag &= ~AIC_START_DMA; -+ return; -+ } -+ break; -+ } -+ /* dump_jz_dma_channel(channel); */ -+} -+ -+/* -+ * place a dma buffer onto the queue for the dma system to handle. -+*/ -+static void jz4740_pcm_enqueue(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ /*struct snd_dma_buffer *buf = &substream->dma_buffer;*/ -+ dma_addr_t pos = prtd->dma_pos; -+ int ret; -+ -+ while (prtd->dma_loaded < prtd->dma_limit) { -+ unsigned long len = prtd->dma_period; -+ -+ if ((pos + len) > prtd->dma_end) { -+ len = prtd->dma_end - pos; -+ } -+ ret = jz4740_dma_buf_enqueue(prtd, pos, len); -+ if (ret == 0) { -+ prtd->dma_loaded++; -+ pos += prtd->dma_period; -+ if (pos >= prtd->dma_end) -+ pos = prtd->dma_start; -+ } else -+ break; -+ } -+ -+ prtd->dma_pos = pos; -+} -+ -+/* -+ * call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer -+ */ -+static irqreturn_t jz4740_pcm_dma_irq(int dma_ch, void *dev_id) -+{ -+ struct snd_pcm_substream *substream = dev_id; -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ /*struct jz4740_dma_buf_aic *aic_buf = prtd->curr;*/ -+ int channel = prtd->params->channel; -+ unsigned long flags; -+ -+ disable_dma(channel); -+ prtd->aic_dma_flag &= ~AIC_START_DMA; -+ /* must clear TT bit in DCCSR to avoid interrupt again */ -+ if (__dmac_channel_transmit_end_detected(channel)) { -+ __dmac_channel_clear_transmit_end(channel); -+ } -+ if (__dmac_channel_transmit_halt_detected(channel)) { -+ __dmac_channel_clear_transmit_halt(channel); -+ } -+ -+ if (__dmac_channel_address_error_detected(channel)) { -+ __dmac_channel_clear_address_error(channel); -+ } -+ -+ if (substream) -+ snd_pcm_period_elapsed(substream); -+ -+ spin_lock(&prtd->lock); -+ prtd->dma_loaded--; -+ if (prtd->state & ST_RUNNING) { -+ jz4740_pcm_enqueue(substream); -+ } -+ spin_unlock(&prtd->lock); -+ -+ local_irq_save(flags); -+ if (prtd->state & ST_RUNNING) { -+ if (prtd->dma_loaded) { -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -+ audio_start_dma(prtd, DMA_MODE_WRITE); -+ else -+ audio_start_dma(prtd, DMA_MODE_READ); -+ } -+ } -+ local_irq_restore(flags); -+ return IRQ_HANDLED; -+} -+ -+/* some parameter about DMA operation */ -+static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct jz4740_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; -+ size_t totbytes = params_buffer_bytes(params); -+ int ret; -+ -+#ifdef CONFIG_SND_OSSEMUL -+ if (hw_params_cnt) -+ return 0; -+ else -+ hw_params_cnt++ ; -+#endif -+ -+ if (!dma) -+ return 0; -+ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S8: -+ tran_bit = 8; -+ break; -+ case SNDRV_PCM_FORMAT_S16_LE: -+ tran_bit = 16; -+ break; -+ } -+ -+ /* prepare DMA */ -+ prtd->params = dma; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name, -+ jz4740_pcm_dma_irq, IRQF_DISABLED, substream); -+ if (ret < 0) -+ return ret; -+ prtd->params->channel = ret; -+ } else { -+ ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name, -+ jz4740_pcm_dma_irq, IRQF_DISABLED, substream); -+ if (ret < 0) -+ return ret; -+ prtd->params->channel = ret; -+ } -+ -+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); -+ runtime->dma_bytes = totbytes; -+ -+ spin_lock_irq(&prtd->lock); -+ prtd->dma_loaded = 0; -+ prtd->aic_dma_flag = 0; -+ prtd->dma_limit = runtime->hw.periods_min; -+ prtd->dma_period = params_period_bytes(params); -+ prtd->dma_start = runtime->dma_addr; -+ prtd->dma_pos = prtd->dma_start; -+ prtd->dma_end = prtd->dma_start + totbytes; -+ prtd->curr = NULL; -+ prtd->next = NULL; -+ prtd->end = NULL; -+ sum_bytes = 0; -+ first_transfer = 1; -+ printk_flag = 0; -+ -+ __dmac_disable_descriptor(prtd->params->channel); -+ __dmac_channel_disable_irq(prtd->params->channel); -+ spin_unlock_irq(&prtd->lock); -+ -+ return ret; -+} -+ -+static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct jz4740_runtime_data *prtd = substream->runtime->private_data; -+ -+ snd_pcm_set_runtime_buffer(substream, NULL); -+ if (prtd->params) { -+ jz_free_dma(prtd->params->channel); -+ prtd->params = NULL; -+ } -+ -+ return 0; -+} -+ -+/* set some dma para for playback/capture */ -+static int jz4740_dma_ctrl(int channel) -+{ -+ -+ disable_dma(channel); -+ -+ /* must clear TT bit in DCCSR to avoid interrupt again */ -+ if (__dmac_channel_transmit_end_detected(channel)) { -+ __dmac_channel_clear_transmit_end(channel); -+ } -+ if (__dmac_channel_transmit_halt_detected(channel)) { -+ __dmac_channel_clear_transmit_halt(channel); -+ } -+ -+ if (__dmac_channel_address_error_detected(channel)) { -+ __dmac_channel_clear_address_error(channel); -+ } -+ -+ return 0; -+ -+} -+ -+static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) -+{ -+ struct jz4740_runtime_data *prtd = substream->runtime->private_data; -+ int ret = 0; -+ -+ /* return if this is a bufferless transfer e.g */ -+ if (!prtd->params) -+ return 0; -+ -+ /* flush the DMA channel and DMA channel bit check */ -+ jz4740_dma_ctrl(prtd->params->channel); -+ prtd->dma_loaded = 0; -+ prtd->dma_pos = prtd->dma_start; -+ -+ /* enqueue dma buffers */ -+ jz4740_pcm_enqueue(substream); -+ -+ return ret; -+ -+} -+ -+static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ -+ int ret = 0; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ prtd->state |= ST_RUNNING; -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ audio_start_dma(prtd, DMA_MODE_WRITE); -+ } else { -+ audio_start_dma(prtd, DMA_MODE_READ); -+ } -+ -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ prtd->state &= ~ST_RUNNING; -+ break; -+ -+ case SNDRV_PCM_TRIGGER_RESUME: -+ printk(" RESUME \n"); -+ break; -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ printk(" RESTART \n"); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static snd_pcm_uframes_t -+jz4740_pcm_pointer(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ struct jz4740_dma_buf_aic *aic_buf = prtd->curr; -+ long count,res; -+ -+ dma_addr_t ptr; -+ snd_pcm_uframes_t x; -+ int channel = prtd->params->channel; -+ -+ spin_lock(&prtd->lock); -+#if 1 -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ count = get_dma_residue(channel); -+ count = aic_buf->size - count; -+ ptr = aic_buf->data + count; -+ res = ptr - prtd->dma_start; -+ } else { -+ count = get_dma_residue(channel); -+ count = aic_buf->size - count; -+ ptr = aic_buf->data + count; -+ res = ptr - prtd->dma_start; -+ } -+ -+# else -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { -+ count = get_dma_residue(channel); -+ count = aic_buf->size - count; -+ ptr = aic_buf->data + count; -+ REG_DMAC_DSAR(channel) = ptr; -+ res = ptr - prtd->dma_start; -+ } else { -+ ptr = REG_DMAC_DSAR(channel); -+ if (ptr == 0x0) -+ printk("\ndma address is 00000000 in running!\n"); -+ res = ptr - prtd->dma_start; -+ } -+ } else { -+ if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { -+ count = get_dma_residue(channel); -+ count = aic_buf->size - count; -+ ptr = aic_buf->data + count; -+ REG_DMAC_DTAR(channel) = ptr; -+ res = ptr - prtd->dma_start; -+ } else { -+ ptr = REG_DMAC_DTAR(channel); -+ if (ptr == 0x0) -+ printk("\ndma address is 00000000 in running!\n"); -+ res = ptr - prtd->dma_start; -+ } -+ } -+#endif -+ spin_unlock(&prtd->lock); -+ x = bytes_to_frames(runtime, res); -+ if (x == runtime->buffer_size) -+ x = 0; -+ -+ return x; -+} -+ -+static int jz4740_pcm_open(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd; -+ -+#ifdef CONFIG_SND_OSSEMUL -+ hw_params_cnt = 0; -+#endif -+ snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); -+ prtd = kzalloc(sizeof(struct jz4740_runtime_data), GFP_KERNEL); -+ if (prtd == NULL) -+ return -ENOMEM; -+ -+ spin_lock_init(&prtd->lock); -+ -+ runtime->private_data = prtd; -+ -+ return 0; -+} -+ -+static int jz4740_pcm_close(struct snd_pcm_substream *substream) -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ struct jz4740_runtime_data *prtd = runtime->private_data; -+ struct jz4740_dma_buf_aic *aic_buf = NULL; -+ -+#ifdef CONFIG_SND_OSSEMUL -+ hw_params_cnt = 0; -+#endif -+ -+ if (prtd) -+ aic_buf = prtd->curr; -+ -+ while (aic_buf != NULL) { -+ prtd->curr = aic_buf->next; -+ prtd->next = aic_buf->next; -+ aic_buf->next = NULL; -+ kfree(aic_buf); -+ aic_buf = NULL; -+ aic_buf = prtd->curr; -+ } -+ -+ if (prtd) { -+ prtd->curr = NULL; -+ prtd->next = NULL; -+ prtd->end = NULL; -+ kfree(prtd); -+ } -+ -+ return 0; -+} -+ -+static int jz4740_pcm_mmap(struct snd_pcm_substream *substream, -+ struct vm_area_struct *vma)//include/linux/mm.h -+{ -+ struct snd_pcm_runtime *runtime = substream->runtime; -+ unsigned long start; -+ unsigned long off; -+ u32 len; -+ int ret = -ENXIO; -+ -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ start = runtime->dma_addr; -+ -+ len = PAGE_ALIGN((start & ~PAGE_MASK) + runtime->dma_bytes); -+ start &= PAGE_MASK; -+ -+ if ((vma->vm_end - vma->vm_start + off) > len) { -+ return -EINVAL; -+ } -+ -+ off += start; -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ vma->vm_flags |= VM_IO; -+ -+#if defined(CONFIG_MIPS32) -+ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; -+ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; -+ /* pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT; */ -+#endif -+ ret = io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, -+ vma->vm_end - vma->vm_start, -+ vma->vm_page_prot); -+ -+ return ret; -+} -+ -+struct snd_pcm_ops jz4740_pcm_ops = { -+ .open = jz4740_pcm_open, -+ .close = jz4740_pcm_close, -+ .ioctl = snd_pcm_lib_ioctl, -+ .hw_params = jz4740_pcm_hw_params, -+ .hw_free = jz4740_pcm_hw_free, -+ .prepare = jz4740_pcm_prepare, -+ .trigger = jz4740_pcm_trigger, -+ .pointer = jz4740_pcm_pointer, -+ .mmap = jz4740_pcm_mmap, -+}; -+ -+static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) -+{ -+ struct snd_pcm_substream *substream = pcm->streams[stream].substream; -+ struct snd_dma_buffer *buf = &substream->dma_buffer; -+ size_t size = jz4740_pcm_hardware.buffer_bytes_max; -+ buf->dev.type = SNDRV_DMA_TYPE_DEV; -+ buf->dev.dev = pcm->card->dev; -+ buf->private_data = NULL; -+ -+ /*buf->area = dma_alloc_coherent(pcm->card->dev, size, -+ &buf->addr, GFP_KERNEL);*/ -+ buf->area = dma_alloc_noncoherent(pcm->card->dev, size, -+ &buf->addr, GFP_KERNEL); -+ if (!buf->area) -+ return -ENOMEM; -+ buf->bytes = size; -+ return 0; -+} -+ -+static void jz4740_pcm_free_dma_buffers(struct snd_pcm *pcm) -+{ -+ struct snd_pcm_substream *substream; -+ struct snd_dma_buffer *buf; -+ int stream; -+ -+ for (stream = 0; stream < 2; stream++) { -+ substream = pcm->streams[stream].substream; -+ if (!substream) -+ continue; -+ -+ buf = &substream->dma_buffer; -+ if (!buf->area) -+ continue; -+ -+ dma_free_noncoherent(pcm->card->dev, buf->bytes, -+ buf->area, buf->addr); -+ buf->area = NULL; -+ } -+} -+ -+static u64 jz4740_pcm_dmamask = DMA_32BIT_MASK; -+ -+int jz4740_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, -+ struct snd_pcm *pcm) -+{ -+ int ret = 0; -+ -+ if (!card->dev->dma_mask) -+ card->dev->dma_mask = &jz4740_pcm_dmamask; -+ if (!card->dev->coherent_dma_mask) -+ card->dev->coherent_dma_mask = DMA_32BIT_MASK; -+ -+ if (dai->playback.channels_min) { -+ ret = jz4740_pcm_preallocate_dma_buffer(pcm, -+ SNDRV_PCM_STREAM_PLAYBACK); -+ if (ret) -+ goto out; -+ } -+ -+ if (dai->capture.channels_min) { -+ ret = jz4740_pcm_preallocate_dma_buffer(pcm, -+ SNDRV_PCM_STREAM_CAPTURE); -+ if (ret) -+ goto out; -+ } -+ out: -+ -+ return ret; -+} -+ -+struct snd_soc_platform jz4740_soc_platform = { -+ .name = "jz4740-audio", -+ .pcm_ops = &jz4740_pcm_ops, -+ .pcm_new = jz4740_pcm_new, -+ .pcm_free = jz4740_pcm_free_dma_buffers, -+}; -+ -+EXPORT_SYMBOL_GPL(jz4740_soc_platform); -+ -+MODULE_AUTHOR("Richard"); -+MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/jz4740-pcm.h linux-2.6.24.7/sound/soc/jz4740/jz4740-pcm.h ---- linux-2.6.24.7.old/sound/soc/jz4740/jz4740-pcm.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/jz4740-pcm.h 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,33 @@ -+/* -+ * -+ * 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 _JZ4740_PCM_H -+#define _JZ4740_PCM_H -+ -+#include -+ -+#define ST_RUNNING (1<<0) -+#define ST_OPENED (1<<1) -+ -+#define AIC_START_DMA (1<<0) -+#define AIC_END_DMA (1<<1) -+ -+struct jz4740_dma_client { -+ char *name; -+}; -+ -+struct jz4740_pcm_dma_params { -+ struct jz4740_dma_client *client; /* stream identifier */ -+ int channel; /* Channel ID */ -+ dma_addr_t dma_addr; -+ int dma_size; /* Size of the DMA transfer */ -+}; -+ -+/* platform data */ -+extern struct snd_soc_platform jz4740_soc_platform; -+ -+#endif -diff -urN linux-2.6.24.7.old/sound/soc/jz4740/pavo.c linux-2.6.24.7/sound/soc/jz4740/pavo.c ---- linux-2.6.24.7.old/sound/soc/jz4740/pavo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7/sound/soc/jz4740/pavo.c 2009-04-12 18:13:57.000000000 +0200 -@@ -0,0 +1,360 @@ -+/* -+ * pavo.c -- SoC audio for PAVO -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../codecs/jzcodec.h" -+#include "jz4740-pcm.h" -+#include "jz4740-i2s.h" -+ -+#define PAVO_HP 0 -+#define PAVO_MIC 1 -+#define PAVO_LINE 2 -+#define PAVO_HEADSET 3 -+#define PAVO_HP_OFF 4 -+#define PAVO_SPK_ON 0 -+#define PAVO_SPK_OFF 1 -+ -+ /* audio clock in Hz - rounded from 12.235MHz */ -+#define PAVO_AUDIO_CLOCK 12288000 -+ -+static int pavo_jack_func; -+static int pavo_spk_func; -+ -+unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) -+{ -+ unsigned short gpio_bit = 0; -+ -+ return gpio_bit; -+} -+ -+unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) -+{ -+ unsigned short gpio_bit = 0; -+ -+ return gpio_bit; -+} -+ -+static void pavo_ext_control(struct snd_soc_codec *codec) -+{ -+ int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; -+ -+ /* set up jack connection */ -+ switch (pavo_jack_func) { -+ case PAVO_HP: -+ hp = 1; -+ /* set = unmute headphone */ -+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); -+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); -+ break; -+ case PAVO_MIC: -+ mic = 1; -+ /* reset = mute headphone */ -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); -+ break; -+ case PAVO_LINE: -+ line = 1; -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); -+ break; -+ case PAVO_HEADSET: -+ hs = 1; -+ mic = 1; -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); -+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); -+ break; -+ } -+ -+ if (pavo_spk_func == PAVO_SPK_ON) -+ spk = 1; -+ -+ /* set the enpoints to their new connetion states */ -+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); -+ snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); -+ snd_soc_dapm_set_endpoint(codec, "Line Jack", line); -+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); -+ snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); -+ -+ /* signal a DAPM event */ -+ snd_soc_dapm_sync_endpoints(codec); -+} -+ -+static int pavo_startup(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_codec *codec = rtd->socdev->codec; -+ -+ /* check the jack status at stream startup */ -+ pavo_ext_control(codec); -+ return 0; -+} -+ -+/* we need to unmute the HP at shutdown as the mute burns power on pavo */ -+static void pavo_shutdown(struct snd_pcm_substream *substream) -+{ -+ /*struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_codec *codec = rtd->socdev->codec;*/ -+ -+ return; -+} -+ -+static int pavo_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; -+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; -+ int ret = 0; -+ -+ /* set codec DAI configuration */ -+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); -+ if (ret < 0) -+ return ret; -+ -+ /* set cpu DAI configuration */ -+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); -+ if (ret < 0) -+ return ret; -+ -+ /* set the codec system clock for DAC and ADC */ -+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, JZCODEC_SYSCLK, 111, -+ SND_SOC_CLOCK_IN); -+ if (ret < 0) -+ return ret; -+ -+ /* set the I2S system clock as input (unused) */ -+ ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, JZ4740_I2S_SYSCLK, 0, -+ SND_SOC_CLOCK_IN); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static struct snd_soc_ops pavo_ops = { -+ .startup = pavo_startup, -+ .hw_params = pavo_hw_params, -+ .shutdown = pavo_shutdown, -+}; -+ -+static int pavo_get_jack(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ ucontrol->value.integer.value[0] = pavo_jack_func; -+ return 0; -+} -+ -+static int pavo_set_jack(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -+ -+ if (pavo_jack_func == ucontrol->value.integer.value[0]) -+ return 0; -+ -+ pavo_jack_func = ucontrol->value.integer.value[0]; -+ pavo_ext_control(codec); -+ return 1; -+} -+ -+static int pavo_get_spk(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ ucontrol->value.integer.value[0] = pavo_spk_func; -+ return 0; -+} -+ -+static int pavo_set_spk(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); -+ -+ if (pavo_spk_func == ucontrol->value.integer.value[0]) -+ return 0; -+ -+ pavo_spk_func = ucontrol->value.integer.value[0]; -+ pavo_ext_control(codec); -+ return 1; -+} -+ -+static int pavo_amp_event(struct snd_soc_dapm_widget *w, int event) -+{ -+ if (SND_SOC_DAPM_EVENT_ON(event)) -+ //set_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON); -+ ; -+ else -+ //reset_scoop_gpio(&corgiscoop_device.dev, PAVO_SCP_APM_ON); -+ ; -+ -+ return 0; -+} -+ -+static int pavo_mic_event(struct snd_soc_dapm_widget *w, int event) -+{ -+ if (SND_SOC_DAPM_EVENT_ON(event)) -+ //set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); -+ ; -+ else -+ //reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MIC_BIAS); -+ ; -+ -+ return 0; -+} -+ -+/* pavo machine dapm widgets */ -+static const struct snd_soc_dapm_widget jzcodec_dapm_widgets[] = { -+SND_SOC_DAPM_HP("Headphone Jack", NULL), -+SND_SOC_DAPM_MIC("Mic Jack",pavo_mic_event), -+SND_SOC_DAPM_SPK("Ext Spk", pavo_amp_event), -+SND_SOC_DAPM_LINE("Line Jack", NULL), -+SND_SOC_DAPM_HP("Headset Jack", NULL), -+}; -+ -+/* pavo machine audio map (connections to the codec pins) */ -+static const char *audio_map[][3] = { -+ -+ /* headset Jack - in = micin, out = LHPOUT*/ -+ {"Headset Jack", NULL, "LHPOUT"}, -+ -+ /* headphone connected to LHPOUT1, RHPOUT1 */ -+ {"Headphone Jack", NULL, "LHPOUT"}, -+ {"Headphone Jack", NULL, "RHPOUT"}, -+ -+ /* speaker connected to LOUT, ROUT */ -+ {"Ext Spk", NULL, "ROUT"}, -+ {"Ext Spk", NULL, "LOUT"}, -+ -+ /* mic is connected to MICIN (via right channel of headphone jack) */ -+ {"MICIN", NULL, "Mic Jack"}, -+ -+ /* Same as the above but no mic bias for line signals */ -+ {"MICIN", NULL, "Line Jack"}, -+ -+ {NULL, NULL, NULL}, -+}; -+ -+static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", -+ "Off"}; -+static const char *spk_function[] = {"On", "Off"}; -+static const struct soc_enum pavo_enum[] = { -+ SOC_ENUM_SINGLE_EXT(5, jack_function), -+ SOC_ENUM_SINGLE_EXT(2, spk_function), -+}; -+ -+static const struct snd_kcontrol_new jzcodec_pavo_controls[] = { -+ SOC_ENUM_EXT("Jack Function", pavo_enum[0], pavo_get_jack, -+ pavo_set_jack), -+ SOC_ENUM_EXT("Speaker Function", pavo_enum[1], pavo_get_spk, -+ pavo_set_spk), -+}; -+ -+/* -+ * Pavo for a jzcodec as connected on jz4740 Device -+ */ -+static int pavo_jzcodec_init(struct snd_soc_codec *codec) -+{ -+ int i, err; -+ -+ snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); -+ snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); -+ -+ /* Add pavo specific controls */ -+ for (i = 0; i < ARRAY_SIZE(jzcodec_pavo_controls); i++) { -+ err = snd_ctl_add(codec->card, -+ snd_soc_cnew(&jzcodec_pavo_controls[i],codec, NULL)); -+ if (err < 0) -+ return err; -+ } -+ -+ /* Add pavo specific widgets */ -+ for(i = 0; i < ARRAY_SIZE(jzcodec_dapm_widgets); i++) { -+ snd_soc_dapm_new_control(codec, &jzcodec_dapm_widgets[i]); -+ } -+ -+ /* Set up pavo specific audio path audio_map */ -+ for(i = 0; audio_map[i][0] != NULL; i++) { -+ snd_soc_dapm_connect_input(codec, audio_map[i][0], -+ audio_map[i][1], audio_map[i][2]); -+ } -+ -+ snd_soc_dapm_sync_endpoints(codec); -+ return 0; -+} -+ -+/* pavo digital audio interface glue - connects codec <--> CPU */ -+static struct snd_soc_dai_link pavo_dai = { -+ .name = "JZCODEC", -+ .stream_name = "JZCODEC", -+ .cpu_dai = &jz4740_i2s_dai, -+ .codec_dai = &jzcodec_dai, -+ .init = pavo_jzcodec_init, -+ .ops = &pavo_ops, -+}; -+ -+/* pavo audio machine driver */ -+static struct snd_soc_machine snd_soc_machine_pavo = { -+ .name = "Pavo", -+ .dai_link = &pavo_dai, -+ .num_links = 1, -+}; -+ -+/* pavo audio subsystem */ -+static struct snd_soc_device pavo_snd_devdata = { -+ .machine = &snd_soc_machine_pavo, -+ .platform = &jz4740_soc_platform, -+ .codec_dev = &soc_codec_dev_jzcodec, -+ //.codec_data -+}; -+ -+static struct platform_device *pavo_snd_device; -+ -+static int __init pavo_init(void) -+{ -+ int ret; -+ -+ pavo_snd_device = platform_device_alloc("soc-audio", -1); -+ -+ if (!pavo_snd_device) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pavo_snd_device, &pavo_snd_devdata); -+ pavo_snd_devdata.dev = &pavo_snd_device->dev; -+ ret = platform_device_add(pavo_snd_device); -+ -+ if (ret) -+ platform_device_put(pavo_snd_device); -+ -+ return ret; -+} -+ -+static void __exit pavo_exit(void) -+{ -+ platform_device_unregister(pavo_snd_device); -+} -+ -+module_init(pavo_init); -+module_exit(pavo_exit); -+ -+/* Module information */ -+MODULE_AUTHOR("Richard"); -+MODULE_DESCRIPTION("ALSA SoC Pavo"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/xburst/patches-2.6.24/002-yaffs2_dists.patch b/target/linux/xburst/patches-2.6.24/002-yaffs2_dists.patch deleted file mode 100644 index de1749e20..000000000 --- a/target/linux/xburst/patches-2.6.24/002-yaffs2_dists.patch +++ /dev/null @@ -1,8842 +0,0 @@ -diff -urN linux-2.6.24.7/fs/yaffs2/Kconfig linux-2.6.24.7.new/fs/yaffs2/Kconfig ---- linux-2.6.24.7/fs/yaffs2/Kconfig 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/Kconfig 2009-04-21 15:01:02.000000000 +0200 -@@ -2,6 +2,8 @@ - # YAFFS file system configurations - # - -+menu "Yaffs2 Filesystems" -+ - config YAFFS_FS - tristate "YAFFS2 file system support" - default n -@@ -12,8 +14,8 @@ - YAFFS2, or Yet Another Flash Filing System, is a filing system - optimised for NAND Flash chips. - -- To compile the YAFFS2 file system support as a module, choose M -- here: the module will be called yaffs2. -+ To compile the YAFFS2 file system support as a module, choose M here: -+ the module will be called yaffs2. - - If unsure, say N. - -@@ -27,29 +29,11 @@ - help - Enable YAFFS1 support -- yaffs for 512 byte / page devices - -- Not needed for 2K-page devices. -- - If unsure, say Y. - --config YAFFS_9BYTE_TAGS -- bool "Use older-style on-NAND data format with pageStatus byte" -- depends on YAFFS_YAFFS1 -- default n -- help -- -- Older-style on-NAND data format has a "pageStatus" byte to record -- chunk/page state. This byte is zero when the page is discarded. -- Choose this option if you have existing on-NAND data using this -- format that you need to continue to support. New data written -- also uses the older-style format. Note: Use of this option -- generally requires that MTD's oob layout be adjusted to use the -- older-style format. See notes on tags formats and MTD versions. -- -- If unsure, say N. -- - config YAFFS_DOES_ECC - bool "Lets Yaffs do its own ECC" -- depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS -+ depends on YAFFS_FS && YAFFS_YAFFS1 - default n - help - This enables Yaffs to use its own ECC functions instead of using -@@ -59,12 +43,12 @@ - - config YAFFS_ECC_WRONG_ORDER - bool "Use the same ecc byte order as Steven Hill's nand_ecc.c" -- depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS -+ depends on YAFFS_FS && YAFFS_DOES_ECC - default n - help -- This makes yaffs_ecc.c use the same ecc byte order as Steven -- Hill's nand_ecc.c. If not set, then you get the same ecc byte -- order as SmartMedia. -+ This makes yaffs_ecc.c use the same ecc byte order as -+ Steven Hill's nand_ecc.c. If not set, then you get the -+ same ecc byte order as SmartMedia. - - If unsure, say N. - -@@ -73,10 +57,39 @@ - depends on YAFFS_FS - default y - help -- Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices -+ Enable YAFFS2 support -- yaffs for >= 2048 byte / page larger devices - - If unsure, say Y. - -+if SOC_JZ4730 || SOC_JZ4740 -+ -+choice -+ prompt "ECC type for oob area" -+ depends on YAFFS_YAFFS2 -+ default CONFIG_YAFFS_ECC_RS -+ help -+ There are 16 bytes for yaffs2 information in oob which should be checked -+ using some type of ECC. -+ -+config YAFFS_ECC_RS -+ bool "Use soft reed solomon ECC for oob area" -+ select REED_SOLOMON -+ select REED_SOLOMON_ENC8 -+ select REED_SOLOMON_DEC8 -+ help -+ The reed solomon ECC could correct 2 5-bit symbols for 16 bytes in oob. -+ It should be selected for MLC nand. -+ -+config YAFFS_ECC_HAMMING -+ bool "Use hamming ECC for oob area" -+ help -+ The hamming ECC could only correct 1 bit for 16 bytes in oob, but it's -+ a bit faster than reed solomon ECC. It should be selected for SLC nand. -+ -+endchoice -+ -+endif -+ - config YAFFS_AUTO_YAFFS2 - bool "Autoselect yaffs2 format" - depends on YAFFS_YAFFS2 -@@ -84,8 +97,7 @@ - help - Without this, you need to explicitely use yaffs2 as the file - system type. With this, you can say "yaffs" and yaffs or yaffs2 -- will be used depending on the device page size (yaffs on -- 512-byte page devices, yaffs2 on 2K page devices). -+ will be used depending on the device page size. - - If unsure, say Y. - -@@ -109,57 +121,30 @@ - - If unsure, say N. - --config YAFFS_CHECKPOINT_RESERVED_BLOCKS -- int "Reserved blocks for checkpointing" -- depends on YAFFS_YAFFS2 -- default 10 -- help -- Give the number of Blocks to reserve for checkpointing. -- Checkpointing saves the state at unmount so that mounting is -- much faster as a scan of all the flash to regenerate this state -- is not needed. These Blocks are reserved per partition, so if -- you have very small partitions the default (10) may be a mess -- for you. You can set this value to 0, but that does not mean -- checkpointing is disabled at all. There only won't be any -- specially reserved blocks for checkpointing, so if there is -- enough free space on the filesystem, it will be used for -- checkpointing. -- -- If unsure, leave at default (10), but don't wonder if there are -- always 2MB used on your large page device partition (10 x 2k -- pagesize). When using small partitions or when being very small -- on space, you probably want to set this to zero. -- - config YAFFS_DISABLE_WIDE_TNODES - bool "Turn off wide tnodes" - depends on YAFFS_FS - default n - help -- Wide tnodes are only used for NAND arrays >=32MB for 512-byte -- page devices and >=128MB for 2k page devices. They use slightly -- more RAM but are faster since they eliminate chunk group -+ Wide tnodes are only used for large NAND arrays (>=32MB for -+ 512-byte page devices and >=128MB for 2k page devices). They use -+ slightly more RAM but are faster since they eliminate chunk group - searching. - -- Setting this to 'y' will force tnode width to 16 bits and save -- memory but make large arrays slower. -+ Setting this to 'y' will force tnode width to 16 bits and make -+ large arrays slower. - - If unsure, say N. - --config YAFFS_ALWAYS_CHECK_CHUNK_ERASED -- bool "Force chunk erase check" -+config YAFFS_DISABLE_CHUNK_ERASED_CHECK -+ bool "Turn off debug chunk erase check" - depends on YAFFS_FS -- default n -+ default y - help -- Normally YAFFS only checks chunks before writing until an erased -- chunk is found. This helps to detect any partially written -- chunks that might have happened due to power loss. -- -- Enabling this forces on the test that chunks are erased in flash -- before writing to them. This takes more time but is potentially -- a bit more secure. -- -- Suggest setting Y during development and ironing out driver -- issues etc. Suggest setting to N if you want faster writing. -+ Enabling this turns off the test that chunks are erased in flash -+ before writing to them. This is safe, since the write verification -+ will fail. Suggest enabling the test (ie. say N) -+ during development to help debug things. - - If unsure, say Y. - -@@ -173,3 +158,10 @@ - but makes look-ups faster. - - If unsure, say Y. -+ -+config YAFFS_CHECKPOINT_RESERVED_BLOCKS -+ int 'Reserved blocks for checkpointing' -+ depends on YAFFS_FS -+ default 10 -+ -+endmenu -diff -urN linux-2.6.24.7/fs/yaffs2/Makefile linux-2.6.24.7.new/fs/yaffs2/Makefile ---- linux-2.6.24.7/fs/yaffs2/Makefile 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/Makefile 2009-04-21 15:01:02.000000000 +0200 -@@ -1,11 +1,10 @@ - # --# Makefile for the linux YAFFS filesystem routines. -+# Makefile for the linux YAFFS2 filesystem routines. - # - --obj-$(CONFIG_YAFFS_FS) += yaffs.o -- --yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o --yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o --yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o --yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o --yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o -+obj-y := yaffs2.o -+obj-$(CONFIG_YAFFS_FS) := yaffs_mtdif.o yaffs_mtdif2.o -+obj-$(CONFIG_YAFFS_FS) += yaffs_ecc.o yaffs_fs.o yaffs_guts.o -+obj-$(CONFIG_YAFFS_FS) += yaffs_packedtags2.o yaffs_qsort.o -+obj-$(CONFIG_YAFFS_FS) += yaffs_tagscompat.o yaffs_tagsvalidity.o -+obj-$(CONFIG_YAFFS_FS) += yaffs_checkptrw.o yaffs_nand.o -diff -urN linux-2.6.24.7/fs/yaffs2/devextras.h linux-2.6.24.7.new/fs/yaffs2/devextras.h ---- linux-2.6.24.7/fs/yaffs2/devextras.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/devextras.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -15,7 +15,7 @@ - - /* - * This file is just holds extra declarations used during development. -- * Most of these are from kernel includes placed here so we can use them in -+ * Most of these are from kernel includes placed here so we can use them in - * applications. - * - */ -diff -urN linux-2.6.24.7/fs/yaffs2/moduleconfig.h linux-2.6.24.7.new/fs/yaffs2/moduleconfig.h ---- linux-2.6.24.7/fs/yaffs2/moduleconfig.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/moduleconfig.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,10 +1,10 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering - * -- * Created by Martin Fouts -+ * Created by Martin Fouts - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 as -@@ -44,21 +44,7 @@ - - /* Default: 10 */ - /* Meaning: set the count of blocks to reserve for checkpointing */ --#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 -- --/* --Older-style on-NAND data format has a "pageStatus" byte to record --chunk/page state. This byte is zeroed when the page is discarded. --Choose this option if you have existing on-NAND data in this format --that you need to continue to support. New data written also uses the --older-style format. --Note: Use of this option generally requires that MTD's oob layout be --adjusted to use the older-style format. See notes on tags formats and --MTD versions. --*/ --/* Default: Not selected */ --/* Meaning: Use older-style on-NAND data format with pageStatus byte */ --#define CONFIG_YAFFS_9BYTE_TAGS -+#define YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 - - #endif /* YAFFS_OUT_OF_TREE */ - -diff -urN linux-2.6.24.7/fs/yaffs2/utils/Makefile linux-2.6.24.7.new/fs/yaffs2/utils/Makefile ---- linux-2.6.24.7/fs/yaffs2/utils/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/Makefile 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,69 @@ -+#Makefile for mkyaffs -+# -+# NB this is not yet suitable for putting into the kernel tree. -+# YAFFS: Yet another Flash File System. A NAND-flash specific file system. -+# -+# Copyright (C) 2002 Aleph One Ltd. -+# for Toby Churchill Ltd and Brightstar Engineering -+# -+# Created by Charles Manning -+# -+# 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. -+ -+## Change or override KERNELDIR to your kernel -+#KERNELDIR = /usr/src/kernel-headers-2.4.18 -+#CFLAGS = -I$(KERNELDIR)/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL -+ -+include ../../../.config -+ -+CFLAGS = -I../../../include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL -+CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations -+CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline -+ -+ifeq ($(CONFIG_YAFFS_ECC_RS), y) -+CFLAGS+= -DCONFIG_YAFFS_ECC_RS -+endif -+ -+ifeq ($(CONFIG_YAFFS_ECC_HAMMING), y) -+CFLAGS+= -DCONFIG_YAFFS_ECC_HAMMING -+endif -+ -+ -+## Change if you are using a cross-compiler -+MAKETOOLS = #mipsel-linux- -+ -+CC=$(MAKETOOLS)gcc -+ -+COMMONLINKS = yaffs_ecc.c -+COMMONOBJS = $(COMMONLINKS:.c=.o) -+ -+ifeq ($(CONFIG_YAFFS_ECC_RS), y) -+COMMONOBJS += ssfdc_rs_ecc.o -+endif -+ -+MKYAFFSSOURCES = mkyaffsimage.c -+MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o) -+ -+MKYAFFS2SOURCES = mkyaffs2image.c -+MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c -+MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o) -+ -+all: mkyaffsimage mkyaffs2image -+ -+$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS): -+ ln -s ../$@ $@ -+ -+$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c -+ $(CC) -c $(CFLAGS) $< -o $@ -+ -+mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) -+ $(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) -+ -+mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) -+ $(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) -+ -+ -+clean: -+ rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core -diff -urN linux-2.6.24.7/fs/yaffs2/utils/README linux-2.6.24.7.new/fs/yaffs2/utils/README ---- linux-2.6.24.7/fs/yaffs2/utils/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/README 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,11 @@ -+This directory contains yaffs/yaffs2 tools to make the fs image. -+ -+To build the tools, type 'make'. -+ -+To make yaffs2 image, use next command: -+ -+ $ mkyaffs2image 1 /myroot myroot.yaffs2 -+ -+To burn the yaffs2 image to the NAND, use next command: -+ -+ $ nandwrite -a -o /dev/mtd0 myroot.yaffs2 -diff -urN linux-2.6.24.7/fs/yaffs2/utils/mkyaffs2image.c linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffs2image.c ---- linux-2.6.24.7/fs/yaffs2/utils/mkyaffs2image.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffs2image.c 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,738 @@ -+/* -+ * YAFFS: Yet another FFS. A NAND-flash specific file system. -+ * -+ * makeyaffsimage.c -+ * -+ * Makes a YAFFS file system image that can be used to load up a file system. -+ * -+ * Copyright (C) 2002 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning -+ * -+ * 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. -+ * -+ * -+ * Nick Bane modifications flagged NCB -+ * -+ * Endian handling patches by James Ng. -+ * -+ * mkyaffs2image hacks by NCB -+ * -+ * Changes by Sergey Kubushin flagged KSI -+ * -+ */ -+ -+/* KSI: -+ * All this nightmare should be rewritten from ground up. Why save return -+ * values if nobody checks them? The read/write function returns only one -+ * error, -1. Positive return value does NOT mean read/write operation has -+ * been completed successfully. If somebody opens files, he MUST close them -+ * when they are not longer needed. Only those brave enough can write 64 -+ * bytes from a yaffs_PackedTags2 structure. The list is too long, there is -+ * enough bugs here to write a couple of thick books on how NOT to write -+ * programs... -+ * -+ * And BTW, what was one supposed to do with that file that this horror -+ * occasionally managed to generate? -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "yaffs_ecc.h" -+#include "yaffs_guts.h" -+ -+#include "yaffs_packedtags2.h" -+ -+unsigned yaffs_traceMask=0; -+ -+#define MAX_OBJECTS 100000 -+#define MAX_CHUNKSIZE 8192 -+#define MAX_SPARESIZE 256 -+ -+#define PT2_BYTES 25 -+ -+const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.1.1.1 2008-10-29 14:29:21 lhhuang Exp $"; -+ -+static int chunkSize = 2048; -+static int spareSize = 64; -+static int layout_no; -+ -+static struct nand_oobinfo oob_layout[] = { -+ /* KSI: -+ * Dummy "raw" layout - no ECC, all the bytes are free. Does NOT -+ * really work, only used for compatibility with CVS YAFFS2 that -+ * never ever worked with any stock MTD. -+ */ -+ { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 0, -+ .eccpos = {}, -+ .oobfree = { {0, 64} } -+ }, -+ /* KSI: -+ * Regular MTD AUTOPLACED ECC for large page NAND devices, the -+ * only one existing in stock MTD so far. It corresponds to layout# 1 -+ * in command line arguments. Any other layouts could be added to -+ * the list when they made their way in kernel's MTD. The structure -+ * is simply copied from kernel's drivers/mtd/nand/nand_base.c as-is. -+ */ -+ /* For 2KB pagesize NAND devices */ -+ { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 24, -+ .eccpos = { -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63}, -+ .oobfree = { {2, 38} } -+ }, -+ /* For 4KB pagesize NAND devices */ -+ { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 72, -+ .eccpos = { -+ 56, 57, 58, 59, 60, 61, 62, 63, -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { {2, 54} } -+ }, -+ /* For 4KB pagesize with 2 planes NAND devices */ -+ { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 72, -+ .eccpos = { -+ 56, 57, 58, 59, 60, 61, 62, 63, -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = { {2, 54} } -+ }, -+ /* End-of-list marker */ -+ { -+ .useecc = -1, -+ } -+}; -+ -+typedef struct -+{ -+ dev_t dev; -+ ino_t ino; -+ int obj; -+} objItem; -+ -+ -+static objItem obj_list[MAX_OBJECTS]; -+static int n_obj = 0; -+static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; -+ -+static int nObjects = 0, nDirectories = 0, nPages = 0; -+ -+static int outFile; -+ -+static int error; -+ -+static int convert_endian = 0; -+ -+static int obj_compare(const void *a, const void * b) -+{ -+ objItem *oa, *ob; -+ -+ oa = (objItem *)a; -+ ob = (objItem *)b; -+ -+ if(oa->dev < ob->dev) return -1; -+ if(oa->dev > ob->dev) return 1; -+ if(oa->ino < ob->ino) return -1; -+ if(oa->ino > ob->ino) return 1; -+ -+ return 0; -+} -+ -+ -+static void add_obj_to_list(dev_t dev, ino_t ino, int obj) -+{ -+ if(n_obj < MAX_OBJECTS) -+ { -+ obj_list[n_obj].dev = dev; -+ obj_list[n_obj].ino = ino; -+ obj_list[n_obj].obj = obj; -+ n_obj++; -+ qsort(obj_list,n_obj,sizeof(objItem),obj_compare); -+ -+ } -+ else -+ { -+ // oops! not enough space in the object array -+ fprintf(stderr,"Not enough space in object array\n"); -+ exit(2); -+ } -+} -+ -+ -+static int find_obj_in_list(dev_t dev, ino_t ino) -+{ -+ objItem *i = NULL; -+ objItem test; -+ -+ test.dev = dev; -+ test.ino = ino; -+ -+ if(n_obj > 0) -+ { -+ i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); -+ } -+ -+ if(i) -+ { -+ return i->obj; -+ } -+ return -1; -+} -+ -+/* KSI: -+ * No big endian for now. This is left for a later time. The existing code -+ * is FUBAR. -+ */ -+#if 0 -+/* This little function converts a little endian tag to a big endian tag. -+ * NOTE: The tag is not usable after this other than calculating the CRC -+ * with. -+ */ -+static void little_to_big_endian(yaffs_Tags *tagsPtr) -+{ -+#if 0 // FIXME NCB -+ yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. -+ yaffs_TagsUnion temp; -+ -+ memset(&temp, 0, sizeof(temp)); -+ // Ick, I hate magic numbers. -+ temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); -+ temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); -+ temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); -+ temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); -+ temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); -+ temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); -+ temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); -+ temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); -+ -+ // Now copy it back. -+ tags->asBytes[0] = temp.asBytes[0]; -+ tags->asBytes[1] = temp.asBytes[1]; -+ tags->asBytes[2] = temp.asBytes[2]; -+ tags->asBytes[3] = temp.asBytes[3]; -+ tags->asBytes[4] = temp.asBytes[4]; -+ tags->asBytes[5] = temp.asBytes[5]; -+ tags->asBytes[6] = temp.asBytes[6]; -+ tags->asBytes[7] = temp.asBytes[7]; -+#endif -+} -+#endif -+ -+void nandmtd2_pt2buf(unsigned char *buf, yaffs_PackedTags2 *pt) -+{ -+ int i, j = 0, k, n; -+ unsigned char pt2_byte_buf[PT2_BYTES]; -+ -+ *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber; -+ *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId; -+ *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId; -+ *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount; -+ pt2_byte_buf[16] = pt->ecc.colParity; -+ pt2_byte_buf[17] = pt->ecc.lineParity & 0xff; -+ pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff; -+ pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff; -+ pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff; -+ pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff; -+ pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; -+ pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; -+ pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; -+ -+ k = oob_layout[layout_no].oobfree[j][0]; -+ n = oob_layout[layout_no].oobfree[j][1]; -+ -+ if (n == 0) { -+ fprintf(stderr, "No OOB space for tags"); -+ exit(-1); -+ } -+ -+ for (i = 0; i < PT2_BYTES; i++) { -+ if (n == 0) { -+ j++; -+ k = oob_layout[layout_no].oobfree[j][0]; -+ n = oob_layout[layout_no].oobfree[j][1]; -+ if (n == 0) { -+ fprintf(stderr, "No OOB space for tags"); -+ exit(-1); -+ } -+ } -+ buf[k++] = pt2_byte_buf[i]; -+ n--; -+ } -+} -+ -+static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) -+{ -+ yaffs_ExtendedTags t; -+ yaffs_PackedTags2 pt; -+ unsigned char spare_buf[MAX_SPARESIZE]; -+ -+ -+ error = write(outFile,data,chunkSize); -+ if(error < 0) return error; -+ -+ yaffs_InitialiseTags(&t); -+ -+ t.chunkId = chunkId; -+// t.serialNumber = 0; -+ t.serialNumber = 1; // **CHECK** -+ t.byteCount = nBytes; -+ t.objectId = objId; -+ -+ t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; -+ -+// added NCB **CHECK** -+ t.chunkUsed = 1; -+ -+/* KSI: Broken anyway -- e.g. &t is pointer to a wrong type... */ -+#if 0 -+ if (convert_endian) -+ { -+ little_to_big_endian(&t); -+ } -+#endif -+ -+ nPages++; -+ -+ yaffs_PackTags2(&pt,&t); -+ -+ memset(spare_buf, 0xff, spareSize); -+ -+ if (layout_no == 0) { -+ memcpy(spare_buf, &pt, sizeof(yaffs_PackedTags2)); -+ } else { -+ nandmtd2_pt2buf(spare_buf, &pt); -+ } -+ -+ return write(outFile,spare_buf,spareSize); -+} -+ -+#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ -+ (((x) & 0x0000FF00) << 8 ) | \ -+ (((x) & 0x00FF0000) >> 8 ) | \ -+ (((x) & 0xFF000000) >> 24)) -+ -+#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ -+ (((x) & 0xFF00) >> 8)) -+ -+/* KSI: Removed for now. TBD later when the proper util (from scratch) is written */ -+#if 0 -+// This one is easier, since the types are more standard. No funky shifts here. -+static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) -+{ -+ oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. -+ oh->parentObjectId = SWAP32(oh->parentObjectId); // int -+ oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. -+ // name = skip. Char array. Not swapped. -+ oh->yst_mode = SWAP32(oh->yst_mode); -+#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. -+ // In fact, WinCE would be *THE* place where this would be an issue! -+ oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); -+ oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); -+ oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); -+ oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); -+ oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); -+#else -+ // Regular POSIX. -+ oh->yst_uid = SWAP32(oh->yst_uid); -+ oh->yst_gid = SWAP32(oh->yst_gid); -+ oh->yst_atime = SWAP32(oh->yst_atime); -+ oh->yst_mtime = SWAP32(oh->yst_mtime); -+ oh->yst_ctime = SWAP32(oh->yst_ctime); -+#endif -+ -+ oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! -+ oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); -+ // alias - char array. -+ oh->yst_rdev = SWAP32(oh->yst_rdev); -+ -+#ifdef CONFIG_YAFFS_WINCE -+ oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); -+ oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); -+ oh->win_atime[0] = SWAP32(oh->win_atime[0]); -+ oh->win_atime[1] = SWAP32(oh->win_atime[1]); -+ oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); -+ oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); -+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); -+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); -+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); -+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); -+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); -+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -+#else -+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); -+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); -+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); -+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); -+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); -+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -+ oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); -+ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); -+ oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); -+ oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); -+ oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); -+ oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); -+#endif -+} -+#endif -+ -+static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) -+{ -+ __u8 bytes[MAX_CHUNKSIZE]; -+ -+ -+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; -+ -+ memset(bytes,0xff,chunkSize); -+ -+ oh->type = t; -+ -+ oh->parentObjectId = parent; -+ -+ strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); -+ -+ -+ if(t != YAFFS_OBJECT_TYPE_HARDLINK) -+ { -+ oh->yst_mode = s->st_mode; -+ oh->yst_uid = s->st_uid; -+// NCB 12/9/02 oh->yst_gid = s->yst_uid; -+ oh->yst_gid = s->st_gid; -+ oh->yst_atime = s->st_atime; -+ oh->yst_mtime = s->st_mtime; -+ oh->yst_ctime = s->st_ctime; -+ oh->yst_rdev = s->st_rdev; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_FILE) -+ { -+ oh->fileSize = s->st_size; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_HARDLINK) -+ { -+ oh->equivalentObjectId = equivalentObj; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_SYMLINK) -+ { -+ strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); -+ } -+ -+/* KSI: FUBAR. Left for a leter time. */ -+#if 0 -+ if (convert_endian) -+ { -+ object_header_little_to_big_endian(oh); -+ } -+#endif -+ -+ return write_chunk(bytes,objId,0,0xffff); -+ -+} -+ -+ -+static int process_directory(int parent, const char *path) -+{ -+ -+ DIR *dir; -+ struct dirent *entry; -+ -+ nDirectories++; -+ -+ dir = opendir(path); -+ -+ if(dir) -+ { -+ while((entry = readdir(dir)) != NULL) -+ { -+ -+ /* Ignore . and .. */ -+ if(strcmp(entry->d_name,".") && -+ strcmp(entry->d_name,"..")) -+ { -+ char full_name[500]; -+ struct stat stats; -+ int equivalentObj; -+ int newObj; -+ -+ sprintf(full_name,"%s/%s",path,entry->d_name); -+ -+ lstat(full_name,&stats); -+ -+ if(S_ISLNK(stats.st_mode) || -+ S_ISREG(stats.st_mode) || -+ S_ISDIR(stats.st_mode) || -+ S_ISFIFO(stats.st_mode) || -+ S_ISBLK(stats.st_mode) || -+ S_ISCHR(stats.st_mode) || -+ S_ISSOCK(stats.st_mode)) -+ { -+ -+ newObj = obj_id++; -+ nObjects++; -+ -+ printf("Object %d, %s is a ",newObj,full_name); -+ -+ /* We're going to create an object for it */ -+ if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) -+ { -+ /* we need to make a hard link */ -+ printf("hard link to object %d\n",equivalentObj); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); -+ } -+ else -+ { -+ -+ add_obj_to_list(stats.st_dev,stats.st_ino,newObj); -+ -+ if(S_ISLNK(stats.st_mode)) -+ { -+ -+ char symname[500]; -+ -+ memset(symname,0, sizeof(symname)); -+ -+ readlink(full_name,symname,sizeof(symname) -1); -+ -+ printf("symlink to \"%s\"\n",symname); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); -+ -+ } -+ else if(S_ISREG(stats.st_mode)) -+ { -+ printf("file, "); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); -+ -+ if(error >= 0) -+ { -+ int h; -+ __u8 bytes[MAX_CHUNKSIZE]; -+ int nBytes; -+ int chunk = 0; -+ -+ h = open(full_name,O_RDONLY); -+ if(h >= 0) -+ { -+ memset(bytes,0xff,chunkSize); -+ while((nBytes = read(h,bytes,chunkSize)) > 0) -+ { -+ chunk++; -+ write_chunk(bytes,newObj,chunk,nBytes); -+ memset(bytes,0xff,chunkSize); -+ } -+ if(nBytes < 0) -+ error = nBytes; -+ -+ printf("%d data chunks written\n",chunk); -+ close(h); -+ } -+ else -+ { -+ perror("Error opening file"); -+ } -+ -+ } -+ -+ } -+ else if(S_ISSOCK(stats.st_mode)) -+ { -+ printf("socket\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISFIFO(stats.st_mode)) -+ { -+ printf("fifo\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISCHR(stats.st_mode)) -+ { -+ printf("character device\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISBLK(stats.st_mode)) -+ { -+ printf("block device\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISDIR(stats.st_mode)) -+ { -+ printf("directory\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); -+// NCB modified 10/9/2001 process_directory(1,full_name); -+ process_directory(newObj,full_name); -+ } -+ } -+ } -+ else -+ { -+ printf(" we don't handle this type\n"); -+ } -+ } -+ } -+ /* KSI: -+ * Who is supposed to close those open directories in this -+ * recursive function, lord Byron? Stock "ulimit -n" is 1024 -+ * and e.g. stock Fedora /etc directory has more that 1024 -+ * directories... -+ */ -+ closedir(dir); -+ } -+ -+ return 0; -+ -+} -+ -+void usage(void) -+{ -+ /* ECC for oob should conform with CONFIG_YAFFS_ECC_XX when building linux kernel, but ecc -+ for oob isn't required when using BCH ECC, as oob will be corrected together with data -+ when using BCH ECC. */ -+#if defined(CONFIG_YAFFS_ECC_RS) -+ printf("Reed-solomn ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n" -+ "so, CONFIG_YAFFS_ECC_RS should be selected when building linux kernel.\n"); -+#elif defined(CONFIG_YAFFS_ECC_HAMMING) -+ printf("Hamming ECC will be used for checking 16 bytes for yaffs2 information in oob area.\n" -+ "so, CONFIG_YAFFS_ECC_HAMMING should be selected when building linux kernel.\n"); -+#endif -+ -+ printf("usage: mkyaffs2image layout# dir image_file [convert]\n"); -+ printf("\n" -+ " layout# NAND OOB layout:\n" -+ " 0 - nand_oob_raw, no used, \n" -+ " 1 - nand_oob_64, for 2KB pagesize, \n" -+ " 2 - nand_oob_128, for 2KB pagesize using multiple planes or 4KB pagesize,\n" -+ " 3 - nand_oob_256, for 4KB pagesize using multiple planes\n"); -+ printf(" dir the directory tree to be converted\n"); -+ printf(" image_file the output file to hold the image\n"); -+ printf(" 'convert' make a big-endian img on a little-endian machine. BROKEN !\n"); -+ printf("\n Example:\n" -+ " mkyaffs2image 1 /nfsroot/root26 root26.yaffs2 \n" -+); -+ -+ exit(1); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ struct stat stats; -+ int i; -+ -+ printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); -+ -+ if ((argc < 4) || (sscanf(argv[1], "%u", &layout_no) != 1)) -+ { -+ usage(); -+ } -+ -+ switch (layout_no) { -+ case 0: -+ printf("Warning: it isn't used by JZSOC!\n"); -+ break; -+ case 1: -+ chunkSize = 2048; -+ spareSize = 64; -+ break; -+ case 2: -+ chunkSize = 4096; -+ spareSize = 128; -+ break; -+ case 3: -+ chunkSize = 8192; -+ spareSize = 256; -+ break; -+ default: -+ usage(); -+ } -+ -+ i = 0; -+ -+ while (oob_layout[i].useecc != -1) -+ i++; -+ -+ if (layout_no >= i) -+ usage(); -+ -+ if ((argc == 5) && (!strncmp(argv[4], "convert", strlen("convert")))) -+ { -+ /* KSI: Broken as of now. TBD. Fail. */ -+ usage(); -+ convert_endian = 1; -+ } -+ -+ if(stat(argv[2],&stats) < 0) -+ { -+ printf("Could not stat %s\n",argv[2]); -+ exit(1); -+ } -+ -+ if(!S_ISDIR(stats.st_mode)) -+ { -+ printf(" %s is not a directory\n",argv[2]); -+ exit(1); -+ } -+ -+ outFile = open(argv[3],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); -+ -+ -+ if(outFile < 0) -+ { -+ printf("Could not open output file %s\n",argv[3]); -+ exit(1); -+ } -+ -+ printf("Processing directory %s into image file %s\n",argv[2],argv[3]); -+ error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); -+ -+ if(error) -+ error = process_directory(YAFFS_OBJECTID_ROOT,argv[2]); -+ -+ close(outFile); -+ -+ if(error < 0) -+ { -+ perror("operation incomplete"); -+ exit(1); -+ } -+ else -+ { -+ printf("Operation complete.\n" -+ "%d objects in %d directories\n" -+ "%d NAND pages\n",nObjects, nDirectories, nPages); -+ } -+ -+ close(outFile); -+ -+ exit(0); -+} -+ -diff -urN linux-2.6.24.7/fs/yaffs2/utils/mkyaffsimage.c linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffsimage.c ---- linux-2.6.24.7/fs/yaffs2/utils/mkyaffsimage.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/mkyaffsimage.c 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,593 @@ -+/* -+ * YAFFS: Yet another FFS. A NAND-flash specific file system. -+ * -+ * makeyaffsimage.c -+ * -+ * Makes a YAFFS file system image that can be used to load up a file system. -+ * -+ * Copyright (C) 2002 Aleph One Ltd. -+ * for Toby Churchill Ltd and Brightstar Engineering -+ * -+ * Created by Charles Manning -+ * -+ * 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. -+ * -+ * -+ * Nick Bane modifications flagged NCB -+ * -+ * Endian handling patches by James Ng. -+ * -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "yaffs_ecc.h" -+#include "yaffs_guts.h" -+ -+ -+#define MAX_OBJECTS 10000 -+ -+const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; -+ -+ -+typedef struct -+{ -+ dev_t dev; -+ ino_t ino; -+ int obj; -+} objItem; -+ -+ -+static objItem obj_list[MAX_OBJECTS]; -+static int n_obj = 0; -+static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; -+ -+static int nObjects, nDirectories, nPages; -+ -+static int outFile; -+ -+static int error; -+ -+static int convert_endian = 0; -+ -+static int obj_compare(const void *a, const void * b) -+{ -+ objItem *oa, *ob; -+ -+ oa = (objItem *)a; -+ ob = (objItem *)b; -+ -+ if(oa->dev < ob->dev) return -1; -+ if(oa->dev > ob->dev) return 1; -+ if(oa->ino < ob->ino) return -1; -+ if(oa->ino > ob->ino) return 1; -+ -+ return 0; -+} -+ -+ -+static void add_obj_to_list(dev_t dev, ino_t ino, int obj) -+{ -+ if(n_obj < MAX_OBJECTS) -+ { -+ obj_list[n_obj].dev = dev; -+ obj_list[n_obj].ino = ino; -+ obj_list[n_obj].obj = obj; -+ n_obj++; -+ qsort(obj_list,n_obj,sizeof(objItem),obj_compare); -+ -+ } -+ else -+ { -+ // oops! not enough space in the object array -+ fprintf(stderr,"Not enough space in object array\n"); -+ exit(2); -+ } -+} -+ -+ -+static int find_obj_in_list(dev_t dev, ino_t ino) -+{ -+ objItem *i = NULL; -+ objItem test; -+ -+ test.dev = dev; -+ test.ino = ino; -+ -+ if(n_obj > 0) -+ { -+ i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); -+ } -+ -+ if(i) -+ { -+ return i->obj; -+ } -+ return -1; -+} -+ -+// NCB added 10/9/2002 -+static __u16 yaffs_CalcNameSum(const char *name) -+{ -+ __u16 sum = 0; -+ __u16 i = 1; -+ -+ __u8 *bname = (__u8 *)name; -+ -+ while (*bname) -+ { -+ sum += (*bname) * i; -+ i++; -+ bname++; -+ } -+ return sum; -+} -+ -+ -+static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) -+{ -+ yaffs_ECCCalculate(data , spare->ecc1); -+ yaffs_ECCCalculate(&data[256] , spare->ecc2); -+} -+ -+static void yaffs_CalcTagsECC(yaffs_Tags *tags) -+{ -+ // Todo don't do anything yet. Need to calculate ecc -+ unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; -+ unsigned i,j; -+ unsigned ecc = 0; -+ unsigned bit = 0; -+ -+ // Clear ECC fields -+ if (!convert_endian) -+ { -+ tags->ecc = 0; -+ } -+ else -+ { -+ // Because we're in "munged tag" mode, we have to clear it manually -+ b[6] &= 0xC0; -+ b[7] &= 0x03; -+ } -+ -+ for(i = 0; i < 8; i++) -+ { -+// NCB modified 20-9-02 for(j = 1; j &0x7f; j<<=1) -+ for(j = 1; j &0xff; j<<=1) -+ { -+ bit++; -+ if(b[i] & j) -+ { -+ ecc ^= bit; -+ } -+ } -+ } -+ -+ // Write out ECC -+ if (!convert_endian) -+ { -+ tags->ecc = ecc; -+ } -+ else -+ { -+ // We have to munge the ECC again. -+ b[6] |= ((ecc >> 6) & 0x3F); -+ b[7] |= ((ecc & 0x3F) << 2); -+ } -+} -+static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) -+{ -+ yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; -+ -+ //yaffs_CalcTagsECC(tagsPtr); -+ -+ sparePtr->tagByte0 = tu->asBytes[0]; -+ sparePtr->tagByte1 = tu->asBytes[1]; -+ sparePtr->tagByte2 = tu->asBytes[2]; -+ sparePtr->tagByte3 = tu->asBytes[3]; -+ sparePtr->tagByte4 = tu->asBytes[4]; -+ sparePtr->tagByte5 = tu->asBytes[5]; -+ sparePtr->tagByte6 = tu->asBytes[6]; -+ sparePtr->tagByte7 = tu->asBytes[7]; -+} -+ -+/* This little function converts a little endian tag to a big endian tag. -+ * NOTE: The tag is not usable after this other than calculating the CRC -+ * with. -+ */ -+static void little_to_big_endian(yaffs_Tags *tagsPtr) -+{ -+ yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. -+ yaffs_TagsUnion temp; -+ -+ memset(&temp, 0, sizeof(temp)); -+ // Ick, I hate magic numbers. -+ temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); -+ temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); -+ temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); -+ temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); -+ temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); -+ temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); -+ temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); -+ temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); -+ -+ // Now copy it back. -+ tags->asBytes[0] = temp.asBytes[0]; -+ tags->asBytes[1] = temp.asBytes[1]; -+ tags->asBytes[2] = temp.asBytes[2]; -+ tags->asBytes[3] = temp.asBytes[3]; -+ tags->asBytes[4] = temp.asBytes[4]; -+ tags->asBytes[5] = temp.asBytes[5]; -+ tags->asBytes[6] = temp.asBytes[6]; -+ tags->asBytes[7] = temp.asBytes[7]; -+} -+ -+static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) -+{ -+ yaffs_Tags t; -+ yaffs_Spare s; -+ -+ error = write(outFile,data,512); -+ if(error < 0) return error; -+ -+ memset(&t,0xff,sizeof (yaffs_Tags)); -+ memset(&s,0xff,sizeof (yaffs_Spare)); -+ -+ t.chunkId = chunkId; -+ t.serialNumber = 0; -+ t.byteCount = nBytes; -+ t.objectId = objId; -+ -+ if (convert_endian) -+ { -+ little_to_big_endian(&t); -+ } -+ -+ yaffs_CalcTagsECC(&t); -+ yaffs_LoadTagsIntoSpare(&s,&t); -+ yaffs_CalcECC(data,&s); -+ -+ nPages++; -+ -+ return write(outFile,&s,sizeof(yaffs_Spare)); -+ -+} -+ -+#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ -+ (((x) & 0x0000FF00) << 8 ) | \ -+ (((x) & 0x00FF0000) >> 8 ) | \ -+ (((x) & 0xFF000000) >> 24)) -+ -+#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ -+ (((x) & 0xFF00) >> 8)) -+ -+// This one is easier, since the types are more standard. No funky shifts here. -+static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) -+{ -+ oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. -+ oh->parentObjectId = SWAP32(oh->parentObjectId); // int -+ oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. -+ // name = skip. Char array. Not swapped. -+ oh->yst_mode = SWAP32(oh->yst_mode); -+#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. -+ // In fact, WinCE would be *THE* place where this would be an issue! -+ oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); -+ oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); -+ oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); -+ oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); -+ oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); -+#else -+ // Regular POSIX. -+ oh->yst_uid = SWAP32(oh->yst_uid); -+ oh->yst_gid = SWAP32(oh->yst_gid); -+ oh->yst_atime = SWAP32(oh->yst_atime); -+ oh->yst_mtime = SWAP32(oh->yst_mtime); -+ oh->yst_ctime = SWAP32(oh->yst_ctime); -+#endif -+ -+ oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! -+ oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); -+ // alias - char array. -+ oh->yst_rdev = SWAP32(oh->yst_rdev); -+ -+#ifdef CONFIG_YAFFS_WINCE -+ oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); -+ oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); -+ oh->win_atime[0] = SWAP32(oh->win_atime[0]); -+ oh->win_atime[1] = SWAP32(oh->win_atime[1]); -+ oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); -+ oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); -+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); -+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); -+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); -+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); -+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); -+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -+#else -+ oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); -+ oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); -+ oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); -+ oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); -+ oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); -+ oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); -+ oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); -+ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); -+ oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); -+ oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); -+ oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); -+ oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); -+#endif -+} -+ -+static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) -+{ -+ __u8 bytes[512]; -+ -+ -+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; -+ -+ memset(bytes,0xff,512); -+ -+ oh->type = t; -+ -+ oh->parentObjectId = parent; -+ -+ strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); -+ -+ -+ if(t != YAFFS_OBJECT_TYPE_HARDLINK) -+ { -+ oh->yst_mode = s->st_mode; -+ oh->yst_uid = s->st_uid; -+// NCB 12/9/02 oh->yst_gid = s->yst_uid; -+ oh->yst_gid = s->st_gid; -+ oh->yst_atime = s->st_atime; -+ oh->yst_mtime = s->st_mtime; -+ oh->yst_ctime = s->st_ctime; -+ oh->yst_rdev = s->st_rdev; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_FILE) -+ { -+ oh->fileSize = s->st_size; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_HARDLINK) -+ { -+ oh->equivalentObjectId = equivalentObj; -+ } -+ -+ if(t == YAFFS_OBJECT_TYPE_SYMLINK) -+ { -+ strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); -+ } -+ -+ if (convert_endian) -+ { -+ object_header_little_to_big_endian(oh); -+ } -+ -+ return write_chunk(bytes,objId,0,0xffff); -+ -+} -+ -+ -+static int process_directory(int parent, const char *path) -+{ -+ -+ DIR *dir; -+ struct dirent *entry; -+ -+ nDirectories++; -+ -+ dir = opendir(path); -+ -+ if(dir) -+ { -+ while((entry = readdir(dir)) != NULL) -+ { -+ -+ /* Ignore . and .. */ -+ if(strcmp(entry->d_name,".") && -+ strcmp(entry->d_name,"..")) -+ { -+ char full_name[500]; -+ struct stat stats; -+ int equivalentObj; -+ int newObj; -+ -+ sprintf(full_name,"%s/%s",path,entry->d_name); -+ -+ lstat(full_name,&stats); -+ -+ if(S_ISLNK(stats.st_mode) || -+ S_ISREG(stats.st_mode) || -+ S_ISDIR(stats.st_mode) || -+ S_ISFIFO(stats.st_mode) || -+ S_ISBLK(stats.st_mode) || -+ S_ISCHR(stats.st_mode) || -+ S_ISSOCK(stats.st_mode)) -+ { -+ -+ newObj = obj_id++; -+ nObjects++; -+ -+ printf("Object %d, %s is a ",newObj,full_name); -+ -+ /* We're going to create an object for it */ -+ if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) -+ { -+ /* we need to make a hard link */ -+ printf("hard link to object %d\n",equivalentObj); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); -+ } -+ else -+ { -+ -+ add_obj_to_list(stats.st_dev,stats.st_ino,newObj); -+ -+ if(S_ISLNK(stats.st_mode)) -+ { -+ -+ char symname[500]; -+ -+ memset(symname,0, sizeof(symname)); -+ -+ readlink(full_name,symname,sizeof(symname) -1); -+ -+ printf("symlink to \"%s\"\n",symname); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); -+ -+ } -+ else if(S_ISREG(stats.st_mode)) -+ { -+ printf("file, "); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); -+ -+ if(error >= 0) -+ { -+ int h; -+ __u8 bytes[512]; -+ int nBytes; -+ int chunk = 0; -+ -+ h = open(full_name,O_RDONLY); -+ if(h >= 0) -+ { -+ memset(bytes,0xff,512); -+ while((nBytes = read(h,bytes,512)) > 0) -+ { -+ chunk++; -+ write_chunk(bytes,newObj,chunk,nBytes); -+ memset(bytes,0xff,512); -+ } -+ if(nBytes < 0) -+ error = nBytes; -+ -+ printf("%d data chunks written\n",chunk); -+ } -+ else -+ { -+ perror("Error opening file"); -+ } -+ close(h); -+ -+ } -+ -+ } -+ else if(S_ISSOCK(stats.st_mode)) -+ { -+ printf("socket\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISFIFO(stats.st_mode)) -+ { -+ printf("fifo\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISCHR(stats.st_mode)) -+ { -+ printf("character device\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISBLK(stats.st_mode)) -+ { -+ printf("block device\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); -+ } -+ else if(S_ISDIR(stats.st_mode)) -+ { -+ printf("directory\n"); -+ error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); -+// NCB modified 10/9/2001 process_directory(1,full_name); -+ process_directory(newObj,full_name); -+ } -+ } -+ } -+ else -+ { -+ printf(" we don't handle this type\n"); -+ } -+ } -+ } -+ } -+ -+ return 0; -+ -+} -+ -+ -+int main(int argc, char *argv[]) -+{ -+ struct stat stats; -+ -+ printf("mkyaffsimage: image building tool for YAFFS built "__DATE__"\n"); -+ -+ if(argc < 3) -+ { -+ printf("usage: mkyaffsimage dir image_file [convert]\n"); -+ printf(" dir the directory tree to be converted\n"); -+ printf(" image_file the output file to hold the image\n"); -+ printf(" 'convert' produce a big-endian image from a little-endian machine\n"); -+ exit(1); -+ } -+ -+ if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) -+ { -+ convert_endian = 1; -+ } -+ -+ if(stat(argv[1],&stats) < 0) -+ { -+ printf("Could not stat %s\n",argv[1]); -+ exit(1); -+ } -+ -+ if(!S_ISDIR(stats.st_mode)) -+ { -+ printf(" %s is not a directory\n",argv[1]); -+ exit(1); -+ } -+ -+ outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); -+ -+ -+ if(outFile < 0) -+ { -+ printf("Could not open output file %s\n",argv[2]); -+ exit(1); -+ } -+ -+ printf("Processing directory %s into image file %s\n",argv[1],argv[2]); -+ error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); -+ if(error) -+ error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); -+ -+ close(outFile); -+ -+ if(error < 0) -+ { -+ perror("operation incomplete"); -+ exit(1); -+ } -+ else -+ { -+ printf("Operation complete.\n" -+ "%d objects in %d directories\n" -+ "%d NAND pages\n",nObjects, nDirectories, nPages); -+ } -+ -+ close(outFile); -+ -+ exit(0); -+} -+ -diff -urN linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.c linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.c ---- linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.c 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,180 @@ -+/* Reed-Solomon decoder -+ * Copyright 2002 Phil Karn, KA9Q -+ * May be used under the terms of the GNU Lesser General Public License (LGPL) -+ */ -+#include "ssfdc_rs_ecc.h" -+ -+#include -+ -+struct CONV_DATA { -+ unsigned char shift0; -+ unsigned char mask0; -+ unsigned char mask1; -+ unsigned char merge_shift; -+} ConvData [8]= { -+ {0x0, 0xff, 0x01, 0x8}, /* 0 */ -+ {0x1, 0x7f, 0x03, 0x7}, /* 1 */ -+ {0x2, 0x3f, 0x07, 0x6}, /* 2 */ -+ {0x3, 0x1f, 0x0f, 0x5}, /* 3 */ -+ {0x4, 0x0f, 0x1f, 0x4}, /* 4 */ -+ {0x5, 0x07, 0x3f, 0x3}, /* 5 */ -+ {0x6, 0x03, 0x7f, 0x2}, /* 6 */ -+ {0x7, 0x01, 0xff, 0x1}, /* 7 */ -+}; -+ -+static void kfree(void *ptr) -+{ -+// return 0; -+} -+ -+static int modnn(struct rs *rs,int x) -+{ -+ while (x >= rs->nn) { -+ x -= rs->nn; -+ x = (x >> rs->mm) + (x & rs->nn); -+ } -+ return x; -+} -+ -+void encode_rs(void *p,data_t *data, unsigned short *bb) -+{ -+ struct rs *rs = (struct rs *)p; -+ int i, j; -+ data_t feedback; -+ -+ memset(bb,0,(rs->nroots)*sizeof(unsigned short)); -+ -+ for(i=0;i<(rs->nn)-(rs->nroots)-(rs->pad);i++){ -+ -+ feedback = (rs->index_of)[data[i] ^ bb[0]]; -+ if(feedback != ((rs->nn))){ -+ for(j=1;j<(rs->nroots);j++) -+ bb[j] ^= (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[(rs->nroots)-j])]; -+ } -+ -+ memmove(&bb[0],&bb[1],sizeof(unsigned short)*((rs->nroots)-1)); -+ -+ if(feedback != ((rs->nn))) { -+ bb[(rs->nroots)-1] = (rs->alpha_to)[modnn(rs,feedback + (rs->genpoly)[0])]; -+ } -+ else -+ bb[(rs->nroots)-1] = 0; -+ } -+ -+} -+ -+void free_rs_int(void *p) -+{ -+ struct rs *rs = (struct rs *)p; -+ -+ free(rs->alpha_to); -+ free(rs->index_of); -+ free(rs->genpoly); -+ free(rs); -+} -+ -+/* -+ * init_rs_int - Initialize a Reed-Solomon codec -+ * @symsize: symbol size -+ * @gfpoly: Field generator polynomial coefficients -+ * @fcr: first root of RS code generator polynomial, index form -+ * @prim: primitive element to generate polynomial roots -+ * @nroots: RS code generator polynomial degree (number of roots) -+ */ -+struct rs *init_rs_int(int symsize,int gfpoly,int fcr,int prim,int nroots,int pad) -+{ -+ struct rs *rs; -+#if 0 -+ static unsigned int rs0[64]={0}; -+ static data_t alpha0[512]={0}; -+ static data_t index0[512]={0}; -+ static data_t genepoly0[9]={0}; -+#endif -+ int i, j, sr,root,iprim; -+ -+ rs = ((void *)0); -+ if(symsize < 0 || symsize > 8*sizeof(data_t)){ -+ goto done; -+ } -+ -+ if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; -+ rs->nn = (1<pad = pad; -+ rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); -+// rs->alpha_to = alpha0; -+ if(rs->alpha_to == ((void *)0)){ -+ kfree(rs); -+ rs = ((void *)0); -+ goto done; -+ } -+ rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); -+// rs->index_of = index0; -+ if(rs->index_of == ((void *)0)){ -+ kfree(rs->alpha_to); -+ kfree(rs); -+ rs = ((void *)0); -+ goto done; -+ } -+ rs->index_of[0] = ((rs->nn)); -+ rs->alpha_to[((rs->nn))] = 0; -+ sr = 1; -+ for(i=0;inn;i++){ -+ rs->index_of[sr] = i; -+ rs->alpha_to[i] = sr; -+ sr <<= 1; -+ if(sr & (1<nn; -+ } -+ if(sr != 1){ -+ kfree(rs->alpha_to); -+ kfree(rs->index_of); -+ kfree(rs); -+ rs = ((void *)0); -+ goto done; -+ } -+ rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1)); -+// rs->genpoly = genepoly0; -+ if(rs->genpoly == ((void *)0)){ -+ kfree(rs->alpha_to); -+ kfree(rs->index_of); -+ kfree(rs); -+ rs = ((void *)0); -+ goto done; -+ } -+ rs->fcr = fcr; -+ rs->prim = prim; -+ rs->nroots = nroots; -+ for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) -+ ; -+ rs->iprim = iprim / prim; -+ rs->genpoly[0] = 1; -+ for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { -+ rs->genpoly[i+1] = 1; -+ for (j = i; j > 0; j--){ -+ if (rs->genpoly[j] != 0) -+ rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; -+ else -+ rs->genpoly[j] = rs->genpoly[j-1]; -+ } -+ rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; -+ } -+ for (i = 0; i <= nroots; i++) -+ rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; -+ done:; -+ return rs; -+} -+ -diff -urN linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.h linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.h ---- linux-2.6.24.7/fs/yaffs2/utils/ssfdc_rs_ecc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.24.7.new/fs/yaffs2/utils/ssfdc_rs_ecc.h 2009-04-21 15:01:02.000000000 +0200 -@@ -0,0 +1,29 @@ -+#ifndef __SSFDC_RS_ECC_H__ -+#define __SSFDC_RS_ECC_H__ -+ -+/* Stuff common to all the general-purpose Reed-Solomon codecs -+ * Copyright 2004 Phil Karn, KA9Q -+ * May be used under the terms of the GNU Lesser General Public License (LGPL) -+ */ -+ -+/* Reed-Solomon codec control block */ -+typedef unsigned char data_t; -+ -+struct rs { -+ int mm; /* Bits per symbol */ -+ int nn; /* Symbols per block (= (1<nErasedBlocks - dev->nReservedBlocks; -- -+ - T(YAFFS_TRACE_CHECKPOINT, - (TSTR("checkpt blocks available = %d" TENDSTR), - blocksAvailable)); -- -- -+ -+ - return (blocksAvailable <= 0) ? 0 : 1; - } - - -+ - static int yaffs_CheckpointErase(yaffs_Device *dev) - { -- -+ - int i; -+ - -- -- if(!dev->eraseBlockInNAND) -+ if(!dev->eraseBlockInNAND) - return 0; - T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), - dev->internalStartBlock,dev->internalEndBlock)); -- -+ - for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); - if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ -@@ -58,9 +59,9 @@ - } - } - } -- -+ - dev->blocksInCheckpoint = 0; -- -+ - return 1; - } - -@@ -72,11 +73,11 @@ - T(YAFFS_TRACE_CHECKPOINT, - (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), - dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); -- -+ - if(dev->checkpointNextBlock >= 0 && - dev->checkpointNextBlock <= dev->internalEndBlock && - blocksAvailable > 0){ -- -+ - for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); - if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ -@@ -88,7 +89,7 @@ - } - } - T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); -- -+ - dev->checkpointNextBlock = -1; - dev->checkpointCurrentBlock = -1; - } -@@ -97,19 +98,19 @@ - { - int i; - yaffs_ExtendedTags tags; -- -+ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), - dev->blocksInCheckpoint, dev->checkpointNextBlock)); -- -- if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) -+ -+ if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks) - for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ - int chunk = i * dev->nChunksPerBlock; - int realignedChunk = chunk - dev->chunkOffset; - - dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags); -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), -+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), - i, tags.objectId,tags.sequenceNumber,tags.eccResult)); -- -+ - if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ - /* Right kind of block */ - dev->checkpointNextBlock = tags.objectId; -@@ -130,7 +131,7 @@ - - int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) - { -- -+ - /* Got the functions we need? */ - if (!dev->writeChunkWithTagsToNAND || - !dev->readChunkWithTagsFromNAND || -@@ -140,31 +141,29 @@ - - if(forWriting && !yaffs_CheckpointSpaceOk(dev)) - return 0; -- -+ - if(!dev->checkpointBuffer) - dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); - if(!dev->checkpointBuffer) - return 0; - -- -+ - dev->checkpointPageSequence = 0; -- -+ - dev->checkpointOpenForWrite = forWriting; -- -+ - dev->checkpointByteCount = 0; -- dev->checkpointSum = 0; -- dev->checkpointXor = 0; - dev->checkpointCurrentBlock = -1; - dev->checkpointCurrentChunk = -1; - dev->checkpointNextBlock = dev->internalStartBlock; -- -+ - /* Erase all the blocks in the checkpoint area */ - if(forWriting){ - memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); - dev->checkpointByteOffset = 0; - return yaffs_CheckpointErase(dev); -- -- -+ -+ - } else { - int i; - /* Set to a value that will kick off a read */ -@@ -177,15 +176,7 @@ - for(i = 0; i < dev->checkpointMaxBlocks; i++) - dev->checkpointBlockList[i] = -1; - } -- -- return 1; --} -- --int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) --{ -- __u32 compositeSum; -- compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); -- *sum = compositeSum; -+ - return 1; - } - -@@ -196,15 +187,15 @@ - int realignedChunk; - - yaffs_ExtendedTags tags; -- -+ - if(dev->checkpointCurrentBlock < 0){ - yaffs_CheckpointFindNextErasedBlock(dev); - dev->checkpointCurrentChunk = 0; - } -- -+ - if(dev->checkpointCurrentBlock < 0) - return 0; -- -+ - tags.chunkDeleted = 0; - tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ - tags.chunkId = dev->checkpointPageSequence + 1; -@@ -217,25 +208,25 @@ - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; - dev->blocksInCheckpoint++; - } -- -+ - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; - -- -+ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), -- chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); -- -+ chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId)); -+ - realignedChunk = chunk - dev->chunkOffset; -- -+ - dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); - dev->checkpointByteOffset = 0; -- dev->checkpointPageSequence++; -+ dev->checkpointPageSequence++; - dev->checkpointCurrentChunk++; - if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ - dev->checkpointCurrentChunk = 0; - dev->checkpointCurrentBlock = -1; - } - memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); -- -+ - return 1; - } - -@@ -245,37 +236,31 @@ - int i=0; - int ok = 1; - -- -+ - __u8 * dataBytes = (__u8 *)data; -- -- -+ -+ - - if(!dev->checkpointBuffer) - return 0; - -- if(!dev->checkpointOpenForWrite) -- return -1; -- - while(i < nBytes && ok) { -+ - -- -- -- dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; -- dev->checkpointSum += *dataBytes; -- dev->checkpointXor ^= *dataBytes; -- -+ -+ dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; - dev->checkpointByteOffset++; - i++; - dataBytes++; - dev->checkpointByteCount++; -- -- -+ -+ - if(dev->checkpointByteOffset < 0 || -- dev->checkpointByteOffset >= dev->nDataBytesPerChunk) -+ dev->checkpointByteOffset >= dev->nDataBytesPerChunk) - ok = yaffs_CheckpointFlushBuffer(dev); - - } -- -+ - return i; - } - -@@ -285,44 +270,41 @@ - int ok = 1; - yaffs_ExtendedTags tags; - -- -+ - int chunk; - int realignedChunk; - - __u8 *dataBytes = (__u8 *)data; -- -+ - if(!dev->checkpointBuffer) - return 0; - -- if(dev->checkpointOpenForWrite) -- return -1; -- - while(i < nBytes && ok) { -- -- -+ -+ - if(dev->checkpointByteOffset < 0 || - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { -- -+ - if(dev->checkpointCurrentBlock < 0){ - yaffs_CheckpointFindNextCheckpointBlock(dev); - dev->checkpointCurrentChunk = 0; - } -- -+ - if(dev->checkpointCurrentBlock < 0) - ok = 0; - else { -- -- chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + -+ -+ chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + - dev->checkpointCurrentChunk; - - realignedChunk = chunk - dev->chunkOffset; - - /* read in the next chunk */ - /* printf("read checkpoint page %d\n",dev->checkpointPage); */ -- dev->readChunkWithTagsFromNAND(dev, realignedChunk, -+ dev->readChunkWithTagsFromNAND(dev, realignedChunk, - dev->checkpointBuffer, - &tags); -- -+ - if(tags.chunkId != (dev->checkpointPageSequence + 1) || - tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) - ok = 0; -@@ -330,30 +312,28 @@ - dev->checkpointByteOffset = 0; - dev->checkpointPageSequence++; - dev->checkpointCurrentChunk++; -- -+ - if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) - dev->checkpointCurrentBlock = -1; - } - } -- -+ - if(ok){ - *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; -- dev->checkpointSum += *dataBytes; -- dev->checkpointXor ^= *dataBytes; - dev->checkpointByteOffset++; - i++; - dataBytes++; - dev->checkpointByteCount++; - } - } -- -+ - return i; - } - - int yaffs_CheckpointClose(yaffs_Device *dev) - { - -- if(dev->checkpointOpenForWrite){ -+ if(dev->checkpointOpenForWrite){ - if(dev->checkpointByteOffset != 0) - yaffs_CheckpointFlushBuffer(dev); - } else { -@@ -373,19 +353,19 @@ - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; - dev->nErasedBlocks -= dev->blocksInCheckpoint; - -- -+ - T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), - dev->checkpointByteCount)); -- -+ - if(dev->checkpointBuffer){ -- /* free the buffer */ -+ /* free the buffer */ - YFREE(dev->checkpointBuffer); - dev->checkpointBuffer = NULL; - return 1; - } - else - return 0; -- -+ - } - - int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.h linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_checkptrw.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_checkptrw.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -24,8 +24,6 @@ - - int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes); - --int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); -- - int yaffs_CheckpointClose(yaffs_Device *dev); - - int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_ecc.c linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_ecc.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.c 2009-04-21 15:01:02.000000000 +0200 -@@ -14,9 +14,9 @@ - /* - * This code implements the ECC algorithm used in SmartMedia. - * -- * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. -+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. - * The two unused bit are set to 1. -- * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC -+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC - * blocks are used on a 512-byte NAND page. - * - */ -@@ -29,7 +29,7 @@ - */ - - const char *yaffs_ecc_c_version = -- "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $"; -+ "$Id: yaffs_ecc.c,v 1.2 2008-07-17 23:07:00 lhhuang Exp $"; - - #include "yportenv.h" - -@@ -83,17 +83,6 @@ - return r; - } - --static int yaffs_CountBits32(unsigned x) --{ -- int r = 0; -- while (x) { -- if (x & 1) -- r++; -- x >>= 1; -- } -- return r; --} -- - /* Calculate the ECC for a 256-byte block of data */ - void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) - { -@@ -228,8 +217,8 @@ - return 1; /* Corrected the error */ - } - -- if ((yaffs_CountBits(d0) + -- yaffs_CountBits(d1) + -+ if ((yaffs_CountBits(d0) + -+ yaffs_CountBits(d1) + - yaffs_CountBits(d2)) == 1) { - /* Reccoverable error in ecc */ - -@@ -239,13 +228,115 @@ - - return 1; /* Corrected the error */ - } -- -+ - /* Unrecoverable error */ - - return -1; - - } - -+#if defined(CONFIG_YAFFS_ECC_RS) -+#ifdef __KERNEL__ -+#include -+struct rs_control *rs_decoder; -+#else -+#include "ssfdc_rs_ecc.h" -+void *rs_init_user; -+#endif -+ -+/* Transfer 16 bytes to 26 5-bit symbols */ -+void Data2Sym(const unsigned char *in, unsigned char *out) -+{ -+ int i, j, shift; -+ -+ for (i = 0; i < 26; i++){ -+ j = (5 * i) >> 3; -+ shift = (5 * i) & 0x7; -+ if (shift > 3) -+ out[i] = ((in[j] >> shift) | (in[j+1] << (8 - shift))) & 0x1f; -+ else -+ out[i] = (in[j] >> shift) & 0x1f; -+ } -+ out[25] &= 0x7; /* the last symbol has only 3 bits */ -+} -+ -+/* -+ * It does reed solomon ECC calcs on 16 bytes of oob data -+ */ -+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, -+ yaffs_ECCOther * eccOther) -+{ -+ unsigned short *par = (unsigned short *)&eccOther->lineParity; -+ unsigned char data5[26]; -+ -+ -+ Data2Sym(data, data5); -+ memset(par, 0, 8); -+ -+#ifdef __KERNEL__ -+ /* Encode 26 symbols in data5. Store parities of 4 symbols in -+ * buffer par whose size is 8 bytes(2 bytes per symbol) */ -+ encode_rs8 (rs_decoder, data5, 26, par, 0); -+#else -+ /* init reed solomon ECC for nand oob area -+ * Symbolsize is 5 (bits) -+ * Primitive polynomial is x^5+x^2+1 -+ * first consecutive root is 0 -+ * primitive element to generate roots = 1 -+ * generator polynomial degree (number of roots) = 4 -+ * pad = (1<lineParity; -+ unsigned char data5[26]; -+ int numerr; -+ -+ Data2Sym(data, data5); -+ -+ /* Decode 26 symbols in data5. */ -+ numerr = decode_rs8 (rs_decoder, data5, par, 26, NULL, 0, NULL, 0, NULL); -+ -+ if (numerr == 0) -+ return 0; -+ else if (numerr > 0 && numerr < 3) -+ return 1; -+ else -+ return -1; -+} -+#else -+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, -+ yaffs_ECCOther * read_ecc, -+ const yaffs_ECCOther * test_ecc) -+{ -+ return 0; -+} -+#endif -+ -+#else -+ -+static int yaffs_CountBits32(unsigned x) -+{ -+ int r = 0; -+ while (x) { -+ if (x & 1) -+ r++; -+ x >>= 1; -+ } -+ return r; -+} - - /* - * ECCxxxOther does ECC calcs on arbitrary n bytes of data -@@ -293,7 +384,7 @@ - if ((cDelta | lDelta | lDeltaPrime) == 0) - return 0; /* no error */ - -- if (lDelta == ~lDeltaPrime && -+ if (lDelta == ~lDeltaPrime && - (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) - { - /* Single bit (recoverable) error in data */ -@@ -309,7 +400,7 @@ - - if(lDelta >= nBytes) - return -1; -- -+ - data[lDelta] ^= (1 << bit); - - return 1; /* corrected */ -@@ -328,4 +419,4 @@ - return -1; - - } -- -+#endif /* YAFFS_ECC_RS */ -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_ecc.h linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_ecc.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_ecc.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -16,9 +16,9 @@ - /* - * This code implements the ECC algorithm used in SmartMedia. - * -- * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. -+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. - * The two unused bit are set to 1. -- * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC -+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC - * blocks are used on a 512-byte NAND page. - * - */ -@@ -32,6 +32,10 @@ - unsigned lineParityPrime; - } yaffs_ECCOther; - -+#if defined(CONFIG_YAFFS_ECC_RS) -+extern struct rs_control *rs_decoder; -+#endif -+ - void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); - int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, - const unsigned char *test_ecc); -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_fs.c linux-2.6.24.7.new/fs/yaffs2/yaffs_fs.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_fs.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_fs.c 2009-04-21 15:01:02.000000000 +0200 -@@ -23,7 +23,7 @@ - * This is the file system front-end to YAFFS that hooks it up to - * the VFS. - * -- * Special notes: -+ * Special notes: - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with - * this superblock - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this -@@ -32,7 +32,7 @@ - */ - - const char *yaffs_fs_c_version = -- "$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $"; -+ "$Id: yaffs_fs.c,v 1.2 2008-07-17 23:59:16 lhhuang Exp $"; - extern const char *yaffs_guts_c_version; - - #include -@@ -76,34 +76,23 @@ - - #endif - --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) --#define WRITE_SIZE_STR "writesize" --#define WRITE_SIZE(mtd) (mtd)->writesize --#else --#define WRITE_SIZE_STR "oobblock" --#define WRITE_SIZE(mtd) (mtd)->oobblock --#endif -- - #include - - #include "yportenv.h" - #include "yaffs_guts.h" - -+unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | -+ YAFFS_TRACE_BAD_BLOCKS/* | -+ YAFFS_TRACE_CHECKPOINT*/ -+ /* | 0xFFFFFFFF */; -+ - #include - #include "yaffs_mtdif.h" --#include "yaffs_mtdif1.h" - #include "yaffs_mtdif2.h" - --unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; --unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; -- --/* Module Parameters */ --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) --module_param(yaffs_traceMask,uint,0644); --module_param(yaffs_wr_attempts,uint,0644); --#else --MODULE_PARM(yaffs_traceMask,"i"); --MODULE_PARM(yaffs_wr_attempts,"i"); -+#if defined(CONFIG_YAFFS_ECC_RS) -+#include -+#include "yaffs_ecc.h" - #endif - - /*#define T(x) printk x */ -@@ -174,6 +163,8 @@ - static int yaffs_write_super(struct super_block *sb); - #endif - -+static int yaffs_remount_fs(struct super_block *, int *, char *); -+ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); - #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) -@@ -213,45 +204,24 @@ - .commit_write = yaffs_commit_write, - }; - --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)) --static struct file_operations yaffs_file_operations = { -- .read = do_sync_read, -- .write = do_sync_write, -- .aio_read = generic_file_aio_read, -- .aio_write = generic_file_aio_write, -- .mmap = generic_file_mmap, -- .flush = yaffs_file_flush, -- .fsync = yaffs_sync_object, -- .splice_read = generic_file_splice_read, -- .splice_write = generic_file_splice_write, --}; -- --#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) -- - static struct file_operations yaffs_file_operations = { -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, -- .mmap = generic_file_mmap, -- .flush = yaffs_file_flush, -- .fsync = yaffs_sync_object, -- .sendfile = generic_file_sendfile, --}; -- - #else -- --static struct file_operations yaffs_file_operations = { - .read = generic_file_read, - .write = generic_file_write, -+#endif - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) - .sendfile = generic_file_sendfile, - #endif -+ - }; --#endif - - static struct inode_operations yaffs_file_inode_operations = { - .setattr = yaffs_setattr, -@@ -287,6 +257,7 @@ - .read_inode = yaffs_read_inode, - .put_inode = yaffs_put_inode, - .put_super = yaffs_put_super, -+ .remount_fs = yaffs_remount_fs, - .delete_inode = yaffs_delete_inode, - .clear_inode = yaffs_clear_inode, - .sync_fs = yaffs_sync_fs, -@@ -391,7 +362,7 @@ - dentry->d_name.name); - - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ -- -+ - /* Can't hold gross lock when calling yaffs_get_inode() */ - yaffs_GrossUnlock(dev); - -@@ -429,6 +400,42 @@ - - } - -+static int yaffs_dump_dev1(yaffs_Device * dev) -+{ -+ printk("startBlock......... %d\n", dev->startBlock); -+ printk("endBlock........... %d\n", dev->endBlock); -+ printk("chunkGroupBits..... %d\n", dev->chunkGroupBits); -+ printk("chunkGroupSize..... %d\n", dev->chunkGroupSize); -+ printk("nErasedBlocks...... %d\n", dev->nErasedBlocks); -+ printk("nTnodesCreated..... %d\n", dev->nTnodesCreated); -+ printk("nFreeTnodes........ %d\n", dev->nFreeTnodes); -+ printk("nObjectsCreated.... %d\n", dev->nObjectsCreated); -+ printk("nFreeObjects....... %d\n", dev->nFreeObjects); -+ printk("nFreeChunks........ %d\n", dev->nFreeChunks); -+ printk("nPageWrites........ %d\n", dev->nPageWrites); -+ printk("nPageReads......... %d\n", dev->nPageReads); -+ printk("nBlockErasures..... %d\n", dev->nBlockErasures); -+ printk("nGCCopies.......... %d\n", dev->nGCCopies); -+ printk("garbageCollections. %d\n", dev->garbageCollections); -+ -+ printk("passiveGCs......... %d\n", dev->passiveGarbageCollections); -+ printk("nRetriedWrites..... %d\n", dev->nRetriedWrites); -+ printk("nRetireBlocks...... %d\n", dev->nRetiredBlocks); -+ printk("eccFixed........... %d\n", dev->eccFixed); -+ printk("eccUnfixed......... %d\n", dev->eccUnfixed); -+ printk("tagsEccFixed....... %d\n", dev->tagsEccFixed); -+ printk("tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); -+ printk("cacheHits.......... %d\n", dev->cacheHits); -+ printk("nDeletedFiles...... %d\n", dev->nDeletedFiles); -+ printk("nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); -+ printk("nBackgroudDeletions %d\n", dev->nBackgroundDeletions); -+ printk("useNANDECC......... %d\n", dev->useNANDECC); -+ printk("isYaffs2........... %d\n", dev->isYaffs2); -+ -+ return 1; -+} -+ -+ - /* For now put inode is just for debugging - * Put inode is called when the inode **structure** is put. - */ -@@ -729,21 +736,21 @@ - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFREG; - } -- -+ - break; - case YAFFS_OBJECT_TYPE_SYMLINK : - if( ! S_ISLNK(mode) ){ - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFLNK; - } -- -+ - break; - case YAFFS_OBJECT_TYPE_DIRECTORY : - if( ! S_ISDIR(mode) ){ - obj->yst_mode &= ~S_IFMT; - obj->yst_mode |= S_IFDIR; - } -- -+ - break; - case YAFFS_OBJECT_TYPE_UNKNOWN : - case YAFFS_OBJECT_TYPE_HARDLINK : -@@ -1020,7 +1027,7 @@ - int error = -ENOSPC; - uid_t uid = current->fsuid; - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; -- -+ - if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) - mode |= S_ISGID; - -@@ -1075,7 +1082,7 @@ - obj = NULL; /* Do we ever get here? */ - break; - } -- -+ - /* Can not call yaffs_get_inode() with gross lock held */ - yaffs_GrossUnlock(dev); - -@@ -1264,13 +1271,13 @@ - target = - yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), - new_dentry->d_name.name); -- -- -+ -+ - - if (target && - target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && - !list_empty(&target->variant.directoryVariant.children)) { -- -+ - T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); - - retVal = YAFFS_FAIL; -@@ -1278,7 +1285,7 @@ - - /* Now does unlinking internally using shadowing mechanism */ - T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n")); -- -+ - retVal = - yaffs_RenameObject(yaffs_InodeToObject(old_dir), - old_dentry->d_name.name, -@@ -1390,7 +1397,7 @@ - - if(dev) - yaffs_CheckpointSave(dev); -- -+ - yaffs_GrossUnlock(dev); - - sb->s_dirt = 0; -@@ -1421,16 +1428,16 @@ - { - - T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); -- -+ - return 0; /* yaffs_do_sync_fs(sb);*/ -- -+ - } - - - static void yaffs_read_inode(struct inode *inode) - { - /* NB This is called as a side effect of other functions, but -- * we had to release the lock to prevent deadlocks, so -+ * we had to release the lock to prevent deadlocks, so - * need to lock again. - */ - -@@ -1441,7 +1448,7 @@ - (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino)); - - yaffs_GrossLock(dev); -- -+ - obj = yaffs_FindObjectByNumber(dev, inode->i_ino); - - yaffs_FillInodeFromObject(inode, obj); -@@ -1451,36 +1458,34 @@ - - static LIST_HEAD(yaffs_dev_list); - --#if 0 // not used - static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) - { - yaffs_Device *dev = yaffs_SuperToDevice(sb); - - if( *flags & MS_RDONLY ) { - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; -- -+ - T(YAFFS_TRACE_OS, - (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name )); - - yaffs_GrossLock(dev); -- -+ - yaffs_FlushEntireDeviceCache(dev); -- -+ - yaffs_CheckpointSave(dev); -- -+ - if (mtd->sync) - mtd->sync(mtd); - - yaffs_GrossUnlock(dev); - } - else { -- T(YAFFS_TRACE_OS, -+ T(YAFFS_TRACE_OS, - (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name )); - } -- -+ - return 0; - } --#endif - - static void yaffs_put_super(struct super_block *sb) - { -@@ -1489,7 +1494,7 @@ - T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); - - yaffs_GrossLock(dev); -- -+ - yaffs_FlushEntireDeviceCache(dev); - - yaffs_CheckpointSave(dev); -@@ -1499,12 +1504,12 @@ - } - - yaffs_Deinitialise(dev); -- -+ - yaffs_GrossUnlock(dev); - - /* we assume this is protected by lock_kernel() in mount/umount */ - list_del(&dev->devList); -- -+ - if(dev->spareBuffer){ - YFREE(dev->spareBuffer); - dev->spareBuffer = NULL; -@@ -1530,61 +1535,12 @@ - static void yaffs_MarkSuperBlockDirty(void *vsb) - { - struct super_block *sb = (struct super_block *)vsb; -- -+ - T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); - // if(sb) - // sb->s_dirt = 1; - } - --typedef struct { -- int inband_tags; -- int skip_checkpoint_read; -- int skip_checkpoint_write; -- int no_cache; --} yaffs_options; -- --#define MAX_OPT_LEN 20 --static int yaffs_parse_options(yaffs_options *options, const char *options_str) --{ -- char cur_opt[MAX_OPT_LEN+1]; -- int p; -- int error = 0; -- -- /* Parse through the options which is a comma seperated list */ -- -- while(options_str && *options_str && !error){ -- memset(cur_opt,0,MAX_OPT_LEN+1); -- p = 0; -- -- while(*options_str && *options_str != ','){ -- if(p < MAX_OPT_LEN){ -- cur_opt[p] = *options_str; -- p++; -- } -- options_str++; -- } -- -- if(!strcmp(cur_opt,"inband-tags")) -- options->inband_tags = 1; -- else if(!strcmp(cur_opt,"no-cache")) -- options->no_cache = 1; -- else if(!strcmp(cur_opt,"no-checkpoint-read")) -- options->skip_checkpoint_read = 1; -- else if(!strcmp(cur_opt,"no-checkpoint-write")) -- options->skip_checkpoint_write = 1; -- else if(!strcmp(cur_opt,"no-checkpoint")){ -- options->skip_checkpoint_read = 1; -- options->skip_checkpoint_write = 1; -- } else { -- printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt); -- error = 1; -- } -- -- } -- -- return error; --} -- - static struct super_block *yaffs_internal_read_super(int yaffsVersion, - struct super_block *sb, - void *data, int silent) -@@ -1596,9 +1552,6 @@ - char devname_buf[BDEVNAME_SIZE + 1]; - struct mtd_info *mtd; - int err; -- char *data_str = (char *)data; -- -- yaffs_options options; - - sb->s_magic = YAFFS_MAGIC; - sb->s_op = &yaffs_super_ops; -@@ -1614,19 +1567,6 @@ - sb->s_dev, - yaffs_devname(sb, devname_buf)); - -- if(!data_str) -- data_str = ""; -- -- printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str); -- -- memset(&options,0,sizeof(options)); -- -- if(yaffs_parse_options(&options,data_str)){ -- /* Option parsing failed */ -- return NULL; -- } -- -- - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); -@@ -1670,14 +1610,18 @@ - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); -- T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) -+ T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize)); -+#else -+ T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock)); -+#endif - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); -- T(YAFFS_TRACE_OS, (" size %d\n", mtd->size)); -- -+ T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); -+ - #ifdef CONFIG_YAFFS_AUTO_YAFFS2 - -- if (yaffsVersion == 1 && -+ if (yaffsVersion == 1 && - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - mtd->writesize >= 2048) { - #else -@@ -1685,10 +1629,10 @@ - #endif - T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); - yaffsVersion = 2; -- } -- -+ } -+ - /* Added NCB 26/5/2006 for completeness */ -- if (yaffsVersion == 2 && -+ if (yaffsVersion == 2 && - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - mtd->writesize == 512) { - #else -@@ -1696,7 +1640,7 @@ - #endif - T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); - yaffsVersion = 1; -- } -+ } - - #endif - -@@ -1747,7 +1691,11 @@ - return NULL; - } - -- if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || -+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) -+ if (mtd->writesize < YAFFS_BYTES_PER_CHUNK || -+#else -+ if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK || -+#endif - mtd->oobsize != YAFFS_BYTES_PER_SPARE) { - T(YAFFS_TRACE_ALWAYS, - ("yaffs: MTD device does not support have the " -@@ -1779,17 +1727,14 @@ - dev->name = mtd->name; - - /* Set up the memory size parameters.... */ -- -- nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); -- dev->startBlock = 0; -- dev->endBlock = nBlocks - 1; - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; - dev->nReservedBlocks = 5; -- dev->nShortOpCaches = (options.no_cache) ? 0 : 10; -+ dev->nShortOpCaches = 10; /* Enable short op caching */ - - /* ... and the functions. */ - if (yaffsVersion == 2) { -+ int block_shift; - dev->writeChunkWithTagsToNAND = - nandmtd2_WriteChunkWithTagsToNAND; - dev->readChunkWithTagsFromNAND = -@@ -1805,24 +1750,18 @@ - dev->nDataBytesPerChunk = mtd->oobblock; - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; - #endif -- nBlocks = mtd->size / mtd->erasesize; -- -+ block_shift = ffs(mtd->erasesize) - 1; -+// nBlocks = mtd->size / mtd->erasesize; -+ nBlocks = mtd->size >> block_shift; - dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; - dev->startBlock = 0; - dev->endBlock = nBlocks - 1; - } else { --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) -- /* use the MTD interface in yaffs_mtdif1.c */ -- dev->writeChunkWithTagsToNAND = -- nandmtd1_WriteChunkWithTagsToNAND; -- dev->readChunkWithTagsFromNAND = -- nandmtd1_ReadChunkWithTagsFromNAND; -- dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; -- dev->queryNANDBlock = nandmtd1_QueryNANDBlock; --#else -+ nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK); -+ dev->startBlock = 0; -+ dev->endBlock = nBlocks - 1; - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; --#endif - dev->isYaffs2 = 0; - } - /* ... and common functions */ -@@ -1830,10 +1769,10 @@ - dev->initialiseNAND = nandmtd_InitialiseNAND; - - dev->putSuperFunc = yaffs_MTDPutSuper; -- -+ - dev->superBlock = (void *)sb; - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; -- -+ - - #ifndef CONFIG_YAFFS_DOES_ECC - dev->useNANDECC = 1; -@@ -1843,9 +1782,6 @@ - dev->wideTnodesDisabled = 1; - #endif - -- dev->skipCheckpointRead = options.skip_checkpoint_read; -- dev->skipCheckpointWrite = options.skip_checkpoint_write; -- - /* we assume this is protected by lock_kernel() in mount/umount */ - list_add_tail(&dev->devList, &yaffs_dev_list); - -@@ -1858,7 +1794,7 @@ - T(YAFFS_TRACE_OS, - ("yaffs_read_super: guts initialised %s\n", - (err == YAFFS_OK) ? "OK" : "FAILED")); -- -+ - /* Release lock before yaffs_get_inode() */ - yaffs_GrossUnlock(dev); - -@@ -1869,7 +1805,6 @@ - - if (!inode) - return NULL; -- - inode->i_op = &yaffs_dir_inode_operations; - inode->i_fop = &yaffs_dir_operations; - -@@ -1884,7 +1819,6 @@ - return NULL; - } - sb->s_root = root; -- - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); - return sb; - } -@@ -1990,13 +1924,9 @@ - { - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); -- buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); -- buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); -- buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks); -- buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); -@@ -2012,7 +1942,6 @@ - sprintf(buf, "passiveGCs......... %d\n", - dev->passiveGarbageCollections); - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); -- buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); -@@ -2075,7 +2004,6 @@ - /** - * Set the verbosity of the warnings and error messages. - * -- * Note that the names can only be a..z or _ with the current code. - */ - - static struct { -@@ -2087,7 +2015,6 @@ - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, - {"buffers", YAFFS_TRACE_BUFFERS}, - {"bug", YAFFS_TRACE_BUG}, -- {"checkpt", YAFFS_TRACE_CHECKPOINT}, - {"deletion", YAFFS_TRACE_DELETION}, - {"erase", YAFFS_TRACE_ERASE}, - {"error", YAFFS_TRACE_ERROR}, -@@ -2099,27 +2026,17 @@ - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, - {"scan", YAFFS_TRACE_SCAN}, - {"tracing", YAFFS_TRACE_TRACING}, -- -- {"verify", YAFFS_TRACE_VERIFY}, -- {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, -- {"verify_full", YAFFS_TRACE_VERIFY_FULL}, -- {"verify_all", YAFFS_TRACE_VERIFY_ALL}, -- - {"write", YAFFS_TRACE_WRITE}, - {"all", 0xffffffff}, - {"none", 0}, - {NULL, 0}, - }; - --#define MAX_MASK_NAME_LENGTH 40 - static int yaffs_proc_write(struct file *file, const char *buf, - unsigned long count, void *data) - { - unsigned rg = 0, mask_bitfield; -- char *end; -- char *mask_name; -- const char *x; -- char substring[MAX_MASK_NAME_LENGTH+1]; -+ char *end, *mask_name; - int i; - int done = 0; - int add, len = 0; -@@ -2146,22 +2063,16 @@ - break; - } - mask_name = NULL; -- - mask_bitfield = simple_strtoul(buf + pos, &end, 0); - if (end > buf + pos) { - mask_name = "numeral"; - len = end - (buf + pos); -- pos += len; - done = 0; - } else { -- for(x = buf + pos, i = 0; -- (*x == '_' || (*x >='a' && *x <= 'z')) && -- i 1){ - if(x & 1) extraBits++; - x>>=1; - nShifts++; - } - -- if(extraBits) -+ if(extraBits) - nShifts++; -- -+ - return nShifts; - } - - /* Function to return the number of shifts to get a 1 in bit 0 - */ -- -+ - static __u32 ShiftDiv(__u32 x) - { - int nShifts; -- -+ - nShifts = 0; -- -+ - if(!x) return 0; -- -+ - while( !(x&1)){ - x>>=1; - nShifts++; - } -- -+ - return nShifts; - } - - - --/* -+/* - * Temporary buffer manipulations. - */ - --static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) --{ -- int i; -- __u8 *buf = (__u8 *)1; -- -- memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); -- -- for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { -- dev->tempBuffer[i].line = 0; /* not in use */ -- dev->tempBuffer[i].buffer = buf = -- YMALLOC_DMA(dev->nDataBytesPerChunk); -- } -- -- return buf ? YAFFS_OK : YAFFS_FAIL; -- --} -- - static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) - { - int i, j; -@@ -290,8 +264,6 @@ - return 0; - } - -- -- - /* - * Chunk bitmap manipulations - */ -@@ -308,16 +280,6 @@ - (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); - } - --static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) --{ -- if(blk < dev->internalStartBlock || blk > dev->internalEndBlock || -- chunk < 0 || chunk >= dev->nChunksPerBlock) { -- T(YAFFS_TRACE_ERROR, -- (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk)); -- YBUG(); -- } --} -- - static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk) - { - __u8 *blkBits = yaffs_BlockBits(dev, blk); -@@ -329,8 +291,6 @@ - { - __u8 *blkBits = yaffs_BlockBits(dev, blk); - -- yaffs_VerifyChunkBitId(dev,blk,chunk); -- - blkBits[chunk / 8] &= ~(1 << (chunk & 7)); - } - -@@ -338,16 +298,12 @@ - { - __u8 *blkBits = yaffs_BlockBits(dev, blk); - -- yaffs_VerifyChunkBitId(dev,blk,chunk); -- - blkBits[chunk / 8] |= (1 << (chunk & 7)); - } - - static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk) - { - __u8 *blkBits = yaffs_BlockBits(dev, blk); -- yaffs_VerifyChunkBitId(dev,blk,chunk); -- - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; - } - -@@ -363,495 +319,10 @@ - return 0; - } - --static int yaffs_CountChunkBits(yaffs_Device * dev, int blk) --{ -- __u8 *blkBits = yaffs_BlockBits(dev, blk); -- int i; -- int n = 0; -- for (i = 0; i < dev->chunkBitmapStride; i++) { -- __u8 x = *blkBits; -- while(x){ -- if(x & 1) -- n++; -- x >>=1; -- } -- -- blkBits++; -- } -- return n; --} -- --/* -- * Verification code -- */ -- --static int yaffs_SkipVerification(yaffs_Device *dev) --{ -- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); --} -- --static int yaffs_SkipFullVerification(yaffs_Device *dev) --{ -- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); --} -- --static int yaffs_SkipNANDVerification(yaffs_Device *dev) --{ -- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); --} -- --static const char * blockStateName[] = { --"Unknown", --"Needs scanning", --"Scanning", --"Empty", --"Allocating", --"Full", --"Dirty", --"Checkpoint", --"Collecting", --"Dead" --}; -- --static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) --{ -- int actuallyUsed; -- int inUse; -- -- if(yaffs_SkipVerification(dev)) -- return; -- -- /* Report illegal runtime states */ -- if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) -- T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); -- -- switch(bi->blockState){ -- case YAFFS_BLOCK_STATE_UNKNOWN: -- case YAFFS_BLOCK_STATE_SCANNING: -- case YAFFS_BLOCK_STATE_NEEDS_SCANNING: -- T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), -- n,blockStateName[bi->blockState])); -- } -- -- /* Check pages in use and soft deletions are legal */ -- -- actuallyUsed = bi->pagesInUse - bi->softDeletions; -- -- if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || -- bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || -- actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) -- T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), -- n,bi->pagesInUse,bi->softDeletions)); -- -- -- /* Check chunk bitmap legal */ -- inUse = yaffs_CountChunkBits(dev,n); -- if(inUse != bi->pagesInUse) -- T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), -- n,bi->pagesInUse,inUse)); -- -- /* Check that the sequence number is valid. -- * Ten million is legal, but is very unlikely -- */ -- if(dev->isYaffs2 && -- (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && -- (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) -- T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), -- n,bi->sequenceNumber)); -- --} -- --static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) --{ -- yaffs_VerifyBlock(dev,bi,n); -- -- /* After collection the block should be in the erased state */ -- /* TODO: This will need to change if we do partial gc */ -- -- if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ -- T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), -- n,bi->blockState)); -- } --} -- --static void yaffs_VerifyBlocks(yaffs_Device *dev) --{ -- int i; -- int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; -- int nIllegalBlockStates = 0; -- -- -- if(yaffs_SkipVerification(dev)) -- return; -- -- memset(nBlocksPerState,0,sizeof(nBlocksPerState)); -- -- -- for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ -- yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); -- yaffs_VerifyBlock(dev,bi,i); -- -- if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) -- nBlocksPerState[bi->blockState]++; -- else -- nIllegalBlockStates++; -- -- } -- -- T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); -- T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); -- -- T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); -- if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) -- T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); -- -- for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("%s %d blocks"TENDSTR), -- blockStateName[i],nBlocksPerState[i])); -- -- if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), -- dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); -- -- if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Erased block count wrong dev %d count %d"TENDSTR), -- dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); -- -- if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), -- nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); -- -- T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); -- --} -- --/* -- * Verify the object header. oh must be valid, but obj and tags may be NULL in which -- * case those tests will not be performed. -- */ --static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) --{ -- if(yaffs_SkipVerification(obj->myDev)) -- return; -- -- if(!(tags && obj && oh)){ -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), -- (__u32)tags,(__u32)obj,(__u32)oh)); -- return; -- } -- -- if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || -- oh->type > YAFFS_OBJECT_TYPE_MAX) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), -- tags->objectId, oh->type)); -- -- if(tags->objectId != obj->objectId) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header mismatch objectId %d"TENDSTR), -- tags->objectId, obj->objectId)); -- -- -- /* -- * Check that the object's parent ids match if parentCheck requested. -- * -- * Tests do not apply to the root object. -- */ -- -- if(parentCheck && tags->objectId > 1 && !obj->parent) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), -- tags->objectId, oh->parentObjectId)); -- -- -- if(parentCheck && obj->parent && -- oh->parentObjectId != obj->parent->objectId && -- (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || -- obj->parent->objectId != YAFFS_OBJECTID_DELETED)) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), -- tags->objectId, oh->parentObjectId, obj->parent->objectId)); -- -- -- if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header name is NULL"TENDSTR), -- obj->objectId)); -- -- if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d header name is 0xFF"TENDSTR), -- obj->objectId)); --} -- -- -- --static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn, -- __u32 level, int chunkOffset) --{ -- int i; -- yaffs_Device *dev = obj->myDev; -- int ok = 1; -- int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; -- -- if (tn) { -- if (level > 0) { -- -- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ -- if (tn->internal[i]) { -- ok = yaffs_VerifyTnodeWorker(obj, -- tn->internal[i], -- level - 1, -- (chunkOffset<objectId; -- -- chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; -- -- for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){ -- __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); -- -- if(theChunk > 0){ -- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ -- yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); -- if(tags.objectId != objectId || tags.chunkId != chunkOffset){ -- T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), -- objectId, chunkOffset, theChunk, -- tags.objectId, tags.chunkId)); -- } -- } -- chunkOffset++; -- } -- } -- } -- -- return ok; -- --} -- -- --static void yaffs_VerifyFile(yaffs_Object *obj) --{ -- int requiredTallness; -- int actualTallness; -- __u32 lastChunk; -- __u32 x; -- __u32 i; -- int ok; -- yaffs_Device *dev; -- yaffs_ExtendedTags tags; -- yaffs_Tnode *tn; -- __u32 objectId; -- -- if(obj && yaffs_SkipVerification(obj->myDev)) -- return; -- -- dev = obj->myDev; -- objectId = obj->objectId; -- -- /* Check file size is consistent with tnode depth */ -- lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; -- x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; -- requiredTallness = 0; -- while (x> 0) { -- x >>= YAFFS_TNODES_INTERNAL_BITS; -- requiredTallness++; -- } -- -- actualTallness = obj->variant.fileVariant.topLevel; -- -- if(requiredTallness > actualTallness ) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), -- obj->objectId,actualTallness, requiredTallness)); -- -- -- /* Check that the chunks in the tnode tree are all correct. -- * We do this by scanning through the tnode tree and -- * checking the tags for every chunk match. -- */ -- -- if(yaffs_SkipNANDVerification(dev)) -- return; -- -- for(i = 1; i <= lastChunk; i++){ -- tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); -- -- if (tn) { -- __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); -- if(theChunk > 0){ -- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ -- yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); -- if(tags.objectId != objectId || tags.chunkId != i){ -- T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), -- objectId, i, theChunk, -- tags.objectId, tags.chunkId)); -- } -- } -- } -- -- } -- --} -- --static void yaffs_VerifyDirectory(yaffs_Object *obj) --{ -- if(obj && yaffs_SkipVerification(obj->myDev)) -- return; -- --} -- --static void yaffs_VerifyHardLink(yaffs_Object *obj) --{ -- if(obj && yaffs_SkipVerification(obj->myDev)) -- return; -- -- /* Verify sane equivalent object */ --} -- --static void yaffs_VerifySymlink(yaffs_Object *obj) --{ -- if(obj && yaffs_SkipVerification(obj->myDev)) -- return; -- -- /* Verify symlink string */ --} -- --static void yaffs_VerifySpecial(yaffs_Object *obj) --{ -- if(obj && yaffs_SkipVerification(obj->myDev)) -- return; --} -- --static void yaffs_VerifyObject(yaffs_Object *obj) --{ -- yaffs_Device *dev; -- -- __u32 chunkMin; -- __u32 chunkMax; -- -- __u32 chunkIdOk; -- __u32 chunkIsLive; -- -- if(!obj) -- return; -- -- dev = obj->myDev; -- -- if(yaffs_SkipVerification(dev)) -- return; -- -- /* Check sane object header chunk */ -- -- chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; -- chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; -- -- chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); -- chunkIsLive = chunkIdOk && -- yaffs_CheckChunkBit(dev, -- obj->chunkId / dev->nChunksPerBlock, -- obj->chunkId % dev->nChunksPerBlock); -- if(!obj->fake && -- (!chunkIdOk || !chunkIsLive)) { -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), -- obj->objectId,obj->chunkId, -- chunkIdOk ? "" : ",out of range", -- chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); -- } -- -- if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { -- yaffs_ExtendedTags tags; -- yaffs_ObjectHeader *oh; -- __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); -- -- oh = (yaffs_ObjectHeader *)buffer; -- -- yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); -- -- yaffs_VerifyObjectHeader(obj,oh,&tags,1); -- -- yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); -- } -- -- /* Verify it has a parent */ -- if(obj && !obj->fake && -- (!obj->parent || obj->parent->myDev != dev)){ -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), -- obj->objectId,obj->parent)); -- } -- -- /* Verify parent is a directory */ -- if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), -- obj->objectId,obj->parent->variantType)); -- } -- -- switch(obj->variantType){ -- case YAFFS_OBJECT_TYPE_FILE: -- yaffs_VerifyFile(obj); -- break; -- case YAFFS_OBJECT_TYPE_SYMLINK: -- yaffs_VerifySymlink(obj); -- break; -- case YAFFS_OBJECT_TYPE_DIRECTORY: -- yaffs_VerifyDirectory(obj); -- break; -- case YAFFS_OBJECT_TYPE_HARDLINK: -- yaffs_VerifyHardLink(obj); -- break; -- case YAFFS_OBJECT_TYPE_SPECIAL: -- yaffs_VerifySpecial(obj); -- break; -- case YAFFS_OBJECT_TYPE_UNKNOWN: -- default: -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Obj %d has illegaltype %d"TENDSTR), -- obj->objectId,obj->variantType)); -- break; -- } -- -- --} -- --static void yaffs_VerifyObjects(yaffs_Device *dev) --{ -- yaffs_Object *obj; -- int i; -- struct list_head *lh; -- -- if(yaffs_SkipVerification(dev)) -- return; -- -- /* Iterate through the objects in each hash entry */ -- -- for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++){ -- list_for_each(lh, &dev->objectBucket[i].list) { -- if (lh) { -- obj = list_entry(lh, yaffs_Object, hashLink); -- yaffs_VerifyObject(obj); -- } -- } -- } -- --} -- -- - /* - * Simple hash function. Needs to have a reasonable spread - */ -- -+ - static Y_INLINE int yaffs_HashFunction(int n) - { - n = abs(n); -@@ -861,7 +332,7 @@ - /* - * Access functions to useful fake objects - */ -- -+ - yaffs_Object *yaffs_Root(yaffs_Device * dev) - { - return dev->rootDir; -@@ -876,7 +347,7 @@ - /* - * Erased NAND checking functions - */ -- -+ - int yaffs_CheckFF(__u8 * buffer, int nBytes) - { - /* Horrible, slow implementation */ -@@ -898,10 +369,10 @@ - int result; - - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); -- -+ - if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) - retval = YAFFS_FAIL; -- -+ - - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { - T(YAFFS_TRACE_NANDACCESS, -@@ -915,90 +386,91 @@ - - } - -- - static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, - const __u8 * data, - yaffs_ExtendedTags * tags, - int useReserve) - { -- int attempts = 0; -- int writeOk = 0; - int chunk; - -+ int writeOk = 0; -+ int erasedOk = 1; -+ int attempts = 0; -+ yaffs_BlockInfo *bi; -+ - yaffs_InvalidateCheckpoint(dev); - - do { -- yaffs_BlockInfo *bi = 0; -- int erasedOk = 0; -+ chunk = yaffs_AllocateChunk(dev, useReserve,&bi); - -- chunk = yaffs_AllocateChunk(dev, useReserve, &bi); -- if (chunk < 0) { -- /* no space */ -- break; -- } -- -- /* First check this chunk is erased, if it needs -- * checking. The checking policy (unless forced -- * always on) is as follows: -- * -- * Check the first page we try to write in a block. -- * If the check passes then we don't need to check any -- * more. If the check fails, we check again... -- * If the block has been erased, we don't need to check. -- * -- * However, if the block has been prioritised for gc, -- * then we think there might be something odd about -- * this block and stop using it. -- * -- * Rationale: We should only ever see chunks that have -- * not been erased if there was a partially written -- * chunk due to power loss. This checking policy should -- * catch that case with very few checks and thus save a -- * lot of checks that are most likely not needed. -- */ -- if (bi->gcPrioritise) { -- yaffs_DeleteChunk(dev, chunk, 1, __LINE__); -- /* try another chunk */ -- continue; -- } -+ if (chunk >= 0) { -+ /* First check this chunk is erased, if it needs checking. -+ * The checking policy (unless forced always on) is as follows: -+ * Check the first page we try to write in a block. -+ * - If the check passes then we don't need to check any more. -+ * - If the check fails, we check again... -+ * If the block has been erased, we don't need to check. -+ * -+ * However, if the block has been prioritised for gc, then -+ * we think there might be something odd about this block -+ * and stop using it. -+ * -+ * Rationale: -+ * We should only ever see chunks that have not been erased -+ * if there was a partially written chunk due to power loss -+ * This checking policy should catch that case with very -+ * few checks and thus save a lot of checks that are most likely not -+ * needed. -+ */ -+ -+ if(bi->gcPrioritise){ -+ yaffs_DeleteChunk(dev, chunk, 1, __LINE__); -+ } else { -+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED - -- /* let's give it a try */ -- attempts++; -+ bi->skipErasedCheck = 0; - --#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED -- bi->skipErasedCheck = 0; - #endif -- if (!bi->skipErasedCheck) { -- erasedOk = yaffs_CheckChunkErased(dev, chunk); -- if (erasedOk != YAFFS_OK) { -- T(YAFFS_TRACE_ERROR, -- (TSTR ("**>> yaffs chunk %d was not erased" -- TENDSTR), chunk)); -+ if(!bi->skipErasedCheck){ -+ erasedOk = yaffs_CheckChunkErased(dev, chunk); -+ if(erasedOk && !bi->gcPrioritise) -+ bi->skipErasedCheck = 1; -+ } - -- /* try another chunk */ -- continue; -+ if (!erasedOk) { -+ T(YAFFS_TRACE_ERROR, -+ (TSTR -+ ("**>> yaffs chunk %d was not erased" -+ TENDSTR), chunk)); -+ } else { -+ writeOk = -+ yaffs_WriteChunkWithTagsToNAND(dev, chunk, -+ data, tags); -+ } -+ -+ attempts++; -+ -+ if (writeOk) { -+ /* -+ * Copy the data into the robustification buffer. -+ * NB We do this at the end to prevent duplicates in the case of a write error. -+ * Todo -+ */ -+ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); -+ -+ } else { -+ /* The erased check or write failed */ -+ yaffs_HandleWriteChunkError(dev, chunk, erasedOk); -+ } - } -- bi->skipErasedCheck = 1; - } - -- writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, -- data, tags); -- if (writeOk != YAFFS_OK) { -- yaffs_HandleWriteChunkError(dev, chunk, erasedOk); -- /* try another chunk */ -- continue; -- } -- -- /* Copy the data into the robustification buffer */ -- yaffs_HandleWriteChunkOk(dev, chunk, data, tags); -- -- } while (writeOk != YAFFS_OK && attempts < yaffs_wr_attempts); -+ } while (chunk >= 0 && !writeOk); - - if (attempts > 1) { - T(YAFFS_TRACE_ERROR, -- (TSTR("**>> yaffs write required %d attempts" TENDSTR), -- attempts)); -- -+ (TSTR("**>> yaffs write required %d attempts" TENDSTR), -+ attempts)); - dev->nRetriedWrites += (attempts - 1); - } - -@@ -1008,13 +480,13 @@ - /* - * Block retiring for handling a broken block. - */ -- -+ - static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) - { - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); - - yaffs_InvalidateCheckpoint(dev); -- -+ - yaffs_MarkBlockBad(dev, blockInNAND); - - bi->blockState = YAFFS_BLOCK_STATE_DEAD; -@@ -1028,7 +500,7 @@ - * Functions for robustisizing TODO - * - */ -- -+ - static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, - const __u8 * data, - const yaffs_ExtendedTags * tags) -@@ -1046,13 +518,28 @@ - bi->gcPrioritise = 1; - dev->hasPendingPrioritisedGCs = 1; - bi->chunkErrorStrikes ++; -- -+ - if(bi->chunkErrorStrikes > 3){ - bi->needsRetiring = 1; /* Too many stikes, so retire this */ - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); - - } -+ -+ } -+} - -+static void yaffs_ReportOddballBlocks(yaffs_Device *dev) -+{ -+ int i; -+ -+ for(i = dev->internalStartBlock; i <= dev->internalEndBlock && (yaffs_traceMask & YAFFS_TRACE_BAD_BLOCKS); i++){ -+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); -+ if(bi->needsRetiring || bi->gcPrioritise) -+ T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("yaffs block %d%s%s" TENDSTR), -+ i, -+ bi->needsRetiring ? " needs retiring" : "", -+ bi->gcPrioritise ? " gc prioritised" : "")); -+ - } - } - -@@ -1061,25 +548,22 @@ - - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); -- -+ - yaffs_HandleChunkError(dev,bi); -- -- -+ - if(erasedOk ) { - /* Was an actual write failure, so mark the block for retirement */ - bi->needsRetiring = 1; - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); -- -- - } -- -+ - /* Delete the chunk */ - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); - } - - --/*---------------- Name handling functions ------------*/ -+/*---------------- Name handling functions ------------*/ - - static __u16 yaffs_CalcNameSum(const YCHAR * name) - { -@@ -1088,7 +572,7 @@ - - YUCHAR *bname = (YUCHAR *) name; - if (bname) { -- while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { -+ while ((*bname) && (i <= YAFFS_MAX_NAME_LENGTH)) { - - #ifdef CONFIG_YAFFS_CASE_INSENSITIVE - sum += yaffs_toupper(*bname) * i; -@@ -1120,7 +604,7 @@ - * The list is hooked together using the first pointer - * in the tnode. - */ -- -+ - /* yaffs_CreateTnodes creates a bunch more tnodes and - * adds them to the tnode free list. - * Don't use this function directly -@@ -1138,7 +622,7 @@ - - if (nTnodes < 1) - return YAFFS_OK; -- -+ - /* Calculate the tnode size in bytes for variable width tnode support. - * Must be a multiple of 32-bits */ - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; -@@ -1175,7 +659,7 @@ - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; - curr->internal[0] = next; - } -- -+ - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; - curr->internal[0] = dev->freeTnodes; - dev->freeTnodes = (yaffs_Tnode *)mem; -@@ -1190,13 +674,12 @@ - * NB If we can't add this to the management list it isn't fatal - * but it just means we can't free this bunch of tnodes later. - */ -- -+ - tnl = YMALLOC(sizeof(yaffs_TnodeList)); - if (!tnl) { - T(YAFFS_TRACE_ERROR, - (TSTR - ("yaffs: Could not add tnodes to management list" TENDSTR))); -- return YAFFS_FAIL; - - } else { - tnl->tnodes = newTnodes; -@@ -1239,11 +722,11 @@ - static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) - { - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); -- -+ - if(tn) - memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); - -- return tn; -+ return tn; - } - - /* FreeTnode frees up a tnode and puts it back on the free list */ -@@ -1299,19 +782,19 @@ - __u32 bitInWord; - __u32 wordInMap; - __u32 mask; -- -+ - pos &= YAFFS_TNODES_LEVEL0_MASK; - val >>= dev->chunkGroupBits; -- -+ - bitInMap = pos * dev->tnodeWidth; - wordInMap = bitInMap /32; - bitInWord = bitInMap & (32 -1); -- -+ - mask = dev->tnodeMask << bitInWord; -- -+ - map[wordInMap] &= ~mask; - map[wordInMap] |= (mask & (val << bitInWord)); -- -+ - if(dev->tnodeWidth > (32-bitInWord)) { - bitInWord = (32 - bitInWord); - wordInMap++;; -@@ -1321,31 +804,31 @@ - } - } - --static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) -+__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) - { - __u32 *map = (__u32 *)tn; - __u32 bitInMap; - __u32 bitInWord; - __u32 wordInMap; - __u32 val; -- -+ - pos &= YAFFS_TNODES_LEVEL0_MASK; -- -+ - bitInMap = pos * dev->tnodeWidth; - wordInMap = bitInMap /32; - bitInWord = bitInMap & (32 -1); -- -+ - val = map[wordInMap] >> bitInWord; -- -+ - if(dev->tnodeWidth > (32-bitInWord)) { - bitInWord = (32 - bitInWord); - wordInMap++;; - val |= (map[wordInMap] << bitInWord); - } -- -+ - val &= dev->tnodeMask; - val <<= dev->chunkGroupBits; -- -+ - return val; - } - -@@ -1394,7 +877,7 @@ - while (level > 0 && tn) { - tn = tn-> - internal[(chunkId >> -- ( YAFFS_TNODES_LEVEL0_BITS + -+ ( YAFFS_TNODES_LEVEL0_BITS + - (level - 1) * - YAFFS_TNODES_INTERNAL_BITS) - ) & -@@ -1416,7 +899,7 @@ - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will - * be plugged into the ttree. - */ -- -+ - static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev, - yaffs_FileStructure * fStruct, - __u32 chunkId, -@@ -1453,7 +936,7 @@ - if (requiredTallness > fStruct->topLevel) { - /* Not tall enough,gotta make the tree taller */ - for (i = fStruct->topLevel; i < requiredTallness; i++) { -- -+ - tn = yaffs_GetTnode(dev); - - if (tn) { -@@ -1472,7 +955,7 @@ - - l = fStruct->topLevel; - tn = fStruct->top; -- -+ - if(l > 0) { - while (l > 0 && tn) { - x = (chunkId >> -@@ -1492,13 +975,13 @@ - if(tn->internal[x]) - yaffs_FreeTnode(dev,tn->internal[x]); - tn->internal[x] = passedTn; -- -+ - } else if(!tn->internal[x]) { - /* Don't have one, none passed in */ - tn->internal[x] = yaffs_GetTnode(dev); - } - } -- -+ - tn = tn->internal[x]; - l--; - } -@@ -1539,7 +1022,7 @@ - - /* DeleteWorker scans backwards through the tnode tree and deletes all the - * chunks and tnodes in the file -- * Returns 1 if the tree was deleted. -+ * Returns 1 if the tree was deleted. - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. - */ - -@@ -1653,7 +1136,7 @@ - * of the tnode. - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. - */ -- -+ - static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, - __u32 level, int chunkOffset) - { -@@ -1694,7 +1177,7 @@ - theChunk = yaffs_GetChunkGroupBase(dev,tn,i); - if (theChunk) { - /* Note this does not find the real chunk, only the chunk group. -- * We make an assumption that a chunk group is not larger than -+ * We make an assumption that a chunk group is not larger than - * a block. - */ - yaffs_SoftDeleteChunk(dev, theChunk); -@@ -1796,7 +1279,7 @@ - /* Now we have a tree with all the non-zero branches NULL but the height - * is the same as it was. - * Let's see if we can trim internal tnodes to shorten the tree. -- * We can do this if only the 0th element in the tnode is in use -+ * We can do this if only the 0th element in the tnode is in use - * (ie all the non-zero are NULL) - */ - -@@ -1839,18 +1322,13 @@ - - /* make these things */ - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); -- list = YMALLOC(sizeof(yaffs_ObjectList)); - -- if (!newObjects || !list) { -- if(newObjects) -- YFREE(newObjects); -- if(list) -- YFREE(list); -+ if (!newObjects) { - T(YAFFS_TRACE_ALLOCATE, - (TSTR("yaffs: Could not allocate more objects" TENDSTR))); - return YAFFS_FAIL; - } -- -+ - /* Hook them into the free list */ - for (i = 0; i < nObjects - 1; i++) { - newObjects[i].siblings.next = -@@ -1864,9 +1342,15 @@ - - /* Now add this bunch of Objects to a list for freeing up. */ - -- list->objects = newObjects; -- list->next = dev->allocatedObjectList; -- dev->allocatedObjectList = list; -+ list = YMALLOC(sizeof(yaffs_ObjectList)); -+ if (!list) { -+ T(YAFFS_TRACE_ALLOCATE, -+ (TSTR("Could not add objects to management list" TENDSTR))); -+ } else { -+ list->objects = newObjects; -+ list->next = dev->allocatedObjectList; -+ dev->allocatedObjectList = list; -+ } - - return YAFFS_OK; - } -@@ -2123,25 +1607,12 @@ - { - - yaffs_Object *theObject; -- yaffs_Tnode *tn; - - if (number < 0) { - number = yaffs_CreateNewObjectNumber(dev); - } - - theObject = yaffs_AllocateEmptyObject(dev); -- if(!theObject) -- return NULL; -- -- if(type == YAFFS_OBJECT_TYPE_FILE){ -- tn = yaffs_GetTnode(dev); -- if(!tn){ -- yaffs_FreeObject(theObject); -- return NULL; -- } -- } -- -- - - if (theObject) { - theObject->fake = 0; -@@ -2168,7 +1639,8 @@ - theObject->variant.fileVariant.scannedFileSize = 0; - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ - theObject->variant.fileVariant.topLevel = 0; -- theObject->variant.fileVariant.top = tn; -+ theObject->variant.fileVariant.top = -+ yaffs_GetTnode(dev); - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - INIT_LIST_HEAD(&theObject->variant.directoryVariant. -@@ -2205,7 +1677,7 @@ - return theObject; - - } -- -+ - - static YCHAR *yaffs_CloneString(const YCHAR * str) - { -@@ -2213,8 +1685,7 @@ - - if (str && *str) { - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); -- if(newStr) -- yaffs_strcpy(newStr, str); -+ yaffs_strcpy(newStr, str); - } - - return newStr; -@@ -2227,7 +1698,7 @@ - * aliasString only has meaning for a sumlink. - * rdev only has meaning for devices (a subset of special objects) - */ -- -+ - static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, - yaffs_Object * parent, - const YCHAR * name, -@@ -2238,7 +1709,6 @@ - const YCHAR * aliasString, __u32 rdev) - { - yaffs_Object *in; -- YCHAR *str; - - yaffs_Device *dev = parent->myDev; - -@@ -2249,16 +1719,6 @@ - - in = yaffs_CreateNewObject(dev, -1, type); - -- if(type == YAFFS_OBJECT_TYPE_SYMLINK){ -- str = yaffs_CloneString(aliasString); -- if(!str){ -- yaffs_FreeObject(in); -- return NULL; -- } -- } -- -- -- - if (in) { - in->chunkId = -1; - in->valid = 1; -@@ -2289,7 +1749,8 @@ - - switch (type) { - case YAFFS_OBJECT_TYPE_SYMLINK: -- in->variant.symLinkVariant.alias = str; -+ in->variant.symLinkVariant.alias = -+ yaffs_CloneString(aliasString); - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - in->variant.hardLinkVariant.equivalentObject = -@@ -2298,7 +1759,7 @@ - equivalentObject->objectId; - list_add(&in->hardLinks, &equivalentObject->hardLinks); - break; -- case YAFFS_OBJECT_TYPE_FILE: -+ case YAFFS_OBJECT_TYPE_FILE: - case YAFFS_OBJECT_TYPE_DIRECTORY: - case YAFFS_OBJECT_TYPE_SPECIAL: - case YAFFS_OBJECT_TYPE_UNKNOWN: -@@ -2382,7 +1843,7 @@ - TENDSTR))); - YBUG(); - } -- -+ - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ - if (obj->myDev->isYaffs2) { - unlinkOp = (newDir == obj->myDev->unlinkedDir); -@@ -2395,9 +1856,9 @@ - - existingTarget = yaffs_FindObjectByName(newDir, newName); - -- /* If the object is a file going into the unlinked directory, -+ /* If the object is a file going into the unlinked directory, - * then it is OK to just stuff it in since duplicate names are allowed. -- * else only proceed if the new name does not exist and if we're putting -+ * else only proceed if the new name does not exist and if we're putting - * it into a directory. - */ - if ((unlinkOp || -@@ -2461,7 +1922,7 @@ - /* There is a target that is a non-empty directory, so we fail */ - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ - } else if (existingTarget && existingTarget != obj) { -- /* Nuke the target first, using shadowing, -+ /* Nuke the target first, using shadowing, - * but only if it isn't the same object - */ - yaffs_ChangeObjectName(obj, newDir, newName, force, -@@ -2479,13 +1940,10 @@ - static int yaffs_InitialiseBlocks(yaffs_Device * dev) - { - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; -- -- dev->blockInfo = NULL; -- dev->chunkBits = NULL; -- -+ - dev->allocationBlock = -1; /* force it to get a new one */ - -- /* If the first allocation strategy fails, thry the alternate one */ -+ /* Todo we're assuming the malloc will pass. */ - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); - if(!dev->blockInfo){ - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); -@@ -2493,20 +1951,17 @@ - } - else - dev->blockInfoAlt = 0; -- -- if(dev->blockInfo){ -- -- /* Set up dynamic blockinfo stuff. */ -- dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ -- dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); -- if(!dev->chunkBits){ -- dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); -- dev->chunkBitsAlt = 1; -- } -- else -- dev->chunkBitsAlt = 0; -+ -+ /* Set up dynamic blockinfo stuff. */ -+ dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ -+ dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); -+ if(!dev->chunkBits){ -+ dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); -+ dev->chunkBitsAlt = 1; - } -- -+ else -+ dev->chunkBitsAlt = 0; -+ - if (dev->blockInfo && dev->chunkBits) { - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); -@@ -2519,18 +1974,17 @@ - - static void yaffs_DeinitialiseBlocks(yaffs_Device * dev) - { -- if(dev->blockInfoAlt && dev->blockInfo) -+ if(dev->blockInfoAlt) - YFREE_ALT(dev->blockInfo); -- else if(dev->blockInfo) -+ else - YFREE(dev->blockInfo); -- - dev->blockInfoAlt = 0; - - dev->blockInfo = NULL; -- -- if(dev->chunkBitsAlt && dev->chunkBits) -+ -+ if(dev->chunkBitsAlt) - YFREE_ALT(dev->chunkBits); -- else if(dev->chunkBits) -+ else - YFREE(dev->chunkBits); - dev->chunkBitsAlt = 0; - dev->chunkBits = NULL; -@@ -2587,18 +2041,17 @@ - int i; - int iterations; - int dirtiest = -1; -- int pagesInUse = 0; -+ int pagesInUse; - int prioritised=0; - yaffs_BlockInfo *bi; -+ static int nonAggressiveSkip = 0; - int pendingPrioritisedExist = 0; -- -+ - /* First let's see if we need to grab a prioritised block */ - if(dev->hasPendingPrioritisedGCs){ - for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ - - bi = yaffs_GetBlockInfo(dev, i); -- //yaffs_VerifyBlock(dev,bi,i); -- - if(bi->gcPrioritise) { - pendingPrioritisedExist = 1; - if(bi->blockState == YAFFS_BLOCK_STATE_FULL && -@@ -2610,7 +2063,7 @@ - } - } - } -- -+ - if(!pendingPrioritisedExist) /* None found, so we can clear this */ - dev->hasPendingPrioritisedGCs = 0; - } -@@ -2621,9 +2074,9 @@ - * block has only a few pages in use. - */ - -- dev->nonAggressiveSkip--; -+ nonAggressiveSkip--; - -- if (!aggressive && (dev->nonAggressiveSkip > 0)) { -+ if (!aggressive && (nonAggressiveSkip > 0)) { - return -1; - } - -@@ -2662,7 +2115,7 @@ - dirtiest = b; - pagesInUse = 0; - } -- else -+ else - #endif - - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && -@@ -2684,7 +2137,7 @@ - dev->oldestDirtySequence = 0; - - if (dirtiest > 0) { -- dev->nonAggressiveSkip = 4; -+ nonAggressiveSkip = 4; - } - - return dirtiest; -@@ -2699,11 +2152,11 @@ - /* If the block is still healthy erase it and mark as clean. - * If the block has had a data failure, then retire it. - */ -- -+ - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); -- -+ - bi->blockState = YAFFS_BLOCK_STATE_DIRTY; - - if (!bi->needsRetiring) { -@@ -2716,8 +2169,7 @@ - } - } - -- if (erasedOk && -- ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { -+ if (erasedOk && (yaffs_traceMask & YAFFS_TRACE_ERASE)) { - int i; - for (i = 0; i < dev->nChunksPerBlock; i++) { - if (!yaffs_CheckChunkErased -@@ -2767,7 +2219,7 @@ - - return -1; - } -- -+ - /* Find an empty block. */ - - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { -@@ -2808,13 +2260,13 @@ - int reservedChunks; - int reservedBlocks = dev->nReservedBlocks; - int checkpointBlocks; -- -+ - checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; - if(checkpointBlocks < 0) - checkpointBlocks = 0; -- -+ - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); -- -+ - return (dev->nFreeChunks > reservedChunks); - } - -@@ -2861,10 +2313,10 @@ - - if(blockUsedPtr) - *blockUsedPtr = bi; -- -+ - return retVal; - } -- -+ - T(YAFFS_TRACE_ERROR, - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); - -@@ -2895,7 +2347,6 @@ - int cleanups = 0; - int i; - int isCheckpointBlock; -- int matchingChunk; - - int chunksBefore = yaffs_GetErasedChunks(dev); - int chunksAfter; -@@ -2907,7 +2358,7 @@ - yaffs_Object *object; - - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); -- -+ - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; - - T(YAFFS_TRACE_TRACING, -@@ -2936,8 +2387,6 @@ - - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); - -- yaffs_VerifyBlock(dev,bi,block); -- - for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; - chunkInBlock < dev->nChunksPerBlock - && yaffs_StillSomeChunkBits(dev, block); -@@ -2963,34 +2412,18 @@ - chunkInBlock, tags.objectId, tags.chunkId, - tags.byteCount)); - -- if(object && !yaffs_SkipVerification(dev)){ -- if(tags.chunkId == 0) -- matchingChunk = object->chunkId; -- else if(object->softDeleted) -- matchingChunk = oldChunk; /* Defeat the test */ -- else -- matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL); -- -- if(oldChunk != matchingChunk) -- T(YAFFS_TRACE_ERROR, -- (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), -- oldChunk,matchingChunk,tags.objectId, tags.chunkId)); -- -- } -- - if (!object) { - T(YAFFS_TRACE_ERROR, - (TSTR -- ("page %d in gc has no object: %d %d %d " -- TENDSTR), oldChunk, -- tags.objectId, tags.chunkId, tags.byteCount)); -+ ("page %d in gc has no object " -+ TENDSTR), oldChunk)); - } - - if (object && object->deleted - && tags.chunkId != 0) { - /* Data chunk in a deleted file, throw it away - * It's a soft deleted data chunk, -- * No need to copy this, just forget about it and -+ * No need to copy this, just forget about it and - * fix up the object. - */ - -@@ -3040,8 +2473,6 @@ - oh->shadowsObject = -1; - tags.extraShadows = 0; - tags.extraIsShrinkHeader = 0; -- -- yaffs_VerifyObjectHeader(object,oh,&tags,1); - } - - newChunk = -@@ -3098,8 +2529,6 @@ - - } - -- yaffs_VerifyCollectedBlock(dev,bi,block); -- - if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { - T(YAFFS_TRACE_GC, - (TSTR -@@ -3127,26 +2556,26 @@ - int aggressive; - int gcOk = YAFFS_OK; - int maxTries = 0; -- -+ - int checkpointBlockAdjust; - - if (dev->isDoingGC) { - /* Bail out so we don't get recursive gc */ - return YAFFS_OK; - } -- -+ - /* This loop should pass the first time. - * We'll only see looping here if the erase of the collected block fails. - */ - - do { - maxTries++; -- -+ - checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); - if(checkpointBlockAdjust < 0) - checkpointBlockAdjust = 0; - -- if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { -+ if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) { - /* We need a block soon...*/ - aggressive = 1; - } else { -@@ -3326,11 +2755,11 @@ - static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, - int chunkInNAND, int inScan) - { -- /* NB inScan is zero unless scanning. -- * For forward scanning, inScan is > 0; -+ /* NB inScan is zero unless scanning. -+ * For forward scanning, inScan is > 0; - * for backward scanning inScan is < 0 - */ -- -+ - yaffs_Tnode *tn; - yaffs_Device *dev = in->myDev; - int existingChunk; -@@ -3354,7 +2783,7 @@ - return YAFFS_OK; - } - -- tn = yaffs_AddOrFindLevel0Tnode(dev, -+ tn = yaffs_AddOrFindLevel0Tnode(dev, - &in->variant.fileVariant, - chunkInInode, - NULL); -@@ -3366,7 +2795,7 @@ - - if (inScan != 0) { - /* If we're scanning then we need to test for duplicates -- * NB This does not need to be efficient since it should only ever -+ * NB This does not need to be efficient since it should only ever - * happen when the power fails during a write, then only one - * chunk should ever be affected. - * -@@ -3407,7 +2836,7 @@ - - } - -- /* NB The deleted flags should be false, otherwise the chunks will -+ /* NB The deleted flags should be false, otherwise the chunks will - * not be loaded during a scan - */ - -@@ -3418,7 +2847,7 @@ - (in->myDev->isYaffs2 || - existingChunk <= 0 || - ((existingSerial + 1) & 3) == newSerial)) { -- /* Forward scanning. -+ /* Forward scanning. - * Use new - * Delete the old one and drop through to update the tnode - */ -@@ -3459,7 +2888,7 @@ - (TSTR("Chunk %d not found zero instead" TENDSTR), - chunkInNAND)); - /* get sane (zero) data if you read a hole */ -- memset(buffer, 0, in->myDev->nDataBytesPerChunk); -+ memset(buffer, 0, in->myDev->nDataBytesPerChunk); - return 0; - } - -@@ -3475,17 +2904,10 @@ - if (chunkId <= 0) - return; - -- - dev->nDeletions++; - block = chunkId / dev->nChunksPerBlock; - page = chunkId % dev->nChunksPerBlock; - -- -- if(!yaffs_CheckChunkBit(dev,block,page)) -- T(YAFFS_TRACE_VERIFY, -- (TSTR("Deleting invalid chunk %d"TENDSTR), -- chunkId)); -- - bi = yaffs_GetBlockInfo(dev, block); - - T(YAFFS_TRACE_DELETION, -@@ -3596,19 +3018,15 @@ - - int newChunkId; - yaffs_ExtendedTags newTags; -- yaffs_ExtendedTags oldTags; - - __u8 *buffer = NULL; - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; - - yaffs_ObjectHeader *oh = NULL; - -- yaffs_strcpy(oldName,"silly old name"); -- - if (!in->fake || force) { - - yaffs_CheckGarbageCollection(dev); -- yaffs_CheckObjectDetailsLoaded(in); - - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); - oh = (yaffs_ObjectHeader *) buffer; -@@ -3617,10 +3035,7 @@ - - if (prevChunkId >= 0) { - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, -- buffer, &oldTags); -- -- yaffs_VerifyObjectHeader(in,oh,&oldTags,0); -- -+ buffer, NULL); - memcpy(oldName, oh->name, sizeof(oh->name)); - } - -@@ -3654,7 +3069,7 @@ - if (name && *name) { - memset(oh->name, 0, sizeof(oh->name)); - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); -- } else if (prevChunkId>=0) { -+ } else if (prevChunkId) { - memcpy(oh->name, oldName, sizeof(oh->name)); - } else { - memset(oh->name, 0, sizeof(oh->name)); -@@ -3708,8 +3123,6 @@ - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; - newTags.extraObjectType = in->variantType; - -- yaffs_VerifyObjectHeader(in,oh,&newTags,1); -- - /* Create new chunk in NAND */ - newChunkId = - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, -@@ -3748,11 +3161,11 @@ - - /*------------------------ Short Operations Cache ---------------------------------------- - * In many situations where there is no high level buffering (eg WinCE) a lot of -- * reads might be short sequential reads, and a lot of writes may be short -+ * reads might be short sequential reads, and a lot of writes may be short - * sequential writes. eg. scanning/writing a jpeg file. -- * In these cases, a short read/write cache can provide a huge perfomance benefit -+ * In these cases, a short read/write cache can provide a huge perfomance benefit - * with dumb-as-a-rock code. -- * In Linux, the page cache provides read buffering aand the short op cache provides write -+ * In Linux, the page cache provides read buffering aand the short op cache provides write - * buffering. - * - * There are a limited number (~10) of cache chunks per device so that we don't -@@ -3765,14 +3178,14 @@ - int i; - yaffs_ChunkCache *cache; - int nCaches = obj->myDev->nShortOpCaches; -- -+ - for(i = 0; i < nCaches; i++){ - cache = &dev->srCache[i]; - if (cache->object == obj && - cache->dirty) - return 1; - } -- -+ - return 0; - } - -@@ -3838,7 +3251,7 @@ - yaffs_Object *obj; - int nCaches = dev->nShortOpCaches; - int i; -- -+ - /* Find a dirty object in the cache and flush it... - * until there are no further dirty objects. - */ -@@ -3848,18 +3261,18 @@ - if (dev->srCache[i].object && - dev->srCache[i].dirty) - obj = dev->srCache[i].object; -- -+ - } - if(obj) - yaffs_FlushFilesChunkCache(obj); -- -+ - } while(obj); -- -+ - } - - - /* Grab us a cache chunk for use. -- * First look for an empty one. -+ * First look for an empty one. - * Then look for the least recently used non-dirty one. - * Then look for the least recently used dirty one...., flush and look again. - */ -@@ -3871,7 +3284,7 @@ - - if (dev->nShortOpCaches > 0) { - for (i = 0; i < dev->nShortOpCaches; i++) { -- if (!dev->srCache[i].object) -+ if (!dev->srCache[i].object) - return &dev->srCache[i]; - } - -@@ -4032,14 +3445,11 @@ - static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head) - { - yaffs_CheckpointValidity cp; -- -- memset(&cp,0,sizeof(cp)); -- - cp.structType = sizeof(cp); - cp.magic = YAFFS_MAGIC; - cp.version = YAFFS_CHECKPOINT_VERSION; - cp.head = (head) ? 1 : 0; -- -+ - return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))? - 1 : 0; - } -@@ -4048,9 +3458,9 @@ - { - yaffs_CheckpointValidity cp; - int ok; -- -+ - ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); -- -+ - if(ok) - ok = (cp.structType == sizeof(cp)) && - (cp.magic == YAFFS_MAGIC) && -@@ -4059,20 +3469,20 @@ - return ok ? 1 : 0; - } - --static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, -+static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, - yaffs_Device *dev) - { - cp->nErasedBlocks = dev->nErasedBlocks; - cp->allocationBlock = dev->allocationBlock; - cp->allocationPage = dev->allocationPage; - cp->nFreeChunks = dev->nFreeChunks; -- -+ - cp->nDeletedFiles = dev->nDeletedFiles; - cp->nUnlinkedFiles = dev->nUnlinkedFiles; - cp->nBackgroundDeletions = dev->nBackgroundDeletions; - cp->sequenceNumber = dev->sequenceNumber; - cp->oldestDirtySequence = dev->oldestDirtySequence; -- -+ - } - - static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, -@@ -4082,7 +3492,7 @@ - dev->allocationBlock = cp->allocationBlock; - dev->allocationPage = cp->allocationPage; - dev->nFreeChunks = cp->nFreeChunks; -- -+ - dev->nDeletedFiles = cp->nDeletedFiles; - dev->nUnlinkedFiles = cp->nUnlinkedFiles; - dev->nBackgroundDeletions = cp->nBackgroundDeletions; -@@ -4098,20 +3508,20 @@ - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); - - int ok; -- -+ - /* Write device runtime values*/ - yaffs_DeviceToCheckpointDevice(&cp,dev); - cp.structType = sizeof(cp); -- -+ - ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); -- -+ - /* Write block info */ - if(ok) { - nBytes = nBlocks * sizeof(yaffs_BlockInfo); - ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes); - } -- -- /* Write chunk bits */ -+ -+ /* Write chunk bits */ - if(ok) { - nBytes = nBlocks * dev->chunkBitmapStride; - ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes); -@@ -4126,28 +3536,28 @@ - __u32 nBytes; - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); - -- int ok; -- -+ int ok; -+ - ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); - if(!ok) - return 0; -- -+ - if(cp.structType != sizeof(cp)) - return 0; -- -- -+ -+ - yaffs_CheckpointDeviceToDevice(dev,&cp); -- -+ - nBytes = nBlocks * sizeof(yaffs_BlockInfo); -- -+ - ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes); -- -+ - if(!ok) - return 0; - nBytes = nBlocks * dev->chunkBitmapStride; -- -+ - ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes); -- -+ - return ok ? 1 : 0; - } - -@@ -4158,7 +3568,7 @@ - cp->objectId = obj->objectId; - cp->parentId = (obj->parent) ? obj->parent->objectId : 0; - cp->chunkId = obj->chunkId; -- cp->variantType = obj->variantType; -+ cp->variantType = obj->variantType; - cp->deleted = obj->deleted; - cp->softDeleted = obj->softDeleted; - cp->unlinked = obj->unlinked; -@@ -4167,7 +3577,7 @@ - cp->unlinkAllowed = obj->unlinkAllowed; - cp->serial = obj->serial; - cp->nDataChunks = obj->nDataChunks; -- -+ - if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; - else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) -@@ -4178,9 +3588,9 @@ - { - - yaffs_Object *parent; -- -+ - obj->objectId = cp->objectId; -- -+ - if(cp->parentId) - parent = yaffs_FindOrCreateObjectByNumber( - obj->myDev, -@@ -4188,12 +3598,12 @@ - YAFFS_OBJECT_TYPE_DIRECTORY); - else - parent = NULL; -- -+ - if(parent) - yaffs_AddObjectToDirectory(parent, obj); -- -+ - obj->chunkId = cp->chunkId; -- obj->variantType = cp->variantType; -+ obj->variantType = cp->variantType; - obj->deleted = cp->deleted; - obj->softDeleted = cp->softDeleted; - obj->unlinked = cp->unlinked; -@@ -4202,12 +3612,12 @@ - obj->unlinkAllowed = cp->unlinkAllowed; - obj->serial = cp->serial; - obj->nDataChunks = cp->nDataChunks; -- -+ - if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; - else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; -- -+ - if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) - obj->lazyLoaded = 1; - } -@@ -4250,17 +3660,17 @@ - { - __u32 endMarker = ~0; - int ok = 1; -- -+ - if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ - ok = yaffs_CheckpointTnodeWorker(obj, - obj->variant.fileVariant.top, - obj->variant.fileVariant.topLevel, - 0); - if(ok) -- ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == -+ ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == - sizeof(endMarker)); - } -- -+ - return ok ? 1 : 0; - } - -@@ -4271,15 +3681,12 @@ - yaffs_Device *dev = obj->myDev; - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; - yaffs_Tnode *tn; -- int nread = 0; -- -+ - ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); -- -+ - while(ok && (~baseChunk)){ -- nread++; - /* Read level 0 tnode */ -- -- -+ - /* printf("read tnode at %d\n",baseChunk); */ - tn = yaffs_GetTnodeRaw(dev); - if(tn) -@@ -4287,27 +3694,22 @@ - (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); - else - ok = 0; -- -+ - if(tn && ok){ - ok = yaffs_AddOrFindLevel0Tnode(dev, - fileStructPtr, - baseChunk, - tn) ? 1 : 0; -- - } -- -+ - if(ok) - ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); -- -+ - } - -- T(YAFFS_TRACE_CHECKPOINT,( -- TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), -- nread,baseChunk,ok)); -- -- return ok ? 1 : 0; -+ return ok ? 1 : 0; - } -- -+ - - static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) - { -@@ -4317,11 +3719,11 @@ - int ok = 1; - struct list_head *lh; - -- -+ - /* Iterate through the objects in each hash entry, - * dumping them to the checkpointing stream. - */ -- -+ - for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ - list_for_each(lh, &dev->objectBucket[i].list) { - if (lh) { -@@ -4333,9 +3735,9 @@ - T(YAFFS_TRACE_CHECKPOINT,( - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), - cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); -- -+ - ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); -- -+ - if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ - ok = yaffs_WriteCheckpointTnodes(obj); - } -@@ -4343,14 +3745,14 @@ - } - } - } -- -+ - /* Dump end of list */ - memset(&cp,0xFF,sizeof(yaffs_CheckpointObject)); - cp.structType = sizeof(cp); -- -+ - if(ok) - ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); -- -+ - return ok ? 1 : 0; - } - -@@ -4361,22 +3763,20 @@ - int ok = 1; - int done = 0; - yaffs_Object *hardList = NULL; -- -+ - while(ok && !done) { - ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); - if(cp.structType != sizeof(cp)) { -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR), -- cp.structType,sizeof(cp),ok)); -+ /* printf("structure parsing failed\n"); */ - ok = 0; - } -- -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), -- cp.objectId,cp.parentId,cp.variantType,cp.chunkId)); -- -+ - if(ok && cp.objectId == ~0) - done = 1; - else if(ok){ - obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); -+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d obj addr %x" TENDSTR), -+ cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); - if(obj) { - yaffs_CheckpointObjectToObject(obj,&cp); - if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { -@@ -4387,93 +3787,39 @@ - hardList; - hardList = obj; - } -- -+ - } - } - } -- -+ - if(ok) - yaffs_HardlinkFixup(dev,hardList); -- -+ - return ok ? 1 : 0; - } - --static int yaffs_WriteCheckpointSum(yaffs_Device *dev) --{ -- __u32 checkpointSum; -- int ok; -- -- yaffs_GetCheckpointSum(dev,&checkpointSum); -- -- ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum)); -- -- if(!ok) -- return 0; -- -- return 1; --} -- --static int yaffs_ReadCheckpointSum(yaffs_Device *dev) --{ -- __u32 checkpointSum0; -- __u32 checkpointSum1; -- int ok; -- -- yaffs_GetCheckpointSum(dev,&checkpointSum0); -- -- ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1)); -- -- if(!ok) -- return 0; -- -- if(checkpointSum0 != checkpointSum1) -- return 0; -- -- return 1; --} -- -- - static int yaffs_WriteCheckpointData(yaffs_Device *dev) - { - -- int ok = 1; -- -- if(dev->skipCheckpointWrite || !dev->isYaffs2){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR))); -- ok = 0; -- } -- -+ int ok; -+ -+ ok = yaffs_CheckpointOpen(dev,1); -+ - if(ok) -- ok = yaffs_CheckpointOpen(dev,1); -- -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); - ok = yaffs_WriteCheckpointValidityMarker(dev,1); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR))); -+ if(ok) - ok = yaffs_WriteCheckpointDevice(dev); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR))); -+ if(ok) - ok = yaffs_WriteCheckpointObjects(dev); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); -+ if(ok) - ok = yaffs_WriteCheckpointValidityMarker(dev,0); -- } -- -- if(ok){ -- ok = yaffs_WriteCheckpointSum(dev); -- } -- -- -+ - if(!yaffs_CheckpointClose(dev)) - ok = 0; -- -+ - if(ok) - dev->isCheckpointed = 1; -- else -+ else - dev->isCheckpointed = 0; - - return dev->isCheckpointed; -@@ -4481,44 +3827,27 @@ - - static int yaffs_ReadCheckpointData(yaffs_Device *dev) - { -- int ok = 1; -- -- if(dev->skipCheckpointRead || !dev->isYaffs2){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR))); -- ok = 0; -- } -- -+ int ok; -+ -+ ok = yaffs_CheckpointOpen(dev,0); /* open for read */ -+ - if(ok) -- ok = yaffs_CheckpointOpen(dev,0); /* open for read */ -- -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); - ok = yaffs_ReadCheckpointValidityMarker(dev,1); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR))); -+ if(ok) - ok = yaffs_ReadCheckpointDevice(dev); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); -+ if(ok) - ok = yaffs_ReadCheckpointObjects(dev); -- } -- if(ok){ -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); -+ if(ok) - ok = yaffs_ReadCheckpointValidityMarker(dev,0); -- } -+ - -- if(ok){ -- ok = yaffs_ReadCheckpointSum(dev); -- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok)); -- } - - if(!yaffs_CheckpointClose(dev)) - ok = 0; - - if(ok) - dev->isCheckpointed = 1; -- else -+ else - dev->isCheckpointed = 0; - - return ok ? 1 : 0; -@@ -4527,7 +3856,7 @@ - - static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) - { -- if(dev->isCheckpointed || -+ if(dev->isCheckpointed || - dev->blocksInCheckpoint > 0){ - dev->isCheckpointed = 0; - yaffs_CheckpointInvalidateStream(dev); -@@ -4539,19 +3868,13 @@ - - int yaffs_CheckpointSave(yaffs_Device *dev) - { -- -+ yaffs_ReportOddballBlocks(dev); - T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - -- yaffs_VerifyObjects(dev); -- yaffs_VerifyBlocks(dev); -- yaffs_VerifyFreeChunks(dev); -- -- if(!dev->isCheckpointed) { -- yaffs_InvalidateCheckpoint(dev); -+ if(!dev->isCheckpointed) - yaffs_WriteCheckpointData(dev); -- } -- -- T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); -+ -+ T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - - return dev->isCheckpointed; - } -@@ -4560,17 +3883,13 @@ - { - int retval; - T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); -- -+ - retval = yaffs_ReadCheckpointData(dev); - -- if(dev->isCheckpointed){ -- yaffs_VerifyObjects(dev); -- yaffs_VerifyBlocks(dev); -- yaffs_VerifyFreeChunks(dev); -- } -- - T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); -- -+ -+ yaffs_ReportOddballBlocks(dev); -+ - return retval; - } - -@@ -4606,7 +3925,7 @@ - chunk++; - - /* OK now check for the curveball where the start and end are in -- * the same chunk. -+ * the same chunk. - */ - if ((start + n) < dev->nDataBytesPerChunk) { - nToCopy = n; -@@ -4763,7 +4082,7 @@ - yaffs_ChunkCache *cache; - /* If we can't find the data in the cache, then load the cache */ - cache = yaffs_FindChunkCache(in, chunk); -- -+ - if (!cache - && yaffs_CheckSpaceForAllocation(in-> - myDev)) { -@@ -4776,12 +4095,12 @@ - cache-> - data); - } -- else if(cache && -+ else if(cache && - !cache->dirty && - !yaffs_CheckSpaceForAllocation(in->myDev)){ - /* Drop the cache if it was a read cache item and - * no space check has been made for it. -- */ -+ */ - cache = NULL; - } - -@@ -4945,9 +4264,9 @@ - int oldFileSize = in->variant.fileVariant.fileSize; - int newSizeOfPartialChunk; - int newFullChunks; -- -+ - yaffs_Device *dev = in->myDev; -- -+ - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); - - yaffs_FlushFilesChunkCache(in); -@@ -4969,7 +4288,7 @@ - - if (newSizeOfPartialChunk != 0) { - int lastChunk = 1 + newFullChunks; -- -+ - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); - - /* Got to read and rewrite the last chunk with its new size and zero pad */ -@@ -4993,8 +4312,8 @@ - in->variant.fileVariant.fileSize = newSize; - } - -- -- -+ -+ - /* Write a new object header. - * show we've shrunk the file, if need be - * Do this only if the file is not in the deleted directories. -@@ -5058,7 +4377,7 @@ - - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { - /* Move to the unlinked directory so we have a record that it was deleted. */ -- yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0); -+ yaffs_ChangeObjectName(in, in->myDev->deletedDir, NULL, 0, 0); - - } - -@@ -5096,7 +4415,7 @@ - if (immediateDeletion) { - retVal = - yaffs_ChangeObjectName(in, in->myDev->deletedDir, -- "deleted", 0, 0); -+ NULL, 0, 0); - T(YAFFS_TRACE_TRACING, - (TSTR("yaffs: immediate deletion of file %d" TENDSTR), - in->objectId)); -@@ -5109,7 +4428,7 @@ - } else { - retVal = - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, -- "unlinked", 0, 0); -+ NULL, 0, 0); - } - - } -@@ -5313,7 +4632,7 @@ - { - yaffs_Object *hl; - yaffs_Object *in; -- -+ - while (hardList) { - hl = hardList; - hardList = (yaffs_Object *) (hardList->hardLinks.next); -@@ -5370,6 +4689,7 @@ - int deleted; - yaffs_BlockState state; - yaffs_Object *hardList = NULL; -+ yaffs_Object *hl; - yaffs_BlockInfo *bi; - int sequenceNumber; - yaffs_ObjectHeader *oh; -@@ -5377,9 +4697,6 @@ - yaffs_Object *parent; - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - -- int alloc_failed = 0; -- -- - __u8 *chunkData; - - yaffs_BlockIndex *blockIndex = NULL; -@@ -5389,9 +4706,9 @@ - (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); - return YAFFS_FAIL; - } -- -+ - //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. -- -+ - T(YAFFS_TRACE_SCAN, - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), - dev->internalStartBlock, dev->internalEndBlock)); -@@ -5402,8 +4719,6 @@ - - if (dev->isYaffs2) { - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); -- if(!blockIndex) -- return YAFFS_FAIL; - } - - /* Scan all the blocks to determine their state */ -@@ -5485,7 +4800,7 @@ - } - - /* For each block.... */ -- for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; -+ for (blockIterator = startIterator; blockIterator <= endIterator; - blockIterator++) { - - if (dev->isYaffs2) { -@@ -5501,7 +4816,7 @@ - deleted = 0; - - /* For each chunk in each block that needs scanning....*/ -- for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && -+ for (c = 0; c < dev->nChunksPerBlock && - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { - /* Read the tags and decide what to do */ - chunk = blk * dev->nChunksPerBlock + c; -@@ -5520,7 +4835,7 @@ - /*T((" %d %d deleted\n",blk,c)); */ - } else if (!tags.chunkUsed) { - /* An unassigned chunk in the block -- * This means that either the block is empty or -+ * This means that either the block is empty or - * this is the one being allocated from - */ - -@@ -5537,9 +4852,9 @@ - state = YAFFS_BLOCK_STATE_ALLOCATING; - dev->allocationBlock = blk; - dev->allocationPage = c; -- dev->allocationBlockFinder = blk; -+ dev->allocationBlockFinder = blk; - /* Set it to here to encourage the allocator to go forth from here. */ -- -+ - /* Yaffs2 sanity check: - * This should be the one with the highest sequence number - */ -@@ -5569,20 +4884,12 @@ - /* PutChunkIntoFile checks for a clash (two data chunks with - * the same chunkId). - */ -- -- if(!in) -- alloc_failed = 1; -- -- if(in){ -- if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1)) -- alloc_failed = 1; -- } -- -+ yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, -+ 1); - endpos = - (tags.chunkId - 1) * dev->nDataBytesPerChunk + - tags.byteCount; -- if (in && -- in->variantType == YAFFS_OBJECT_TYPE_FILE -+ if (in->variantType == YAFFS_OBJECT_TYPE_FILE - && in->variant.fileVariant.scannedFileSize < - endpos) { - in->variant.fileVariant. -@@ -5613,7 +4920,7 @@ - tags.objectId); - if (in && in->variantType != oh->type) { - /* This should not happen, but somehow -- * Wev'e ended up with an objectId that has been reused but not yet -+ * Wev'e ended up with an objectId that has been reused but not yet - * deleted, and worse still it has changed type. Delete the old object. - */ - -@@ -5627,17 +4934,14 @@ - objectId, - oh->type); - -- if(!in) -- alloc_failed = 1; -- -- if (in && oh->shadowsObject > 0) { -+ if (oh->shadowsObject > 0) { - yaffs_HandleShadowedObject(dev, - oh-> - shadowsObject, - 0); - } - -- if (in && in->valid) { -+ if (in->valid) { - /* We have already filled this one. We have a duplicate and need to resolve it. */ - - unsigned existingSerial = in->serial; -@@ -5658,7 +4962,7 @@ - } - } - -- if (in && !in->valid && -+ if (!in->valid && - (tags.objectId == YAFFS_OBJECTID_ROOT || - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { - /* We only load some info, don't fiddle with directory structure */ -@@ -5683,7 +4987,7 @@ - #endif - in->chunkId = chunk; - -- } else if (in && !in->valid) { -+ } else if (!in->valid) { - /* we need to load this info */ - - in->valid = 1; -@@ -5752,11 +5056,11 @@ - * Since we might scan a hardlink before its equivalent object is scanned - * we put them all in a list. - * After scanning is complete, we should have all the objects, so we run through this -- * list and fix up all the chains. -+ * list and fix up all the chains. - */ - - switch (in->variantType) { -- case YAFFS_OBJECT_TYPE_UNKNOWN: -+ case YAFFS_OBJECT_TYPE_UNKNOWN: - /* Todo got a problem */ - break; - case YAFFS_OBJECT_TYPE_FILE: -@@ -5791,11 +5095,10 @@ - case YAFFS_OBJECT_TYPE_SPECIAL: - /* Do nothing */ - break; -- case YAFFS_OBJECT_TYPE_SYMLINK: -- in->variant.symLinkVariant.alias = -+ case YAFFS_OBJECT_TYPE_SYMLINK: -+ in->variant.symLinkVariant. -+ alias = - yaffs_CloneString(oh->alias); -- if(!in->variant.symLinkVariant.alias) -- alloc_failed = 1; - break; - } - -@@ -5826,11 +5129,11 @@ - if (blockIndex) { - YFREE(blockIndex); - } -- -- -+ -+ - /* Ok, we've done all the scanning. - * Fix up the hard link chains. -- * We should now have scanned all the objects, now it's time to add these -+ * We should now have scanned all the objects, now it's time to add these - * hardlinks. - */ - -@@ -5857,13 +5160,8 @@ - - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - -- if(alloc_failed){ -- return YAFFS_FAIL; -- } -- - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); - -- - return YAFFS_OK; - } - -@@ -5874,23 +5172,19 @@ - yaffs_Device *dev = in->myDev; - yaffs_ExtendedTags tags; - int result; -- int alloc_failed = 0; -- -- if(!in) -- return; -- -+ - #if 0 - T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), - in->objectId, - in->lazyLoaded ? "not yet" : "already")); - #endif -- -+ - if(in->lazyLoaded){ - in->lazyLoaded = 0; - chunkData = yaffs_GetTempBuffer(dev, __LINE__); - - result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); -- oh = (yaffs_ObjectHeader *) chunkData; -+ oh = (yaffs_ObjectHeader *) chunkData; - - in->yst_mode = oh->yst_mode; - #ifdef CONFIG_YAFFS_WINCE -@@ -5907,17 +5201,14 @@ - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; -- -+ - #endif - yaffs_SetObjectName(in, oh->name); -- -- if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ -+ -+ if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) - in->variant.symLinkVariant.alias = - yaffs_CloneString(oh->alias); -- if(!in->variant.symLinkVariant.alias) -- alloc_failed = 1; /* Not returned to caller */ -- } -- -+ - yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); - } - } -@@ -5945,13 +5236,12 @@ - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; - int itsUnlinked; - __u8 *chunkData; -- -+ - int fileSize; - int isShrink; - int foundChunksInBlock; - int equivalentObjectId; -- int alloc_failed = 0; -- -+ - - yaffs_BlockIndex *blockIndex = NULL; - int altBlockIndex = 0; -@@ -5971,20 +5261,18 @@ - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; - - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); -- -+ - if(!blockIndex) { - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); - altBlockIndex = 1; - } -- -+ - if(!blockIndex) { - T(YAFFS_TRACE_SCAN, - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); - return YAFFS_FAIL; - } -- -- dev->blocksInCheckpoint = 0; -- -+ - chunkData = yaffs_GetTempBuffer(dev, __LINE__); - - /* Scan all the blocks to determine their state */ -@@ -6001,15 +5289,15 @@ - - if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; -- -+ - T(YAFFS_TRACE_SCAN_DEBUG, - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, - state, sequenceNumber)); - -- -+ - if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ -- dev->blocksInCheckpoint++; -- -+ /* todo .. fix free space ? */ -+ - } else if (state == YAFFS_BLOCK_STATE_DEAD) { - T(YAFFS_TRACE_BAD_BLOCKS, - (TSTR("block %d is bad" TENDSTR), blk)); -@@ -6053,12 +5341,14 @@ - - /* Sort the blocks */ - #ifndef CONFIG_YAFFS_USE_OWN_SORT -- yaffs_qsort(blockIndex, nBlocksToScan, -- sizeof(yaffs_BlockIndex), ybicmp); -+ { -+ /* Use qsort now. */ -+ qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); -+ } - #else - { - /* Dungy old bubble sort... */ -- -+ - yaffs_BlockIndex temp; - int i; - int j; -@@ -6084,7 +5374,7 @@ - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); - - /* For each block.... backwards */ -- for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; -+ for (blockIterator = endIterator; blockIterator >= startIterator; - blockIterator--) { - /* Cooperative multitasking! This loop can run for so - long that watchdog timers expire. */ -@@ -6094,22 +5384,18 @@ - blk = blockIndex[blockIterator].block; - - bi = yaffs_GetBlockInfo(dev, blk); -- -- - state = bi->blockState; - - deleted = 0; - - /* For each chunk in each block that needs scanning.... */ - foundChunksInBlock = 0; -- for (c = dev->nChunksPerBlock - 1; -- !alloc_failed && c >= 0 && -+ for (c = dev->nChunksPerBlock - 1; c >= 0 && - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { -- /* Scan backwards... -+ /* Scan backwards... - * Read the tags and decide what to do - */ -- - chunk = blk * dev->nChunksPerBlock + c; - - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, -@@ -6123,14 +5409,14 @@ - * it is a chunk that was skipped due to failing the erased - * check. Just skip it so that it can be deleted. - * But, more typically, We get here when this is an unallocated -- * chunk and his means that either the block is empty or -+ * chunk and his means that either the block is empty or - * this is the one being allocated from - */ - - if(foundChunksInBlock) - { - /* This is a chunk that was skipped due to failing the erased check */ -- -+ - } else if (c == 0) { - /* We're looking at the first chunk in the block so the block is unused */ - state = YAFFS_BLOCK_STATE_EMPTY; -@@ -6140,7 +5426,7 @@ - state == YAFFS_BLOCK_STATE_ALLOCATING) { - if(dev->sequenceNumber == bi->sequenceNumber) { - /* this is the block being allocated from */ -- -+ - T(YAFFS_TRACE_SCAN, - (TSTR - (" Allocating from %d %d" -@@ -6149,34 +5435,34 @@ - state = YAFFS_BLOCK_STATE_ALLOCATING; - dev->allocationBlock = blk; - dev->allocationPage = c; -- dev->allocationBlockFinder = blk; -+ dev->allocationBlockFinder = blk; - } - else { - /* This is a partially written block that is not - * the current allocation block. This block must have - * had a write failure, so set up for retirement. - */ -- -+ - bi->needsRetiring = 1; - bi->gcPrioritise = 1; -- -+ - T(YAFFS_TRACE_ALWAYS, - (TSTR("Partially written block %d being set for retirement" TENDSTR), - blk)); - } - - } -- -+ - } - - dev->nFreeChunks++; -- -+ - } else if (tags.chunkId > 0) { - /* chunkId > 0 so it is a data chunk... */ - unsigned int endpos; - __u32 chunkBase = - (tags.chunkId - 1) * dev->nDataBytesPerChunk; -- -+ - foundChunksInBlock = 1; - - -@@ -6187,29 +5473,21 @@ - tags. - objectId, - YAFFS_OBJECT_TYPE_FILE); -- if(!in){ -- /* Out of memory */ -- alloc_failed = 1; -- } -- -- if (in && -- in->variantType == YAFFS_OBJECT_TYPE_FILE -+ if (in->variantType == YAFFS_OBJECT_TYPE_FILE - && chunkBase < - in->variant.fileVariant.shrinkSize) { - /* This has not been invalidated by a resize */ -- if(!yaffs_PutChunkIntoFile(in, tags.chunkId, -- chunk, -1)){ -- alloc_failed = 1; -- } -+ yaffs_PutChunkIntoFile(in, tags.chunkId, -+ chunk, -1); - -- /* File size is calculated by looking at the data chunks if we have not -+ /* File size is calculated by looking at the data chunks if we have not - * seen an object header yet. Stop this practice once we find an object header. - */ - endpos = - (tags.chunkId - - 1) * dev->nDataBytesPerChunk + - tags.byteCount; -- -+ - if (!in->valid && /* have not got an object header yet */ - in->variant.fileVariant. - scannedFileSize < endpos) { -@@ -6221,7 +5499,7 @@ - scannedFileSize; - } - -- } else if(in) { -+ } else { - /* This chunk has been invalidated by a resize, so delete */ - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); - -@@ -6255,7 +5533,7 @@ - ) { - - /* If we don't have valid info then we need to read the chunk -- * TODO In future we can probably defer reading the chunk and -+ * TODO In future we can probably defer reading the chunk and - * living with invalid data until needed. - */ - -@@ -6283,12 +5561,12 @@ - - if (in->valid) { - /* We have already filled this one. -- * We have a duplicate that will be discarded, but -+ * We have a duplicate that will be discarded, but - * we first have to suck out resize info if it is a file. - */ - -- if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && -- ((oh && -+ if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && -+ ((oh && - oh-> type == YAFFS_OBJECT_TYPE_FILE)|| - (tags.extraHeaderInfoAvailable && - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE)) -@@ -6339,7 +5617,7 @@ - YAFFS_OBJECTID_LOSTNFOUND)) { - /* We only load some info, don't fiddle with directory structure */ - in->valid = 1; -- -+ - if(oh) { - in->variantType = oh->type; - -@@ -6358,13 +5636,13 @@ - in->yst_mtime = oh->yst_mtime; - in->yst_ctime = oh->yst_ctime; - in->yst_rdev = oh->yst_rdev; -- -+ - #endif - } else { - in->variantType = tags.extraObjectType; - in->lazyLoaded = 1; - } -- -+ - in->chunkId = chunk; - - } else if (!in->valid) { -@@ -6372,7 +5650,7 @@ - - in->valid = 1; - in->chunkId = chunk; -- -+ - if(oh) { - in->variantType = oh->type; - -@@ -6393,12 +5671,12 @@ - in->yst_rdev = oh->yst_rdev; - #endif - -- if (oh->shadowsObject > 0) -+ if (oh->shadowsObject > 0) - yaffs_HandleShadowedObject(dev, - oh-> - shadowsObject, - 1); -- -+ - - yaffs_SetObjectName(in, oh->name); - parent = -@@ -6466,11 +5744,11 @@ - * Since we might scan a hardlink before its equivalent object is scanned - * we put them all in a list. - * After scanning is complete, we should have all the objects, so we run -- * through this list and fix up all the chains. -+ * through this list and fix up all the chains. - */ - - switch (in->variantType) { -- case YAFFS_OBJECT_TYPE_UNKNOWN: -+ case YAFFS_OBJECT_TYPE_UNKNOWN: - /* Todo got a problem */ - break; - case YAFFS_OBJECT_TYPE_FILE: -@@ -6479,7 +5757,7 @@ - scannedFileSize < fileSize) { - /* This covers the case where the file size is greater - * than where the data is -- * This will happen if the file is resized to be larger -+ * This will happen if the file is resized to be larger - * than its current data extents. - */ - in->variant.fileVariant.fileSize = fileSize; -@@ -6509,21 +5787,16 @@ - /* Do nothing */ - break; - case YAFFS_OBJECT_TYPE_SYMLINK: -- if(oh){ -+ if(oh) - in->variant.symLinkVariant.alias = - yaffs_CloneString(oh-> - alias); -- if(!in->variant.symLinkVariant.alias) -- alloc_failed = 1; -- } - break; - } - - } -- - } -- -- } /* End of scanning for each chunk */ -+ } - - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { - /* If we got this far while scanning, then the block is fully allocated. */ -@@ -6541,19 +5814,19 @@ - - } - -- if (altBlockIndex) -+ if (altBlockIndex) - YFREE_ALT(blockIndex); - else - YFREE(blockIndex); -- -+ - /* Ok, we've done all the scanning. - * Fix up the hard link chains. -- * We should now have scanned all the objects, now it's time to add these -+ * We should now have scanned all the objects, now it's time to add these - * hardlinks. - */ - yaffs_HardlinkFixup(dev,hardList); -- -- -+ -+ - /* - * Sort out state of unlinked and deleted objects. - */ -@@ -6587,10 +5860,6 @@ - - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); - -- if(alloc_failed){ -- return YAFFS_FAIL; -- } -- - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); - - return YAFFS_OK; -@@ -6601,10 +5870,10 @@ - static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) - { - yaffs_Device *dev = obj->myDev; -- -+ - if(dev && dev->removeObjectCallback) - dev->removeObjectCallback(obj); -- -+ - list_del_init(&obj->siblings); - obj->parent = NULL; - } -@@ -6682,7 +5951,7 @@ - list_for_each(i, &directory->variant.directoryVariant.children) { - if (i) { - l = list_entry(i, yaffs_Object, siblings); -- -+ - yaffs_CheckObjectDetailsLoaded(l); - - /* Special case for lost-n-found */ -@@ -6690,14 +5959,14 @@ - if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { - return l; - } -- } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) -+ } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) - { - /* LostnFound cunk called Objxxx - * Do a real check - */ - yaffs_GetObjectName(l, buffer, - YAFFS_MAX_NAME_LENGTH); -- if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) { -+ if (yaffs_strcmp(name, buffer) == 0) { - return l; - } - -@@ -6753,7 +6022,6 @@ - if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { - /* We want the object id of the equivalent object, not this one */ - obj = obj->variant.hardLinkVariant.equivalentObject; -- yaffs_CheckObjectDetailsLoaded(obj); - } - return obj; - -@@ -6762,7 +6030,7 @@ - int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) - { - memset(name, 0, buffSize * sizeof(YCHAR)); -- -+ - yaffs_CheckObjectDetailsLoaded(obj); - - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { -@@ -6991,16 +6259,15 @@ - } - - --static int yaffs_CreateInitialDirectories(yaffs_Device *dev) -+static void yaffs_CreateInitialDirectories(yaffs_Device *dev) - { - /* Initialise the unlinked, deleted, root and lost and found directories */ -- -+ - dev->lostNFoundDir = dev->rootDir = NULL; - dev->unlinkedDir = dev->deletedDir = NULL; - - dev->unlinkedDir = - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); -- - dev->deletedDir = - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); - -@@ -7010,18 +6277,11 @@ - dev->lostNFoundDir = - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, - YAFFS_LOSTNFOUND_MODE | S_IFDIR); -- -- if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ -- yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); -- return YAFFS_OK; -- } -- -- return YAFFS_FAIL; -+ yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); - } - - int yaffs_GutsInitialise(yaffs_Device * dev) - { -- int init_failed = 0; - unsigned x; - int bits; - -@@ -7049,12 +6309,12 @@ - - /* Check geometry parameters. */ - -- if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || -- (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || -- dev->nChunksPerBlock < 2 || -- dev->nReservedBlocks < 2 || -- dev->internalStartBlock <= 0 || -- dev->internalEndBlock <= 0 || -+ if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || -+ (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || -+ dev->nChunksPerBlock < 2 || -+ dev->nReservedBlocks < 2 || -+ dev->internalStartBlock <= 0 || -+ dev->internalEndBlock <= 0 || - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small - ) { - T(YAFFS_TRACE_ALWAYS, -@@ -7100,9 +6360,9 @@ - - - /* OK now calculate a few things for the device */ -- -+ - /* -- * Calculate all the chunk size manipulation numbers: -+ * Calculate all the chunk size manipulation numbers: - */ - /* Start off assuming it is a power of 2 */ - dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); -@@ -7121,7 +6381,7 @@ - dev->chunkShift = 0; - dev->chunkMask = 0; - } -- -+ - - /* - * Calculate chunkGroupBits. -@@ -7129,9 +6389,9 @@ - */ - - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); -- -+ - bits = ShiftsGE(x); -- -+ - /* Set up tnode width if wide tnodes are enabled. */ - if(!dev->wideTnodesDisabled){ - /* bits must be even so that we end up with 32-bit words */ -@@ -7144,20 +6404,20 @@ - } - else - dev->tnodeWidth = 16; -- -+ - dev->tnodeMask = (1<tnodeWidth)-1; -- -+ - /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), - * so if the bitwidth of the - * chunk range we're using is greater than 16 we need - * to figure out chunk shift and chunkGroupSize - */ -- -+ - if (bits <= dev->tnodeWidth) - dev->chunkGroupBits = 0; - else - dev->chunkGroupBits = bits - dev->tnodeWidth; -- -+ - - dev->chunkGroupSize = 1 << dev->chunkGroupBits; - -@@ -7193,111 +6453,71 @@ - dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ - - /* Initialise temporary buffers and caches. */ -- if(!yaffs_InitialiseTempBuffers(dev)) -- init_failed = 1; -- -- dev->srCache = NULL; -- dev->gcCleanupList = NULL; -- -- -- if (!init_failed && -- dev->nShortOpCaches > 0) { -+ { -+ int i; -+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { -+ dev->tempBuffer[i].line = 0; /* not in use */ -+ dev->tempBuffer[i].buffer = -+ YMALLOC_DMA(dev->nDataBytesPerChunk); -+ } -+ } -+ -+ if (dev->nShortOpCaches > 0) { - int i; -- __u8 *buf; -- int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); - - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; - } - -- buf = dev->srCache = YMALLOC(srCacheBytes); -+ dev->srCache = -+ YMALLOC(dev->nShortOpCaches * sizeof(yaffs_ChunkCache)); - -- if(dev->srCache) -- memset(dev->srCache,0,srCacheBytes); -- -- for (i = 0; i < dev->nShortOpCaches && buf; i++) { -+ for (i = 0; i < dev->nShortOpCaches; i++) { - dev->srCache[i].object = NULL; - dev->srCache[i].lastUse = 0; - dev->srCache[i].dirty = 0; -- dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk); -+ dev->srCache[i].data = YMALLOC_DMA(dev->nDataBytesPerChunk); - } -- if(!buf) -- init_failed = 1; -- - dev->srLastUse = 0; - } - - dev->cacheHits = 0; -- -- if(!init_failed){ -- dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); -- if(!dev->gcCleanupList) -- init_failed = 1; -- } -+ -+ dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); - - if (dev->isYaffs2) { - dev->useHeaderFileSize = 1; - } -- if(!init_failed && !yaffs_InitialiseBlocks(dev)) -- init_failed = 1; - -+ yaffs_InitialiseBlocks(dev); - yaffs_InitialiseTnodes(dev); - yaffs_InitialiseObjects(dev); - -- if(!init_failed && !yaffs_CreateInitialDirectories(dev)) -- init_failed = 1; -- -- -- if(!init_failed){ -- /* Now scan the flash. */ -- if (dev->isYaffs2) { -- if(yaffs_CheckpointRestore(dev)) { -- T(YAFFS_TRACE_ALWAYS, -- (TSTR("yaffs: restored from checkpoint" TENDSTR))); -- } else { -- -- /* Clean up the mess caused by an aborted checkpoint load -- * and scan backwards. -- */ -- yaffs_DeinitialiseBlocks(dev); -- yaffs_DeinitialiseTnodes(dev); -- yaffs_DeinitialiseObjects(dev); -- -- -- dev->nErasedBlocks = 0; -- dev->nFreeChunks = 0; -- dev->allocationBlock = -1; -- dev->allocationPage = -1; -- dev->nDeletedFiles = 0; -- dev->nUnlinkedFiles = 0; -- dev->nBackgroundDeletions = 0; -- dev->oldestDirtySequence = 0; -+ yaffs_CreateInitialDirectories(dev); - -- if(!init_failed && !yaffs_InitialiseBlocks(dev)) -- init_failed = 1; - -- yaffs_InitialiseTnodes(dev); -- yaffs_InitialiseObjects(dev); -- -- if(!init_failed && !yaffs_CreateInitialDirectories(dev)) -- init_failed = 1; -- -- if(!init_failed && !yaffs_ScanBackwards(dev)) -- init_failed = 1; -- } -- }else -- if(!yaffs_Scan(dev)) -- init_failed = 1; -- } -+ /* Now scan the flash. */ -+ if (dev->isYaffs2) { -+ if(yaffs_CheckpointRestore(dev)) { -+ T(YAFFS_TRACE_ALWAYS, -+ (TSTR("yaffs: restored from checkpoint" TENDSTR))); -+ } else { - -- if(init_failed){ -- /* Clean up the mess */ -- T(YAFFS_TRACE_TRACING, -- (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); -+ /* Clean up the mess caused by an aborted checkpoint load -+ * and scan backwards. -+ */ -+ yaffs_DeinitialiseBlocks(dev); -+ yaffs_DeinitialiseTnodes(dev); -+ yaffs_DeinitialiseObjects(dev); -+ yaffs_InitialiseBlocks(dev); -+ yaffs_InitialiseTnodes(dev); -+ yaffs_InitialiseObjects(dev); -+ yaffs_CreateInitialDirectories(dev); - -- yaffs_Deinitialise(dev); -- return YAFFS_FAIL; -- } -+ yaffs_ScanBackwards(dev); -+ } -+ }else -+ yaffs_Scan(dev); - - /* Zero out stats */ - dev->nPageReads = 0; -@@ -7309,9 +6529,6 @@ - dev->nRetiredBlocks = 0; - - yaffs_VerifyFreeChunks(dev); -- yaffs_VerifyBlocks(dev); -- -- - T(YAFFS_TRACE_TRACING, - (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); - return YAFFS_OK; -@@ -7326,17 +6543,13 @@ - yaffs_DeinitialiseBlocks(dev); - yaffs_DeinitialiseTnodes(dev); - yaffs_DeinitialiseObjects(dev); -- if (dev->nShortOpCaches > 0 && -- dev->srCache) { -+ if (dev->nShortOpCaches > 0) { - - for (i = 0; i < dev->nShortOpCaches; i++) { -- if(dev->srCache[i].data) -- YFREE(dev->srCache[i].data); -- dev->srCache[i].data = NULL; -+ YFREE(dev->srCache[i].data); - } - - YFREE(dev->srCache); -- dev->srCache = NULL; - } - - YFREE(dev->gcCleanupList); -@@ -7394,7 +6607,7 @@ - #endif - - nFree += dev->nDeletedFiles; -- -+ - /* Now count the number of dirty chunks in the cache and subtract those */ - - { -@@ -7408,12 +6621,12 @@ - nFree -= nDirtyCacheChunks; - - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); -- -+ - /* Now we figure out how much to reserve for the checkpoint and report that... */ - blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; - if(blocksForCheckpoint < 0) - blocksForCheckpoint = 0; -- -+ - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); - - if (nFree < 0) -@@ -7427,15 +6640,9 @@ - - static void yaffs_VerifyFreeChunks(yaffs_Device * dev) - { -- int counted; -- int difference; -- -- if(yaffs_SkipVerification(dev)) -- return; -- -- counted = yaffs_CountFreeChunks(dev); -+ int counted = yaffs_CountFreeChunks(dev); - -- difference = dev->nFreeChunks - counted; -+ int difference = dev->nFreeChunks - counted; - - if (difference) { - T(YAFFS_TRACE_ALWAYS, -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_guts.h linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_guts.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_guts.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -22,11 +22,11 @@ - #define YAFFS_OK 1 - #define YAFFS_FAIL 0 - --/* Give us a Y=0x59, -- * Give us an A=0x41, -- * Give us an FF=0xFF -+/* Give us a Y=0x59, -+ * Give us an A=0x41, -+ * Give us an FF=0xFF - * Give us an S=0x53 -- * And what have we got... -+ * And what have we got... - */ - #define YAFFS_MAGIC 0x5941FF53 - -@@ -63,7 +63,9 @@ - - #define YAFFS_OBJECT_SPACE 0x40000 - --#define YAFFS_CHECKPOINT_VERSION 3 -+#define YAFFS_NCHECKPOINT_OBJECTS 5000 -+ -+#define YAFFS_CHECKPOINT_VERSION 2 - - #ifdef CONFIG_YAFFS_UNICODE - #define YAFFS_MAX_NAME_LENGTH 127 -@@ -92,17 +94,11 @@ - - #define YAFFS_N_TEMP_BUFFERS 4 - --/* We limit the number attempts at sucessfully saving a chunk of data. -- * Small-page devices have 32 pages per block; large-page devices have 64. -- * Default to something in the order of 5 to 10 blocks worth of chunks. -- */ --#define YAFFS_WR_ATTEMPTS (5*64) -- - /* Sequence numbers are used in YAFFS2 to determine block allocation order. - * The range is limited slightly to help distinguish bad numbers from good. - * This also allows us to perhaps in the future use special numbers for - * special purposes. -- * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, -+ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, - * and is a larger number than the lifetime of a 2GB device. - */ - #define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 -@@ -166,8 +162,6 @@ - YAFFS_OBJECT_TYPE_SPECIAL - } yaffs_ObjectType; - --#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL -- - typedef struct { - - unsigned validMarker0; -@@ -178,7 +172,7 @@ - - /* The following stuff only has meaning when we read */ - yaffs_ECCResult eccResult; -- unsigned blockBad; -+ unsigned blockBad; - - /* YAFFS 1 stuff */ - unsigned chunkDeleted; /* The chunk is marked deleted */ -@@ -244,35 +238,32 @@ - /* This block is empty */ - - YAFFS_BLOCK_STATE_ALLOCATING, -- /* This block is partially allocated. -+ /* This block is partially allocated. - * At least one page holds valid data. - * This is the one currently being used for page - * allocation. Should never be more than one of these - */ - -- YAFFS_BLOCK_STATE_FULL, -+ YAFFS_BLOCK_STATE_FULL, - /* All the pages in this block have been allocated. - */ - - YAFFS_BLOCK_STATE_DIRTY, -- /* All pages have been allocated and deleted. -+ /* All pages have been allocated and deleted. - * Erase me, reuse me. - */ - -- YAFFS_BLOCK_STATE_CHECKPOINT, -+ YAFFS_BLOCK_STATE_CHECKPOINT, - /* This block is assigned to holding checkpoint data. - */ - -- YAFFS_BLOCK_STATE_COLLECTING, -+ YAFFS_BLOCK_STATE_COLLECTING, - /* This block is being garbage collected */ - -- YAFFS_BLOCK_STATE_DEAD -+ YAFFS_BLOCK_STATE_DEAD - /* This block has failed and is not in use */ - } yaffs_BlockState; - --#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) -- -- - typedef struct { - - int softDeletions:10; /* number of soft deleted pages */ -@@ -281,7 +272,7 @@ - __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ - /* and retire the block. */ - __u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */ -- __u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block. -+ __u32 gcPrioritise: 1; /* An ECC check or bank check has failed on this block. - It should be prioritised for GC */ - __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ - -@@ -408,7 +399,7 @@ - __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ - __u8 unlinkAllowed:1; - __u8 dirty:1; /* the object needs to be written to flash */ -- __u8 valid:1; /* When the file system is being loaded up, this -+ __u8 valid:1; /* When the file system is being loaded up, this - * object might be created before the data - * is available (ie. file data records appear before the header). - */ -@@ -430,11 +421,11 @@ - - /* directory structure stuff */ - /* also used for linking up the free list */ -- struct yaffs_ObjectStruct *parent; -+ struct yaffs_ObjectStruct *parent; - struct list_head siblings; - - /* Where's my object header in NAND? */ -- int chunkId; -+ int chunkId; - - int nDataChunks; /* Number of data chunks attached to the file. */ - -@@ -490,26 +481,26 @@ - } yaffs_ObjectBucket; - - --/* yaffs_CheckpointObject holds the definition of an object as dumped -+/* yaffs_CheckpointObject holds the definition of an object as dumped - * by checkpointing. - */ - - typedef struct { - int structType; -- __u32 objectId; -+ __u32 objectId; - __u32 parentId; - int chunkId; -- -+ - yaffs_ObjectType variantType:3; -- __u8 deleted:1; -- __u8 softDeleted:1; -- __u8 unlinked:1; -- __u8 fake:1; -+ __u8 deleted:1; -+ __u8 softDeleted:1; -+ __u8 unlinked:1; -+ __u8 fake:1; - __u8 renameAllowed:1; - __u8 unlinkAllowed:1; -- __u8 serial; -- -- int nDataChunks; -+ __u8 serial; -+ -+ int nDataChunks; - __u32 fileSizeOrEquivalentObjectId; - - }yaffs_CheckpointObject; -@@ -539,14 +530,17 @@ - int endBlock; /* End block we're allowed to use */ - int nReservedBlocks; /* We want this tuneable so that we can reduce */ - /* reserved blocks on NOR and RAM. */ -- -- -+ -+ /* Stuff used by the partitioned checkpointing mechanism */ -+ int checkpointStartBlock; -+ int checkpointEndBlock; -+ - /* Stuff used by the shared space checkpointing mechanism */ - /* If this value is zero, then this mechanism is disabled */ -- -+ - int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ - -- -+ - - - int nShortOpCaches; /* If <= 0, then short op caching is disabled, else -@@ -561,7 +555,7 @@ - * On an mtd this holds the mtd pointer. - */ - void *superBlock; -- -+ - /* NAND access functions (Must be set before calling YAFFS)*/ - - int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev, -@@ -587,57 +581,53 @@ - #endif - - int isYaffs2; -- -- /* The removeObjectCallback function must be supplied by OS flavours that -+ -+ /* The removeObjectCallback function must be supplied by OS flavours that - * need it. The Linux kernel does not use this, but yaffs direct does use - * it to implement the faster readdir - */ - void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); -- -+ - /* Callback to mark the superblock dirsty */ - void (*markSuperBlockDirty)(void * superblock); -- -+ - int wideTnodesDisabled; /* Set to disable wide tnodes */ -- -+ - - /* End of stuff that must be set before initialisation. */ - -- /* Checkpoint control. Can be set before or after initialisation */ -- __u8 skipCheckpointRead; -- __u8 skipCheckpointWrite; -- - /* Runtime parameters. Set up by YAFFS. */ - - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ - __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ -- -+ - /* Stuff to support wide tnodes */ - __u32 tnodeWidth; - __u32 tnodeMask; -- -+ - /* Stuff to support various file offses to chunk/offset translations */ - /* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ - __u32 crumbMask; - __u32 crumbShift; - __u32 crumbsPerChunk; -- -+ - /* Straight shifting for nDataBytesPerChunk being a power of 2 */ - __u32 chunkShift; - __u32 chunkMask; -- -+ - - #ifdef __KERNEL__ - - struct semaphore sem; /* Semaphore for waiting on erasure.*/ - struct semaphore grossLock; /* Gross locking semaphore */ -- __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer -+ __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer - * at compile time so we have to allocate it. - */ - void (*putSuperFunc) (struct super_block * sb); - #endif - - int isMounted; -- -+ - int isCheckpointed; - - -@@ -646,7 +636,7 @@ - int internalEndBlock; - int blockOffset; - int chunkOffset; -- -+ - - /* Runtime checkpointing stuff */ - int checkpointPageSequence; /* running sequence number of checkpoint pages */ -@@ -660,15 +650,13 @@ - int checkpointNextBlock; - int *checkpointBlockList; - int checkpointMaxBlocks; -- __u32 checkpointSum; -- __u32 checkpointXor; -- -+ - /* Block Info */ - yaffs_BlockInfo *blockInfo; - __u8 *chunkBits; /* bitmap of chunks in use */ - unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ - unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ -- int chunkBitmapStride; /* Number of bytes of chunkBits per block. -+ int chunkBitmapStride; /* Number of bytes of chunkBits per block. - * Must be consistent with nChunksPerBlock. - */ - -@@ -698,7 +686,6 @@ - int currentDirtyChecker; /* Used to find current dirtiest block */ - - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ -- int nonAggressiveSkip; /* GC state/mode */ - - /* Statistcs */ - int nPageWrites; -@@ -716,7 +703,7 @@ - int tagsEccUnfixed; - int nDeletions; - int nUnmarkedDeletions; -- -+ - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ - - /* Special directories */ -@@ -727,7 +714,7 @@ - * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; - * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; - */ -- -+ - int bufferedBlock; /* Which block is buffered here? */ - int doingBufferedBlockRewrite; - -@@ -768,7 +755,7 @@ - int endBlock; - int rfu[100]; - } yaffs_SuperBlockHeader; -- -+ - /* The CheckpointDevice structure holds the device information that changes at runtime and - * must be preserved over unmount/mount cycles. - */ -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.c 2009-04-21 15:01:02.000000000 +0200 -@@ -12,13 +12,10 @@ - */ - - const char *yaffs_mtdif_c_version = -- "$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $"; -+ "$Id: yaffs_mtdif.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; - - #include "yportenv.h" -- -- - #include "yaffs_mtdif.h" -- - #include "linux/mtd/mtd.h" - #include "linux/types.h" - #include "linux/time.h" -@@ -54,6 +51,7 @@ - static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) - { - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; -+ - spare->tagByte0 = oob[0]; - spare->tagByte1 = oob[1]; - spare->tagByte2 = oob[2]; -@@ -68,6 +66,11 @@ - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; - - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ -+#if 0 -+ char i; -+ for (i=0;i<8;i++) -+ printk("oob %d :%x",i,oob[i]); -+#endif - } - #endif - -@@ -78,10 +81,11 @@ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - struct mtd_oob_ops ops; - #endif -- size_t dummy; -+ size_mtd_t dummy; - int retval = 0; - -- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; -+ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - __u8 spareAsBytes[8]; /* OOB */ - -@@ -142,10 +146,11 @@ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - struct mtd_oob_ops ops; - #endif -- size_t dummy; -+ size_mtd_t dummy; - int retval = 0; - -- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; -+ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - __u8 spareAsBytes[8]; /* OOB */ - -@@ -164,7 +169,7 @@ - ops.datbuf = data; - ops.ooboffs = 0; - ops.oobbuf = spareAsBytes; -- retval = mtd->read_oob(mtd, addr, &ops); -+ retval = mtd->read_oob(mtd, addr, &ops); - if (dev->useNANDECC) - translate_oob2spare(spare, spareAsBytes); - } -@@ -172,7 +177,7 @@ - __u8 *spareAsBytes = (__u8 *) spare; - - if (data && spare) { -- if (dev->useNANDECC) { -+ if (dev->useNANDECC) { - /* Careful, this call adds 2 ints */ - /* to the end of the spare data. Calling function */ - /* should allocate enough memory for spare, */ -@@ -208,8 +213,8 @@ - int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber) - { - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -- __u32 addr = -- ((loff_t) blockNumber) * dev->nDataBytesPerChunk -+ __u64 addr = -+ ((loff_mtd_t) blockNumber) * dev->nDataBytesPerChunk - * dev->nChunksPerBlock; - struct erase_info ei; - int retval = 0; -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1-compat.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1-compat.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1-compat.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1-compat.c 1970-01-01 01:00:00.000000000 +0100 -@@ -1,434 +0,0 @@ --From ian@brightstareng.com Fri May 18 15:06:49 2007 --From ian@brightstareng.com Fri May 18 15:08:21 2007 --Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com) -- by apollo.linkchoose.co.uk with esmtp (Exim 4.60) -- (envelope-from ) -- id 1Hp380-00011e-T6 -- for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100 --Received: from localhost (localhost.localdomain [127.0.0.1]) -- by zebra.brightstareng.com (Postfix) with ESMTP -- id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT) --Received: from zebra.brightstareng.com ([127.0.0.1]) -- by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP -- id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT) --Received: from pippin (unknown [192.168.1.25]) -- by zebra.brightstareng.com (Postfix) with ESMTP -- id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT) --From: Ian McDonnell --To: David Goodenough --Subject: Re: something tested this time -- yaffs_mtdif1-compat.c --Date: Fri, 18 May 2007 10:06:49 -0400 --User-Agent: KMail/1.9.1 --References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk> --In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk> --Cc: Andrea Conti , -- Charles Manning --MIME-Version: 1.0 --Content-Type: Multipart/Mixed; -- boundary="Boundary-00=_5LbTGmt62YoutxM" --Message-Id: <200705181006.49860.ian@brightstareng.com> --X-Virus-Scanned: by amavisd-new at brightstareng.com --Status: R --X-Status: NT --X-KMail-EncryptionState: --X-KMail-SignatureState: --X-KMail-MDN-Sent: -- ----Boundary-00=_5LbTGmt62YoutxM --Content-Type: text/plain; -- charset="iso-8859-15" --Content-Transfer-Encoding: 7bit --Content-Disposition: inline -- --David, Andrea, -- --On Friday 18 May 2007 08:34, you wrote: --> Yea team. With this fix in place (I put it in the wrong place --> at first) I can now mount and ls the Yaffs partition without --> an error messages! -- --Good news! -- --Attached is a newer yaffs_mtdif1.c with a bandaid to help the --2.6.18 and 2.6.19 versions of MTD not trip on the oob read. --See the LINUX_VERSION_CODE conditional in --nandmtd1_ReadChunkWithTagsFromNAND. -- ---imcd -- ----Boundary-00=_5LbTGmt62YoutxM --Content-Type: text/x-csrc; -- charset="iso-8859-15"; -- name="yaffs_mtdif1.c" --Content-Transfer-Encoding: 7bit --Content-Disposition: attachment; -- filename="yaffs_mtdif1.c" -- --/* -- * YAFFS: Yet another FFS. A NAND-flash specific file system. -- * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. -- * -- * Copyright (C) 2002 Aleph One Ltd. -- * for Toby Churchill Ltd and Brightstar Engineering -- * -- * 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 module provides the interface between yaffs_nand.c and the -- * MTD API. This version is used when the MTD interface supports the -- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, -- * and we have small-page NAND device. -- * -- * These functions are invoked via function pointers in yaffs_nand.c. -- * This replaces functionality provided by functions in yaffs_mtdif.c -- * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are -- * called in yaffs_mtdif.c when the function pointers are NULL. -- * We assume the MTD layer is performing ECC (useNANDECC is true). -- */ -- --#include "yportenv.h" --#include "yaffs_guts.h" --#include "yaffs_packedtags1.h" --#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC -- --#include "linux/kernel.h" --#include "linux/version.h" --#include "linux/types.h" --#include "linux/mtd/mtd.h" -- --/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) -- --const char *yaffs_mtdif1_c_version = "$Id$"; -- --#ifndef CONFIG_YAFFS_9BYTE_TAGS --# define YTAG1_SIZE 8 --#else --# define YTAG1_SIZE 9 --#endif -- --#if 0 --/* Use the following nand_ecclayout with MTD when using -- * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. -- * If you have existing Yaffs images and the byte order differs from this, -- * adjust 'oobfree' to match your existing Yaffs data. -- * -- * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the -- * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to -- * the 9th byte. -- * -- * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 -- * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P -- * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus -- * byte and B is the small-page bad-block indicator byte. -- */ --static struct nand_ecclayout nand_oob_16 = { -- .eccbytes = 6, -- .eccpos = { 8, 9, 10, 13, 14, 15 }, -- .oobavail = 9, -- .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } --}; --#endif -- --/* Write a chunk (page) of data to NAND. -- * -- * Caller always provides ExtendedTags data which are converted to a more -- * compact (packed) form for storage in NAND. A mini-ECC runs over the -- * contents of the tags meta-data; used to valid the tags when read. -- * -- * - Pack ExtendedTags to PackedTags1 form -- * - Compute mini-ECC for PackedTags1 -- * - Write data and packed tags to NAND. -- * -- * Note: Due to the use of the PackedTags1 meta-data which does not include -- * a full sequence number (as found in the larger PackedTags2 form) it is -- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as -- * discarded and dirty. This is not ideal: newer NAND parts are supposed -- * to be written just once. When Yaffs performs this operation, this -- * function is called with a NULL data pointer -- calling MTD write_oob -- * without data is valid usage (2.6.17). -- * -- * Any underlying MTD error results in YAFFS_FAIL. -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, -- int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkBytes = dev->nDataBytesPerChunk; -- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; -- struct mtd_oob_ops ops; -- yaffs_PackedTags1 pt1; -- int retval; -- -- /* we assume that PackedTags1 and yaffs_Tags are compatible */ -- compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); -- compile_time_assertion(sizeof(yaffs_Tags) == 8); -- -- yaffs_PackTags1(&pt1, etags); -- yaffs_CalcTagsECC((yaffs_Tags *)&pt1); -- -- /* When deleting a chunk, the upper layer provides only skeletal -- * etags, one with chunkDeleted set. However, we need to update the -- * tags, not erase them completely. So we use the NAND write property -- * that only zeroed-bits stick and set tag bytes to all-ones and -- * zero just the (not) deleted bit. -- */ --#ifndef CONFIG_YAFFS_9BYTE_TAGS -- if (etags->chunkDeleted) { -- memset(&pt1, 0xff, 8); -- /* clear delete status bit to indicate deleted */ -- pt1.deleted = 0; -- } --#else -- ((__u8 *)&pt1)[8] = 0xff; -- if (etags->chunkDeleted) { -- memset(&pt1, 0xff, 8); -- /* zero pageStatus byte to indicate deleted */ -- ((__u8 *)&pt1)[8] = 0; -- } --#endif -- -- memset(&ops, 0, sizeof(ops)); -- ops.mode = MTD_OOB_AUTO; -- ops.len = (data) ? chunkBytes : 0; -- ops.ooblen = YTAG1_SIZE; -- ops.datbuf = (__u8 *)data; -- ops.oobbuf = (__u8 *)&pt1; -- -- retval = mtd->write_oob(mtd, addr, &ops); -- if (retval) { -- yaffs_trace(YAFFS_TRACE_MTD, -- "write_oob failed, chunk %d, mtd error %d\n", -- chunkInNAND, retval); -- } -- return retval ? YAFFS_FAIL : YAFFS_OK; --} -- --/* Return with empty ExtendedTags but add eccResult. -- */ --static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval) --{ -- if (etags) { -- memset(etags, 0, sizeof(*etags)); -- etags->eccResult = eccResult; -- } -- return retval; --} -- --/* Read a chunk (page) from NAND. -- * -- * Caller expects ExtendedTags data to be usable even on error; that is, -- * all members except eccResult and blockBad are zeroed. -- * -- * - Check ECC results for data (if applicable) -- * - Check for blank/erased block (return empty ExtendedTags if blank) -- * - Check the PackedTags1 mini-ECC (correct if necessary/possible) -- * - Convert PackedTags1 to ExtendedTags -- * - Update eccResult and blockBad members to refect state. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, -- int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkBytes = dev->nDataBytesPerChunk; -- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; -- int eccres = YAFFS_ECC_RESULT_NO_ERROR; -- struct mtd_oob_ops ops; -- yaffs_PackedTags1 pt1; -- int retval; -- int deleted; -- -- memset(&ops, 0, sizeof(ops)); -- ops.mode = MTD_OOB_AUTO; -- ops.len = (data) ? chunkBytes : 0; -- ops.ooblen = YTAG1_SIZE; -- ops.datbuf = data; -- ops.oobbuf = (__u8 *)&pt1; -- --#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) -- /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; -- * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. -- */ -- ops.len = (ops.datbuf) ? ops.len : ops.ooblen; --#endif -- /* Read page and oob using MTD. -- * Check status and determine ECC result. -- */ -- retval = mtd->read_oob(mtd, addr, &ops); -- if (retval) { -- yaffs_trace(YAFFS_TRACE_MTD, -- "read_oob failed, chunk %d, mtd error %d\n", -- chunkInNAND, retval); -- } -- -- switch (retval) { -- case 0: -- /* no error */ -- break; -- -- case -EUCLEAN: -- /* MTD's ECC fixed the data */ -- eccres = YAFFS_ECC_RESULT_FIXED; -- dev->eccFixed++; -- break; -- -- case -EBADMSG: -- /* MTD's ECC could not fix the data */ -- dev->eccUnfixed++; -- /* fall into... */ -- default: -- rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); -- etags->blockBad = (mtd->block_isbad)(mtd, addr); -- return YAFFS_FAIL; -- } -- -- /* Check for a blank/erased chunk. -- */ -- if (yaffs_CheckFF((__u8 *)&pt1, 8)) { -- /* when blank, upper layers want eccResult to be <= NO_ERROR */ -- return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); -- } -- --#ifndef CONFIG_YAFFS_9BYTE_TAGS -- /* Read deleted status (bit) then return it to it's non-deleted -- * state before performing tags mini-ECC check. pt1.deleted is -- * inverted. -- */ -- deleted = !pt1.deleted; -- pt1.deleted = 1; --#else -- (void) deleted; /* not used */ --#endif -- -- /* Check the packed tags mini-ECC and correct if necessary/possible. -- */ -- retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); -- switch (retval) { -- case 0: -- /* no tags error, use MTD result */ -- break; -- case 1: -- /* recovered tags-ECC error */ -- dev->tagsEccFixed++; -- eccres = YAFFS_ECC_RESULT_FIXED; -- break; -- default: -- /* unrecovered tags-ECC error */ -- dev->tagsEccUnfixed++; -- return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); -- } -- -- /* Unpack the tags to extended form and set ECC result. -- * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] -- */ -- pt1.shouldBeFF = 0xFFFFFFFF; -- yaffs_UnpackTags1(etags, &pt1); -- etags->eccResult = eccres; -- -- /* Set deleted state. -- */ --#ifndef CONFIG_YAFFS_9BYTE_TAGS -- etags->chunkDeleted = deleted; --#else -- etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); --#endif -- return YAFFS_OK; --} -- --/* Mark a block bad. -- * -- * This is a persistant state. -- * Use of this function should be rare. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; -- int retval; -- -- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo); -- -- retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); -- return (retval) ? YAFFS_FAIL : YAFFS_OK; --} -- --/* Check any MTD prerequists. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --static int nandmtd1_TestPrerequists(struct mtd_info * mtd) --{ -- /* 2.6.18 has mtd->ecclayout->oobavail */ -- /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ -- int oobavail = mtd->ecclayout->oobavail; -- -- if (oobavail < YTAG1_SIZE) { -- yaffs_trace(YAFFS_TRACE_ERROR, -- "mtd device has only %d bytes for tags, need %d", -- oobavail, YTAG1_SIZE); -- return YAFFS_FAIL; -- } -- return YAFFS_OK; --} -- --/* Query for the current state of a specific block. -- * -- * Examine the tags of the first chunk of the block and return the state: -- * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad -- * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use -- * - YAFFS_BLOCK_STATE_EMPTY, the block is clean -- * -- * Always returns YAFFS_OK. -- */ --int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, -- yaffs_BlockState * pState, int *pSequenceNumber) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkNo = blockNo * dev->nChunksPerBlock; -- yaffs_ExtendedTags etags; -- int state = YAFFS_BLOCK_STATE_DEAD; -- int seqnum = 0; -- int retval; -- -- /* We don't yet have a good place to test for MTD config prerequists. -- * Do it here as we are called during the initial scan. -- */ -- if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) { -- return YAFFS_FAIL; -- } -- -- retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); -- if (etags.blockBad) { -- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -- "block %d is marked bad", blockNo); -- state = YAFFS_BLOCK_STATE_DEAD; -- } -- else if (etags.chunkUsed) { -- state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -- seqnum = etags.sequenceNumber; -- } -- else { -- state = YAFFS_BLOCK_STATE_EMPTY; -- } -- -- *pState = state; -- *pSequenceNumber = seqnum; -- -- /* query always succeeds */ -- return YAFFS_OK; --} -- --#endif /*KERNEL_VERSION*/ -- ----Boundary-00=_5LbTGmt62YoutxM-- -- -- -- -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.c 1970-01-01 01:00:00.000000000 +0100 -@@ -1,363 +0,0 @@ --/* -- * YAFFS: Yet another FFS. A NAND-flash specific file system. -- * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. -- * -- * Copyright (C) 2002 Aleph One Ltd. -- * for Toby Churchill Ltd and Brightstar Engineering -- * -- * 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 module provides the interface between yaffs_nand.c and the -- * MTD API. This version is used when the MTD interface supports the -- * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, -- * and we have small-page NAND device. -- * -- * These functions are invoked via function pointers in yaffs_nand.c. -- * This replaces functionality provided by functions in yaffs_mtdif.c -- * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are -- * called in yaffs_mtdif.c when the function pointers are NULL. -- * We assume the MTD layer is performing ECC (useNANDECC is true). -- */ -- --#include "yportenv.h" --#include "yaffs_guts.h" --#include "yaffs_packedtags1.h" --#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC -- --#include "linux/kernel.h" --#include "linux/version.h" --#include "linux/types.h" --#include "linux/mtd/mtd.h" -- --/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ --#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) -- --const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $"; -- --#ifndef CONFIG_YAFFS_9BYTE_TAGS --# define YTAG1_SIZE 8 --#else --# define YTAG1_SIZE 9 --#endif -- --#if 0 --/* Use the following nand_ecclayout with MTD when using -- * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. -- * If you have existing Yaffs images and the byte order differs from this, -- * adjust 'oobfree' to match your existing Yaffs data. -- * -- * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the -- * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to -- * the 9th byte. -- * -- * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 -- * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P -- * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus -- * byte and B is the small-page bad-block indicator byte. -- */ --static struct nand_ecclayout nand_oob_16 = { -- .eccbytes = 6, -- .eccpos = { 8, 9, 10, 13, 14, 15 }, -- .oobavail = 9, -- .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } --}; --#endif -- --/* Write a chunk (page) of data to NAND. -- * -- * Caller always provides ExtendedTags data which are converted to a more -- * compact (packed) form for storage in NAND. A mini-ECC runs over the -- * contents of the tags meta-data; used to valid the tags when read. -- * -- * - Pack ExtendedTags to PackedTags1 form -- * - Compute mini-ECC for PackedTags1 -- * - Write data and packed tags to NAND. -- * -- * Note: Due to the use of the PackedTags1 meta-data which does not include -- * a full sequence number (as found in the larger PackedTags2 form) it is -- * necessary for Yaffs to re-write a chunk/page (just once) to mark it as -- * discarded and dirty. This is not ideal: newer NAND parts are supposed -- * to be written just once. When Yaffs performs this operation, this -- * function is called with a NULL data pointer -- calling MTD write_oob -- * without data is valid usage (2.6.17). -- * -- * Any underlying MTD error results in YAFFS_FAIL. -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, -- int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkBytes = dev->nDataBytesPerChunk; -- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; -- struct mtd_oob_ops ops; -- yaffs_PackedTags1 pt1; -- int retval; -- -- /* we assume that PackedTags1 and yaffs_Tags are compatible */ -- compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); -- compile_time_assertion(sizeof(yaffs_Tags) == 8); -- -- dev->nPageWrites++; -- -- yaffs_PackTags1(&pt1, etags); -- yaffs_CalcTagsECC((yaffs_Tags *)&pt1); -- -- /* When deleting a chunk, the upper layer provides only skeletal -- * etags, one with chunkDeleted set. However, we need to update the -- * tags, not erase them completely. So we use the NAND write property -- * that only zeroed-bits stick and set tag bytes to all-ones and -- * zero just the (not) deleted bit. -- */ --#ifndef CONFIG_YAFFS_9BYTE_TAGS -- if (etags->chunkDeleted) { -- memset(&pt1, 0xff, 8); -- /* clear delete status bit to indicate deleted */ -- pt1.deleted = 0; -- } --#else -- ((__u8 *)&pt1)[8] = 0xff; -- if (etags->chunkDeleted) { -- memset(&pt1, 0xff, 8); -- /* zero pageStatus byte to indicate deleted */ -- ((__u8 *)&pt1)[8] = 0; -- } --#endif -- -- memset(&ops, 0, sizeof(ops)); -- ops.mode = MTD_OOB_AUTO; -- ops.len = (data) ? chunkBytes : 0; -- ops.ooblen = YTAG1_SIZE; -- ops.datbuf = (__u8 *)data; -- ops.oobbuf = (__u8 *)&pt1; -- -- retval = mtd->write_oob(mtd, addr, &ops); -- if (retval) { -- yaffs_trace(YAFFS_TRACE_MTD, -- "write_oob failed, chunk %d, mtd error %d\n", -- chunkInNAND, retval); -- } -- return retval ? YAFFS_FAIL : YAFFS_OK; --} -- --/* Return with empty ExtendedTags but add eccResult. -- */ --static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval) --{ -- if (etags) { -- memset(etags, 0, sizeof(*etags)); -- etags->eccResult = eccResult; -- } -- return retval; --} -- --/* Read a chunk (page) from NAND. -- * -- * Caller expects ExtendedTags data to be usable even on error; that is, -- * all members except eccResult and blockBad are zeroed. -- * -- * - Check ECC results for data (if applicable) -- * - Check for blank/erased block (return empty ExtendedTags if blank) -- * - Check the PackedTags1 mini-ECC (correct if necessary/possible) -- * - Convert PackedTags1 to ExtendedTags -- * - Update eccResult and blockBad members to refect state. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, -- int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkBytes = dev->nDataBytesPerChunk; -- loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; -- int eccres = YAFFS_ECC_RESULT_NO_ERROR; -- struct mtd_oob_ops ops; -- yaffs_PackedTags1 pt1; -- int retval; -- int deleted; -- -- dev->nPageReads++; -- -- memset(&ops, 0, sizeof(ops)); -- ops.mode = MTD_OOB_AUTO; -- ops.len = (data) ? chunkBytes : 0; -- ops.ooblen = YTAG1_SIZE; -- ops.datbuf = data; -- ops.oobbuf = (__u8 *)&pt1; -- --#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) -- /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; -- * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. -- */ -- ops.len = (ops.datbuf) ? ops.len : ops.ooblen; --#endif -- /* Read page and oob using MTD. -- * Check status and determine ECC result. -- */ -- retval = mtd->read_oob(mtd, addr, &ops); -- if (retval) { -- yaffs_trace(YAFFS_TRACE_MTD, -- "read_oob failed, chunk %d, mtd error %d\n", -- chunkInNAND, retval); -- } -- -- switch (retval) { -- case 0: -- /* no error */ -- break; -- -- case -EUCLEAN: -- /* MTD's ECC fixed the data */ -- eccres = YAFFS_ECC_RESULT_FIXED; -- dev->eccFixed++; -- break; -- -- case -EBADMSG: -- /* MTD's ECC could not fix the data */ -- dev->eccUnfixed++; -- /* fall into... */ -- default: -- rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); -- etags->blockBad = (mtd->block_isbad)(mtd, addr); -- return YAFFS_FAIL; -- } -- -- /* Check for a blank/erased chunk. -- */ -- if (yaffs_CheckFF((__u8 *)&pt1, 8)) { -- /* when blank, upper layers want eccResult to be <= NO_ERROR */ -- return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); -- } -- --#ifndef CONFIG_YAFFS_9BYTE_TAGS -- /* Read deleted status (bit) then return it to it's non-deleted -- * state before performing tags mini-ECC check. pt1.deleted is -- * inverted. -- */ -- deleted = !pt1.deleted; -- pt1.deleted = 1; --#else -- deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); --#endif -- -- /* Check the packed tags mini-ECC and correct if necessary/possible. -- */ -- retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); -- switch (retval) { -- case 0: -- /* no tags error, use MTD result */ -- break; -- case 1: -- /* recovered tags-ECC error */ -- dev->tagsEccFixed++; -- if (eccres == YAFFS_ECC_RESULT_NO_ERROR) -- eccres = YAFFS_ECC_RESULT_FIXED; -- break; -- default: -- /* unrecovered tags-ECC error */ -- dev->tagsEccUnfixed++; -- return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); -- } -- -- /* Unpack the tags to extended form and set ECC result. -- * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] -- */ -- pt1.shouldBeFF = 0xFFFFFFFF; -- yaffs_UnpackTags1(etags, &pt1); -- etags->eccResult = eccres; -- -- /* Set deleted state */ -- etags->chunkDeleted = deleted; -- return YAFFS_OK; --} -- --/* Mark a block bad. -- * -- * This is a persistant state. -- * Use of this function should be rare. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; -- int retval; -- -- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo); -- -- retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); -- return (retval) ? YAFFS_FAIL : YAFFS_OK; --} -- --/* Check any MTD prerequists. -- * -- * Returns YAFFS_OK or YAFFS_FAIL. -- */ --static int nandmtd1_TestPrerequists(struct mtd_info * mtd) --{ -- /* 2.6.18 has mtd->ecclayout->oobavail */ -- /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ -- int oobavail = mtd->ecclayout->oobavail; -- -- if (oobavail < YTAG1_SIZE) { -- yaffs_trace(YAFFS_TRACE_ERROR, -- "mtd device has only %d bytes for tags, need %d\n", -- oobavail, YTAG1_SIZE); -- return YAFFS_FAIL; -- } -- return YAFFS_OK; --} -- --/* Query for the current state of a specific block. -- * -- * Examine the tags of the first chunk of the block and return the state: -- * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad -- * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use -- * - YAFFS_BLOCK_STATE_EMPTY, the block is clean -- * -- * Always returns YAFFS_OK. -- */ --int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, -- yaffs_BlockState * pState, int *pSequenceNumber) --{ -- struct mtd_info * mtd = dev->genericDevice; -- int chunkNo = blockNo * dev->nChunksPerBlock; -- yaffs_ExtendedTags etags; -- int state = YAFFS_BLOCK_STATE_DEAD; -- int seqnum = 0; -- int retval; -- -- /* We don't yet have a good place to test for MTD config prerequists. -- * Do it here as we are called during the initial scan. -- */ -- if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) { -- return YAFFS_FAIL; -- } -- -- retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); -- if (etags.blockBad) { -- yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, -- "block %d is marked bad", blockNo); -- state = YAFFS_BLOCK_STATE_DEAD; -- } -- else if (etags.chunkUsed) { -- state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; -- seqnum = etags.sequenceNumber; -- } -- else { -- state = YAFFS_BLOCK_STATE_EMPTY; -- } -- -- *pState = state; -- *pSequenceNumber = seqnum; -- -- /* query always succeeds */ -- return YAFFS_OK; --} -- --#endif /*KERNEL_VERSION*/ -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif1.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif1.h 1970-01-01 01:00:00.000000000 +0100 -@@ -1,28 +0,0 @@ --/* -- * YAFFS: Yet another Flash File System. A NAND-flash specific file system. -- * -- * Copyright (C) 2002-2007 Aleph One Ltd. -- * for Toby Churchill Ltd and Brightstar Engineering -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU Lesser General Public License version 2.1 as -- * published by the Free Software Foundation. -- * -- * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. -- */ -- --#ifndef __YAFFS_MTDIF1_H__ --#define __YAFFS_MTDIF1_H__ -- --int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, -- const __u8 * data, const yaffs_ExtendedTags * tags); -- --int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, -- __u8 * data, yaffs_ExtendedTags * tags); -- --int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); -- --int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, -- yaffs_BlockState * state, int *sequenceNumber); -- --#endif -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.c linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.c 2009-04-21 15:01:02.000000000 +0200 -@@ -14,19 +14,152 @@ - /* mtd interface for YAFFS2 */ - - const char *yaffs_mtdif2_c_version = -- "$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $"; -+ "$Id: yaffs_mtdif2.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; - - #include "yportenv.h" -- -- - #include "yaffs_mtdif2.h" -- - #include "linux/mtd/mtd.h" - #include "linux/types.h" - #include "linux/time.h" - - #include "yaffs_packedtags2.h" - -+#define PT2_BYTES 25 -+ -+void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) -+{ -+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -+ int i, j = 0, k, n; -+ __u8 pt2_byte_buf[PT2_BYTES]; -+ -+ /* Pack buffer with 0xff */ -+ for (i = 0; i < mtd->oobsize; i++) -+ dev->spareBuffer[i] = 0xff; -+ -+ if (!is_raw) { -+ *((unsigned int *) &dev->spareBuffer[0]) = pt->t.sequenceNumber; -+ *((unsigned int *) &dev->spareBuffer[4]) = pt->t.objectId; -+ *((unsigned int *) &dev->spareBuffer[8]) = pt->t.chunkId; -+ *((unsigned int *) &dev->spareBuffer[12]) = pt->t.byteCount; -+ dev->spareBuffer[16] = pt->ecc.colParity; -+ dev->spareBuffer[17] = pt->ecc.lineParity & 0xff; -+ dev->spareBuffer[18] = (pt->ecc.lineParity >> 8) & 0xff; -+ dev->spareBuffer[19] = (pt->ecc.lineParity >> 16) & 0xff; -+ dev->spareBuffer[20] = (pt->ecc.lineParity >> 24) & 0xff; -+ dev->spareBuffer[21] = pt->ecc.lineParityPrime & 0xff; -+ dev->spareBuffer[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; -+ dev->spareBuffer[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; -+ dev->spareBuffer[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; -+ } else { -+ *((unsigned int *) &pt2_byte_buf[0]) = pt->t.sequenceNumber; -+ *((unsigned int *) &pt2_byte_buf[4]) = pt->t.objectId; -+ *((unsigned int *) &pt2_byte_buf[8]) = pt->t.chunkId; -+ *((unsigned int *) &pt2_byte_buf[12]) = pt->t.byteCount; -+ pt2_byte_buf[16] = pt->ecc.colParity; -+ pt2_byte_buf[17] = pt->ecc.lineParity & 0xff; -+ pt2_byte_buf[18] = (pt->ecc.lineParity >> 8) & 0xff; -+ pt2_byte_buf[19] = (pt->ecc.lineParity >> 16) & 0xff; -+ pt2_byte_buf[20] = (pt->ecc.lineParity >> 24) & 0xff; -+ pt2_byte_buf[21] = pt->ecc.lineParityPrime & 0xff; -+ pt2_byte_buf[22] = (pt->ecc.lineParityPrime >> 8) & 0xff; -+ pt2_byte_buf[23] = (pt->ecc.lineParityPrime >> 16) & 0xff; -+ pt2_byte_buf[24] = (pt->ecc.lineParityPrime >> 24) & 0xff; -+ -+// k = mtd->oobinfo.oobfree[j][0]; -+// n = mtd->oobinfo.oobfree[j][1]; -+ -+ k = mtd->ecclayout->oobfree[j].offset; -+ n = mtd->ecclayout->oobfree[j].length; -+ if (n == 0) { -+ T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); -+ YBUG(); -+ } -+ -+ for (i = 0; i < PT2_BYTES; i++) { -+ if (n == 0) { -+ j++; -+// k = mtd->oobinfo.oobfree[j][0]; -+// n = mtd->oobinfo.oobfree[j][1]; -+ k = mtd->ecclayout->oobfree[j].offset; -+ n = mtd->ecclayout->oobfree[j].length; -+ -+ if (n == 0) { -+ T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); -+ YBUG(); -+ } -+ } -+ dev->spareBuffer[k++] = pt2_byte_buf[i]; -+ n--; -+ } -+ } -+ -+} -+ -+void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) -+{ -+ struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); -+ int i, j = 0, k, n; -+ __u8 pt2_byte_buf[PT2_BYTES]; -+ -+ -+ if (!is_raw) { -+ pt->t.sequenceNumber = *((unsigned int *) &dev->spareBuffer[0]); -+ pt->t.objectId = *((unsigned int *) &dev->spareBuffer[4]); -+ pt->t.chunkId = *((unsigned int *) &dev->spareBuffer[8]); -+ pt->t.byteCount = *((unsigned int *) &dev->spareBuffer[12]); -+ pt->ecc.colParity = dev->spareBuffer[16]; -+ pt->ecc.lineParity = (dev->spareBuffer[17] & 0x000000ff) | -+ ((dev->spareBuffer[18] << 8) & 0x0000ff00) | -+ ((dev->spareBuffer[19] << 16) & 0x00ff0000) | -+ ((dev->spareBuffer[20] << 24) & 0xff000000); -+ pt->ecc.lineParityPrime = (dev->spareBuffer[21] & 0x000000ff) | -+ ((dev->spareBuffer[22] << 8) & 0x0000ff00) | -+ ((dev->spareBuffer[23] << 16) & 0x00ff0000) | -+ ((dev->spareBuffer[24] << 24) & 0xff000000); -+ } else { -+// k = mtd->oobinfo.oobfree[j][0]; -+// n = mtd->oobinfo.oobfree[j][1]; -+ -+ k = mtd->ecclayout->oobfree[j].offset; -+ n = mtd->ecclayout->oobfree[j].length; -+ -+ if (n == 0) { -+ T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); -+ YBUG(); -+ } -+ -+ for (i = 0; i < PT2_BYTES; i++) { -+ if (n == 0) { -+ j++; -+// k = mtd->oobinfo.oobfree[j][0]; -+// n = mtd->oobinfo.oobfree[j][1]; -+ k = mtd->ecclayout->oobfree[j].offset; -+ n = mtd->ecclayout->oobfree[j].length; -+ -+ if (n == 0) { -+ T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); -+ YBUG(); -+ } -+ } -+ pt2_byte_buf[i] = dev->spareBuffer[k++]; -+ n--; -+ } -+ pt->t.sequenceNumber = *((unsigned int *) &pt2_byte_buf[0]); -+ pt->t.objectId = *((unsigned int *) &pt2_byte_buf[4]); -+ pt->t.chunkId = *((unsigned int *) &pt2_byte_buf[8]); -+ pt->t.byteCount = *((unsigned int *) &pt2_byte_buf[12]); -+ pt->ecc.colParity = pt2_byte_buf[16]; -+ pt->ecc.lineParity = (pt2_byte_buf[17] & 0x000000ff) | -+ ((pt2_byte_buf[18] << 8) & 0x0000ff00) | -+ ((pt2_byte_buf[19] << 16) & 0x00ff0000) | -+ ((pt2_byte_buf[20] << 24) & 0xff000000); -+ pt->ecc.lineParityPrime = (pt2_byte_buf[21] & 0x000000ff) | -+ ((pt2_byte_buf[22] << 8) & 0x0000ff00) | -+ ((pt2_byte_buf[23] << 16) & 0x00ff0000) | -+ ((pt2_byte_buf[24] << 24) & 0xff000000); -+ } -+} -+ - int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, - const __u8 * data, - const yaffs_ExtendedTags * tags) -@@ -38,9 +171,7 @@ - size_t dummy; - #endif - int retval = 0; -- -- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -- -+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; - yaffs_PackedTags2 pt; - - T(YAFFS_TRACE_MTD, -@@ -55,12 +186,14 @@ - BUG(); /* both tags and data should always be present */ - - if (data) { -+ nandmtd2_pt2buf(dev, &pt, 0); //modify - ops.mode = MTD_OOB_AUTO; - ops.ooblen = sizeof(pt); - ops.len = dev->nDataBytesPerChunk; - ops.ooboffs = 0; - ops.datbuf = (__u8 *)data; -- ops.oobbuf = (void *)&pt; -+// ops.oobbuf = (void *)&pt; //modify -+ ops.oobbuf = (void *)dev->spareBuffer; //modify - retval = mtd->write_oob(mtd, addr, &ops); - } else - BUG(); /* both tags and data should always be present */ -@@ -70,24 +203,27 @@ - } - - if (data && tags) { -+ nandmtd2_pt2buf(dev, &pt, 0); - if (dev->useNANDECC) - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, -- &dummy, data, (__u8 *) & pt, NULL); -+ &dummy, data, dev->spareBuffer, NULL); - else - retval = - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, -- &dummy, data, (__u8 *) & pt, NULL); -+ &dummy, data, dev->spareBuffer, NULL); - } else { -- if (data) -+ if (data) { - retval = - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); -- if (tags) -+ } -+ if (tags) { -+ nandmtd2_pt2buf(dev, &pt, 1); - retval = - mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, -- (__u8 *) & pt); -- -+ dev->spareBuffer); -+ } - } - #endif - -@@ -104,11 +240,9 @@ - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) - struct mtd_oob_ops ops; - #endif -- size_t dummy; -+ size_mtd_t dummy; - int retval = 0; -- -- loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; -- -+ loff_mtd_t addr = ((loff_mtd_t) chunkInNAND) * dev->nDataBytesPerChunk; - yaffs_PackedTags2 pt; - - T(YAFFS_TRACE_MTD, -@@ -128,6 +262,7 @@ - ops.datbuf = data; - ops.oobbuf = dev->spareBuffer; - retval = mtd->read_oob(mtd, addr, &ops); -+ nandmtd2_buf2pt(dev, &pt, 0); //modify by yliu - } - #else - if (data && tags) { -@@ -142,23 +277,25 @@ - &dummy, data, dev->spareBuffer, - NULL); - } -+ nandmtd2_buf2pt(dev, &pt, 0); - } else { -- if (data) -+ if (data) { - retval = - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, - data); -- if (tags) -+ } -+ if (tags) { - retval = - mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, - dev->spareBuffer); -+ nandmtd2_buf2pt(dev, &pt, 1); -+ } - } - #endif - -- memcpy(&pt, dev->spareBuffer, sizeof(pt)); -- - if (tags) - yaffs_UnpackTags2(tags, &pt); -- -+ - if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; - -@@ -177,7 +314,7 @@ - - retval = - mtd->block_markbad(mtd, -- blockNo * dev->nChunksPerBlock * -+ (u64)blockNo * dev->nChunksPerBlock * - dev->nDataBytesPerChunk); - - if (retval == 0) -@@ -195,11 +332,11 @@ - - T(YAFFS_TRACE_MTD, - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); -+ - retval = - mtd->block_isbad(mtd, -- blockNo * dev->nChunksPerBlock * -+ (u64)blockNo * dev->nChunksPerBlock * - dev->nDataBytesPerChunk); -- - if (retval) { - T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); - -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.h linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_mtdif2.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_mtdif2.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nand.c linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_nand.c 2009-04-21 14:57:10.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.c 2009-04-21 15:01:02.000000000 +0200 -@@ -10,9 +10,9 @@ - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -- -+ - const char *yaffs_nand_c_version = -- "$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $"; -+ "$Id: yaffs_nand.c,v 1.1.1.1 2008-03-28 04:29:21 jlwei Exp $"; - - #include "yaffs_nand.h" - #include "yaffs_tagscompat.h" -@@ -25,9 +25,9 @@ - { - int result; - yaffs_ExtendedTags localTags; -- -+ - int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; -- -+ - /* If there are no tags provided, use local tags to get prioritised gc working */ - if(!tags) - tags = &localTags; -@@ -39,14 +39,14 @@ - result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, - realignedChunkInNAND, - buffer, -- tags); -- if(tags && -- tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ -+ tags); - -+ if(tags && -+ tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); - yaffs_HandleChunkError(dev,bi); - } -- -+ - return result; - } - -@@ -57,7 +57,7 @@ - { - chunkInNAND -= dev->chunkOffset; - -- -+ - if (tags) { - tags->sequenceNumber = dev->sequenceNumber; - tags->chunkUsed = 1; -@@ -131,4 +131,4 @@ - } - - -- -+ -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nand.h linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_nand.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nand.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.24.7.new/fs/yaffs2/yaffs_nandemul2k.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_nandemul2k.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_nandemul2k.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags1.h linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags1.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags1.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags1.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.c linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.c 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.c 2009-04-21 15:01:02.000000000 +0200 -@@ -40,7 +40,8 @@ - static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) - { - T(YAFFS_TRACE_MTD, -- (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), -+// T(YAFFS_TRACE_ALWAYS, -+ (TSTR("packed tags obj %x chunk %x byte %x seq %x" TENDSTR), - pt->t.objectId, pt->t.chunkId, pt->t.byteCount, - pt->t.sequenceNumber)); - } -@@ -48,9 +49,10 @@ - static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) - { - T(YAFFS_TRACE_MTD, -+// T(YAFFS_TRACE_ALWAYS, - (TSTR -- ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " -- "%d del %d ser %d seq %d" -+ ("ext.tags eccres %x blkbad %x chused %x obj %x chunk%x byte " -+ "%x del %x ser %x seq %x" - TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, - t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, - t->sequenceNumber)); -@@ -89,10 +91,10 @@ - } - } - -- yaffs_DumpPackedTags2(pt); -- yaffs_DumpTags2(t); -+// yaffs_DumpPackedTags2(pt); -+// yaffs_DumpTags2(t); - --#ifndef YAFFS_IGNORE_TAGS_ECC -+#if !defined(YAFFS_IGNORE_TAGS_ECC) && !defined(CONFIG_MTD_HW_BCH_ECC) - { - yaffs_ECCCalculateOther((unsigned char *)&pt->t, - sizeof(yaffs_PackedTags2TagsPart), -@@ -103,14 +105,11 @@ - - void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) - { -- -- memset(t, 0, sizeof(yaffs_ExtendedTags)); -- - yaffs_InitialiseTags(t); - - if (pt->t.sequenceNumber != 0xFFFFFFFF) { - /* Page is in use */ --#ifdef YAFFS_IGNORE_TAGS_ECC -+#if defined(YAFFS_IGNORE_TAGS_ECC) || defined(CONFIG_MTD_HW_BCH_ECC) - { - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; - } -@@ -118,20 +117,23 @@ - { - yaffs_ECCOther ecc; - int result; -+#if defined(CONFIG_YAFFS_ECC_HAMMING) - yaffs_ECCCalculateOther((unsigned char *)&pt->t, - sizeof - (yaffs_PackedTags2TagsPart), - &ecc); -+#endif - result = - yaffs_ECCCorrectOther((unsigned char *)&pt->t, - sizeof - (yaffs_PackedTags2TagsPart), - &pt->ecc, &ecc); -+ - switch(result){ -- case 0: -- t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; -+ case 0: -+ t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; - break; -- case 1: -+ case 1: - t->eccResult = YAFFS_ECC_RESULT_FIXED; - break; - case -1: -@@ -175,8 +177,8 @@ - } - } - } -- -+// printk("\n TAG %d",t->chunkUsed); - yaffs_DumpPackedTags2(pt); - yaffs_DumpTags2(t); -- -+// printk("\n TAG %d",t->chunkUsed); - } -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.h linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_packedtags2.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_packedtags2.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_qsort.c linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_qsort.c 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.c 2009-04-21 15:01:02.000000000 +0200 -@@ -50,7 +50,7 @@ - static __inline void - swapfunc(char *a, char *b, int n, int swaptype) - { -- if (swaptype <= 1) -+ if (swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -@@ -74,13 +74,8 @@ - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); - } - --#ifndef min --#define min(a,b) (((a) < (b)) ? (a) : (b)) --#endif -- - void --yaffs_qsort(void *aa, size_t n, size_t es, -- int (*cmp)(const void *, const void *)) -+qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *)) - { - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; -@@ -137,7 +132,7 @@ - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) -- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; -+ for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; -@@ -149,12 +144,12 @@ - r = min((long)(pd - pc), (long)(pn - pd - es)); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) -- yaffs_qsort(a, r / es, es, cmp); -- if ((r = pd - pc) > es) { -+ qsort(a, r / es, es, cmp); -+ if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } --/* yaffs_qsort(pn - r, r / es, es, cmp);*/ -+/* qsort(pn - r, r / es, es, cmp);*/ - } -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_qsort.h linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_qsort.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_qsort.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -17,7 +17,7 @@ - #ifndef __YAFFS_QSORT_H__ - #define __YAFFS_QSORT_H__ - --extern void yaffs_qsort (void *const base, size_t total_elems, size_t size, -+extern void qsort (void *const base, size_t total_elems, size_t size, - int (*cmp)(const void *, const void *)); - - #endif -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.c linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.c ---- linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.c 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.c 2009-04-21 15:01:02.000000000 +0200 -@@ -45,7 +45,7 @@ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 - }; - --int yaffs_CountBits(__u8 x) -+static int yaffs_CountBits(__u8 x) - { - int retVal; - retVal = yaffs_countBitsTable[x]; -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.h linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_tagscompat.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagscompat.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -33,8 +33,4 @@ - int blockNo, yaffs_BlockState * - state, int *sequenceNumber); - --void yaffs_CalcTagsECC(yaffs_Tags * tags); --int yaffs_CheckECCOnTags(yaffs_Tags * tags); --int yaffs_CountBits(__u8 byte); -- - #endif -diff -urN linux-2.6.24.7/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.24.7.new/fs/yaffs2/yaffs_tagsvalidity.h ---- linux-2.6.24.7/fs/yaffs2/yaffs_tagsvalidity.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffs_tagsvalidity.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yaffsinterface.h linux-2.6.24.7.new/fs/yaffs2/yaffsinterface.h ---- linux-2.6.24.7/fs/yaffs2/yaffsinterface.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yaffsinterface.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -diff -urN linux-2.6.24.7/fs/yaffs2/yportenv.h linux-2.6.24.7.new/fs/yaffs2/yportenv.h ---- linux-2.6.24.7/fs/yaffs2/yportenv.h 2009-04-09 17:39:09.000000000 +0200 -+++ linux-2.6.24.7.new/fs/yaffs2/yportenv.h 2009-04-21 15:01:02.000000000 +0200 -@@ -1,5 +1,5 @@ - /* -- * YAFFS: Yet another Flash File System . A NAND-flash specific file system. -+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system. - * - * Copyright (C) 2002-2007 Aleph One Ltd. - * for Toby Churchill Ltd and Brightstar Engineering -@@ -32,7 +32,6 @@ - #endif - #include - #include --#include - #include - #include - #include -@@ -42,7 +41,6 @@ - #define _Y(x) x - #define yaffs_strcpy(a,b) strcpy(a,b) - #define yaffs_strncpy(a,b,c) strncpy(a,b,c) --#define yaffs_strncmp(a,b,c) strncmp(a,b,c) - #define yaffs_strlen(s) strlen(s) - #define yaffs_sprintf sprintf - #define yaffs_toupper(a) toupper(a) -@@ -62,7 +60,7 @@ - // KR - added for use in scan so processes aren't blocked indefinitely. - #define YYIELD() schedule() - --#define YAFFS_ROOT_MODE 0666 -+#define YAFFS_ROOT_MODE 0666 - #define YAFFS_LOSTNFOUND_MODE 0666 - - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) -@@ -80,14 +78,6 @@ - #define TSTR(x) KERN_WARNING x - #define TOUT(p) printk p - --#define yaffs_trace(mask, fmt, args...) \ -- do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ -- printk(KERN_WARNING "yaffs: " fmt, ## args); \ -- } while (0) -- --#define compile_time_assertion(assertion) \ -- ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) -- - #elif defined CONFIG_YAFFS_DIRECT - - /* Direct interface */ -@@ -142,15 +132,9 @@ - - #endif - --/* see yaffs_fs.c */ --extern unsigned int yaffs_traceMask; --extern unsigned int yaffs_wr_attempts; -- --/* -- * Tracing flags. -- * The flags masked in YAFFS_TRACE_ALWAYS are always traced. -- */ -+extern unsigned yaffs_traceMask; - -+#define YAFFS_TRACE_ERROR 0x00000001 - #define YAFFS_TRACE_OS 0x00000002 - #define YAFFS_TRACE_ALLOCATE 0x00000004 - #define YAFFS_TRACE_SCAN 0x00000008 -@@ -166,19 +150,10 @@ - #define YAFFS_TRACE_SCAN_DEBUG 0x00002000 - #define YAFFS_TRACE_MTD 0x00004000 - #define YAFFS_TRACE_CHECKPOINT 0x00008000 -- --#define YAFFS_TRACE_VERIFY 0x00010000 --#define YAFFS_TRACE_VERIFY_NAND 0x00020000 --#define YAFFS_TRACE_VERIFY_FULL 0x00040000 --#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 -- -- --#define YAFFS_TRACE_ERROR 0x40000000 -+#define YAFFS_TRACE_ALWAYS 0x40000000 - #define YAFFS_TRACE_BUG 0x80000000 --#define YAFFS_TRACE_ALWAYS 0xF0000000 -- - --#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0) -+#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ERROR)) TOUT(p);} while(0) - - #ifndef CONFIG_YAFFS_WINCE - #define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))