[generic-2.6] Remove files now present upstream in files-2.6.25
authornoz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 16 May 2008 19:25:20 +0000 (19:25 +0000)
committernoz <noz@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 16 May 2008 19:25:20 +0000 (19:25 +0000)
    (This is mostly just drivers/ssb and include/linux/ssb)
[brcm47xx] Regenerate patches against 2.6.25.1 kernel+files set
    Default is still to build against 2.6.23.16

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11155 3c298f89-4303-0410-b956-a3cf2f4a3e73

100 files changed:
target/linux/brcm47xx/config-2.6.25 [new file with mode: 0644]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/cfe_env.c [new file with mode: 0644]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/include/nvram.h [new file with mode: 0644]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/nvram.c [new file with mode: 0644]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c [deleted file]
target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h [deleted file]
target/linux/brcm47xx/files-2.6.25/drivers/mtd/maps/bcm47xx-flash.c
target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h [deleted file]
target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm47xx/kernel-entry-init.h [new file with mode: 0644]
target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h [deleted file]
target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h [deleted file]
target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/100-board_support.patch
target/linux/brcm47xx/patches-2.6.25/110-flash_map.patch
target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/130-remove_scache.patch
target/linux/brcm47xx/patches-2.6.25/150-cpu_fixes.patch
target/linux/brcm47xx/patches-2.6.25/160-kmap_coherent.patch
target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/220-bcm5354.patch
target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/250-ohci-ssb-usb2.patch
target/linux/brcm47xx/patches-2.6.25/260-ohci-set-dma-mask.patch
target/linux/brcm47xx/patches-2.6.25/300-fork_cacheflush.patch
target/linux/brcm47xx/patches-2.6.25/310-no_highpage.patch
target/linux/brcm47xx/patches-2.6.25/400-arch-bcm47xx.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/500-lzma_initramfs.patch
target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/601-mips-remove-pci-collision-check.patch
target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/620-ssb-modinit-fix.patch
target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch [deleted file]
target/linux/brcm47xx/patches-2.6.25/680-ssb-support-8bit-writes.patch
target/linux/brcm47xx/patches-2.6.25/690-mips-allow-pciregister-after-boot.patch
target/linux/brcm47xx/patches-2.6.25/700-ssb-gigabit-ethernet-driver.patch
target/linux/brcm47xx/patches-2.6.25/800-cfe-workaround.patch [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/gpio/gpio_dev.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/input/misc/gpio_buttons.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/leds/leds-alix.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-default-on.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-morse.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-netdev.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/drivers/spi/spi_gpio.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Kconfig [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Makefile [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/devextras.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/moduleconfig.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_fs.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1-compat.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nandemul2k.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.c [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffsinterface.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yportenv.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/include/linux/gpio_buttons.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/include/linux/gpio_dev.h [new file with mode: 0644]
target/linux/generic-2.6/files-2.6.25/include/linux/spi/spi_gpio.h [new file with mode: 0644]
target/linux/generic-2.6/patches-2.6.25/150-netfilter_imq.patch
target/linux/generic-2.6/patches-2.6.25/190-netfilter_rtsp.patch
target/linux/generic-2.6/patches-2.6.25/420-gpiodev.patch [new file with mode: 0644]

diff --git a/target/linux/brcm47xx/config-2.6.25 b/target/linux/brcm47xx/config-2.6.25
new file mode 100644 (file)
index 0000000..3ca3f71
--- /dev/null
@@ -0,0 +1,252 @@
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+# CONFIG_8139TOO is not set
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_ARPD is not set
+# CONFIG_ATMEL is not set
+CONFIG_B44=y
+CONFIG_BASE_SMALL=0
+# CONFIG_BCM43XX is not set
+CONFIG_BCM47XX=y
+CONFIG_BITREVERSE=y
+# CONFIG_BONDING is not set
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_CFE=y
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CLS_U32_MARK is not set
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd console=ttyS0,115200"
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_CONNECTOR=m
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_LOONGSON2 is not set
+CONFIG_CPU_MIPS32=y
+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_MIPSR1=y
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_DEVPORT=y
+# CONFIG_DM9000 is not set
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_E100 is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HID=m
+# CONFIG_HID_SUPPORT is not set
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_I2C is not set
+# CONFIG_IDE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IPW2200_QOS=y
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IRQ_CPU=y
+# CONFIG_LEDS_ALIX is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEMOTE_FULONG is not set
+# CONFIG_LLC2 is not set
+# CONFIG_MACH_ALCHEMY is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+CONFIG_MIPS=y
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_COBALT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MALTA is not set
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_BCM47XX=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_ONENAND is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PROC_KCORE is not set
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_RFKILL_LEDS=y
+# CONFIG_RTC is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_WAIT_SCAN=m
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_RSA is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SSB=y
+CONFIG_SSB_DEBUG=y
+CONFIG_SSB_DRIVER_EXTIF=y
+# CONFIG_SSB_DRIVER_GIGE is not set
+CONFIG_SSB_DRIVER_MIPS=y
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y
+CONFIG_SSB_EMBEDDED=y
+CONFIG_SSB_PCICORE_HOSTMODE=y
+CONFIG_SSB_PCIHOST=y
+CONFIG_SSB_PCIHOST_POSSIBLE=y
+CONFIG_SSB_POSSIBLE=y
+CONFIG_SSB_SERIAL=y
+# CONFIG_SSB_SILENT is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+# CONFIG_TC35815 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_USB_CATC is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_SSB=y
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USER_NS is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/cfe_env.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/cfe_env.c
new file mode 100644 (file)
index 0000000..c1d5eee
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * CFE environment variable access
+ *
+ * Copyright 2001-2003, Broadcom Corporation
+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
+ * 
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define NVRAM_SIZE       (0x1ff0)
+static char _nvdata[NVRAM_SIZE];
+static char _valuestr[256];
+
+/*
+ * TLV types.  These codes are used in the "type-length-value"
+ * encoding of the items stored in the NVRAM device (flash or EEPROM)
+ *
+ * The layout of the flash/nvram is as follows:
+ *
+ * <type> <length> <data ...> <type> <length> <data ...> <type_end>
+ *
+ * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
+ * The "length" field marks the length of the data section, not
+ * including the type and length fields.
+ *
+ * Environment variables are stored as follows:
+ *
+ * <type_env> <length> <flags> <name> = <value>
+ *
+ * If bit 0 (low bit) is set, the length is an 8-bit value.
+ * If bit 0 (low bit) is clear, the length is a 16-bit value
+ * 
+ * Bit 7 set indicates "user" TLVs.  In this case, bit 0 still
+ * indicates the size of the length field.  
+ *
+ * Flags are from the constants below:
+ *
+ */
+#define ENV_LENGTH_16BITS      0x00    /* for low bit */
+#define ENV_LENGTH_8BITS       0x01
+
+#define ENV_TYPE_USER          0x80
+
+#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
+#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
+
+/*
+ * The actual TLV types we support
+ */
+
+#define ENV_TLV_TYPE_END       0x00    
+#define ENV_TLV_TYPE_ENV       ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
+
+/*
+ * Environment variable flags 
+ */
+
+#define ENV_FLG_NORMAL         0x00    /* normal read/write */
+#define ENV_FLG_BUILTIN                0x01    /* builtin - not stored in flash */
+#define ENV_FLG_READONLY       0x02    /* read-only - cannot be changed */
+
+#define ENV_FLG_MASK           0xFF    /* mask of attributes we keep */
+#define ENV_FLG_ADMIN          0x100   /* lets us internally override permissions */
+
+
+/*  *********************************************************************
+    *  _nvram_read(buffer,offset,length)
+    *  
+    *  Read data from the NVRAM device
+    *  
+    *  Input parameters: 
+    *             buffer - destination buffer
+    *             offset - offset of data to read
+    *             length - number of bytes to read
+    *             
+    *  Return value:
+    *             number of bytes read, or <0 if error occured
+    ********************************************************************* */
+static int
+_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
+{
+    int i;
+    if (offset > NVRAM_SIZE)
+       return -1; 
+
+    for ( i = 0; i < length; i++) {
+       buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
+    }
+    return length;
+}
+
+
+static char*
+_strnchr(const char *dest,int c,size_t cnt)
+{
+       while (*dest && (cnt > 0)) {
+       if (*dest == c) return (char *) dest;
+       dest++;
+       cnt--;
+       }
+       return NULL;
+}
+
+
+
+/*
+ * Core support API: Externally visible.
+ */
+
+/*
+ * Get the value of an NVRAM variable
+ * @param      name    name of variable to get
+ * @return     value of variable or NULL if undefined
+ */
+
+char* 
+cfe_env_get(unsigned char *nv_buf, char* name)
+{
+    int size;
+    unsigned char *buffer;
+    unsigned char *ptr;
+    unsigned char *envval;
+    unsigned int reclen;
+    unsigned int rectype;
+    int offset;
+    int flg;
+    
+       if (!strcmp(name, "nvram_type"))
+               return "cfe";
+       
+    size = NVRAM_SIZE;
+    buffer = &_nvdata[0];
+
+    ptr = buffer;
+    offset = 0;
+
+    /* Read the record type and length */
+    if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
+       goto error;
+    }
+    
+    while ((*ptr != ENV_TLV_TYPE_END)  && (size > 1)) {
+
+       /* Adjust pointer for TLV type */
+       rectype = *(ptr);
+       offset++;
+       size--;
+
+       /* 
+        * Read the length.  It can be either 1 or 2 bytes
+        * depending on the code 
+        */
+       if (rectype & ENV_LENGTH_8BITS) {
+           /* Read the record type and length - 8 bits */
+           if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
+               goto error;
+           }
+           reclen = *(ptr);
+           size--;
+           offset++;
+       }
+       else {
+           /* Read the record type and length - 16 bits, MSB first */
+           if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
+               goto error;
+           }
+           reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
+           size -= 2;
+           offset += 2;
+       }
+
+       if (reclen > size)
+           break;      /* should not happen, bad NVRAM */
+
+       switch (rectype) {
+           case ENV_TLV_TYPE_ENV:
+               /* Read the TLV data */
+               if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
+                   goto error;
+               flg = *ptr++;
+               envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
+               if (envval) {
+                   *envval++ = '\0';
+                   memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
+                   _valuestr[(reclen-1)-(envval-ptr)] = '\0';
+#if 0                  
+                   printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
+#endif
+                   if(!strcmp(ptr, name)){
+                       return _valuestr;
+                   }
+                   if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
+                       return _valuestr;
+               }
+               break;
+               
+           default: 
+               /* Unknown TLV type, skip it. */
+               break;
+           }
+
+       /*
+        * Advance to next TLV 
+        */
+               
+       size -= (int)reclen;
+       offset += reclen;
+
+       /* Read the next record type */
+       ptr = buffer;
+       if (_nvram_read(nv_buf, ptr,offset,1) != 1)
+           goto error;
+       }
+
+error:
+    return NULL;
+
+}
+
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/include/nvram.h b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/include/nvram.h
new file mode 100644 (file)
index 0000000..6bb18e8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  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 __NVRAM_H
+#define __NVRAM_H
+
+struct nvram_header {
+       u32 magic;
+       u32 len;
+       u32 crc_ver_init;       /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+       u32 config_refresh;     /* 0:15 sdram_config, 16:31 sdram_refresh */
+       u32 config_ncdl;        /* ncdl values for memc */
+};
+
+struct nvram_tuple {
+       char *name;
+       char *value;
+       struct nvram_tuple *next;
+};
+
+#define NVRAM_HEADER           0x48534C46      /* 'FLSH' */
+#define NVRAM_VERSION          1
+#define NVRAM_HEADER_SIZE      20
+#define NVRAM_SPACE            0x8000
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+char *nvram_get(const char *name);
+
+#endif
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/nvram.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm47xx/nvram.c
new file mode 100644 (file)
index 0000000..3f32ad9
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
+ * 
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/ssb/ssb.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <nvram.h>
+
+#define MB * 1048576
+extern struct ssb_bus ssb;
+
+static char nvram_buf[NVRAM_SPACE];
+static int cfe_env;
+extern char *cfe_env_get(char *nv_buf, const char *name);
+               
+/* Probe for NVRAM header */
+static void __init early_nvram_init(void)
+{
+       struct ssb_mipscore *mcore = &ssb.mipscore;
+       struct nvram_header *header;
+       int i;
+       u32 base, lim, off;
+       u32 *src, *dst;
+       
+       base = mcore->flash_window;
+       lim = mcore->flash_window_size;
+       cfe_env = 0;
+
+       
+       /* XXX: hack for supporting the CFE environment stuff on WGT634U */
+       if (lim >= 8 MB) {
+               src = (u32 *) KSEG1ADDR(base + 8 MB - 0x2000);
+               dst = (u32 *) nvram_buf;
+
+               if ((*src & 0xff00ff) == 0x000001) {
+                       printk("early_nvram_init: WGT634U NVRAM found.\n");
+
+                       for (i = 0; i < 0x1ff0; i++) {
+                               if (*src == 0xFFFFFFFF)
+                                       break;
+                               *dst++ = *src++;
+                       }
+                       cfe_env = 1;
+                       return;
+               }
+       }
+
+       off = 0x20000;
+       while (off <= lim) {
+               /* Windowed flash access */
+               header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
+               if (header->magic == NVRAM_HEADER)
+                       goto found;
+               off <<= 1;
+       }
+
+       /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+       header = (struct nvram_header *) KSEG1ADDR(base + 4096);
+       if (header->magic == NVRAM_HEADER)
+               goto found;
+       
+       header = (struct nvram_header *) KSEG1ADDR(base + 1024);
+       if (header->magic == NVRAM_HEADER)
+               goto found;
+       
+       return;
+
+found:
+       src = (u32 *) header;
+       dst = (u32 *) nvram_buf;
+       for (i = 0; i < sizeof(struct nvram_header); i += 4)
+               *dst++ = *src++;
+       for (; i < header->len && i < NVRAM_SPACE; i += 4)
+               *dst++ = le32_to_cpu(*src++);
+}
+
+char *nvram_get(const char *name)
+{
+       char *var, *value, *end, *eq;
+
+       if (!name)
+               return NULL;
+
+       if (!nvram_buf[0])
+               early_nvram_init();
+
+       if (cfe_env)
+               return cfe_env_get(nvram_buf, name);
+
+       /* Look for name=value and return value */
+       var = &nvram_buf[sizeof(struct nvram_header)];
+       end = nvram_buf + sizeof(nvram_buf) - 2;
+       end[0] = end[1] = '\0';
+       for (; *var; var = value + strlen(value) + 1) {
+               if (!(eq = strchr(var, '=')))
+                       break;
+               value = eq + 1;
+               if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
+                       return value;
+       }
+
+       return NULL;
+}
+
+EXPORT_SYMBOL(nvram_get);
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/Makefile
deleted file mode 100644 (file)
index f80945c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the BCM47xx specific kernel interface routines
-# under Linux.
-#
-
-obj-y := irq.o prom.o setup.o time.o
-obj-y += nvram.o cfe_env.o
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/cfe_env.c
deleted file mode 100644 (file)
index c1d5eee..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * CFE environment variable access
- *
- * Copyright 2001-2003, Broadcom Corporation
- * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
- * 
- * 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 <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define NVRAM_SIZE       (0x1ff0)
-static char _nvdata[NVRAM_SIZE];
-static char _valuestr[256];
-
-/*
- * TLV types.  These codes are used in the "type-length-value"
- * encoding of the items stored in the NVRAM device (flash or EEPROM)
- *
- * The layout of the flash/nvram is as follows:
- *
- * <type> <length> <data ...> <type> <length> <data ...> <type_end>
- *
- * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
- * The "length" field marks the length of the data section, not
- * including the type and length fields.
- *
- * Environment variables are stored as follows:
- *
- * <type_env> <length> <flags> <name> = <value>
- *
- * If bit 0 (low bit) is set, the length is an 8-bit value.
- * If bit 0 (low bit) is clear, the length is a 16-bit value
- * 
- * Bit 7 set indicates "user" TLVs.  In this case, bit 0 still
- * indicates the size of the length field.  
- *
- * Flags are from the constants below:
- *
- */
-#define ENV_LENGTH_16BITS      0x00    /* for low bit */
-#define ENV_LENGTH_8BITS       0x01
-
-#define ENV_TYPE_USER          0x80
-
-#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
-#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
-
-/*
- * The actual TLV types we support
- */
-
-#define ENV_TLV_TYPE_END       0x00    
-#define ENV_TLV_TYPE_ENV       ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
-
-/*
- * Environment variable flags 
- */
-
-#define ENV_FLG_NORMAL         0x00    /* normal read/write */
-#define ENV_FLG_BUILTIN                0x01    /* builtin - not stored in flash */
-#define ENV_FLG_READONLY       0x02    /* read-only - cannot be changed */
-
-#define ENV_FLG_MASK           0xFF    /* mask of attributes we keep */
-#define ENV_FLG_ADMIN          0x100   /* lets us internally override permissions */
-
-
-/*  *********************************************************************
-    *  _nvram_read(buffer,offset,length)
-    *  
-    *  Read data from the NVRAM device
-    *  
-    *  Input parameters: 
-    *             buffer - destination buffer
-    *             offset - offset of data to read
-    *             length - number of bytes to read
-    *             
-    *  Return value:
-    *             number of bytes read, or <0 if error occured
-    ********************************************************************* */
-static int
-_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
-{
-    int i;
-    if (offset > NVRAM_SIZE)
-       return -1; 
-
-    for ( i = 0; i < length; i++) {
-       buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
-    }
-    return length;
-}
-
-
-static char*
-_strnchr(const char *dest,int c,size_t cnt)
-{
-       while (*dest && (cnt > 0)) {
-       if (*dest == c) return (char *) dest;
-       dest++;
-       cnt--;
-       }
-       return NULL;
-}
-
-
-
-/*
- * Core support API: Externally visible.
- */
-
-/*
- * Get the value of an NVRAM variable
- * @param      name    name of variable to get
- * @return     value of variable or NULL if undefined
- */
-
-char* 
-cfe_env_get(unsigned char *nv_buf, char* name)
-{
-    int size;
-    unsigned char *buffer;
-    unsigned char *ptr;
-    unsigned char *envval;
-    unsigned int reclen;
-    unsigned int rectype;
-    int offset;
-    int flg;
-    
-       if (!strcmp(name, "nvram_type"))
-               return "cfe";
-       
-    size = NVRAM_SIZE;
-    buffer = &_nvdata[0];
-
-    ptr = buffer;
-    offset = 0;
-
-    /* Read the record type and length */
-    if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
-       goto error;
-    }
-    
-    while ((*ptr != ENV_TLV_TYPE_END)  && (size > 1)) {
-
-       /* Adjust pointer for TLV type */
-       rectype = *(ptr);
-       offset++;
-       size--;
-
-       /* 
-        * Read the length.  It can be either 1 or 2 bytes
-        * depending on the code 
-        */
-       if (rectype & ENV_LENGTH_8BITS) {
-           /* Read the record type and length - 8 bits */
-           if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
-               goto error;
-           }
-           reclen = *(ptr);
-           size--;
-           offset++;
-       }
-       else {
-           /* Read the record type and length - 16 bits, MSB first */
-           if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
-               goto error;
-           }
-           reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
-           size -= 2;
-           offset += 2;
-       }
-
-       if (reclen > size)
-           break;      /* should not happen, bad NVRAM */
-
-       switch (rectype) {
-           case ENV_TLV_TYPE_ENV:
-               /* Read the TLV data */
-               if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
-                   goto error;
-               flg = *ptr++;
-               envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
-               if (envval) {
-                   *envval++ = '\0';
-                   memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
-                   _valuestr[(reclen-1)-(envval-ptr)] = '\0';
-#if 0                  
-                   printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
-#endif
-                   if(!strcmp(ptr, name)){
-                       return _valuestr;
-                   }
-                   if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
-                       return _valuestr;
-               }
-               break;
-               
-           default: 
-               /* Unknown TLV type, skip it. */
-               break;
-           }
-
-       /*
-        * Advance to next TLV 
-        */
-               
-       size -= (int)reclen;
-       offset += reclen;
-
-       /* Read the next record type */
-       ptr = buffer;
-       if (_nvram_read(nv_buf, ptr,offset,1) != 1)
-           goto error;
-       }
-
-error:
-    return NULL;
-
-}
-
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/include/nvram.h
deleted file mode 100644 (file)
index 6bb18e8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- *
- *  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 __NVRAM_H
-#define __NVRAM_H
-
-struct nvram_header {
-       u32 magic;
-       u32 len;
-       u32 crc_ver_init;       /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
-       u32 config_refresh;     /* 0:15 sdram_config, 16:31 sdram_refresh */
-       u32 config_ncdl;        /* ncdl values for memc */
-};
-
-struct nvram_tuple {
-       char *name;
-       char *value;
-       struct nvram_tuple *next;
-};
-
-#define NVRAM_HEADER           0x48534C46      /* 'FLSH' */
-#define NVRAM_VERSION          1
-#define NVRAM_HEADER_SIZE      20
-#define NVRAM_SPACE            0x8000
-
-#define NVRAM_MAX_VALUE_LEN 255
-#define NVRAM_MAX_PARAM_LEN 64
-
-char *nvram_get(const char *name);
-
-#endif
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/irq.c
deleted file mode 100644 (file)
index d707894..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *  Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
- *  Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  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 <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ssb/ssb.h>
-
-#include <asm/cpu.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/irq_cpu.h>
-
-
-extern struct ssb_bus ssb;
-
-
-void plat_irq_dispatch(void)
-{
-       u32 cause;
-
-       cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
-
-       clear_c0_status(cause);
-
-       if (cause & CAUSEF_IP7)
-               do_IRQ(7);
-       if (cause & CAUSEF_IP2)
-               do_IRQ(2);
-       if (cause & CAUSEF_IP3)
-               do_IRQ(3);
-       if (cause & CAUSEF_IP4)
-               do_IRQ(4);
-       if (cause & CAUSEF_IP5)
-               do_IRQ(5);
-       if (cause & CAUSEF_IP6)
-               do_IRQ(6);
-}
-
-void __init arch_init_irq(void)
-{
-       mips_cpu_irq_init();
-}
-
-int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       int res;
-
-       res = ssb_pcibios_map_irq(dev, slot, pin);
-       if (res < 0) {
-               printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
-                      dev->dev.bus_id);
-               return 0;
-       }
-       /* IRQ-0 and IRQ-1 are software interrupts. */
-       WARN_ON((res == 0) || (res == 1));
-
-       return res;
-}
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/nvram.c
deleted file mode 100644 (file)
index 3f32ad9..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * BCM947xx nvram variable access
- *
- * Copyright 2005, Broadcom Corporation
- * Copyright 2006, Felix Fietkau <nbd@openwrt.org>
- * 
- * 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 <linux/init.h>
-#include <linux/module.h>
-#include <linux/ssb/ssb.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/bootinfo.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <nvram.h>
-
-#define MB * 1048576
-extern struct ssb_bus ssb;
-
-static char nvram_buf[NVRAM_SPACE];
-static int cfe_env;
-extern char *cfe_env_get(char *nv_buf, const char *name);
-               
-/* Probe for NVRAM header */
-static void __init early_nvram_init(void)
-{
-       struct ssb_mipscore *mcore = &ssb.mipscore;
-       struct nvram_header *header;
-       int i;
-       u32 base, lim, off;
-       u32 *src, *dst;
-       
-       base = mcore->flash_window;
-       lim = mcore->flash_window_size;
-       cfe_env = 0;
-
-       
-       /* XXX: hack for supporting the CFE environment stuff on WGT634U */
-       if (lim >= 8 MB) {
-               src = (u32 *) KSEG1ADDR(base + 8 MB - 0x2000);
-               dst = (u32 *) nvram_buf;
-
-               if ((*src & 0xff00ff) == 0x000001) {
-                       printk("early_nvram_init: WGT634U NVRAM found.\n");
-
-                       for (i = 0; i < 0x1ff0; i++) {
-                               if (*src == 0xFFFFFFFF)
-                                       break;
-                               *dst++ = *src++;
-                       }
-                       cfe_env = 1;
-                       return;
-               }
-       }
-
-       off = 0x20000;
-       while (off <= lim) {
-               /* Windowed flash access */
-               header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
-               if (header->magic == NVRAM_HEADER)
-                       goto found;
-               off <<= 1;
-       }
-
-       /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
-       header = (struct nvram_header *) KSEG1ADDR(base + 4096);
-       if (header->magic == NVRAM_HEADER)
-               goto found;
-       
-       header = (struct nvram_header *) KSEG1ADDR(base + 1024);
-       if (header->magic == NVRAM_HEADER)
-               goto found;
-       
-       return;
-
-found:
-       src = (u32 *) header;
-       dst = (u32 *) nvram_buf;
-       for (i = 0; i < sizeof(struct nvram_header); i += 4)
-               *dst++ = *src++;
-       for (; i < header->len && i < NVRAM_SPACE; i += 4)
-               *dst++ = le32_to_cpu(*src++);
-}
-
-char *nvram_get(const char *name)
-{
-       char *var, *value, *end, *eq;
-
-       if (!name)
-               return NULL;
-
-       if (!nvram_buf[0])
-               early_nvram_init();
-
-       if (cfe_env)
-               return cfe_env_get(nvram_buf, name);
-
-       /* Look for name=value and return value */
-       var = &nvram_buf[sizeof(struct nvram_header)];
-       end = nvram_buf + sizeof(nvram_buf) - 2;
-       end[0] = end[1] = '\0';
-       for (; *var; var = value + strlen(value) + 1) {
-               if (!(eq = strchr(var, '=')))
-                       break;
-               value = eq + 1;
-               if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
-                       return value;
-       }
-
-       return NULL;
-}
-
-EXPORT_SYMBOL(nvram_get);
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/prom.c
deleted file mode 100644 (file)
index 41ea087..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
- *
- *  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 <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <asm/pmon.h>
-#include "../cfe/cfe_private.h"
-
-const char *get_system_type(void)
-{
-       return "Broadcom BCM47xx";
-}
-
-void __init prom_init(void)
-{
-       unsigned long mem;
-
-        mips_machgroup = MACH_GROUP_BRCM;
-        mips_machtype = MACH_BCM47XX;
-
-       cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3);
-               
-       /* Figure out memory size by finding aliases */
-       for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
-               if (*(unsigned long *)((unsigned long)(prom_init) + mem) == 
-                   *(unsigned long *)(prom_init))
-                       break;
-       }
-
-       add_memory_region(0, mem, BOOT_MEM_RAM);
-}
-
-void __init prom_free_prom_memory(void)
-{
-}
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/setup.c
deleted file mode 100644 (file)
index 41d7b0b..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- *  Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
- *  Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
- *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
- *  Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  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 <linux/init.h>
-#include <linux/types.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-#include <linux/serial_8250.h>
-#include <asm/bootinfo.h>
-#include <asm/time.h>
-#include <asm/reboot.h>
-#include <asm/cfe.h>
-#include <linux/pm.h>
-#include <linux/ssb/ssb.h>
-#include <linux/ssb/ssb_embedded.h>
-
-#include <nvram.h>
-
-extern void bcm47xx_pci_init(void);
-extern void bcm47xx_time_init(void);
-
-struct ssb_bus ssb;
-
-
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
-       int err;
-
-       err = ssb_pcibios_plat_dev_init(dev);
-       if (err) {
-               printk(KERN_ALERT "PCI: Failed to init device %s\n",
-                      pci_name(dev));
-       }
-
-       return err;
-}
-
-static void bcm47xx_machine_restart(char *command)
-{
-       printk(KERN_ALERT "Please stand by while rebooting the system...\n");
-       local_irq_disable();
-       /* CFE has a reboot callback, but that does not work.
-        * Oopses with: Reserved instruction in kernel code.
-        */
-
-       /* Set the watchdog timer to reset immediately */
-       if (ssb_watchdog_timer_set(&ssb, 1))
-               printk(KERN_EMERG "SSB watchdog-triggered reboot failed!\n");
-       while (1)
-               cpu_relax();
-}
-
-static void bcm47xx_machine_halt(void)
-{
-       /* Disable interrupts and watchdog and spin forever */
-       local_irq_disable();
-       if (ssb_watchdog_timer_set(&ssb, 0))
-               printk(KERN_EMERG "Failed to disable SSB watchdog!\n");
-       while (1)
-               cpu_relax();
-}
-
-static void e_aton(char *str, char *dest)
-{
-       int i = 0;
-
-       if (str == NULL) {
-               memset(dest, 0, 6);
-               return;
-       }
-       
-       for (;;) {
-               dest[i++] = (char) simple_strtoul(str, NULL, 16);
-               str += 2;
-               if (!*str++ || i == 6)
-                       break;
-       }
-}
-
-static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
-{
-       char *s;
-
-       memset(sprom, 0xFF, sizeof(struct ssb_sprom));
-
-       sprom->revision = 1;
-       if ((s = nvram_get("il0macaddr")))
-               e_aton(s, sprom->il0mac);
-       if ((s = nvram_get("et0macaddr")))
-               e_aton(s, sprom->et0mac);
-       if ((s = nvram_get("et1macaddr")))
-               e_aton(s, sprom->et1mac);
-       if ((s = nvram_get("et0phyaddr")))
-               sprom->et0phyaddr = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("et1phyaddr")))
-               sprom->et1phyaddr = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("et0mdcport")))
-               sprom->et0mdcport = !!simple_strtoul(s, NULL, 10);
-       if ((s = nvram_get("et1mdcport")))
-               sprom->et1mdcport = !!simple_strtoul(s, NULL, 10);
-       if ((s = nvram_get("pa0b0")))
-               sprom->pa0b0 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa0b1")))
-               sprom->pa0b1 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa0b2")))
-               sprom->pa0b2 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa1b0")))
-               sprom->pa1b0 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa1b1")))
-               sprom->pa1b1 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa1b2")))
-               sprom->pa1b2 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("wl0gpio0")))
-               sprom->gpio0 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("wl0gpio1")))
-               sprom->gpio1 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("wl0gpio2")))
-               sprom->gpio2 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("wl0gpio3")))
-               sprom->gpio3 = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa0maxpwr")))
-               sprom->maxpwr_bg = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa1maxpwr")))
-               sprom->maxpwr_a = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa0itssit")))
-               sprom->itssi_bg = simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("pa1itssit")))
-               sprom->itssi_a = simple_strtoul(s, NULL, 0);
-       sprom->boardflags_lo = 0;
-       if ((s = nvram_get("boardflags")))
-               sprom->boardflags_lo = simple_strtoul(s, NULL, 0);
-       sprom->boardflags_hi = 0;
-       if ((s = nvram_get("boardflags2")))
-               sprom->boardflags_hi = simple_strtoul(s, NULL, 0);
-}
-
-static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv)
-{
-       char *s;
-
-       iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
-       if ((s = nvram_get("boardtype")))
-               iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0);
-       if ((s = nvram_get("boardrev")))
-               iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0);
-
-       bcm47xx_fill_sprom(&iv->sprom);
-
-       if ((s = nvram_get("cardbus")))
-               iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10);
-
-       return 0;
-}
-
-void __init plat_mem_setup(void)
-{
-       int i, err;
-       char *s;
-       struct ssb_mipscore *mcore;
-
-       err = ssb_bus_ssbbus_register(&ssb, SSB_ENUM_BASE, bcm47xx_get_invariants);
-       if (err) {
-               const char *msg = "Failed to initialize SSB bus (err %d)\n";
-               cfe_printk(msg, err); /* Make sure the message gets out of the box. */
-               panic(msg, err);
-       }
-       mcore = &ssb.mipscore;
-
-       s = nvram_get("kernel_args");
-       if (s && !strncmp(s, "console=ttyS1", 13)) {
-               struct ssb_serial_port port;
-
-               cfe_printk("Swapping serial ports!\n");
-               /* swap serial ports */
-               memcpy(&port, &mcore->serial_ports[0], sizeof(port));
-               memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
-               memcpy(&mcore->serial_ports[1], &port, sizeof(port));
-       }
-
-       for (i = 0; i < mcore->nr_serial_ports; i++) {
-               struct ssb_serial_port *port = &(mcore->serial_ports[i]);
-               struct uart_port s;
-       
-               memset(&s, 0, sizeof(s));
-               s.line = i;
-               s.membase = port->regs;
-               s.irq = port->irq + 2;
-               s.uartclk = port->baud_base;
-               s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-               s.iotype = SERIAL_IO_MEM;
-               s.regshift = port->reg_shift;
-
-               early_serial_setup(&s);
-       }
-       cfe_printk("Serial init done.\n");
-
-       _machine_restart = bcm47xx_machine_restart;
-       _machine_halt = bcm47xx_machine_halt;
-       pm_power_off = bcm47xx_machine_halt;
-       board_time_init = bcm47xx_time_init;
-}
-
-static int __init bcm47xx_register_gpiodev(void)
-{
-       static struct resource res = {
-               .start = 0xFFFFFFFF,
-       };
-       struct platform_device *pdev;
-
-       pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
-       if (!pdev) {
-               printk(KERN_ERR "bcm47xx: GPIODEV init failed\n");
-               return -ENODEV;
-       }
-
-       return 0;
-}
-device_initcall(bcm47xx_register_gpiodev);
-
-EXPORT_SYMBOL(ssb);
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/bcm947xx/time.c
deleted file mode 100644 (file)
index 62120eb..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
- *
- *  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 <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/serial_reg.h>
-#include <linux/interrupt.h>
-#include <linux/ssb/ssb.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-#include <asm/time.h>
-
-extern struct ssb_bus ssb;
-
-void __init
-bcm47xx_time_init(void)
-{
-       unsigned long hz;
-
-       /*
-        * Use deterministic values for initial counter interrupt
-        * so that calibrate delay avoids encountering a counter wrap.
-        */
-       write_c0_count(0);
-       write_c0_compare(0xffff);
-
-       hz = ssb_cpu_clock(&ssb.mipscore) / 2;
-       if (!hz)
-               hz = 100000000;
-
-       /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
-       mips_hpt_frequency = hz;
-}
-
-void __init
-plat_timer_setup(struct irqaction *irq)
-{
-       /* Enable the timer interrupt */
-       setup_irq(7, irq);
-}
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/Makefile
deleted file mode 100644 (file)
index d9f046a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Broadcom Common Firmware Environment support
-#
-
-obj-y += cfe.o
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe.c
deleted file mode 100644 (file)
index 6d16111..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Broadcom Common Firmware Environment (CFE) support
- *
- * Copyright 2000, 2001, 2002
- * Broadcom Corporation. All rights reserved.
- *
- * Copyright (C) 2006 Michael Buesch
- *
- * Original Authors:  Mitch Lichtenberg, Chris Demetriou
- *
- * This software is furnished under license and may be used and copied only
- * in accordance with the following terms and conditions.  Subject to these
- * conditions, you may download, copy, install, use, modify and distribute
- * modified or unmodified copies of this software in source and/or binary
- * form. No title or ownership is transferred hereby.
- *
- * 1) Any source code used, modified or distributed must reproduce and
- *    retain this copyright notice and list of conditions as they appear in
- *    the source file.
- *
- * 2) No right is granted to use any trade name, trademark, or logo of
- *    Broadcom Corporation.  The "Broadcom Corporation" name may not be
- *    used to endorse or promote products derived from this software
- *    without the prior written permission of Broadcom Corporation.
- *
- * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
- *    WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
- *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
- *    NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
- *    FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
- *    LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <asm/cfe.h>
-
-#include "cfe_private.h"
-
-
-static cfe_uint_t cfe_handle;
-static int (*cfe_trampoline)(long handle, long iocb);
-
-
-#include <linux/kernel.h>
-
-void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
-                     unsigned long fwarg2, unsigned long fwarg3)
-{
-       if (fwarg3 == 0x80300000) {
-               /* WRT54G workaround */
-               fwarg3 = CFE_EPTSEAL;
-               fwarg2 = 0xBFC00500;
-       }
-       if (fwarg3 != CFE_EPTSEAL) {
-               /* We are not booted from CFE */
-               return;
-       }
-       if (fwarg1 == 0) {
-               /* We are on the boot CPU */
-               cfe_handle = (cfe_uint_t)fwarg0;
-               cfe_trampoline = CFE_TO_PTR(fwarg2);
-       }
-}
-
-int cfe_vprintk(const char *fmt, va_list args)
-{
-       static char buffer[1024];
-       static DEFINE_SPINLOCK(lock);
-       static const char pfx[] = "CFE-console: ";
-       static const size_t pfx_len = sizeof(pfx) - 1;
-       unsigned long flags;
-       int len, cnt, pos;
-       int handle;
-       int res;
-
-       if (!cfe_present())
-               return -ENODEV;
-
-       spin_lock_irqsave(&lock, flags);
-       handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
-       if (CFE_ISERR(handle)) {
-               len = -EIO;
-               goto out;
-       }
-       strcpy(buffer, pfx);
-       len = vscnprintf(buffer + pfx_len,
-                        sizeof(buffer) - pfx_len - 2,
-                        fmt, args);
-       len += pfx_len;
-       /* The CFE console requires CR-LF line-ends.
-        * Add a CR, if we only terminate lines with a LF.
-        * This does only fix CR-LF at the end of the string.
-        * So for multiple lines, use multiple cfe_vprintk calls.
-        */
-       if (len > 1 &&
-           buffer[len - 1] == '\n' && buffer[len - 2] != '\r') {
-               buffer[len - 1] = '\r';
-               buffer[len] = '\n';
-               len += 1;
-       }
-       cnt = len;
-       pos = 0;
-       while (cnt > 0) {
-               res = cfe_write(handle, buffer + pos, len - pos);
-               if (CFE_ISERR(res)) {
-                       len = -EIO;
-                       goto out;
-               }
-               cnt -= res;
-               pos += res;
-       }
-out:
-       spin_unlock_irqrestore(&lock, flags);
-
-       return len;
-}
-
-int cfe_printk(const char *fmt, ...)
-{
-       va_list args;
-       int res;
-
-       va_start(args, fmt);
-       res = cfe_vprintk(fmt, args);
-       va_end(args);
-
-       return res;
-}
-
-static int cfe_iocb_dispatch(struct cfe_iocb *iocb)
-{
-       if (!cfe_present())
-               return CFE_ERR_UNSUPPORTED;
-       return cfe_trampoline((long)cfe_handle, (long)iocb);
-}
-
-int cfe_present(void)
-{
-       return (cfe_trampoline != NULL);
-}
-
-int cfe_close(int handle)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_CLOSE;
-       iocb.handle = handle;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_CPUCTL;
-       iocb.psize = sizeof(struct cfe_iocb_cpuctl);
-       iocb.cpuctl.number = cpu;
-       iocb.cpuctl.command = CFE_CPU_CMD_START;
-       iocb.cpuctl.gp = gp;
-       iocb.cpuctl.sp = sp;
-       iocb.cpuctl.a1 = a1;
-       iocb.cpuctl.start_addr = (long)fn;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_cpu_stop(int cpu)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_CPUCTL;
-       iocb.psize = sizeof(struct cfe_iocb_cpuctl);
-       iocb.cpuctl.number = cpu;
-       iocb.cpuctl.command = CFE_CPU_CMD_STOP;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_ENV_ENUM;
-       iocb.psize = sizeof(struct cfe_iocb_envbuf);
-       iocb.envbuf.index = idx;
-       iocb.envbuf.name = PTR_TO_CFE(name);
-       iocb.envbuf.name_len = namelen;
-       iocb.envbuf.val = PTR_TO_CFE(val);
-       iocb.envbuf.val_len = vallen;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_enumdev(int idx, char *name, int namelen)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-
-       iocb.fcode = CFE_CMD_DEV_ENUM;
-       iocb.psize = sizeof(struct cfe_iocb_envbuf);
-       iocb.envbuf.index = idx;
-       iocb.envbuf.name = PTR_TO_CFE(name);
-       iocb.envbuf.name_len = namelen;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
-               u64 *type)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-
-       iocb.fcode = CFE_CMD_FW_MEMENUM;
-       iocb.flags = flags;
-       iocb.psize = sizeof(struct cfe_iocb_meminfo);
-       iocb.meminfo.index = idx;
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (!CFE_ISERR(iocb.status)) {
-               *start = iocb.meminfo.addr;
-               *length = iocb.meminfo.size;
-               *type = iocb.meminfo.type;
-       }
-
-       return iocb.status;
-}
-
-int cfe_exit(int warm, int status)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-printk("CFE REBOOT\n");
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_RESTART;
-       if (warm)
-               iocb.flags = CFE_FLG_WARMSTART;
-       iocb.psize = sizeof(struct cfe_iocb_exitstat);
-       iocb.exitstat.status = status;
-
-printk("CALL\n");
-       err = cfe_iocb_dispatch(&iocb);
-printk("DONE\n");
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_flushcache(int flags)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_FLUSHCACHE;
-       iocb.flags = flags;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_getdevinfo(char *name)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_GETINFO;
-       iocb.psize = sizeof(struct cfe_iocb_buf);
-       iocb.buffer.ptr = PTR_TO_CFE(name);
-       iocb.buffer.length = strlen(name);
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.buffer.devflags;
-}
-
-int cfe_getenv(char *name, char *dest, int destlen)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       dest[0] = '\0';
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_ENV_GET;
-       iocb.psize = sizeof(struct cfe_iocb_envbuf);
-       iocb.envbuf.name = PTR_TO_CFE(name);
-       iocb.envbuf.name_len = strlen(name);
-       iocb.envbuf.val = PTR_TO_CFE(dest);
-       iocb.envbuf.val_len = destlen;
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_getfwinfo(struct cfe_fwinfo *info)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_GETINFO;
-       iocb.psize = sizeof(struct cfe_iocb_fwinfo);
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return err;
-
-       info->version = iocb.fwinfo.version;
-       info->totalmem = iocb.fwinfo.totalmem;
-       info->flags = iocb.fwinfo.flags;
-       info->boardid = iocb.fwinfo.boardid;
-       info->bootarea_va = iocb.fwinfo.bootarea_va;
-       info->bootarea_pa = iocb.fwinfo.bootarea_pa;
-       info->bootarea_size = iocb.fwinfo.bootarea_size;
-
-       return iocb.status;
-}
-
-int cfe_getstdhandle(int handletype)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_GETHANDLE;
-       iocb.flags = handletype;
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.handle;
-}
-
-int cfe_getticks(s64 *ticks)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_FW_GETTIME;
-       iocb.psize = sizeof(struct cfe_iocb_time);
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (!CFE_ISERR(iocb.status))
-               *ticks = iocb.time.ticks;
-
-       return iocb.status;
-}
-
-int cfe_inpstat(int handle)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_INPSTAT;
-       iocb.handle = handle;
-       iocb.psize = sizeof(struct cfe_iocb_inpstat);
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.inpstat.status;
-}
-
-int cfe_ioctl(int handle, unsigned int ioctlnum,
-             unsigned char *buffer, int length,
-             int *retlen, u64 offset)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_IOCTL;
-       iocb.handle = handle;
-       iocb.psize = sizeof(struct cfe_iocb_buf);
-       iocb.buffer.offset = offset;
-       iocb.buffer.ioctlcmd = ioctlnum;
-       iocb.buffer.ptr = PTR_TO_CFE(buffer);
-       iocb.buffer.length = length;
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-       if (retlen)
-               *retlen = iocb.buffer.retlen;
-
-       return iocb.status;
-}
-
-int cfe_open(char *name)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_OPEN;
-       iocb.psize = sizeof(struct cfe_iocb_buf);
-       iocb.buffer.ptr = PTR_TO_CFE(name);
-       iocb.buffer.length = strlen(name);
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.handle;
-}
-
-int cfe_read(int handle, unsigned char *buffer, int length)
-{
-       return cfe_readblk(handle, 0, buffer, length);
-}
-
-int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_READ;
-       iocb.handle = handle;
-       iocb.psize = sizeof(struct cfe_iocb_buf);
-       iocb.buffer.offset = offset;
-       iocb.buffer.ptr = PTR_TO_CFE(buffer);
-       iocb.buffer.length = length;
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.buffer.retlen;
-}
-
-int cfe_setenv(char *name, char *val)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_ENV_SET;
-       iocb.psize = sizeof(struct cfe_iocb_envbuf);
-       iocb.envbuf.name = PTR_TO_CFE(name);
-       iocb.envbuf.name_len = strlen(name);
-       iocb.envbuf.val = PTR_TO_CFE(val);
-       iocb.envbuf.val_len = strlen(val);
-
-       err = cfe_iocb_dispatch(&iocb);
-
-       return (CFE_ISERR(err)) ? err : iocb.status;
-}
-
-int cfe_write(int handle, unsigned char *buffer, int length)
-{
-       return cfe_writeblk(handle, 0, buffer, length);
-}
-
-int cfe_writeblk(int handle, s64 offset, unsigned char *buffer, int length)
-{
-       struct cfe_iocb iocb;
-       int err;
-
-       memset(&iocb, 0, sizeof(iocb));
-       iocb.fcode = CFE_CMD_DEV_WRITE;
-       iocb.handle = handle;
-       iocb.psize = sizeof(struct cfe_iocb_buf);
-       iocb.buffer.offset = offset;
-       iocb.buffer.ptr = PTR_TO_CFE(buffer);
-       iocb.buffer.length = length;
-
-       err = cfe_iocb_dispatch(&iocb);
-       if (CFE_ISERR(err))
-               return err;
-       if (CFE_ISERR(iocb.status))
-               return iocb.status;
-
-       return iocb.buffer.retlen;
-}
diff --git a/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h b/target/linux/brcm47xx/files-2.6.25/arch/mips/cfe/cfe_private.h
deleted file mode 100644 (file)
index 0a604d3..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Broadcom Common Firmware Environment (CFE) support
- *
- * Copyright 2000, 2001, 2002
- * Broadcom Corporation. All rights reserved.
- *
- * Copyright (C) 2006 Michael Buesch
- *
- * Original Authors:  Mitch Lichtenberg, Chris Demetriou
- *
- * This software is furnished under license and may be used and copied only
- * in accordance with the following terms and conditions.  Subject to these
- * conditions, you may download, copy, install, use, modify and distribute
- * modified or unmodified copies of this software in source and/or binary
- * form. No title or ownership is transferred hereby.
- *
- * 1) Any source code used, modified or distributed must reproduce and
- *    retain this copyright notice and list of conditions as they appear in
- *    the source file.
- *
- * 2) No right is granted to use any trade name, trademark, or logo of
- *    Broadcom Corporation.  The "Broadcom Corporation" name may not be
- *    used to endorse or promote products derived from this software
- *    without the prior written permission of Broadcom Corporation.
- *
- * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
- *    WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
- *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
- *    NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
- *    FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
- *    LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LINUX_CFE_PRIVATE_H_
-#define LINUX_CFE_PRIVATE_H_
-
-#ifndef __ASSEMBLY__
-
-/* Seal indicating CFE's presence, passed to the kernel. */
-#define CFE_EPTSEAL            0x43464531
-
-#define CFE_CMD_FW_GETINFO     0
-#define CFE_CMD_FW_RESTART     1
-#define CFE_CMD_FW_BOOT                2
-#define CFE_CMD_FW_CPUCTL      3
-#define CFE_CMD_FW_GETTIME      4
-#define CFE_CMD_FW_MEMENUM     5
-#define CFE_CMD_FW_FLUSHCACHE  6
-
-#define CFE_CMD_DEV_GETHANDLE  9
-#define CFE_CMD_DEV_ENUM       10
-#define CFE_CMD_DEV_OPEN       11
-#define CFE_CMD_DEV_INPSTAT    12
-#define CFE_CMD_DEV_READ       13
-#define CFE_CMD_DEV_WRITE      14
-#define CFE_CMD_DEV_IOCTL      15
-#define CFE_CMD_DEV_CLOSE      16
-#define CFE_CMD_DEV_GETINFO    17
-
-#define CFE_CMD_ENV_ENUM       20
-#define CFE_CMD_ENV_GET                22
-#define CFE_CMD_ENV_SET                23
-#define CFE_CMD_ENV_DEL                24
-
-#define CFE_CMD_MAX            32
-
-#define CFE_CMD_VENDOR_USE     0x8000  /* codes above this are for customer use */
-
-typedef u64 cfe_uint_t;
-typedef s64 cfe_int_t;
-typedef s64 cfe_ptr_t;
-
-/* Cast a pointer from native to CFE-API pointer and back */
-#define CFE_TO_PTR(p)          ((void *)(unsigned long)(p))
-#define PTR_TO_CFE(p)          ((cfe_ptr_t)(unsigned long)(p))
-
-struct cfe_iocb_buf {
-       cfe_uint_t      offset;         /* offset on device (bytes) */
-       cfe_ptr_t       ptr;            /* pointer to a buffer */
-       cfe_uint_t      length;         /* length of this buffer */
-       cfe_uint_t      retlen;         /* returned length (for read ops) */
-       union {
-               cfe_uint_t      ioctlcmd;       /* IOCTL command (used only for IOCTLs) */
-               cfe_uint_t      devflags;       /* Returned device info flags */
-       };
-};
-
-struct cfe_iocb_inpstat {
-       cfe_uint_t      status;         /* 1 means input available */
-};
-
-struct cfe_iocb_envbuf {
-       cfe_int_t       index;          /* 0-based enumeration index */
-       cfe_ptr_t       name;           /* name string buffer */
-       cfe_int_t       name_len;       /* size of name buffer */
-       cfe_ptr_t       val;            /* value string buffer */
-       cfe_int_t       val_len;        /* size of value string buffer */
-};
-
-struct cfe_iocb_cpuctl {
-       cfe_uint_t      number;         /* cpu number to control */
-       cfe_uint_t      command;        /* command to issue to CPU */
-       cfe_uint_t      start_addr;     /* CPU start address */
-       cfe_uint_t      gp;             /* starting GP value */
-       cfe_uint_t      sp;             /* starting SP value */
-       cfe_uint_t      a1;             /* starting A1 value */
-};
-
-struct cfe_iocb_time {
-       cfe_int_t       ticks;          /* current time in ticks */
-};
-
-struct cfe_iocb_exitstat {
-       cfe_int_t       status;
-};
-
-struct cfe_iocb_meminfo {
-       cfe_int_t       index;          /* 0-based enumeration index */
-       cfe_int_t       type;           /* type of memory block */
-       cfe_uint_t      addr;           /* physical start address */
-       cfe_uint_t      size;           /* block size */
-};
-
-struct cfe_iocb_fwinfo {
-       cfe_int_t       version;        /* major, minor, eco version */
-       cfe_int_t       totalmem;       /* total installed mem */
-       cfe_int_t       flags;          /* various flags */
-       cfe_int_t       boardid;        /* board ID */
-       cfe_int_t       bootarea_va;    /* VA of boot area */
-       cfe_int_t       bootarea_pa;    /* PA of boot area */
-       cfe_int_t       bootarea_size;  /* size of boot area */
-       cfe_int_t       reserved1;
-       cfe_int_t       reserved2;
-       cfe_int_t       reserved3;
-};
-
-/* CFE I/O Control Block */
-struct cfe_iocb {
-       cfe_uint_t      fcode;          /* IOCB function code */
-       cfe_int_t       status;         /* return status */
-       cfe_int_t       handle;         /* file/device handle */
-       cfe_uint_t      flags;          /* flags for this IOCB */
-       cfe_uint_t      psize;          /* size of parameter list */
-       union {
-               struct cfe_iocb_buf             buffer;         /* buffer parameters */
-               struct cfe_iocb_inpstat         inpstat;        /* input status parameters */
-               struct cfe_iocb_envbuf          envbuf;         /* environment function parameters */
-               struct cfe_iocb_cpuctl          cpuctl;         /* CPU control parameters */
-               struct cfe_iocb_time            time;           /* timer parameters */
-               struct cfe_iocb_meminfo         meminfo;        /* memory arena info parameters */
-               struct cfe_iocb_fwinfo          fwinfo;         /* firmware information */
-               struct cfe_iocb_exitstat        exitstat;       /* Exit Status */
-       };
-};
-
-
-#include <linux/init.h>
-
-void __init cfe_setup(unsigned long fwarg0, unsigned long fwarg1,
-                     unsigned long fwarg2, unsigned long fwarg3);
-
-#else /* __ASSEMBLY__ */
-
-       .macro  cfe_early_init
-#ifdef CONFIG_CFE
-               jal     cfe_setup
-#endif
-       .endm
-
-#endif /* __ASSEMBLY__ */
-#endif /* LINUX_CFE_PRIVATE_H_ */
index 6a82f36..118d4c4 100644 (file)
@@ -76,11 +76,11 @@ struct trx_header {
 #define BUSWIDTH 2
 
 #ifdef CONFIG_SSB
 #define BUSWIDTH 2
 
 #ifdef CONFIG_SSB
-extern struct ssb_bus ssb;
+extern struct ssb_bus ssb_bcm47xx;
 #endif
 #endif
-static struct mtd_info *bcm947xx_mtd;
+static struct mtd_info *bcm47xx_mtd;
 
 
-static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void bcm47xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
        if (len==1) {
                memcpy_fromio(to, map->virt + from, len);
 {
        if (len==1) {
                memcpy_fromio(to, map->virt + from, len);
@@ -96,7 +96,7 @@ static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long
        }
 }
 
        }
 }
 
-static struct map_info bcm947xx_map = {
+static struct map_info bcm47xx_map = {
        name: "Physically mapped flash",
        size: WINDOW_SIZE,
        bankwidth: BUSWIDTH,
        name: "Physically mapped flash",
        size: WINDOW_SIZE,
        bankwidth: BUSWIDTH,
@@ -105,7 +105,7 @@ static struct map_info bcm947xx_map = {
 
 #ifdef CONFIG_MTD_PARTITIONS
 
 
 #ifdef CONFIG_MTD_PARTITIONS
 
-static struct mtd_partition bcm947xx_parts[] = {
+static struct mtd_partition bcm47xx_parts[] = {
        { name: "cfe",  offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
        { name: "linux", offset: 0, size: 0, },
        { name: "rootfs", offset: 0, size: 0, },
        { name: "cfe",  offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
        { name: "linux", offset: 0, size: 0, },
        { name: "rootfs", offset: 0, size: 0, },
@@ -323,46 +323,46 @@ init_mtd_partitions(struct mtd_info *mtd, size_t size)
                return NULL;
 
        /* boot loader */
                return NULL;
 
        /* boot loader */
-       bcm947xx_parts[0].offset = 0;
-       bcm947xx_parts[0].size   = cfe_size;
+       bcm47xx_parts[0].offset = 0;
+       bcm47xx_parts[0].size   = cfe_size;
 
        /* nvram */
        if (cfe_size != 384 * 1024) {
 
        /* nvram */
        if (cfe_size != 384 * 1024) {
-               bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
-               bcm947xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
+               bcm47xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
+               bcm47xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
        } else {
                /* nvram (old 128kb config partition on netgear wgt634u) */
        } else {
                /* nvram (old 128kb config partition on netgear wgt634u) */
-               bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
-               bcm947xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
+               bcm47xx_parts[3].offset = bcm47xx_parts[0].size;
+               bcm47xx_parts[3].size   = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
        }
 
        /* linux (kernel and rootfs) */
        if (cfe_size != 384 * 1024) {
        }
 
        /* linux (kernel and rootfs) */
        if (cfe_size != 384 * 1024) {
-               bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
-               bcm947xx_parts[1].size   = bcm947xx_parts[3].offset - 
-                       bcm947xx_parts[1].offset;
+               bcm47xx_parts[1].offset = bcm47xx_parts[0].size;
+               bcm47xx_parts[1].size   = bcm47xx_parts[3].offset - 
+                       bcm47xx_parts[1].offset;
        } else {
                /* do not count the elf loader, which is on one block */
        } else {
                /* do not count the elf loader, which is on one block */
-               bcm947xx_parts[1].offset = bcm947xx_parts[0].size + 
-                       bcm947xx_parts[3].size + mtd->erasesize;
-               bcm947xx_parts[1].size   = size - 
-                       bcm947xx_parts[0].size - 
-                       (2*bcm947xx_parts[3].size) - 
+               bcm47xx_parts[1].offset = bcm47xx_parts[0].size + 
+                       bcm47xx_parts[3].size + mtd->erasesize;
+               bcm47xx_parts[1].size   = size - 
+                       bcm47xx_parts[0].size - 
+                       (2*bcm47xx_parts[3].size) - 
                        mtd->erasesize;
        }
 
        /* find and size rootfs */
                        mtd->erasesize;
        }
 
        /* find and size rootfs */
-       find_root(mtd,size,&bcm947xx_parts[2]);
-       bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset - bcm947xx_parts[3].size;
+       find_root(mtd,size,&bcm47xx_parts[2]);
+       bcm47xx_parts[2].size = size - bcm47xx_parts[2].offset - bcm47xx_parts[3].size;
 
 
-       return bcm947xx_parts;
+       return bcm47xx_parts;
 }
 #endif
 
 }
 #endif
 
-int __init init_bcm947xx_map(void)
+int __init init_bcm47xx_map(void)
 {
 #ifdef CONFIG_SSB
 {
 #ifdef CONFIG_SSB
-       struct ssb_mipscore *mcore = &ssb.mipscore;
+       struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
 #endif
        size_t size;
        int ret = 0;
 #endif
        size_t size;
        int ret = 0;
@@ -376,40 +376,40 @@ int __init init_bcm947xx_map(void)
        u32 window_size = mcore->flash_window_size;
 
        printk("flash init: 0x%08x 0x%08x\n", window, window_size);
        u32 window_size = mcore->flash_window_size;
 
        printk("flash init: 0x%08x 0x%08x\n", window, window_size);
-       bcm947xx_map.phys = window;
-       bcm947xx_map.size = window_size;
-       bcm947xx_map.virt = ioremap_nocache(window, window_size);
+       bcm47xx_map.phys = window;
+       bcm47xx_map.size = window_size;
+       bcm47xx_map.virt = ioremap_nocache(window, window_size);
 #else
        printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
 #else
        printk("flash init: 0x%08x 0x%08x\n", WINDOW_ADDR, WINDOW_SIZE);
-       bcm947xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
+       bcm47xx_map.virt = ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
 #endif
 
 #endif
 
-       if (!bcm947xx_map.virt) {
+       if (!bcm47xx_map.virt) {
                printk("Failed to ioremap\n");
                return -EIO;
        }
 
                printk("Failed to ioremap\n");
                return -EIO;
        }
 
-       simple_map_init(&bcm947xx_map);
+       simple_map_init(&bcm47xx_map);
        
        
-       if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
+       if (!(bcm47xx_mtd = do_map_probe("cfi_probe", &bcm47xx_map))) {
                printk("Failed to do_map_probe\n");
                printk("Failed to do_map_probe\n");
-               iounmap((void *)bcm947xx_map.virt);
+               iounmap((void *)bcm47xx_map.virt);
                return -ENXIO;
        }
 
        /* override copy_from routine */
                return -ENXIO;
        }
 
        /* override copy_from routine */
-       bcm947xx_map.copy_from = bcm947xx_map_copy_from;
+       bcm47xx_map.copy_from = bcm47xx_map_copy_from;
 
 
-       bcm947xx_mtd->owner = THIS_MODULE;
+       bcm47xx_mtd->owner = THIS_MODULE;
 
 
-       size = bcm947xx_mtd->size;
+       size = bcm47xx_mtd->size;
 
        printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
 
 #ifdef CONFIG_MTD_PARTITIONS
 
        printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
 
 #ifdef CONFIG_MTD_PARTITIONS
-       parts = init_mtd_partitions(bcm947xx_mtd, size);
+       parts = init_mtd_partitions(bcm47xx_mtd, size);
        for (i = 0; parts[i].name; i++);
        for (i = 0; parts[i].name; i++);
-       ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
+       ret = add_mtd_partitions(bcm47xx_mtd, parts, i);
        if (ret) {
                printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
                goto fail;
        if (ret) {
                printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
                goto fail;
@@ -418,22 +418,22 @@ int __init init_bcm947xx_map(void)
        return 0;
 
  fail:
        return 0;
 
  fail:
-       if (bcm947xx_mtd)
-               map_destroy(bcm947xx_mtd);
-       if (bcm947xx_map.virt)
-               iounmap((void *)bcm947xx_map.virt);
-       bcm947xx_map.virt = 0;
+       if (bcm47xx_mtd)
+               map_destroy(bcm47xx_mtd);
+       if (bcm47xx_map.virt)
+               iounmap((void *)bcm47xx_map.virt);
+       bcm47xx_map.virt = 0;
        return ret;
 }
 
        return ret;
 }
 
-void __exit cleanup_bcm947xx_map(void)
+void __exit cleanup_bcm47xx_map(void)
 {
 #ifdef CONFIG_MTD_PARTITIONS
 {
 #ifdef CONFIG_MTD_PARTITIONS
-       del_mtd_partitions(bcm947xx_mtd);
+       del_mtd_partitions(bcm47xx_mtd);
 #endif
 #endif
-       map_destroy(bcm947xx_mtd);
-       iounmap((void *)bcm947xx_map.virt);
+       map_destroy(bcm47xx_mtd);
+       iounmap((void *)bcm47xx_map.virt);
 }
 
 }
 
-module_init(init_bcm947xx_map);
-module_exit(cleanup_bcm947xx_map);
+module_init(init_bcm47xx_map);
+module_exit(cleanup_bcm47xx_map);
diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/cfe.h
deleted file mode 100644 (file)
index 47c3f56..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Broadcom Common Firmware Environment (CFE) support
- *
- * Copyright 2000, 2001, 2002
- * Broadcom Corporation. All rights reserved.
- *
- * Copyright (C) 2006 Michael Buesch
- *
- * Original Authors:  Mitch Lichtenberg, Chris Demetriou
- *
- * This software is furnished under license and may be used and copied only
- * in accordance with the following terms and conditions.  Subject to these
- * conditions, you may download, copy, install, use, modify and distribute
- * modified or unmodified copies of this software in source and/or binary
- * form. No title or ownership is transferred hereby.
- *
- * 1) Any source code used, modified or distributed must reproduce and
- *    retain this copyright notice and list of conditions as they appear in
- *    the source file.
- *
- * 2) No right is granted to use any trade name, trademark, or logo of
- *    Broadcom Corporation.  The "Broadcom Corporation" name may not be
- *    used to endorse or promote products derived from this software
- *    without the prior written permission of Broadcom Corporation.
- *
- * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
- *    WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
- *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
- *    NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
- *    FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
- *    LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef LINUX_CFE_API_H_
-#define LINUX_CFE_API_H_
-
-#include <linux/types.h>
-
-
-#define CFE_MI_RESERVED                0               /* memory is reserved, do not use */
-#define CFE_MI_AVAILABLE       1               /* memory is available */
-
-#define CFE_FLG_WARMSTART      0x00000001
-#define CFE_FLG_FULL_ARENA     0x00000001
-#define CFE_FLG_ENV_PERMANENT  0x00000001
-
-#define CFE_CPU_CMD_START      1
-#define CFE_CPU_CMD_STOP       0
-
-#define CFE_STDHANDLE_CONSOLE  0
-
-#define CFE_DEV_NETWORK        1
-#define CFE_DEV_DISK           2
-#define CFE_DEV_FLASH          3
-#define CFE_DEV_SERIAL         4
-#define CFE_DEV_CPU            5
-#define CFE_DEV_NVRAM          6
-#define CFE_DEV_CLOCK           7
-#define CFE_DEV_OTHER          8
-#define CFE_DEV_MASK           0x0F
-
-#define CFE_CACHE_FLUSH_D      1
-#define CFE_CACHE_INVAL_I      2
-#define CFE_CACHE_INVAL_D      4
-#define CFE_CACHE_INVAL_L2     8
-
-#define CFE_FWI_64BIT          0x00000001
-#define CFE_FWI_32BIT          0x00000002
-#define CFE_FWI_RELOC          0x00000004
-#define CFE_FWI_UNCACHED       0x00000008
-#define CFE_FWI_MULTICPU       0x00000010
-#define CFE_FWI_FUNCSIM                0x00000020
-#define CFE_FWI_RTLSIM         0x00000040
-
-struct cfe_fwinfo {
-       s64 version;            /* major, minor, eco version */
-       s64 totalmem;           /* total installed mem */
-       s64 flags;              /* various flags */
-       s64 boardid;            /* board ID */
-       s64 bootarea_va;        /* VA of boot area */
-       s64 bootarea_pa;        /* PA of boot area */
-       s64 bootarea_size;      /* size of boot area */
-};
-
-
-/* The public CFE API */
-
-int cfe_present(void); /* Check if we booted from CFE. Returns bool */
-
-int cfe_getticks(s64 *ticks);
-int cfe_close(int handle);
-int cfe_cpu_start(int cpu, void (*fn)(void), long sp, long gp, long a1);
-int cfe_cpu_stop(int cpu);
-int cfe_enumenv(int idx, char *name, int namelen, char *val, int vallen);
-int cfe_enumdev(int idx, char *name, int namelen);
-int cfe_enummem(int idx, int flags, u64 *start, u64 *length,
-               u64 *type);
-int cfe_exit(int warm, int status);
-int cfe_flushcache(int flags);
-int cfe_getdevinfo(char *name);
-int cfe_getenv(char *name, char *dest, int destlen);
-int cfe_getfwinfo(struct cfe_fwinfo *info);
-int cfe_getstdhandle(int handletype);
-int cfe_inpstat(int handle);
-int cfe_ioctl(int handle, unsigned int ioctlnum, unsigned char *buffer,
-             int length, int *retlen, u64 offset);
-int cfe_open(char *name);
-int cfe_read(int handle, unsigned char *buffer, int length);
-int cfe_readblk(int handle, s64 offset, unsigned char *buffer, int length);
-int cfe_setenv(char *name, char *val);
-int cfe_write(int handle, unsigned char *buffer, int length);
-int cfe_writeblk(int handle, s64 offset, unsigned char *buffer,
-                int length);
-
-
-/* High level API */
-
-/* Print some information to CFE's console (most likely serial line) */
-int cfe_printk(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
-int cfe_vprintk(const char *fmt, va_list args);
-
-
-
-/* Error codes returned by the low API functions */
-
-#define CFE_ISERR(errcode)     (errcode < 0)
-
-#define CFE_OK                  0
-#define CFE_ERR                 -1     /* generic error */
-#define CFE_ERR_INV_COMMAND    -2
-#define CFE_ERR_EOF            -3
-#define CFE_ERR_IOERR          -4
-#define CFE_ERR_NOMEM          -5
-#define CFE_ERR_DEVNOTFOUND    -6
-#define CFE_ERR_DEVOPEN                -7
-#define CFE_ERR_INV_PARAM      -8
-#define CFE_ERR_ENVNOTFOUND    -9
-#define CFE_ERR_ENVREADONLY    -10
-
-#define CFE_ERR_NOTELF         -11
-#define CFE_ERR_NOT32BIT       -12
-#define CFE_ERR_WRONGENDIAN    -13
-#define CFE_ERR_BADELFVERS     -14
-#define CFE_ERR_NOTMIPS        -15
-#define CFE_ERR_BADELFFMT      -16
-#define CFE_ERR_BADADDR        -17
-
-#define CFE_ERR_FILENOTFOUND   -18
-#define CFE_ERR_UNSUPPORTED    -19
-
-#define CFE_ERR_HOSTUNKNOWN    -20
-
-#define CFE_ERR_TIMEOUT                -21
-
-#define CFE_ERR_PROTOCOLERR    -22
-
-#define CFE_ERR_NETDOWN                -23
-#define CFE_ERR_NONAMESERVER   -24
-
-#define CFE_ERR_NOHANDLES      -25
-#define CFE_ERR_ALREADYBOUND   -26
-
-#define CFE_ERR_CANNOTSET      -27
-#define CFE_ERR_NOMORE         -28
-#define CFE_ERR_BADFILESYS     -29
-#define CFE_ERR_FSNOTAVAIL     -30
-
-#define CFE_ERR_INVBOOTBLOCK   -31
-#define CFE_ERR_WRONGDEVTYPE   -32
-#define CFE_ERR_BBCHECKSUM     -33
-#define CFE_ERR_BOOTPROGCHKSUM -34
-
-#define CFE_ERR_LDRNOTAVAIL    -35
-
-#define CFE_ERR_NOTREADY       -36
-
-#define CFE_ERR_GETMEM          -37
-#define CFE_ERR_SETMEM          -38
-
-#define CFE_ERR_NOTCONN                -39
-#define CFE_ERR_ADDRINUSE      -40
-
-
-#endif /* LINUX_CFE_API_H_ */
diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm47xx/kernel-entry-init.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm47xx/kernel-entry-init.h
new file mode 100644 (file)
index 0000000..7df0dc2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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) 2005 Embedded Alley Solutions, Inc
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006 Michael Buesch
+ */
+#ifndef __ASM_MACH_GENERIC_KERNEL_ENTRY_H
+#define __ASM_MACH_GENERIC_KERNEL_ENTRY_H
+
+/* Intentionally empty macro, used in head.S. Override in
+ * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
+ */
+       .macro  kernel_entry_setup
+       .endm
+
+/*
+ * Do SMP slave processor setup necessary before we can savely execute C code.
+ */
+       .macro  smp_slave_setup
+       .endm
+
+
+#endif /* __ASM_MACH_GENERIC_KERNEL_ENTRY_H */
diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/gpio.h
deleted file mode 100644 (file)
index e7807ce..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef __BCM947XX_GPIO_H
-#define __BCM947XX_GPIO_H
-
-#include <linux/ssb/ssb_embedded.h>
-
-extern struct ssb_bus ssb;
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-       return 0;
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-       ssb_gpio_outen(&ssb, 1 << gpio, 0);
-       return 0;
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-       ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0));
-       ssb_gpio_outen(&ssb, 1 << gpio, 1 << gpio);
-       return 0;
-}
-
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-       struct ssb_device *dev;
-
-       dev = ssb.chipco.dev;
-       if (!dev)
-               dev = ssb.extif.dev;
-       if (!dev)
-               return -EINVAL;
-
-       return ssb_mips_irq(dev) + 2;
-}
-
-static inline int irq_to_gpio(unsigned gpio)
-{
-       return -EINVAL;
-}
-
-
-static inline int gpio_get_value(unsigned gpio)
-{
-       return !!ssb_gpio_in(&ssb, 1 << gpio);
-}
-
-static inline int gpio_set_value(unsigned gpio, int value)
-{
-       ssb_gpio_out(&ssb, 1 << gpio, (value ? 1 << gpio : 0));
-       return 0;
-}
-
-
-/* cansleep wrappers */
-#include <asm-generic/gpio.h>
-
-
-#endif /* __BCM947XX_GPIO_H */
-
diff --git a/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h b/target/linux/brcm47xx/files-2.6.25/include/asm-mips/mach-bcm947xx/kernel-entry-init.h
deleted file mode 100644 (file)
index 7df0dc2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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) 2005 Embedded Alley Solutions, Inc
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2006 Michael Buesch
- */
-#ifndef __ASM_MACH_GENERIC_KERNEL_ENTRY_H
-#define __ASM_MACH_GENERIC_KERNEL_ENTRY_H
-
-/* Intentionally empty macro, used in head.S. Override in
- * arch/mips/mach-xxx/kernel-entry-init.h when necessary.
- */
-       .macro  kernel_entry_setup
-       .endm
-
-/*
- * Do SMP slave processor setup necessary before we can savely execute C code.
- */
-       .macro  smp_slave_setup
-       .endm
-
-
-#endif /* __ASM_MACH_GENERIC_KERNEL_ENTRY_H */
diff --git a/target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch b/target/linux/brcm47xx/patches-2.6.25/001-ssb-fix-gpio-api.patch
deleted file mode 100644 (file)
index f8d454f..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c       2008-02-19 14:37:06.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c    2008-02-19 14:37:08.000000000 +0100
-@@ -39,12 +39,14 @@ static inline void chipco_write32(struct
-       ssb_write32(cc->dev, offset, value);
- }
--static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
--                                       u32 mask, u32 value)
-+static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
-+                                      u32 mask, u32 value)
- {
-       value &= mask;
-       value |= chipco_read32(cc, offset) & ~mask;
-       chipco_write32(cc, offset, value);
-+
-+      return value;
- }
- void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
-@@ -355,16 +357,37 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco
- {
-       return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
- }
-+EXPORT_SYMBOL(ssb_chipco_gpio_in);
-+
-+u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
-+{
-+      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
-+}
-+EXPORT_SYMBOL(ssb_chipco_gpio_out);
-+
-+u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
-+{
-+      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
-+}
-+EXPORT_SYMBOL(ssb_chipco_gpio_outen);
-+
-+u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
-+{
-+      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
-+}
-+EXPORT_SYMBOL(ssb_chipco_gpio_control);
--void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
-+u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
--      chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
-+      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
- }
-+EXPORT_SYMBOL(ssb_chipco_gpio_intmask);
--void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
-+u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
--      chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
-+      return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
- }
-+EXPORT_SYMBOL(ssb_chipco_gpio_polarity);
- #ifdef CONFIG_SSB_SERIAL
- int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
-Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c    2008-02-19 14:37:06.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 14:37:08.000000000 +0100
-@@ -27,12 +27,14 @@ static inline void extif_write32(struct 
-       ssb_write32(extif->dev, offset, value);
- }
--static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
--                                      u32 mask, u32 value)
-+static inline u32 extif_write32_masked(struct ssb_extif *extif, u16 offset,
-+                                     u32 mask, u32 value)
- {
-       value &= mask;
-       value |= extif_read32(extif, offset) & ~mask;
-       extif_write32(extif, offset, value);
-+
-+      return value;
- }
- #ifdef CONFIG_SSB_SERIAL
-@@ -114,16 +116,30 @@ u32 ssb_extif_gpio_in(struct ssb_extif *
- {
-       return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
- }
-+EXPORT_SYMBOL(ssb_extif_gpio_in);
--void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
-+u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
-                                  mask, value);
- }
-+EXPORT_SYMBOL(ssb_extif_gpio_out);
--void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
-+u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
-                                  mask, value);
- }
-+EXPORT_SYMBOL(ssb_extif_gpio_outen);
-+
-+u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
-+{
-+      return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
-+}
-+EXPORT_SYMBOL(ssb_extif_gpio_polarity);
-+u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
-+{
-+      return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
-+}
-+EXPORT_SYMBOL(ssb_extif_gpio_intmask);
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h     2008-02-19 14:37:06.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h  2008-02-19 14:37:08.000000000 +0100
-@@ -382,11 +382,13 @@ extern void ssb_chipco_set_clockmode(str
- extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
-                                         u32 ticks);
-+/* Chipcommon GPIO pin access. */
- u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask);
--
--void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
--
--void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
-+u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
-+u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
-+u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value);
-+u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value);
-+u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value);
- #ifdef CONFIG_SSB_SERIAL
- extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h  2008-02-19 14:37:06.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h       2008-02-19 14:37:08.000000000 +0100
-@@ -171,11 +171,12 @@ extern void ssb_extif_get_clockcontrol(s
- extern void ssb_extif_timing_init(struct ssb_extif *extif,
-                                 unsigned long ns);
-+/* Extif GPIO pin access */
- u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
--
--void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
--
--void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
-+u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
-+u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
-+u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value);
-+u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value);
- #ifdef CONFIG_SSB_SERIAL
- extern int ssb_extif_serial_init(struct ssb_extif *extif,
index 7f28f34..d094b9b 100644 (file)
-Index: linux-2.6.23/arch/mips/Kconfig
-===================================================================
---- linux-2.6.23.orig/arch/mips/Kconfig        2007-10-13 02:23:06.662507926 +0200
-+++ linux-2.6.23/arch/mips/Kconfig     2007-10-13 02:23:41.484492317 +0200
-@@ -4,6 +4,10 @@
-       # Horrible source of confusion.  Die, die, die ...
-       select EMBEDDED
-+config CFE
-+      bool
-+      # Common Firmware Environment
-+
- mainmenu "Linux/MIPS Kernel Configuration"
- menu "Machine selection"
-@@ -44,6 +48,23 @@
-         note that a kernel built with this option selected will not be
-         able to run on normal units.
-+config BCM947XX
-+      bool "Support for BCM947xx based boards"
-+      select DMA_NONCOHERENT
-+      select HW_HAS_PCI
-+      select IRQ_CPU
-+      select SYS_HAS_CPU_MIPS32_R1
-+      select SYS_SUPPORTS_32BIT_KERNEL
-+      select SYS_SUPPORTS_LITTLE_ENDIAN
-+      select SSB
+Index: linux-2.6.25/arch/mips/Kconfig
+===================================================================
+--- linux-2.6.25.orig/arch/mips/Kconfig        2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/Kconfig     2008-04-26 22:08:17.000000000 +0100
+@@ -50,8 +50,10 @@ config BCM47XX
+       select SYS_SUPPORTS_32BIT_KERNEL
+       select SYS_SUPPORTS_LITTLE_ENDIAN
+       select SSB
 +      select SSB_SERIAL
 +      select SSB_SERIAL
+       select SSB_DRIVER_MIPS
+       select SSB_DRIVER_EXTIF
 +      select SSB_DRIVER_PCICORE
 +      select SSB_DRIVER_PCICORE
-+      select SSB_PCICORE_HOSTMODE
-+      select CFE
-+      select GENERIC_GPIO
-+      help
-+       Support for BCM947xx based boards
-+
- config MIPS_COBALT
-       bool "Cobalt Server"
-       select DMA_NONCOHERENT
-Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
-===================================================================
---- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c     2007-10-13 02:23:06.666508151 +0200
-+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c  2007-10-13 02:23:11.210767122 +0200
-@@ -793,6 +793,28 @@
- }
+       select SSB_PCICORE_HOSTMODE if PCI
+       select GENERIC_GPIO
+       select SYS_HAS_EARLY_PRINTK
+@@ -790,6 +792,7 @@ config CSRC_SB1250
  
  
+ config CFE
+       bool
++      # Common Firmware Environment
  
  
-+static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
-+{
-+      decode_config1(c);
-+      switch (c->processor_id & 0xff00) {
-+              case PRID_IMP_BCM3302:
-+                      c->cputype = CPU_BCM3302;
-+                      c->isa_level = MIPS_CPU_ISA_M32R1;
-+                      c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-+                                      MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
-+              break;
-+              case PRID_IMP_BCM4710:
-+                      c->cputype = CPU_BCM4710;
-+                      c->isa_level = MIPS_CPU_ISA_M32R1;
-+                      c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-+                                      MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
-+              break;
-+      default:
-+              c->cputype = CPU_UNKNOWN;
-+              break;
-+      }
-+}
-+
- __init void cpu_probe(void)
- {
-       struct cpuinfo_mips *c = &current_cpu_data;
-@@ -815,6 +837,9 @@
-       case PRID_COMP_SIBYTE:
-               cpu_probe_sibyte(c);
-               break;
-+      case PRID_COMP_BROADCOM:
-+              cpu_probe_broadcom(c);
-+              break;
-       case PRID_COMP_SANDCRAFT:
-               cpu_probe_sandcraft(c);
-               break;
-Index: linux-2.6.23/arch/mips/kernel/proc.c
-===================================================================
---- linux-2.6.23.orig/arch/mips/kernel/proc.c  2007-10-13 02:23:06.678508839 +0200
-+++ linux-2.6.23/arch/mips/kernel/proc.c       2007-10-13 02:23:11.210767122 +0200
-@@ -82,6 +82,8 @@
-       [CPU_VR4181]    = "NEC VR4181",
-       [CPU_VR4181A]   = "NEC VR4181A",
-       [CPU_SR71000]   = "Sandcraft SR71000",
-+      [CPU_BCM3302]   = "Broadcom BCM3302",
-+      [CPU_BCM4710]   = "Broadcom BCM4710",
-       [CPU_PR4450]    = "Philips PR4450",
-       [CPU_LOONGSON2] = "ICT Loongson-2",
- };
-Index: linux-2.6.23/arch/mips/Makefile
-===================================================================
---- linux-2.6.23.orig/arch/mips/Makefile       2007-10-13 02:23:06.682509066 +0200
-+++ linux-2.6.23/arch/mips/Makefile    2007-10-13 02:23:11.210767122 +0200
-@@ -533,6 +533,18 @@
- load-$(CONFIG_SIBYTE_BIGSUR)  := 0xffffffff80100000
- #
-+# Broadcom BCM47XX boards
-+#
-+core-$(CONFIG_BCM947XX)               += arch/mips/bcm947xx/
-+cflags-$(CONFIG_BCM947XX)     += -Iarch/mips/bcm947xx/include -Iinclude/asm-mips/mach-bcm947xx
-+load-$(CONFIG_BCM947XX)               := 0xffffffff80001000
-+
-+#
-+# Common Firmware Environment
-+#
-+core-$(CONFIG_CFE)            += arch/mips/cfe/
-+
-+#
- # SNI RM
- #
- core-$(CONFIG_SNI_RM)         += arch/mips/sni/
-Index: linux-2.6.23/arch/mips/mm/tlbex.c
-===================================================================
---- linux-2.6.23.orig/arch/mips/mm/tlbex.c     2007-10-13 02:23:06.694509748 +0200
-+++ linux-2.6.23/arch/mips/mm/tlbex.c  2007-10-13 02:26:00.272401391 +0200
-@@ -895,6 +895,8 @@
-       case CPU_AU1550:
-       case CPU_AU1200:
-       case CPU_PR4450:
-+      case CPU_BCM3302:
-+      case CPU_BCM4710:
-               i_nop(p);
-               tlbw(p);
-               break;
-Index: linux-2.6.23/drivers/Kconfig
-===================================================================
---- linux-2.6.23.orig/drivers/Kconfig  2007-10-13 02:23:06.702510206 +0200
-+++ linux-2.6.23/drivers/Kconfig       2007-10-13 02:23:11.214767346 +0200
-@@ -58,6 +58,8 @@
- source "drivers/hwmon/Kconfig"
-+source "drivers/ssb/Kconfig"
-+
- source "drivers/mfd/Kconfig"
- source "drivers/media/Kconfig"
-Index: linux-2.6.23/include/asm-mips/bootinfo.h
+ config DMA_COHERENT
+       bool
+Index: linux-2.6.25/include/asm-mips/bootinfo.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/bootinfo.h      2007-10-13 02:23:06.718511119 +0200
-+++ linux-2.6.23/include/asm-mips/bootinfo.h   2007-10-13 02:23:11.214767346 +0200
-@@ -208,6 +208,12 @@
- #define MACH_GROUP_WINDRIVER   28     /* Windriver boards */
- #define MACH_WRPPMC             1
+--- linux-2.6.25.orig/include/asm-mips/bootinfo.h      2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/bootinfo.h   2008-04-26 21:57:10.000000000 +0100
+@@ -94,6 +94,12 @@
+ #define MACH_MSP7120_FPGA       5     /* PMC-Sierra MSP7120 Emulation */
+ #define MACH_MSP_OTHER        255     /* PMC-Sierra unknown board type */
  
 +/*
 + * Valid machtype for group Broadcom
  
 +/*
 + * Valid machtype for group Broadcom
@@ -158,51 +37,12 @@ Index: linux-2.6.23/include/asm-mips/bootinfo.h
 +
  #define CL_SIZE                       COMMAND_LINE_SIZE
  
 +
  #define CL_SIZE                       COMMAND_LINE_SIZE
  
- const char *get_system_type(void);
-Index: linux-2.6.23/include/asm-mips/cpu.h
-===================================================================
---- linux-2.6.23.orig/include/asm-mips/cpu.h   2007-10-13 02:23:06.726511570 +0200
-+++ linux-2.6.23/include/asm-mips/cpu.h        2007-10-13 02:27:43.994312161 +0200
-@@ -106,6 +106,13 @@
- #define PRID_IMP_SR71000        0x0400
- /*
-+ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
-+ */
-+
-+#define PRID_IMP_BCM4710      0x4000
-+#define PRID_IMP_BCM3302      0x9000
-+
-+/*
-  * Definitions for 7:0 on legacy processors
-  */
-@@ -217,8 +224,10 @@
- #define CPU_R14000            64
- #define CPU_LOONGSON1           65
- #define CPU_LOONGSON2           66
-+#define CPU_BCM3302           67
-+#define CPU_BCM4710           68
--#define CPU_LAST              66
-+#define CPU_LAST              68
- /*
-  * ISA Level encodings
-Index: linux-2.6.23.1/drivers/Makefile
-===================================================================
---- linux-2.6.23.1.orig/drivers/Makefile       2008-01-27 04:34:31.000000000 +0100
-+++ linux-2.6.23.1/drivers/Makefile            2008-01-27 04:39:57.000000000 +0100
-@@ -89,3 +89,4 @@
- obj-$(CONFIG_PPC_PS3)         += ps3/
- obj-$(CONFIG_OF)              += of/
- obj-$(CONFIG_GPIO_DEVICE)     += gpio/
-+obj-$(CONFIG_SSB)             += ssb/
-Index: linux-2.6.23.1/include/linux/pci_ids.h
+ extern char *system_type;
+Index: linux-2.6.25/include/linux/pci_ids.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.1.orig/include/linux/pci_ids.h        2008-01-27 04:55:18.000000000 +0100
-+++ linux-2.6.23.1/include/linux/pci_ids.h     2008-01-27 04:55:22.000000000 +0100
-@@ -1972,6 +1972,7 @@
+--- linux-2.6.25.orig/include/linux/pci_ids.h  2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/linux/pci_ids.h       2008-04-26 21:57:10.000000000 +0100
+@@ -2000,6 +2000,7 @@
  #define PCI_DEVICE_ID_TIGON3_5906M    0x1713
  #define PCI_DEVICE_ID_BCM4401         0x4401
  #define PCI_DEVICE_ID_BCM4401B0               0x4402
  #define PCI_DEVICE_ID_TIGON3_5906M    0x1713
  #define PCI_DEVICE_ID_BCM4401         0x4401
  #define PCI_DEVICE_ID_BCM4401B0               0x4402
index 7dc05b6..11422b7 100644 (file)
@@ -1,25 +1,25 @@
-Index: linux-2.6.23/drivers/mtd/maps/Kconfig
+Index: linux-2.6.25/drivers/mtd/maps/Kconfig
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/drivers/mtd/maps/Kconfig 2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/drivers/mtd/maps/Kconfig      2007-10-13 02:28:13.644001805 +0200
-@@ -352,6 +352,12 @@
+--- linux-2.6.25.orig/drivers/mtd/maps/Kconfig 2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/drivers/mtd/maps/Kconfig      2008-04-26 21:57:12.000000000 +0100
+@@ -337,6 +337,12 @@ config MTD_CFI_FLAGADM
          Mapping for the Flaga digital module. If you don't have one, ignore
          this setting.
  
 +config MTD_BCM47XX
 +      tristate "BCM47xx flash device"
          Mapping for the Flaga digital module. If you don't have one, ignore
          this setting.
  
 +config MTD_BCM47XX
 +      tristate "BCM47xx flash device"
-+      depends on MIPS && MTD_CFI && BCM947XX
++      depends on MIPS && MTD_CFI && BCM47XX
 +      help
 +        Support for the flash chips on the BCM947xx board.
 +
  config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
 +      help
 +        Support for the flash chips on the BCM947xx board.
 +
  config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
-       depends on MTD_JEDECPROBE && WALNUT
-Index: linux-2.6.23/drivers/mtd/maps/Makefile
+       depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
+Index: linux-2.6.25/drivers/mtd/maps/Makefile
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/drivers/mtd/maps/Makefile        2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/drivers/mtd/maps/Makefile     2007-10-13 02:27:56.727037761 +0200
-@@ -33,6 +33,7 @@
+--- linux-2.6.25.orig/drivers/mtd/maps/Makefile        2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/drivers/mtd/maps/Makefile     2008-04-26 21:57:12.000000000 +0100
+@@ -31,6 +31,7 @@ obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcm
  obj-$(CONFIG_MTD_PCMCIA)      += pcmciamtd.o
  obj-$(CONFIG_MTD_RPXLITE)     += rpxlite.o
  obj-$(CONFIG_MTD_TQM8XXL)     += tqm8xxl.o
  obj-$(CONFIG_MTD_PCMCIA)      += pcmciamtd.o
  obj-$(CONFIG_MTD_RPXLITE)     += rpxlite.o
  obj-$(CONFIG_MTD_TQM8XXL)     += tqm8xxl.o
diff --git a/target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch b/target/linux/brcm47xx/patches-2.6.25/120-b44_ssb_support.patch
deleted file mode 100644 (file)
index 29125c6..0000000
+++ /dev/null
@@ -1,1544 +0,0 @@
-Index: linux-2.6.23.16/drivers/net/b44.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/net/b44.c     2008-02-19 01:35:58.000000000 +0100
-+++ linux-2.6.23.16/drivers/net/b44.c  2008-02-19 01:37:04.000000000 +0100
-@@ -1,7 +1,9 @@
--/* b44.c: Broadcom 4400 device driver.
-+/* b44.c: Broadcom 4400/47xx device driver.
-  *
-  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
-- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
-+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
-+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
-+ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
-  * Copyright (C) 2006 Broadcom Corporation.
-  *
-  * Distribute under GPL.
-@@ -21,11 +23,13 @@
- #include <linux/delay.h>
- #include <linux/init.h>
- #include <linux/dma-mapping.h>
-+#include <linux/ssb/ssb.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/irq.h>
-+
- #include "b44.h"
- #define DRV_MODULE_NAME               "b44"
-@@ -87,8 +91,8 @@
- static char version[] __devinitdata =
-       DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
--MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
--MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
-+MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
-+MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
- MODULE_LICENSE("GPL");
- MODULE_VERSION(DRV_MODULE_VERSION);
-@@ -96,18 +100,11 @@ static int b44_debug = -1;        /* -1 == use 
- module_param(b44_debug, int, 0);
- MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
--static struct pci_device_id b44_pci_tbl[] = {
--      { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
--        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
--      { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
--        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
--      { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
--        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
--      { }     /* terminate list with empty entry */
-+static struct ssb_device_id b44_ssb_tbl[] = {
-+      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
-+      SSB_DEVTABLE_END
- };
--MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
--
- static void b44_halt(struct b44 *);
- static void b44_init_rings(struct b44 *);
-@@ -119,6 +116,7 @@ static void b44_init_hw(struct b44 *, in
- static int dma_desc_align_mask;
- static int dma_desc_sync_size;
-+static int instance;
- static const char b44_gstrings[][ETH_GSTRING_LEN] = {
- #define _B44(x...)    # x,
-@@ -126,35 +124,24 @@ B44_STAT_REG_DECLARE
- #undef _B44
- };
--static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
--                                                dma_addr_t dma_base,
--                                                unsigned long offset,
--                                                enum dma_data_direction dir)
--{
--      dma_sync_single_range_for_device(&pdev->dev, dma_base,
--                                       offset & dma_desc_align_mask,
--                                       dma_desc_sync_size, dir);
--}
--
--static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
--                                             dma_addr_t dma_base,
--                                             unsigned long offset,
--                                             enum dma_data_direction dir)
--{
--      dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
--                                    offset & dma_desc_align_mask,
--                                    dma_desc_sync_size, dir);
--}
--
--static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
--{
--      return readl(bp->regs + reg);
--}
--
--static inline void bw32(const struct b44 *bp,
--                      unsigned long reg, unsigned long val)
--{
--      writel(val, bp->regs + reg);
-+static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
-+                                             dma_addr_t dma_base,
-+                                             unsigned long offset,
-+                                             enum dma_data_direction dir)
-+{
-+      dma_sync_single_range_for_device(sdev->dev, dma_base,
-+                                      offset & dma_desc_align_mask,
-+                                      dma_desc_sync_size, dir);
-+}
-+
-+static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
-+                                          dma_addr_t dma_base,
-+                                          unsigned long offset,
-+                                          enum dma_data_direction dir)
-+{
-+      dma_sync_single_range_for_cpu(sdev->dev, dma_base,
-+                                   offset & dma_desc_align_mask,
-+                                   dma_desc_sync_size, dir);
- }
- static int b44_wait_bit(struct b44 *bp, unsigned long reg,
-@@ -182,117 +169,29 @@ static int b44_wait_bit(struct b44 *bp, 
-       return 0;
- }
--/* Sonics SiliconBackplane support routines.  ROFL, you should see all the
-- * buzz words used on this company's website :-)
-- *
-- * All of these routines must be invoked with bp->lock held and
-- * interrupts disabled.
-- */
--
--#define SB_PCI_DMA             0x40000000      /* Client Mode PCI memory access space (1 GB) */
--#define BCM4400_PCI_CORE_ADDR  0x18002000      /* Address of PCI core on BCM4400 cards */
--
--static u32 ssb_get_core_rev(struct b44 *bp)
--{
--      return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
--}
--
--static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
--{
--      u32 bar_orig, pci_rev, val;
--
--      pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
--      pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
--      pci_rev = ssb_get_core_rev(bp);
--
--      val = br32(bp, B44_SBINTVEC);
--      val |= cores;
--      bw32(bp, B44_SBINTVEC, val);
--
--      val = br32(bp, SSB_PCI_TRANS_2);
--      val |= SSB_PCI_PREF | SSB_PCI_BURST;
--      bw32(bp, SSB_PCI_TRANS_2, val);
--
--      pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
--
--      return pci_rev;
--}
--
--static void ssb_core_disable(struct b44 *bp)
--{
--      if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
--              return;
--
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
--      b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
--      b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
--                          SBTMSLOW_REJECT | SBTMSLOW_RESET));
--      br32(bp, B44_SBTMSLOW);
--      udelay(1);
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
--      br32(bp, B44_SBTMSLOW);
--      udelay(1);
--}
--
--static void ssb_core_reset(struct b44 *bp)
-+static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
- {
-       u32 val;
--      ssb_core_disable(bp);
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
--      br32(bp, B44_SBTMSLOW);
--      udelay(1);
--
--      /* Clear SERR if set, this is a hw bug workaround.  */
--      if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
--              bw32(bp, B44_SBTMSHIGH, 0);
--
--      val = br32(bp, B44_SBIMSTATE);
--      if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
--              bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
--
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
--      br32(bp, B44_SBTMSLOW);
--      udelay(1);
-+      bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
-+                          (index << CAM_CTRL_INDEX_SHIFT)));
--      bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
--      br32(bp, B44_SBTMSLOW);
--      udelay(1);
--}
-+      b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
--static int ssb_core_unit(struct b44 *bp)
--{
--#if 0
--      u32 val = br32(bp, B44_SBADMATCH0);
--      u32 base;
-+      val = br32(bp, B44_CAM_DATA_LO);
--      type = val & SBADMATCH0_TYPE_MASK;
--      switch (type) {
--      case 0:
--              base = val & SBADMATCH0_BS0_MASK;
--              break;
-+      data[2] = (val >> 24) & 0xFF;
-+      data[3] = (val >> 16) & 0xFF;
-+      data[4] = (val >> 8) & 0xFF;
-+      data[5] = (val >> 0) & 0xFF;
--      case 1:
--              base = val & SBADMATCH0_BS1_MASK;
--              break;
-+      val = br32(bp, B44_CAM_DATA_HI);
--      case 2:
--      default:
--              base = val & SBADMATCH0_BS2_MASK;
--              break;
--      };
--#endif
--      return 0;
-+      data[0] = (val >> 8) & 0xFF;
-+      data[1] = (val >> 0) & 0xFF;
- }
--static int ssb_is_core_up(struct b44 *bp)
--{
--      return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
--              == SBTMSLOW_CLOCK);
--}
--
--static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
-+static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
- {
-       u32 val;
-@@ -328,14 +227,14 @@ static void b44_enable_ints(struct b44 *
-       bw32(bp, B44_IMASK, bp->imask);
- }
--static int b44_readphy(struct b44 *bp, int reg, u32 *val)
-+static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
- {
-       int err;
-       bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
-       bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
-                            (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
--                           (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
-+                           (phy_addr << MDIO_DATA_PMD_SHIFT) |
-                            (reg << MDIO_DATA_RA_SHIFT) |
-                            (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
-       err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
-@@ -344,18 +243,34 @@ static int b44_readphy(struct b44 *bp, i
-       return err;
- }
--static int b44_writephy(struct b44 *bp, int reg, u32 val)
-+static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
- {
-       bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
-       bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
-                            (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
--                           (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
-+                           (phy_addr << MDIO_DATA_PMD_SHIFT) |
-                            (reg << MDIO_DATA_RA_SHIFT) |
-                            (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
-                            (val & MDIO_DATA_DATA)));
-       return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
- }
-+static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
-+{
-+      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+              return 0;
-+
-+      return __b44_readphy(bp, bp->phy_addr, reg, val);
-+}
-+
-+static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
-+{
-+      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+              return 0;
-+
-+      return __b44_writephy(bp, bp->phy_addr, reg, val);
-+}
-+
- /* miilib interface */
- /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
-  * due to code existing before miilib use was added to this driver.
-@@ -384,6 +299,8 @@ static int b44_phy_reset(struct b44 *bp)
-       u32 val;
-       int err;
-+      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+              return 0;
-       err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
-       if (err)
-               return err;
-@@ -442,11 +359,27 @@ static void b44_set_flow_ctrl(struct b44
-       __b44_set_flow_ctrl(bp, pause_enab);
- }
-+
-+extern char *nvram_get(char *name); //FIXME: move elsewhere
- static int b44_setup_phy(struct b44 *bp)
- {
-       u32 val;
-       int err;
-+      /*
-+       * workaround for bad hardware design in Linksys WAP54G v1.0
-+       * see https://dev.openwrt.org/ticket/146
-+       * check and reset bit "isolate"
-+       */
-+      if ((atoi(nvram_get("boardnum")) == 2) &&
-+                      (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) &&
-+                      (val & BMCR_ISOLATE) &&
-+                      (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) {
-+              printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
-+      }
-+
-+      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
-+              return 0;
-       if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
-               goto out;
-       if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
-@@ -542,6 +475,19 @@ static void b44_check_phy(struct b44 *bp
- {
-       u32 bmsr, aux;
-+      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
-+              bp->flags |= B44_FLAG_100_BASE_T;
-+              bp->flags |= B44_FLAG_FULL_DUPLEX;
-+              if (!netif_carrier_ok(bp->dev)) {
-+                      u32 val = br32(bp, B44_TX_CTRL);
-+                      val |= TX_CTRL_DUPLEX;
-+                      bw32(bp, B44_TX_CTRL, val);
-+                      netif_carrier_on(bp->dev);
-+                      b44_link_report(bp);
-+              }
-+              return;
-+      }
-+
-       if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
-           !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
-           (bmsr != 0xffff)) {
-@@ -617,10 +563,10 @@ static void b44_tx(struct b44 *bp)
-               BUG_ON(skb == NULL);
--              pci_unmap_single(bp->pdev,
-+              dma_unmap_single(bp->sdev->dev,
-                                pci_unmap_addr(rp, mapping),
-                                skb->len,
--                               PCI_DMA_TODEVICE);
-+                               DMA_TO_DEVICE);
-               rp->skb = NULL;
-               dev_kfree_skb_irq(skb);
-       }
-@@ -657,9 +603,9 @@ static int b44_alloc_rx_skb(struct b44 *
-       if (skb == NULL)
-               return -ENOMEM;
--      mapping = pci_map_single(bp->pdev, skb->data,
-+      mapping = dma_map_single(bp->sdev->dev, skb->data,
-                                RX_PKT_BUF_SZ,
--                               PCI_DMA_FROMDEVICE);
-+                               DMA_FROM_DEVICE);
-       /* Hardware bug work-around, the chip is unable to do PCI DMA
-          to/from anything above 1GB :-( */
-@@ -667,18 +613,18 @@ static int b44_alloc_rx_skb(struct b44 *
-               mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
-               /* Sigh... */
-               if (!dma_mapping_error(mapping))
--                      pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
-+                      dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
-               dev_kfree_skb_any(skb);
-               skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
-               if (skb == NULL)
-                       return -ENOMEM;
--              mapping = pci_map_single(bp->pdev, skb->data,
-+              mapping = dma_map_single(bp->sdev->dev, skb->data,
-                                        RX_PKT_BUF_SZ,
--                                       PCI_DMA_FROMDEVICE);
-+                                       DMA_FROM_DEVICE);
-               if (dma_mapping_error(mapping) ||
-                       mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
--                              pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
-+                              dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
-                       dev_kfree_skb_any(skb);
-                       return -ENOMEM;
-               }
-@@ -705,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 *
-       dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
-       if (bp->flags & B44_FLAG_RX_RING_HACK)
--              b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
--                                           dest_idx * sizeof(dp),
--                                           DMA_BIDIRECTIONAL);
-+              b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
-+                                          dest_idx * sizeof(dp),
-+                                          DMA_BIDIRECTIONAL);
-       return RX_PKT_BUF_SZ;
- }
-@@ -734,9 +680,9 @@ static void b44_recycle_rx(struct b44 *b
-                          pci_unmap_addr(src_map, mapping));
-       if (bp->flags & B44_FLAG_RX_RING_HACK)
--              b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
--                                        src_idx * sizeof(src_desc),
--                                        DMA_BIDIRECTIONAL);
-+              b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
-+                                       src_idx * sizeof(src_desc),
-+                                       DMA_BIDIRECTIONAL);
-       ctrl = src_desc->ctrl;
-       if (dest_idx == (B44_RX_RING_SIZE - 1))
-@@ -750,13 +696,13 @@ static void b44_recycle_rx(struct b44 *b
-       src_map->skb = NULL;
-       if (bp->flags & B44_FLAG_RX_RING_HACK)
--              b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
--                                           dest_idx * sizeof(dest_desc),
--                                           DMA_BIDIRECTIONAL);
-+              b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
-+                                          dest_idx * sizeof(dest_desc),
-+                                          DMA_BIDIRECTIONAL);
--      pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr),
-+      dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr),
-                                      RX_PKT_BUF_SZ,
--                                     PCI_DMA_FROMDEVICE);
-+                                     DMA_FROM_DEVICE);
- }
- static int b44_rx(struct b44 *bp, int budget)
-@@ -776,9 +722,9 @@ static int b44_rx(struct b44 *bp, int bu
-               struct rx_header *rh;
-               u16 len;
--              pci_dma_sync_single_for_cpu(bp->pdev, map,
-+              dma_sync_single_for_cpu(bp->sdev->dev, map,
-                                           RX_PKT_BUF_SZ,
--                                          PCI_DMA_FROMDEVICE);
-+                                          DMA_FROM_DEVICE);
-               rh = (struct rx_header *) skb->data;
-               len = le16_to_cpu(rh->len);
-               if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
-@@ -810,8 +756,8 @@ static int b44_rx(struct b44 *bp, int bu
-                       skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
-                       if (skb_size < 0)
-                               goto drop_it;
--                      pci_unmap_single(bp->pdev, map,
--                                       skb_size, PCI_DMA_FROMDEVICE);
-+                      dma_unmap_single(bp->sdev->dev, map,
-+                                       skb_size, DMA_FROM_DEVICE);
-                       /* Leave out rx_header */
-                       skb_put(skb, len + RX_PKT_OFFSET);
-                       skb_pull(skb, RX_PKT_OFFSET);
-@@ -982,24 +928,24 @@ static int b44_start_xmit(struct sk_buff
-               goto err_out;
-       }
--      mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-+      mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
-       if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
-               struct sk_buff *bounce_skb;
-               /* Chip can't handle DMA to/from >1GB, use bounce buffer */
-               if (!dma_mapping_error(mapping))
--                      pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
-+                      dma_unmap_single(bp->sdev->dev, mapping, len, DMA_TO_DEVICE);
-               bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
-               if (!bounce_skb)
-                       goto err_out;
--              mapping = pci_map_single(bp->pdev, bounce_skb->data,
--                                       len, PCI_DMA_TODEVICE);
-+              mapping = dma_map_single(bp->sdev->dev, bounce_skb->data,
-+                                       len, DMA_TO_DEVICE);
-               if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
-                       if (!dma_mapping_error(mapping))
--                              pci_unmap_single(bp->pdev, mapping,
--                                               len, PCI_DMA_TODEVICE);
-+                              dma_unmap_single(bp->sdev->dev, mapping,
-+                                               len, DMA_TO_DEVICE);
-                       dev_kfree_skb_any(bounce_skb);
-                       goto err_out;
-               }
-@@ -1022,9 +968,9 @@ static int b44_start_xmit(struct sk_buff
-       bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
-       if (bp->flags & B44_FLAG_TX_RING_HACK)
--              b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
--                                           entry * sizeof(bp->tx_ring[0]),
--                                           DMA_TO_DEVICE);
-+              b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
-+                                          entry * sizeof(bp->tx_ring[0]),
-+                                          DMA_TO_DEVICE);
-       entry = NEXT_TX(entry);
-@@ -1097,10 +1043,10 @@ static void b44_free_rings(struct b44 *b
-               if (rp->skb == NULL)
-                       continue;
--              pci_unmap_single(bp->pdev,
-+              dma_unmap_single(bp->sdev->dev,
-                                pci_unmap_addr(rp, mapping),
-                                RX_PKT_BUF_SZ,
--                               PCI_DMA_FROMDEVICE);
-+                               DMA_FROM_DEVICE);
-               dev_kfree_skb_any(rp->skb);
-               rp->skb = NULL;
-       }
-@@ -1111,10 +1057,10 @@ static void b44_free_rings(struct b44 *b
-               if (rp->skb == NULL)
-                       continue;
--              pci_unmap_single(bp->pdev,
-+              dma_unmap_single(bp->sdev->dev,
-                                pci_unmap_addr(rp, mapping),
-                                rp->skb->len,
--                               PCI_DMA_TODEVICE);
-+                               DMA_TO_DEVICE);
-               dev_kfree_skb_any(rp->skb);
-               rp->skb = NULL;
-       }
-@@ -1136,14 +1082,14 @@ static void b44_init_rings(struct b44 *b
-       memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
-       if (bp->flags & B44_FLAG_RX_RING_HACK)
--              dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
--                                         DMA_TABLE_BYTES,
--                                         PCI_DMA_BIDIRECTIONAL);
-+              dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma,
-+                                        DMA_TABLE_BYTES,
-+                                        DMA_BIDIRECTIONAL);
-       if (bp->flags & B44_FLAG_TX_RING_HACK)
--              dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
--                                         DMA_TABLE_BYTES,
--                                         PCI_DMA_TODEVICE);
-+              dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
-+                                        DMA_TABLE_BYTES,
-+                                        DMA_TO_DEVICE);
-       for (i = 0; i < bp->rx_pending; i++) {
-               if (b44_alloc_rx_skb(bp, -1, i) < 0)
-@@ -1163,24 +1109,24 @@ static void b44_free_consistent(struct b
-       bp->tx_buffers = NULL;
-       if (bp->rx_ring) {
-               if (bp->flags & B44_FLAG_RX_RING_HACK) {
--                      dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
--                                       DMA_TABLE_BYTES,
--                                       DMA_BIDIRECTIONAL);
-+                      dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma,
-+                                      DMA_TABLE_BYTES,
-+                                      DMA_BIDIRECTIONAL);
-                       kfree(bp->rx_ring);
-               } else
--                      pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
-+                      dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
-                                           bp->rx_ring, bp->rx_ring_dma);
-               bp->rx_ring = NULL;
-               bp->flags &= ~B44_FLAG_RX_RING_HACK;
-       }
-       if (bp->tx_ring) {
-               if (bp->flags & B44_FLAG_TX_RING_HACK) {
--                      dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
--                                       DMA_TABLE_BYTES,
--                                       DMA_TO_DEVICE);
-+                      dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma,
-+                                      DMA_TABLE_BYTES,
-+                                      DMA_TO_DEVICE);
-                       kfree(bp->tx_ring);
-               } else
--                      pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
-+                      dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
-                                           bp->tx_ring, bp->tx_ring_dma);
-               bp->tx_ring = NULL;
-               bp->flags &= ~B44_FLAG_TX_RING_HACK;
-@@ -1206,7 +1152,7 @@ static int b44_alloc_consistent(struct b
-               goto out_err;
-       size = DMA_TABLE_BYTES;
--      bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
-+      bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, GFP_ATOMIC);
-       if (!bp->rx_ring) {
-               /* Allocation may have failed due to pci_alloc_consistent
-                  insisting on use of GFP_DMA, which is more restrictive
-@@ -1218,9 +1164,9 @@ static int b44_alloc_consistent(struct b
-               if (!rx_ring)
-                       goto out_err;
--              rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
--                                           DMA_TABLE_BYTES,
--                                           DMA_BIDIRECTIONAL);
-+              rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring,
-+                                          DMA_TABLE_BYTES,
-+                                          DMA_BIDIRECTIONAL);
-               if (dma_mapping_error(rx_ring_dma) ||
-                       rx_ring_dma + size > DMA_30BIT_MASK) {
-@@ -1233,9 +1179,9 @@ static int b44_alloc_consistent(struct b
-               bp->flags |= B44_FLAG_RX_RING_HACK;
-       }
--      bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
-+      bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, GFP_ATOMIC);
-       if (!bp->tx_ring) {
--              /* Allocation may have failed due to pci_alloc_consistent
-+              /* Allocation may have failed due to dma_alloc_coherent
-                  insisting on use of GFP_DMA, which is more restrictive
-                  than necessary...  */
-               struct dma_desc *tx_ring;
-@@ -1245,9 +1191,9 @@ static int b44_alloc_consistent(struct b
-               if (!tx_ring)
-                       goto out_err;
--              tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
--                                           DMA_TABLE_BYTES,
--                                           DMA_TO_DEVICE);
-+              tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring,
-+                                          DMA_TABLE_BYTES,
-+                                          DMA_TO_DEVICE);
-               if (dma_mapping_error(tx_ring_dma) ||
-                       tx_ring_dma + size > DMA_30BIT_MASK) {
-@@ -1282,7 +1228,9 @@ static void b44_clear_stats(struct b44 *
- /* bp->lock is held. */
- static void b44_chip_reset(struct b44 *bp)
- {
--      if (ssb_is_core_up(bp)) {
-+      struct ssb_device *sdev = bp->sdev;
-+
-+      if (ssb_device_is_enabled(bp->sdev)) {
-               bw32(bp, B44_RCV_LAZY, 0);
-               bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
-               b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
-@@ -1294,19 +1242,24 @@ static void b44_chip_reset(struct b44 *b
-               }
-               bw32(bp, B44_DMARX_CTRL, 0);
-               bp->rx_prod = bp->rx_cons = 0;
--      } else {
--              ssb_pci_setup(bp, (bp->core_unit == 0 ?
--                                 SBINTVEC_ENET0 :
--                                 SBINTVEC_ENET1));
-       }
--      ssb_core_reset(bp);
--
-+      ssb_device_enable(bp->sdev, 0);
-       b44_clear_stats(bp);
--      /* Make PHY accessible. */
--      bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-+      switch (sdev->bus->bustype) {
-+      case SSB_BUSTYPE_SSB:
-+                      bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-+                           (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
-+                           & MDIO_CTRL_MAXF_MASK)));
-+              break;
-+      case SSB_BUSTYPE_PCI:
-+      case SSB_BUSTYPE_PCMCIA:
-+              bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-                            (0x0d & MDIO_CTRL_MAXF_MASK)));
-+              break;
-+      }
-+
-       br32(bp, B44_MDIO_CTRL);
-       if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
-@@ -1349,6 +1302,7 @@ static int b44_set_mac_addr(struct net_d
- {
-       struct b44 *bp = netdev_priv(dev);
-       struct sockaddr *addr = p;
-+      u32 val;
-       if (netif_running(dev))
-               return -EBUSY;
-@@ -1359,7 +1313,11 @@ static int b44_set_mac_addr(struct net_d
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       spin_lock_irq(&bp->lock);
--      __b44_set_mac_addr(bp);
-+
-+      val = br32(bp, B44_RXCONFIG);
-+      if (!(val & RXCONFIG_CAM_ABSENT))
-+              __b44_set_mac_addr(bp);
-+
-       spin_unlock_irq(&bp->lock);
-       return 0;
-@@ -1445,18 +1403,6 @@ out:
-       return err;
- }
--#if 0
--/*static*/ void b44_dump_state(struct b44 *bp)
--{
--      u32 val32, val32_2, val32_3, val32_4, val32_5;
--      u16 val16;
--
--      pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
--      printk("DEBUG: PCI status [%04x] \n", val16);
--
--}
--#endif
--
- #ifdef CONFIG_NET_POLL_CONTROLLER
- /*
-  * Polling receive - used by netconsole and other diagnostic tools
-@@ -1570,7 +1516,6 @@ static void b44_setup_pseudo_magicp(stru
- static void b44_setup_wol(struct b44 *bp)
- {
-       u32 val;
--      u16 pmval;
-       bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
-@@ -1594,13 +1539,6 @@ static void b44_setup_wol(struct b44 *bp
-       } else {
-               b44_setup_pseudo_magicp(bp);
-       }
--
--      val = br32(bp, B44_SBTMSLOW);
--      bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
--
--      pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
--      pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
--
- }
- static int b44_close(struct net_device *dev)
-@@ -1700,7 +1638,7 @@ static void __b44_set_rx_mode(struct net
-       val = br32(bp, B44_RXCONFIG);
-       val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
--      if (dev->flags & IFF_PROMISC) {
-+      if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
-               val |= RXCONFIG_PROMISC;
-               bw32(bp, B44_RXCONFIG, val);
-       } else {
-@@ -1747,12 +1685,8 @@ static void b44_set_msglevel(struct net_
- static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
- {
--      struct b44 *bp = netdev_priv(dev);
--      struct pci_dev *pci_dev = bp->pdev;
--
-       strcpy (info->driver, DRV_MODULE_NAME);
-       strcpy (info->version, DRV_MODULE_VERSION);
--      strcpy (info->bus_info, pci_name(pci_dev));
- }
- static int b44_nway_reset(struct net_device *dev)
-@@ -2035,6 +1969,245 @@ static const struct ethtool_ops b44_etht
-       .get_ethtool_stats      = b44_get_ethtool_stats,
- };
-+static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
-+{
-+      struct b44 *bp = dev->priv;
-+      u32 ethcmd;
-+
-+      if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-+              return -EFAULT;
-+
-+      switch (ethcmd) {
-+      case ETHTOOL_GDRVINFO: {
-+              struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-+              strcpy (info.driver, DRV_MODULE_NAME);
-+              strcpy (info.version, DRV_MODULE_VERSION);
-+              memset(&info.fw_version, 0, sizeof(info.fw_version));
-+              info.eedump_len = 0;
-+              info.regdump_len = 0;
-+              if (copy_to_user (useraddr, &info, sizeof (info)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+
-+      case ETHTOOL_GSET: {
-+              struct ethtool_cmd cmd = { ETHTOOL_GSET };
-+
-+              if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
-+                      return -EAGAIN;
-+              cmd.supported = (SUPPORTED_Autoneg);
-+              cmd.supported |= (SUPPORTED_100baseT_Half |
-+                                SUPPORTED_100baseT_Full |
-+                                SUPPORTED_10baseT_Half |
-+                                SUPPORTED_10baseT_Full |
-+                                SUPPORTED_MII);
-+
-+              cmd.advertising = 0;
-+              if (bp->flags & B44_FLAG_ADV_10HALF)
-+                      cmd.advertising |= ADVERTISE_10HALF;
-+              if (bp->flags & B44_FLAG_ADV_10FULL)
-+                      cmd.advertising |= ADVERTISE_10FULL;
-+              if (bp->flags & B44_FLAG_ADV_100HALF)
-+                      cmd.advertising |= ADVERTISE_100HALF;
-+              if (bp->flags & B44_FLAG_ADV_100FULL)
-+                      cmd.advertising |= ADVERTISE_100FULL;
-+              cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
-+              cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
-+                      SPEED_100 : SPEED_10;
-+              cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
-+                      DUPLEX_FULL : DUPLEX_HALF;
-+              cmd.port = 0;
-+              cmd.phy_address = bp->phy_addr;
-+              cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
-+                      XCVR_INTERNAL : XCVR_EXTERNAL;
-+              cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
-+                      AUTONEG_DISABLE : AUTONEG_ENABLE;
-+              cmd.maxtxpkt = 0;
-+              cmd.maxrxpkt = 0;
-+              if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+      case ETHTOOL_SSET: {
-+              struct ethtool_cmd cmd;
-+
-+              if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
-+                      return -EAGAIN;
-+
-+              if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
-+                      return -EFAULT;
-+
-+              /* We do not support gigabit. */
-+              if (cmd.autoneg == AUTONEG_ENABLE) {
-+                      if (cmd.advertising &
-+                          (ADVERTISED_1000baseT_Half |
-+                           ADVERTISED_1000baseT_Full))
-+                              return -EINVAL;
-+              } else if ((cmd.speed != SPEED_100 &&
-+                          cmd.speed != SPEED_10) ||
-+                         (cmd.duplex != DUPLEX_HALF &&
-+                          cmd.duplex != DUPLEX_FULL)) {
-+                              return -EINVAL;
-+              }
-+
-+              spin_lock_irq(&bp->lock);
-+
-+              if (cmd.autoneg == AUTONEG_ENABLE) {
-+                      bp->flags &= ~B44_FLAG_FORCE_LINK;
-+                      bp->flags &= ~(B44_FLAG_ADV_10HALF |
-+                                     B44_FLAG_ADV_10FULL |
-+                                     B44_FLAG_ADV_100HALF |
-+                                     B44_FLAG_ADV_100FULL);
-+                      if (cmd.advertising & ADVERTISE_10HALF)
-+                              bp->flags |= B44_FLAG_ADV_10HALF;
-+                      if (cmd.advertising & ADVERTISE_10FULL)
-+                              bp->flags |= B44_FLAG_ADV_10FULL;
-+                      if (cmd.advertising & ADVERTISE_100HALF)
-+                              bp->flags |= B44_FLAG_ADV_100HALF;
-+                      if (cmd.advertising & ADVERTISE_100FULL)
-+                              bp->flags |= B44_FLAG_ADV_100FULL;
-+              } else {
-+                      bp->flags |= B44_FLAG_FORCE_LINK;
-+                      if (cmd.speed == SPEED_100)
-+                              bp->flags |= B44_FLAG_100_BASE_T;
-+                      if (cmd.duplex == DUPLEX_FULL)
-+                              bp->flags |= B44_FLAG_FULL_DUPLEX;
-+              }
-+
-+              b44_setup_phy(bp);
-+
-+              spin_unlock_irq(&bp->lock);
-+
-+              return 0;
-+      }
-+
-+      case ETHTOOL_GMSGLVL: {
-+              struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-+              edata.data = bp->msg_enable;
-+              if (copy_to_user(useraddr, &edata, sizeof(edata)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+      case ETHTOOL_SMSGLVL: {
-+              struct ethtool_value edata;
-+              if (copy_from_user(&edata, useraddr, sizeof(edata)))
-+                      return -EFAULT;
-+              bp->msg_enable = edata.data;
-+              return 0;
-+      }
-+      case ETHTOOL_NWAY_RST: {
-+              u32 bmcr;
-+              int r;
-+
-+              spin_lock_irq(&bp->lock);
-+              b44_readphy(bp, MII_BMCR, &bmcr);
-+              b44_readphy(bp, MII_BMCR, &bmcr);
-+              r = -EINVAL;
-+              if (bmcr & BMCR_ANENABLE) {
-+                      b44_writephy(bp, MII_BMCR,
-+                                   bmcr | BMCR_ANRESTART);
-+                      r = 0;
-+              }
-+              spin_unlock_irq(&bp->lock);
-+
-+              return r;
-+      }
-+      case ETHTOOL_GLINK: {
-+              struct ethtool_value edata = { ETHTOOL_GLINK };
-+              edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
-+              if (copy_to_user(useraddr, &edata, sizeof(edata)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+      case ETHTOOL_GRINGPARAM: {
-+              struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
-+
-+              ering.rx_max_pending = B44_RX_RING_SIZE - 1;
-+              ering.rx_pending = bp->rx_pending;
-+
-+              /* XXX ethtool lacks a tx_max_pending, oops... */
-+
-+              if (copy_to_user(useraddr, &ering, sizeof(ering)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+      case ETHTOOL_SRINGPARAM: {
-+              struct ethtool_ringparam ering;
-+
-+              if (copy_from_user(&ering, useraddr, sizeof(ering)))
-+                      return -EFAULT;
-+
-+              if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
-+                  (ering.rx_mini_pending != 0) ||
-+                  (ering.rx_jumbo_pending != 0) ||
-+                  (ering.tx_pending > B44_TX_RING_SIZE - 1))
-+                      return -EINVAL;
-+
-+              spin_lock_irq(&bp->lock);
-+
-+              bp->rx_pending = ering.rx_pending;
-+              bp->tx_pending = ering.tx_pending;
-+
-+              b44_halt(bp);
-+              b44_init_rings(bp);
-+              b44_init_hw(bp, 1);
-+              netif_wake_queue(bp->dev);
-+              spin_unlock_irq(&bp->lock);
-+
-+              b44_enable_ints(bp);
-+
-+              return 0;
-+      }
-+      case ETHTOOL_GPAUSEPARAM: {
-+              struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
-+
-+              epause.autoneg =
-+                      (bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
-+              epause.rx_pause =
-+                      (bp->flags & B44_FLAG_RX_PAUSE) != 0;
-+              epause.tx_pause =
-+                      (bp->flags & B44_FLAG_TX_PAUSE) != 0;
-+              if (copy_to_user(useraddr, &epause, sizeof(epause)))
-+                      return -EFAULT;
-+              return 0;
-+      }
-+      case ETHTOOL_SPAUSEPARAM: {
-+              struct ethtool_pauseparam epause;
-+
-+              if (copy_from_user(&epause, useraddr, sizeof(epause)))
-+                      return -EFAULT;
-+
-+              spin_lock_irq(&bp->lock);
-+              if (epause.autoneg)
-+                      bp->flags |= B44_FLAG_PAUSE_AUTO;
-+              else
-+                      bp->flags &= ~B44_FLAG_PAUSE_AUTO;
-+              if (epause.rx_pause)
-+                      bp->flags |= B44_FLAG_RX_PAUSE;
-+              else
-+                      bp->flags &= ~B44_FLAG_RX_PAUSE;
-+              if (epause.tx_pause)
-+                      bp->flags |= B44_FLAG_TX_PAUSE;
-+              else
-+                      bp->flags &= ~B44_FLAG_TX_PAUSE;
-+              if (bp->flags & B44_FLAG_PAUSE_AUTO) {
-+                      b44_halt(bp);
-+                      b44_init_rings(bp);
-+                      b44_init_hw(bp, 1);
-+              } else {
-+                      __b44_set_flow_ctrl(bp, bp->flags);
-+              }
-+              spin_unlock_irq(&bp->lock);
-+
-+              b44_enable_ints(bp);
-+
-+              return 0;
-+      }
-+      };
-+
-+      return -EOPNOTSUPP;
-+}
-+
- static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
- {
-       struct mii_ioctl_data *data = if_mii(ifr);
-@@ -2044,40 +2217,64 @@ static int b44_ioctl(struct net_device *
-       if (!netif_running(dev))
-               goto out;
--      spin_lock_irq(&bp->lock);
--      err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
--      spin_unlock_irq(&bp->lock);
--out:
--      return err;
--}
-+      switch (cmd) {
-+      case SIOCETHTOOL:
-+             return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data);
--/* Read 128-bytes of EEPROM. */
--static int b44_read_eeprom(struct b44 *bp, u8 *data)
--{
--      long i;
--      __le16 *ptr = (__le16 *) data;
-+      case SIOCGMIIPHY:
-+             data->phy_id = bp->phy_addr;
--      for (i = 0; i < 128; i += 2)
--              ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
-+             /* fallthru */
-+      case SIOCGMIIREG: {
-+             u32 mii_regval;
-+             spin_lock_irq(&bp->lock);
-+             err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
-+             spin_unlock_irq(&bp->lock);
--      return 0;
-+             data->val_out = mii_regval;
-+
-+             return err;
-+      }
-+
-+      case SIOCSMIIREG:
-+             if (!capable(CAP_NET_ADMIN))
-+                    return -EPERM;
-+
-+             spin_lock_irq(&bp->lock);
-+             err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-+             spin_unlock_irq(&bp->lock);
-+
-+             return err;
-+
-+      default:
-+             break;
-+      };
-+      return -EOPNOTSUPP;
-+
-+out:
-+      return err;
- }
- static int __devinit b44_get_invariants(struct b44 *bp)
- {
--      u8 eeprom[128];
--      int err;
-+      struct ssb_device *sdev = bp->sdev;
-+      int err = 0;
-+      u8 *addr;
--      err = b44_read_eeprom(bp, &eeprom[0]);
--      if (err)
--              goto out;
-+      bp->dma_offset = ssb_dma_translation(sdev);
--      bp->dev->dev_addr[0] = eeprom[79];
--      bp->dev->dev_addr[1] = eeprom[78];
--      bp->dev->dev_addr[2] = eeprom[81];
--      bp->dev->dev_addr[3] = eeprom[80];
--      bp->dev->dev_addr[4] = eeprom[83];
--      bp->dev->dev_addr[5] = eeprom[82];
-+      switch (instance) {
-+      case 1:
-+             addr = sdev->bus->sprom.et0mac;
-+             bp->phy_addr = sdev->bus->sprom.et0phyaddr;
-+             break;
-+      default:
-+             addr = sdev->bus->sprom.et1mac;
-+             bp->phy_addr = sdev->bus->sprom.et1phyaddr;
-+             break;
-+      }
-+
-+      memcpy(bp->dev->dev_addr, addr, 6);
-       if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
-               printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
-@@ -2086,103 +2283,52 @@ static int __devinit b44_get_invariants(
-       memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
--      bp->phy_addr = eeprom[90] & 0x1f;
--
-       bp->imask = IMASK_DEF;
--      bp->core_unit = ssb_core_unit(bp);
--      bp->dma_offset = SB_PCI_DMA;
--
-       /* XXX - really required?
-          bp->flags |= B44_FLAG_BUGGY_TXPTR;
-          */
--      if (ssb_get_core_rev(bp) >= 7)
-+      if (bp->sdev->id.revision >= 7)
-               bp->flags |= B44_FLAG_B0_ANDLATER;
--out:
-       return err;
- }
--static int __devinit b44_init_one(struct pci_dev *pdev,
--                                const struct pci_device_id *ent)
-+static int __devinit b44_init_one(struct ssb_device *sdev,
-+                                const struct ssb_device_id *ent)
- {
-       static int b44_version_printed = 0;
--      unsigned long b44reg_base, b44reg_len;
-       struct net_device *dev;
-       struct b44 *bp;
-       int err, i;
-+      instance++;
-+
-       if (b44_version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
--      err = pci_enable_device(pdev);
--      if (err) {
--              dev_err(&pdev->dev, "Cannot enable PCI device, "
--                     "aborting.\n");
--              return err;
--      }
--
--      if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
--              dev_err(&pdev->dev,
--                      "Cannot find proper PCI device "
--                     "base address, aborting.\n");
--              err = -ENODEV;
--              goto err_out_disable_pdev;
--      }
--
--      err = pci_request_regions(pdev, DRV_MODULE_NAME);
--      if (err) {
--              dev_err(&pdev->dev,
--                      "Cannot obtain PCI resources, aborting.\n");
--              goto err_out_disable_pdev;
--      }
--
--      pci_set_master(pdev);
--
--      err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK);
--      if (err) {
--              dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
--              goto err_out_free_res;
--      }
--
--      err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK);
--      if (err) {
--              dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
--              goto err_out_free_res;
--      }
--
--      b44reg_base = pci_resource_start(pdev, 0);
--      b44reg_len = pci_resource_len(pdev, 0);
--
-       dev = alloc_etherdev(sizeof(*bp));
-       if (!dev) {
--              dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
-+              dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
-               err = -ENOMEM;
--              goto err_out_free_res;
-+              goto out;
-       }
-       SET_MODULE_OWNER(dev);
--      SET_NETDEV_DEV(dev,&pdev->dev);
-+      SET_NETDEV_DEV(dev,sdev->dev);
-       /* No interesting netdevice features in this card... */
-       dev->features |= 0;
-       bp = netdev_priv(dev);
--      bp->pdev = pdev;
-+      bp->sdev = sdev;
-       bp->dev = dev;
-       bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
-       spin_lock_init(&bp->lock);
--      bp->regs = ioremap(b44reg_base, b44reg_len);
--      if (bp->regs == 0UL) {
--              dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
--              err = -ENOMEM;
--              goto err_out_free_dev;
--      }
--
-       bp->rx_pending = B44_DEF_RX_RING_PENDING;
-       bp->tx_pending = B44_DEF_TX_RING_PENDING;
-@@ -2201,16 +2347,16 @@ static int __devinit b44_init_one(struct
-       dev->poll_controller = b44_poll_controller;
- #endif
-       dev->change_mtu = b44_change_mtu;
--      dev->irq = pdev->irq;
-+      dev->irq = sdev->irq;
-       SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
-       netif_carrier_off(dev);
-       err = b44_get_invariants(bp);
-       if (err) {
--              dev_err(&pdev->dev,
-+              dev_err(sdev->dev,
-                       "Problem fetching invariants of chip, aborting.\n");
--              goto err_out_iounmap;
-+              goto err_out_free_dev;
-       }
-       bp->mii_if.dev = dev;
-@@ -2229,61 +2375,52 @@ static int __devinit b44_init_one(struct
-       err = register_netdev(dev);
-       if (err) {
--              dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
--              goto err_out_iounmap;
-+              dev_err(sdev->dev, "Cannot register net device, aborting.\n");
-+              goto out;
-       }
--      pci_set_drvdata(pdev, dev);
--
--      pci_save_state(bp->pdev);
-+      ssb_set_drvdata(sdev, dev);
-       /* Chip reset provides power to the b44 MAC & PCI cores, which
-        * is necessary for MAC register access.
-        */
-       b44_chip_reset(bp);
--      printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
-+      printk(KERN_INFO "%s: Broadcom 10/100BaseT Ethernet ", dev->name);
-       for (i = 0; i < 6; i++)
-               printk("%2.2x%c", dev->dev_addr[i],
-                      i == 5 ? '\n' : ':');
--      return 0;
-+      /* Initialize phy */
-+      spin_lock_irq(&bp->lock);
-+      b44_chip_reset(bp);
-+      spin_unlock_irq(&bp->lock);
--err_out_iounmap:
--      iounmap(bp->regs);
-+      return 0;
- err_out_free_dev:
-       free_netdev(dev);
--err_out_free_res:
--      pci_release_regions(pdev);
--
--err_out_disable_pdev:
--      pci_disable_device(pdev);
--      pci_set_drvdata(pdev, NULL);
-+out:
-       return err;
- }
--static void __devexit b44_remove_one(struct pci_dev *pdev)
-+static void __devexit b44_remove_one(struct ssb_device *pdev)
- {
--      struct net_device *dev = pci_get_drvdata(pdev);
--      struct b44 *bp = netdev_priv(dev);
-+      struct net_device *dev = ssb_get_drvdata(pdev);
-       unregister_netdev(dev);
--      iounmap(bp->regs);
-       free_netdev(dev);
--      pci_release_regions(pdev);
--      pci_disable_device(pdev);
--      pci_set_drvdata(pdev, NULL);
-+      ssb_set_drvdata(pdev, NULL);
- }
--static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
-+static int b44_suspend(struct ssb_device *pdev, pm_message_t state)
- {
--      struct net_device *dev = pci_get_drvdata(pdev);
-+      struct net_device *dev = ssb_get_drvdata(pdev);
-       struct b44 *bp = netdev_priv(dev);
-         if (!netif_running(dev))
--                 return 0;
-+              return 0;
-       del_timer_sync(&bp->timer);
-@@ -2301,33 +2438,22 @@ static int b44_suspend(struct pci_dev *p
-               b44_init_hw(bp, B44_PARTIAL_RESET);
-               b44_setup_wol(bp);
-       }
--      pci_disable_device(pdev);
-+
-       return 0;
- }
--static int b44_resume(struct pci_dev *pdev)
-+static int b44_resume(struct ssb_device *pdev)
- {
--      struct net_device *dev = pci_get_drvdata(pdev);
-+      struct net_device *dev = ssb_get_drvdata(pdev);
-       struct b44 *bp = netdev_priv(dev);
-       int rc = 0;
--      pci_restore_state(pdev);
--      rc = pci_enable_device(pdev);
--      if (rc) {
--              printk(KERN_ERR PFX "%s: pci_enable_device failed\n",
--                      dev->name);
--              return rc;
--      }
--
--      pci_set_master(pdev);
--
-       if (!netif_running(dev))
-               return 0;
-       rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
-       if (rc) {
-               printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
--              pci_disable_device(pdev);
-               return rc;
-       }
-@@ -2346,29 +2472,31 @@ static int b44_resume(struct pci_dev *pd
-       return 0;
- }
--static struct pci_driver b44_driver = {
-+static struct ssb_driver b44_driver = {
-       .name           = DRV_MODULE_NAME,
--      .id_table       = b44_pci_tbl,
-+      .id_table       = b44_ssb_tbl,
-       .probe          = b44_init_one,
-       .remove         = __devexit_p(b44_remove_one),
--        .suspend        = b44_suspend,
--        .resume         = b44_resume,
-+      .suspend        = b44_suspend,
-+      .resume         = b44_resume,
- };
- static int __init b44_init(void)
- {
-       unsigned int dma_desc_align_size = dma_get_cache_alignment();
-+      instance = 0;
-+
-       /* Setup paramaters for syncing RX/TX DMA descriptors */
-       dma_desc_align_mask = ~(dma_desc_align_size - 1);
-       dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
--      return pci_register_driver(&b44_driver);
-+      return ssb_driver_register(&b44_driver);
- }
- static void __exit b44_cleanup(void)
- {
--      pci_unregister_driver(&b44_driver);
-+      ssb_driver_unregister(&b44_driver);
- }
- module_init(b44_init);
-Index: linux-2.6.23.16/drivers/net/b44.h
-===================================================================
---- linux-2.6.23.16.orig/drivers/net/b44.h     2008-02-19 01:35:58.000000000 +0100
-+++ linux-2.6.23.16/drivers/net/b44.h  2008-02-19 01:36:00.000000000 +0100
-@@ -129,6 +129,7 @@
- #define  RXCONFIG_FLOW                0x00000020 /* Flow Control Enable */
- #define  RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
- #define  RXCONFIG_RFILT               0x00000080 /* Reject Filter */
-+#define  RXCONFIG_CAM_ABSENT  0x00000100 /* CAM Absent */
- #define B44_RXMAXLEN  0x0404UL /* EMAC RX Max Packet Length */
- #define B44_TXMAXLEN  0x0408UL /* EMAC TX Max Packet Length */
- #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
-@@ -227,75 +228,9 @@
- #define B44_RX_PAUSE  0x05D4UL /* MIB RX Pause Packets */
- #define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
--/* Silicon backplane register definitions */
--#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
--#define  SBIMSTATE_PC         0x0000000f /* Pipe Count */
--#define  SBIMSTATE_AP_MASK    0x00000030 /* Arbitration Priority */
--#define  SBIMSTATE_AP_BOTH    0x00000000 /* Use both timeslices and token */
--#define  SBIMSTATE_AP_TS      0x00000010 /* Use timeslices only */
--#define  SBIMSTATE_AP_TK      0x00000020 /* Use token only */
--#define  SBIMSTATE_AP_RSV     0x00000030 /* Reserved */
--#define  SBIMSTATE_IBE                0x00020000 /* In Band Error */
--#define  SBIMSTATE_TO         0x00040000 /* Timeout */
--#define B44_SBINTVEC  0x0F94UL /* SB Interrupt Mask */
--#define  SBINTVEC_PCI         0x00000001 /* Enable interrupts for PCI */
--#define  SBINTVEC_ENET0               0x00000002 /* Enable interrupts for enet 0 */
--#define  SBINTVEC_ILINE20     0x00000004 /* Enable interrupts for iline20 */
--#define  SBINTVEC_CODEC               0x00000008 /* Enable interrupts for v90 codec */
--#define  SBINTVEC_USB         0x00000010 /* Enable interrupts for usb */
--#define  SBINTVEC_EXTIF               0x00000020 /* Enable interrupts for external i/f */
--#define  SBINTVEC_ENET1               0x00000040 /* Enable interrupts for enet 1 */
--#define B44_SBTMSLOW  0x0F98UL /* SB Target State Low */
--#define  SBTMSLOW_RESET               0x00000001 /* Reset */
--#define  SBTMSLOW_REJECT      0x00000002 /* Reject */
--#define  SBTMSLOW_CLOCK               0x00010000 /* Clock Enable */
--#define  SBTMSLOW_FGC         0x00020000 /* Force Gated Clocks On */
--#define  SBTMSLOW_PE          0x40000000 /* Power Management Enable */
--#define  SBTMSLOW_BE          0x80000000 /* BIST Enable */
--#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
--#define  SBTMSHIGH_SERR               0x00000001 /* S-error */
--#define  SBTMSHIGH_INT                0x00000002 /* Interrupt */
--#define  SBTMSHIGH_BUSY               0x00000004 /* Busy */
--#define  SBTMSHIGH_GCR                0x20000000 /* Gated Clock Request */
--#define  SBTMSHIGH_BISTF      0x40000000 /* BIST Failed */
--#define  SBTMSHIGH_BISTD      0x80000000 /* BIST Done */
--#define B44_SBIDHIGH  0x0FFCUL /* SB Identification High */
--#define  SBIDHIGH_RC_MASK     0x0000000f /* Revision Code */
--#define  SBIDHIGH_CC_MASK     0x0000fff0 /* Core Code */
--#define  SBIDHIGH_CC_SHIFT    4
--#define  SBIDHIGH_VC_MASK     0xffff0000 /* Vendor Code */
--#define  SBIDHIGH_VC_SHIFT    16
--
--/* SSB PCI config space registers.  */
--#define SSB_PMCSR             0x44
--#define  SSB_PE                       0x100
--#define       SSB_BAR0_WIN            0x80
--#define       SSB_BAR1_WIN            0x84
--#define       SSB_SPROM_CONTROL       0x88
--#define       SSB_BAR1_CONTROL        0x8c
--
--/* SSB core and host control registers.  */
--#define SSB_CONTROL           0x0000UL
--#define SSB_ARBCONTROL                0x0010UL
--#define SSB_ISTAT             0x0020UL
--#define SSB_IMASK             0x0024UL
--#define SSB_MBOX              0x0028UL
--#define SSB_BCAST_ADDR                0x0050UL
--#define SSB_BCAST_DATA                0x0054UL
--#define SSB_PCI_TRANS_0               0x0100UL
--#define SSB_PCI_TRANS_1               0x0104UL
--#define SSB_PCI_TRANS_2               0x0108UL
--#define SSB_SPROM             0x0800UL
--
--#define SSB_PCI_MEM           0x00000000
--#define SSB_PCI_IO            0x00000001
--#define SSB_PCI_CFG0          0x00000002
--#define SSB_PCI_CFG1          0x00000003
--#define SSB_PCI_PREF          0x00000004
--#define SSB_PCI_BURST         0x00000008
--#define SSB_PCI_MASK0         0xfc000000
--#define SSB_PCI_MASK1         0xfc000000
--#define SSB_PCI_MASK2         0xc0000000
-+#define br32(bp, REG) ssb_read32((bp)->sdev, (REG))
-+#define bw32(bp, REG, VAL)    ssb_write32((bp)->sdev, (REG), (VAL))
-+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
- /* 4400 PHY registers */
- #define B44_MII_AUXCTRL               24      /* Auxiliary Control */
-@@ -346,10 +281,12 @@ struct rx_header {
- struct ring_info {
-       struct sk_buff          *skb;
--      DECLARE_PCI_UNMAP_ADDR(mapping);
-+      dma_addr_t      mapping;
- };
- #define B44_MCAST_TABLE_SIZE  32
-+#define B44_PHY_ADDR_NO_PHY   30
-+#define B44_MDC_RATIO         5000000
- #define       B44_STAT_REG_DECLARE            \
-       _B44(tx_good_octets)            \
-@@ -425,9 +362,10 @@ struct b44 {
-       u32                     dma_offset;
-       u32                     flags;
--#define B44_FLAG_B0_ANDLATER  0x00000001
-+#define B44_FLAG_INIT_COMPLETE        0x00000001
- #define B44_FLAG_BUGGY_TXPTR  0x00000002
- #define B44_FLAG_REORDER_BUG  0x00000004
-+#define B44_FLAG_B0_ANDLATER    0x00000008
- #define B44_FLAG_PAUSE_AUTO   0x00008000
- #define B44_FLAG_FULL_DUPLEX  0x00010000
- #define B44_FLAG_100_BASE_T   0x00020000
-@@ -450,8 +388,7 @@ struct b44 {
-       struct net_device_stats stats;
-       struct b44_hw_stats     hw_stats;
--      void __iomem            *regs;
--      struct pci_dev          *pdev;
-+      struct ssb_device       *sdev;
-       struct net_device       *dev;
-       dma_addr_t              rx_ring_dma, tx_ring_dma;
-Index: linux-2.6.23.16/drivers/net/Kconfig
-===================================================================
---- linux-2.6.23.16.orig/drivers/net/Kconfig   2008-02-19 01:35:58.000000000 +0100
-+++ linux-2.6.23.16/drivers/net/Kconfig        2008-02-19 01:36:00.000000000 +0100
-@@ -1577,7 +1577,7 @@ config APRICOT
- config B44
-       tristate "Broadcom 4400 ethernet support"
--      depends on NET_PCI && PCI
-+      depends on SSB && EXPERIMENTAL
-       select MII
-       help
-         If you have a network (Ethernet) controller of this type, say Y and
diff --git a/target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch b/target/linux/brcm47xx/patches-2.6.25/121-fix_b44_phyaddr.patch
deleted file mode 100644 (file)
index c93d517..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-Index: linux-2.6.23.16/drivers/net/b44.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/net/b44.c     2008-03-22 19:52:40.000000000 -0700
-+++ linux-2.6.23.16/drivers/net/b44.c  2008-03-22 19:52:41.000000000 -0700
-@@ -2273,6 +2273,10 @@
-              bp->phy_addr = sdev->bus->sprom.et1phyaddr;
-              break;
-       }
-+      /* Some ROMs have buggy PHY addresses with the high
-+       * bits set (sign extension?). Truncate them to a
-+       * valid PHY address. */
-+      bp->phy_addr &= 0x1F;
-       memcpy(bp->dev->dev_addr, addr, 6);
index eea4e26..ae66ab7 100644 (file)
@@ -1,8 +1,8 @@
-Index: linux-2.6.23/arch/mips/Kconfig
+Index: linux-2.6.25/arch/mips/Kconfig
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/Kconfig        2007-10-13 02:23:41.484492317 +0200
-+++ linux-2.6.23/arch/mips/Kconfig     2007-10-13 02:47:02.784347843 +0200
-@@ -192,7 +192,6 @@
+--- linux-2.6.25.orig/arch/mips/Kconfig        2008-04-26 21:57:10.000000000 +0100
++++ linux-2.6.25/arch/mips/Kconfig     2008-04-26 21:57:13.000000000 +0100
+@@ -228,7 +228,6 @@ config MIPS_MALTA
        select I8259
        select MIPS_BOARDS_GEN
        select MIPS_BONITO64
        select I8259
        select MIPS_BOARDS_GEN
        select MIPS_BONITO64
@@ -10,7 +10,7 @@ Index: linux-2.6.23/arch/mips/Kconfig
        select PCI_GT64XXX_PCI0
        select MIPS_MSC
        select SWAP_IO_SPACE
        select PCI_GT64XXX_PCI0
        select MIPS_MSC
        select SWAP_IO_SPACE
-@@ -1281,13 +1280,6 @@
+@@ -1421,13 +1420,6 @@ config IP22_CPU_SCACHE
        bool
        select BOARD_SCACHE
  
        bool
        select BOARD_SCACHE
  
@@ -24,11 +24,11 @@ Index: linux-2.6.23/arch/mips/Kconfig
  config R5000_CPU_SCACHE
        bool
        select BOARD_SCACHE
  config R5000_CPU_SCACHE
        bool
        select BOARD_SCACHE
-Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
+Index: linux-2.6.25/arch/mips/kernel/cpu-probe.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c     2007-10-13 02:23:11.210767122 +0200
-+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c  2007-10-13 02:47:02.788348072 +0200
-@@ -701,6 +701,8 @@
+--- linux-2.6.25.orig/arch/mips/kernel/cpu-probe.c     2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/kernel/cpu-probe.c  2008-04-26 21:57:13.000000000 +0100
+@@ -704,6 +704,8 @@ static inline void cpu_probe_mips(struct
                break;
        case PRID_IMP_25KF:
                c->cputype = CPU_25KF;
                break;
        case PRID_IMP_25KF:
                c->cputype = CPU_25KF;
@@ -37,19 +37,19 @@ Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
                break;
        case PRID_IMP_34K:
                c->cputype = CPU_34K;
                break;
        case PRID_IMP_34K:
                c->cputype = CPU_34K;
-Index: linux-2.6.23/arch/mips/mm/c-r4k.c
+Index: linux-2.6.25/arch/mips/mm/c-r4k.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/c-r4k.c     2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/arch/mips/mm/c-r4k.c  2007-10-13 02:47:02.792348301 +0200
-@@ -1086,7 +1086,6 @@
+--- linux-2.6.25.orig/arch/mips/mm/c-r4k.c     2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/c-r4k.c  2008-04-26 22:08:15.000000000 +0100
+@@ -1103,7 +1103,6 @@ static void __init loongson2_sc_init(voi
  
  extern int r5k_sc_init(void);
  extern int rm7k_sc_init(void);
 -extern int mips_sc_init(void);
  
  
  extern int r5k_sc_init(void);
  extern int rm7k_sc_init(void);
 -extern int mips_sc_init(void);
  
- static void __init setup_scache(void)
+ static void __cpuinit setup_scache(void)
  {
  {
-@@ -1140,29 +1139,17 @@
+@@ -1157,29 +1156,17 @@ static void __cpuinit setup_scache(void)
  #endif
  
        default:
  #endif
  
        default:
@@ -84,11 +84,11 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        /* compute a couple of other cache variables */
        c->scache.waysize = scache_size / c->scache.ways;
  
        /* compute a couple of other cache variables */
        c->scache.waysize = scache_size / c->scache.ways;
  
-Index: linux-2.6.23/arch/mips/mm/Makefile
+Index: linux-2.6.25/arch/mips/mm/Makefile
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/Makefile    2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/arch/mips/mm/Makefile 2007-10-13 02:47:23.393522295 +0200
-@@ -31,6 +31,5 @@
+--- linux-2.6.25.orig/arch/mips/mm/Makefile    2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/Makefile 2008-04-26 21:57:13.000000000 +0100
+@@ -32,6 +32,5 @@ obj-$(CONFIG_CPU_VR41XX)     += c-r4k.o cex-
  obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
  obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
  obj-$(CONFIG_RM7000_CPU_SCACHE)       += sc-rm7k.o
  obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
  obj-$(CONFIG_R5000_CPU_SCACHE)  += sc-r5k.o
  obj-$(CONFIG_RM7000_CPU_SCACHE)       += sc-rm7k.o
index d19ba81..a5f9a88 100644 (file)
@@ -1,23 +1,23 @@
-Index: linux-2.6.23/arch/mips/kernel/genex.S
+Index: linux-2.6.25/arch/mips/kernel/genex.S
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/kernel/genex.S 2007-10-13 11:29:46.219648163 +0200
-+++ linux-2.6.23/arch/mips/kernel/genex.S      2007-10-13 11:29:49.619841933 +0200
-@@ -51,6 +51,10 @@
+--- linux-2.6.25.orig/arch/mips/kernel/genex.S 2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/kernel/genex.S      2008-04-26 21:57:14.000000000 +0100
+@@ -51,6 +51,10 @@ NESTED(except_vec1_generic, 0, sp)
  NESTED(except_vec3_generic, 0, sp)
        .set    push
        .set    noat
  NESTED(except_vec3_generic, 0, sp)
        .set    push
        .set    noat
-+#ifdef CONFIG_BCM947XX
++#ifdef CONFIG_BCM47XX
 +      nop
 +      nop
 +#endif
  #if R5432_CP0_INTERRUPT_WAR
        mfc0    k0, CP0_INDEX
  #endif
 +      nop
 +      nop
 +#endif
  #if R5432_CP0_INTERRUPT_WAR
        mfc0    k0, CP0_INDEX
  #endif
-Index: linux-2.6.23/arch/mips/mm/c-r4k.c
+Index: linux-2.6.25/arch/mips/mm/c-r4k.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/c-r4k.c     2007-10-13 11:29:46.227648623 +0200
-+++ linux-2.6.23/arch/mips/mm/c-r4k.c  2007-10-13 11:29:49.619841933 +0200
-@@ -30,6 +30,9 @@
+--- linux-2.6.25.orig/arch/mips/mm/c-r4k.c     2008-04-26 21:57:13.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/c-r4k.c  2008-04-26 21:57:14.000000000 +0100
+@@ -33,6 +33,9 @@
  #include <asm/cacheflush.h> /* for run_uncached() */
  
  
  #include <asm/cacheflush.h> /* for run_uncached() */
  
  
@@ -27,7 +27,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
  /*
   * Special Variant of smp_call_function for use by cache functions:
   *
  /*
   * Special Variant of smp_call_function for use by cache functions:
   *
-@@ -94,6 +97,9 @@
+@@ -97,6 +100,9 @@ static void __cpuinit r4k_blast_dcache_p
  {
        unsigned long  dc_lsize = cpu_dcache_line_size();
  
  {
        unsigned long  dc_lsize = cpu_dcache_line_size();
  
@@ -37,7 +37,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        if (dc_lsize == 0)
                r4k_blast_dcache_page = (void *)cache_noop;
        else if (dc_lsize == 16)
        if (dc_lsize == 0)
                r4k_blast_dcache_page = (void *)cache_noop;
        else if (dc_lsize == 16)
-@@ -108,6 +114,9 @@
+@@ -111,6 +117,9 @@ static void __cpuinit r4k_blast_dcache_p
  {
        unsigned long dc_lsize = cpu_dcache_line_size();
  
  {
        unsigned long dc_lsize = cpu_dcache_line_size();
  
@@ -47,7 +47,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        if (dc_lsize == 0)
                r4k_blast_dcache_page_indexed = (void *)cache_noop;
        else if (dc_lsize == 16)
        if (dc_lsize == 0)
                r4k_blast_dcache_page_indexed = (void *)cache_noop;
        else if (dc_lsize == 16)
-@@ -122,6 +131,9 @@
+@@ -125,6 +134,9 @@ static void __cpuinit r4k_blast_dcache_s
  {
        unsigned long dc_lsize = cpu_dcache_line_size();
  
  {
        unsigned long dc_lsize = cpu_dcache_line_size();
  
@@ -57,7 +57,7 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        if (dc_lsize == 0)
                r4k_blast_dcache = (void *)cache_noop;
        else if (dc_lsize == 16)
        if (dc_lsize == 0)
                r4k_blast_dcache = (void *)cache_noop;
        else if (dc_lsize == 16)
-@@ -623,6 +635,8 @@
+@@ -630,6 +642,8 @@ static void local_r4k_flush_cache_sigtra
        unsigned long addr = (unsigned long) arg;
  
        R4600_HIT_CACHEOP_WAR_IMPL;
        unsigned long addr = (unsigned long) arg;
  
        R4600_HIT_CACHEOP_WAR_IMPL;
@@ -66,10 +66,10 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        if (dc_lsize)
                protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
        if (!cpu_icache_snoops_remote_store && scache_size)
        if (dc_lsize)
                protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
        if (!cpu_icache_snoops_remote_store && scache_size)
-@@ -1198,6 +1212,17 @@
+@@ -1215,6 +1229,17 @@ static void __cpuinit coherency_setup(vo
         * silly idea of putting something else there ...
         */
         * silly idea of putting something else there ...
         */
-       switch (current_cpu_data.cputype) {
+       switch (current_cpu_type()) {
 +      case CPU_BCM3302:
 +              {
 +                      u32 cm;
 +      case CPU_BCM3302:
 +              {
 +                      u32 cm;
@@ -84,12 +84,12 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        case CPU_R4000PC:
        case CPU_R4000SC:
        case CPU_R4000MC:
        case CPU_R4000PC:
        case CPU_R4000SC:
        case CPU_R4000MC:
-@@ -1228,6 +1253,15 @@
-       /* Default cache error handler for R4000 and R5000 family */
-       set_uncached_handler (0x100, &except_vec2_generic, 0x80);
+@@ -1254,6 +1279,15 @@ void __cpuinit r4k_cache_init(void)
+               break;
+       }
  
 +      /* Check if special workarounds are required */
  
 +      /* Check if special workarounds are required */
-+#ifdef CONFIG_BCM947XX
++#ifdef CONFIG_BCM47XX
 +      if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
 +              printk("Enabling BCM4710A0 cache workarounds.\n");
 +              bcm4710 = 1;
 +      if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
 +              printk("Enabling BCM4710A0 cache workarounds.\n");
 +              bcm4710 = 1;
@@ -100,11 +100,11 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        probe_pcache();
        setup_scache();
  
        probe_pcache();
        setup_scache();
  
-@@ -1273,5 +1307,13 @@
+@@ -1303,5 +1337,13 @@ void __cpuinit r4k_cache_init(void)
        build_clear_page();
        build_copy_page();
        local_r4k___flush_cache_all(NULL);
        build_clear_page();
        build_copy_page();
        local_r4k___flush_cache_all(NULL);
-+#ifdef CONFIG_BCM947XX
++#ifdef CONFIG_BCM47XX
 +      {
 +              static void (*_coherency_setup)(void);
 +              _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
 +      {
 +              static void (*_coherency_setup)(void);
 +              _coherency_setup = (void (*)(void)) KSEG1ADDR(coherency_setup);
@@ -114,39 +114,39 @@ Index: linux-2.6.23/arch/mips/mm/c-r4k.c
        coherency_setup();
 +#endif
  }
        coherency_setup();
 +#endif
  }
-Index: linux-2.6.23/arch/mips/mm/tlbex.c
+Index: linux-2.6.25/arch/mips/mm/tlbex.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/tlbex.c     2007-10-13 11:29:46.235649074 +0200
-+++ linux-2.6.23/arch/mips/mm/tlbex.c  2007-10-13 11:35:46.076155216 +0200
-@@ -1273,6 +1273,9 @@
-               /* No need for i_nop */
+--- linux-2.6.25.orig/arch/mips/mm/tlbex.c     2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/tlbex.c  2008-04-26 21:57:14.000000000 +0100
+@@ -677,6 +677,9 @@ static void __cpuinit build_r4000_tlb_re
+               /* No need for uasm_i_nop */
        }
  
        }
  
-+#ifdef CONFIG_BCM947XX
-+      i_nop(&p);
++#ifdef CONFIG_BCM47XX
++      uasm_i_nop(&p);
 +#endif
  #ifdef CONFIG_64BIT
        build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
  #else
 +#endif
  #ifdef CONFIG_64BIT
        build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
  #else
-@@ -1708,6 +1711,9 @@
-                                  struct reloc **r, unsigned int pte,
+@@ -1084,6 +1087,9 @@ build_r4000_tlbchange_handler_head(u32 *
+                                  struct uasm_reloc **r, unsigned int pte,
                                   unsigned int ptr)
  {
                                   unsigned int ptr)
  {
-+#ifdef CONFIG_BCM947XX
-+      i_nop(p);
++#ifdef CONFIG_BCM47XX
++      uasm_i_nop(p);
 +#endif
  #ifdef CONFIG_64BIT
        build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
  #else
 +#endif
  #ifdef CONFIG_64BIT
        build_get_pmde64(p, l, r, pte, ptr); /* get pmd in ptr */
  #else
-Index: linux-2.6.23/include/asm-mips/r4kcache.h
+Index: linux-2.6.25/include/asm-mips/r4kcache.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/r4kcache.h      2007-10-13 11:29:46.255650214 +0200
-+++ linux-2.6.23/include/asm-mips/r4kcache.h   2007-10-13 11:29:49.631842613 +0200
+--- linux-2.6.25.orig/include/asm-mips/r4kcache.h      2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/r4kcache.h   2008-04-26 21:57:14.000000000 +0100
 @@ -17,6 +17,20 @@
  #include <asm/cpu-features.h>
  #include <asm/mipsmtregs.h>
  
 @@ -17,6 +17,20 @@
  #include <asm/cpu-features.h>
  #include <asm/mipsmtregs.h>
  
-+#ifdef CONFIG_BCM947XX
++#ifdef CONFIG_BCM47XX
 +#include <asm/paccess.h>
 +#include <linux/ssb/ssb.h>
 +#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
 +#include <asm/paccess.h>
 +#include <linux/ssb/ssb.h>
 +#define BCM4710_DUMMY_RREG() ((void) *((u8 *) KSEG1ADDR(SSB_ENUM_BASE + SSB_IMSTATE)))
@@ -163,7 +163,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
  /*
   * This macro return a properly sign-extended address suitable as base address
   * for indexed cache operations.  Two issues here:
  /*
   * This macro return a properly sign-extended address suitable as base address
   * for indexed cache operations.  Two issues here:
-@@ -150,6 +164,7 @@
+@@ -150,6 +164,7 @@ static inline void flush_icache_line_ind
  static inline void flush_dcache_line_indexed(unsigned long addr)
  {
        __dflush_prologue
  static inline void flush_dcache_line_indexed(unsigned long addr)
  {
        __dflush_prologue
@@ -171,7 +171,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        cache_op(Index_Writeback_Inv_D, addr);
        __dflush_epilogue
  }
        cache_op(Index_Writeback_Inv_D, addr);
        __dflush_epilogue
  }
-@@ -169,6 +184,7 @@
+@@ -169,6 +184,7 @@ static inline void flush_icache_line(uns
  static inline void flush_dcache_line(unsigned long addr)
  {
        __dflush_prologue
  static inline void flush_dcache_line(unsigned long addr)
  {
        __dflush_prologue
@@ -179,7 +179,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        cache_op(Hit_Writeback_Inv_D, addr);
        __dflush_epilogue
  }
        cache_op(Hit_Writeback_Inv_D, addr);
        __dflush_epilogue
  }
-@@ -176,6 +192,7 @@
+@@ -176,6 +192,7 @@ static inline void flush_dcache_line(uns
  static inline void invalidate_dcache_line(unsigned long addr)
  {
        __dflush_prologue
  static inline void invalidate_dcache_line(unsigned long addr)
  {
        __dflush_prologue
@@ -187,7 +187,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        cache_op(Hit_Invalidate_D, addr);
        __dflush_epilogue
  }
        cache_op(Hit_Invalidate_D, addr);
        __dflush_epilogue
  }
-@@ -208,6 +225,7 @@
+@@ -208,6 +225,7 @@ static inline void flush_scache_line(uns
   */
  static inline void protected_flush_icache_line(unsigned long addr)
  {
   */
  static inline void protected_flush_icache_line(unsigned long addr)
  {
@@ -195,7 +195,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        protected_cache_op(Hit_Invalidate_I, addr);
  }
  
        protected_cache_op(Hit_Invalidate_I, addr);
  }
  
-@@ -219,6 +237,7 @@
+@@ -219,6 +237,7 @@ static inline void protected_flush_icach
   */
  static inline void protected_writeback_dcache_line(unsigned long addr)
  {
   */
  static inline void protected_writeback_dcache_line(unsigned long addr)
  {
@@ -203,7 +203,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        protected_cache_op(Hit_Writeback_Inv_D, addr);
  }
  
        protected_cache_op(Hit_Writeback_Inv_D, addr);
  }
  
-@@ -339,8 +358,52 @@
+@@ -339,8 +358,52 @@ static inline void invalidate_tcache_pag
                : "r" (base),                                           \
                  "i" (op));
  
                : "r" (base),                                           \
                  "i" (op));
  
@@ -257,23 +257,23 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
  static inline void blast_##pfx##cache##lsize(void)                    \
  {                                                                     \
        unsigned long start = INDEX_BASE;                               \
  static inline void blast_##pfx##cache##lsize(void)                    \
  {                                                                     \
        unsigned long start = INDEX_BASE;                               \
-@@ -352,6 +415,7 @@
+@@ -352,6 +415,7 @@ static inline void blast_##pfx##cache##l
                                                                        \
        __##pfx##flush_prologue                                         \
                                                                        \
 +      war                                                             \
        for (ws = 0; ws < ws_end; ws += ws_inc)                         \
                for (addr = start; addr < end; addr += lsize * 32)      \
                                                                        \
        __##pfx##flush_prologue                                         \
                                                                        \
 +      war                                                             \
        for (ws = 0; ws < ws_end; ws += ws_inc)                         \
                for (addr = start; addr < end; addr += lsize * 32)      \
-                       cache##lsize##_unroll32(addr|ws,indexop);       \
-@@ -366,6 +430,7 @@
+                       cache##lsize##_unroll32(addr|ws, indexop);      \
+@@ -366,6 +430,7 @@ static inline void blast_##pfx##cache##l
                                                                        \
        __##pfx##flush_prologue                                         \
                                                                        \
 +      war                                                             \
        do {                                                            \
                                                                        \
        __##pfx##flush_prologue                                         \
                                                                        \
 +      war                                                             \
        do {                                                            \
-               cache##lsize##_unroll32(start,hitop);                   \
+               cache##lsize##_unroll32(start, hitop);                  \
                start += lsize * 32;                                    \
                start += lsize * 32;                                    \
-@@ -384,6 +449,8 @@
+@@ -384,6 +449,8 @@ static inline void blast_##pfx##cache##l
                               current_cpu_data.desc.waybit;            \
        unsigned long ws, addr;                                         \
                                                                        \
                               current_cpu_data.desc.waybit;            \
        unsigned long ws, addr;                                         \
                                                                        \
@@ -282,7 +282,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
        __##pfx##flush_prologue                                         \
                                                                        \
        for (ws = 0; ws < ws_end; ws += ws_inc)                         \
        __##pfx##flush_prologue                                         \
                                                                        \
        for (ws = 0; ws < ws_end; ws += ws_inc)                         \
-@@ -393,28 +460,30 @@
+@@ -393,35 +460,37 @@ static inline void blast_##pfx##cache##l
        __##pfx##flush_epilogue                                         \
  }
  
        __##pfx##flush_epilogue                                         \
  }
  
@@ -295,6 +295,13 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
 -__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)
 -__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)
+-
+-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16)
+-__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32)
+-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16)
+-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32)
+-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64)
+-__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128)
 +__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, BCM4710_FILL_TLB(start);)
 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
 +__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, BCM4710_FILL_TLB(start);)
 +__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
@@ -304,6 +311,13 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
 +__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, )
 +__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
 +__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, )
++
++__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 16, )
++__BUILD_BLAST_CACHE(inv_d, dcache, Index_Writeback_Inv_D, Hit_Invalidate_D, 32, )
++__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 16, )
++__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 32, )
++__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 64, )
++__BUILD_BLAST_CACHE(inv_s, scache, Index_Writeback_Inv_SD, Hit_Invalidate_SD, 128, )
  
  /* build blast_xxx_range, protected_blast_xxx_range */
 -#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
  
  /* build blast_xxx_range, protected_blast_xxx_range */
 -#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
@@ -323,7 +337,7 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
                prot##cache_op(hitop, addr);                            \
                if (addr == aend)                                       \
                        break;                                          \
                prot##cache_op(hitop, addr);                            \
                if (addr == aend)                                       \
                        break;                                          \
-@@ -424,13 +493,13 @@
+@@ -431,13 +500,13 @@ static inline void prot##blast_##pfx##ca
        __##pfx##flush_epilogue                                         \
  }
  
        __##pfx##flush_epilogue                                         \
  }
  
@@ -344,15 +358,15 @@ Index: linux-2.6.23/include/asm-mips/r4kcache.h
 +__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
  
  #endif /* _ASM_R4KCACHE_H */
 +__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD,,, )
  
  #endif /* _ASM_R4KCACHE_H */
-Index: linux-2.6.23/include/asm-mips/stackframe.h
+Index: linux-2.6.25/include/asm-mips/stackframe.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/stackframe.h    2007-10-13 11:29:46.263650671 +0200
-+++ linux-2.6.23/include/asm-mips/stackframe.h 2007-10-13 11:33:38.504885346 +0200
-@@ -350,6 +350,10 @@
+--- linux-2.6.25.orig/include/asm-mips/stackframe.h    2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/stackframe.h 2008-04-26 21:57:14.000000000 +0100
+@@ -359,6 +359,10 @@
                .macro  RESTORE_SP_AND_RET
                LONG_L  sp, PT_R29(sp)
                .set    mips3
                .macro  RESTORE_SP_AND_RET
                LONG_L  sp, PT_R29(sp)
                .set    mips3
-+#ifdef CONFIG_BCM947XX
++#ifdef CONFIG_BCM47XX
 +              nop
 +              nop
 +#endif
 +              nop
 +              nop
 +#endif
index 8a3bd0e..1b50bb3 100644 (file)
@@ -1,38 +1,38 @@
-Index: linux-2.6.23/arch/mips/mm/init.c
+Index: linux-2.6.25/arch/mips/mm/init.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/init.c      2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/arch/mips/mm/init.c   2007-10-13 02:57:18.483434538 +0200
-@@ -211,7 +211,7 @@
+--- linux-2.6.25.orig/arch/mips/mm/init.c      2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/init.c   2008-04-26 22:07:48.000000000 +0100
+@@ -211,7 +211,7 @@ void copy_user_highpage(struct page *to,
        void *vfrom, *vto;
  
        vto = kmap_atomic(to, KM_USER1);
        void *vfrom, *vto;
  
        vto = kmap_atomic(to, KM_USER1);
--      if (cpu_has_dc_aliases && !Page_dcache_dirty(from)) {
-+      if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) {
+-      if (cpu_has_dc_aliases &&
++      if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
+           page_mapped(from) && !Page_dcache_dirty(from)) {
                vfrom = kmap_coherent(from, vaddr);
                copy_page(vto, vfrom);
                vfrom = kmap_coherent(from, vaddr);
                copy_page(vto, vfrom);
-               kunmap_coherent();
-@@ -234,7 +234,7 @@
+@@ -235,7 +235,7 @@ void copy_to_user_page(struct vm_area_st
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
  {
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
  {
--      if (cpu_has_dc_aliases) {
-+      if (cpu_has_dc_aliases && cpu_use_kmap_coherent) {
+-      if (cpu_has_dc_aliases &&
++      if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
+           page_mapped(page) && !Page_dcache_dirty(page)) {
                void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
                memcpy(vto, src, len);
                void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
                memcpy(vto, src, len);
-               kunmap_coherent();
-@@ -250,7 +250,7 @@
+@@ -255,7 +255,7 @@ void copy_from_user_page(struct vm_area_
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
  {
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
  {
--      if (cpu_has_dc_aliases) {
-+      if (cpu_has_dc_aliases && cpu_use_kmap_coherent) {
-               void *vfrom =
-                       kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
+-      if (cpu_has_dc_aliases &&
++      if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
+           page_mapped(page) && !Page_dcache_dirty(page)) {
+               void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
                memcpy(dst, vfrom, len);
                memcpy(dst, vfrom, len);
-Index: linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h
+Index: linux-2.6.25/include/asm-mips/mach-bcm47xx/cpu-feature-overrides.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h        2007-10-13 02:56:22.020216880 +0200
++++ linux-2.6.25/include/asm-mips/mach-bcm47xx/cpu-feature-overrides.h 2008-04-26 21:57:15.000000000 +0100
 @@ -0,0 +1,13 @@
 +/*
 + * This file is subject to the terms and conditions of the GNU General Public
 @@ -0,0 +1,13 @@
 +/*
 + * This file is subject to the terms and conditions of the GNU General Public
@@ -41,16 +41,16 @@ Index: linux-2.6.23/include/asm-mips/mach-bcm947xx/cpu-feature-overrides.h
 + *
 + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
 + */
 + *
 + * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
 + */
-+#ifndef __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H
-+#define __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H
++#ifndef __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
++#define __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
 +
 +#define cpu_use_kmap_coherent 0
 +
 +
 +#define cpu_use_kmap_coherent 0
 +
-+#endif /* __ASM_MACH_BCM947XX_CPU_FEATURE_OVERRIDES_H */
-Index: linux-2.6.23/include/asm-mips/cpu-features.h
++#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */
+Index: linux-2.6.25/include/asm-mips/cpu-features.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/cpu-features.h  2007-10-09 22:31:38.000000000 +0200
-+++ linux-2.6.23/include/asm-mips/cpu-features.h       2007-10-13 02:56:22.028217337 +0200
+--- linux-2.6.25.orig/include/asm-mips/cpu-features.h  2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/cpu-features.h       2008-04-26 21:57:15.000000000 +0100
 @@ -101,6 +101,9 @@
  #ifndef cpu_has_pindexed_dcache
  #define cpu_has_pindexed_dcache       (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
 @@ -101,6 +101,9 @@
  #ifndef cpu_has_pindexed_dcache
  #define cpu_has_pindexed_dcache       (cpu_data[0].dcache.flags & MIPS_CACHE_PINDEX)
diff --git a/target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch b/target/linux/brcm47xx/patches-2.6.25/170-cpu_wait.patch
deleted file mode 100644 (file)
index 62b3b12..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Index: linux-2.6.23/arch/mips/kernel/cpu-probe.c
-===================================================================
---- linux-2.6.23.orig/arch/mips/kernel/cpu-probe.c     2007-10-13 02:47:02.788348072 +0200
-+++ linux-2.6.23/arch/mips/kernel/cpu-probe.c  2007-10-13 02:57:46.293019312 +0200
-@@ -159,6 +159,7 @@
-       case CPU_5KC:
-       case CPU_25KF:
-       case CPU_PR4450:
-+      case CPU_BCM3302:
-               cpu_wait = r4k_wait;
-               break;
index 53818ab..2e1f77c 100644 (file)
@@ -1,7 +1,7 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
+Index: linux-2.6.25/drivers/ssb/driver_chipcommon.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c       2008-02-19 13:46:08.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c    2008-02-19 13:46:17.000000000 +0100
+--- linux-2.6.25.orig/drivers/ssb/driver_chipcommon.c  2008-04-27 21:36:52.000000000 +0100
++++ linux-2.6.25/drivers/ssb/driver_chipcommon.c       2008-04-27 21:43:50.000000000 +0100
 @@ -270,6 +270,8 @@ void ssb_chipco_resume(struct ssb_chipco
  void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
                               u32 *plltype, u32 *n, u32 *m)
 @@ -270,6 +270,8 @@ void ssb_chipco_resume(struct ssb_chipco
  void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
                               u32 *plltype, u32 *n, u32 *m)
@@ -20,11 +20,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
        *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
        *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
        switch (*plltype) {
        *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
        *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
        switch (*plltype) {
-Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
+Index: linux-2.6.25/drivers/ssb/driver_mipscore.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-02-19 13:46:08.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c      2008-02-19 13:46:17.000000000 +0100
-@@ -160,6 +160,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
+--- linux-2.6.25.orig/drivers/ssb/driver_mipscore.c    2008-04-17 03:49:44.000000000 +0100
++++ linux-2.6.25/drivers/ssb/driver_mipscore.c 2008-04-27 21:43:50.000000000 +0100
+@@ -161,6 +161,8 @@ u32 ssb_cpu_clock(struct ssb_mipscore *m
  
        if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
                rate = 200000000;
  
        if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
                rate = 200000000;
@@ -33,11 +33,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
        } else {
                rate = ssb_calc_clock_rate(pll_type, n, m);
        }
        } else {
                rate = ssb_calc_clock_rate(pll_type, n, m);
        }
-Index: linux-2.6.23.16/drivers/ssb/main.c
+Index: linux-2.6.25/drivers/ssb/main.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-19 13:46:08.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 13:46:17.000000000 +0100
-@@ -862,6 +862,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
+--- linux-2.6.25.orig/drivers/ssb/main.c       2008-04-17 03:49:44.000000000 +0100
++++ linux-2.6.25/drivers/ssb/main.c    2008-04-27 21:43:50.000000000 +0100
+@@ -867,6 +867,8 @@ u32 ssb_clockspeed(struct ssb_bus *bus)
  
        if (bus->chip_id == 0x5365) {
                rate = 100000000;
  
        if (bus->chip_id == 0x5365) {
                rate = 100000000;
diff --git a/target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch b/target/linux/brcm47xx/patches-2.6.25/230-ohci-ssb.patch
deleted file mode 100644 (file)
index 5be1a66..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-From: Michael Buesch <mb@bu3sch.de>
-Date: Wed, 10 Oct 2007 06:47:17 +0000 (-0700)
-Subject: USB: ohci SSB bus glue
-X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=c604e851486eabcbeb73e984279d436ce121fd5d
-
-USB: ohci SSB bus glue
-
-This adds SSB bus glue for the USB OHCI HCD.
-
-Signed-off-by: Michael Buesch <mb@bu3sch.de>
-Signed-off-by: John W. Linville <linville@tuxdriver.com>
-Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
----
-
-Index: linux-2.6.23.16/drivers/usb/host/Kconfig
-===================================================================
---- linux-2.6.23.16.orig/drivers/usb/host/Kconfig      2008-02-19 00:47:29.000000000 +0100
-+++ linux-2.6.23.16/drivers/usb/host/Kconfig   2008-02-19 00:47:51.000000000 +0100
-@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
-         Enables support for PCI-bus plug-in USB controller cards.
-         If unsure, say Y.
-+config USB_OHCI_HCD_SSB
-+      bool "OHCI support for Broadcom SSB OHCI core"
-+      depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
-+      default n
-+      ---help---
-+        Support for the Sonics Silicon Backplane (SSB) attached
-+        Broadcom USB OHCI core.
-+
-+        This device is present in some embedded devices with
-+        Broadcom based SSB bus.
-+
-+        If unsure, say N.
-+
- config USB_OHCI_BIG_ENDIAN_DESC
-       bool
-       depends on USB_OHCI_HCD
-Index: linux-2.6.23.16/drivers/usb/host/ohci-hcd.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/usb/host/ohci-hcd.c   2008-02-19 00:47:29.000000000 +0100
-+++ linux-2.6.23.16/drivers/usb/host/ohci-hcd.c        2008-02-19 00:47:51.000000000 +0100
-@@ -926,11 +926,17 @@ MODULE_LICENSE ("GPL");
- #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
- #endif
-+#ifdef CONFIG_USB_OHCI_HCD_SSB
-+#include "ohci-ssb.c"
-+#define SSB_OHCI_DRIVER               ssb_ohci_driver
-+#endif
-+
- #if   !defined(PCI_DRIVER) &&         \
-       !defined(PLATFORM_DRIVER) &&    \
-       !defined(OF_PLATFORM_DRIVER) && \
-       !defined(SA1111_DRIVER) &&      \
--      !defined(PS3_SYSTEM_BUS_DRIVER)
-+      !defined(PS3_SYSTEM_BUS_DRIVER) && \
-+      !defined(SSB_OHCI_DRIVER)
- #error "missing bus glue for ohci-hcd"
- #endif
-@@ -975,10 +981,20 @@ static int __init ohci_hcd_mod_init(void
-               goto error_pci;
- #endif
-+#ifdef SSB_OHCI_DRIVER
-+      retval = ssb_driver_register(&SSB_OHCI_DRIVER);
-+      if (retval)
-+              goto error_ssb;
-+#endif
-+
-       return retval;
-       /* Error path */
-+#ifdef SSB_OHCI_DRIVER
-+ error_ssb:
-+#endif
- #ifdef PCI_DRIVER
-+      pci_unregister_driver(&PCI_DRIVER);
-  error_pci:
- #endif
- #ifdef SA1111_DRIVER
-@@ -1003,6 +1019,9 @@ module_init(ohci_hcd_mod_init);
- static void __exit ohci_hcd_mod_exit(void)
- {
-+#ifdef SSB_OHCI_DRIVER
-+      ssb_driver_unregister(&SSB_OHCI_DRIVER);
-+#endif
- #ifdef PCI_DRIVER
-       pci_unregister_driver(&PCI_DRIVER);
- #endif
-Index: linux-2.6.23.16/drivers/usb/host/ohci-ssb.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23.16/drivers/usb/host/ohci-ssb.c        2008-02-19 00:47:51.000000000 +0100
-@@ -0,0 +1,247 @@
-+/*
-+ * Sonics Silicon Backplane
-+ * Broadcom USB-core OHCI driver
-+ *
-+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
-+ *
-+ * Derived from the OHCI-PCI driver
-+ * Copyright 1999 Roman Weissgaerber
-+ * Copyright 2000-2002 David Brownell
-+ * Copyright 1999 Linus Torvalds
-+ * Copyright 1999 Gregory P. Smith
-+ *
-+ * Derived from the USBcore related parts of Broadcom-SB
-+ * Copyright 2005 Broadcom Corporation
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+#include <linux/ssb/ssb.h>
-+
-+
-+#define SSB_OHCI_TMSLOW_HOSTMODE      (1 << 29)
-+
-+struct ssb_ohci_device {
-+      struct ohci_hcd ohci; /* _must_ be at the beginning. */
-+
-+      u32 enable_flags;
-+};
-+
-+static inline
-+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
-+{
-+      return (struct ssb_ohci_device *)(hcd->hcd_priv);
-+}
-+
-+
-+static int ssb_ohci_reset(struct usb_hcd *hcd)
-+{
-+      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-+      struct ohci_hcd *ohci = &ohcidev->ohci;
-+      int err;
-+
-+      ohci_hcd_init(ohci);
-+      err = ohci_init(ohci);
-+
-+      return err;
-+}
-+
-+static int ssb_ohci_start(struct usb_hcd *hcd)
-+{
-+      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-+      struct ohci_hcd *ohci = &ohcidev->ohci;
-+      int err;
-+
-+      err = ohci_run(ohci);
-+      if (err < 0) {
-+              ohci_err(ohci, "can't start\n");
-+              ohci_stop(hcd);
-+      }
-+
-+      return err;
-+}
-+
-+#ifdef CONFIG_PM
-+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
-+{
-+      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-+      struct ohci_hcd *ohci = &ohcidev->ohci;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&ohci->lock, flags);
-+
-+      ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-+      ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
-+
-+      /* make sure snapshot being resumed re-enumerates everything */
-+      if (message.event == PM_EVENT_PRETHAW)
-+              ohci_usb_reset(ohci);
-+
-+      clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-+
-+      spin_unlock_irqrestore(&ohci->lock, flags);
-+      return 0;
-+}
-+
-+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
-+{
-+      set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-+      usb_hcd_resume_root_hub(hcd);
-+      return 0;
-+}
-+#endif /* CONFIG_PM */
-+
-+static const struct hc_driver ssb_ohci_hc_driver = {
-+      .description            = "ssb-usb-ohci",
-+      .product_desc           = "SSB OHCI Controller",
-+      .hcd_priv_size          = sizeof(struct ssb_ohci_device),
-+
-+      .irq                    = ohci_irq,
-+      .flags                  = HCD_MEMORY | HCD_USB11,
-+
-+      .reset                  = ssb_ohci_reset,
-+      .start                  = ssb_ohci_start,
-+      .stop                   = ohci_stop,
-+      .shutdown               = ohci_shutdown,
-+
-+#ifdef CONFIG_PM
-+      .suspend                = ssb_ohci_hcd_suspend,
-+      .resume                 = ssb_ohci_hcd_resume,
-+#endif
-+
-+      .urb_enqueue            = ohci_urb_enqueue,
-+      .urb_dequeue            = ohci_urb_dequeue,
-+      .endpoint_disable       = ohci_endpoint_disable,
-+
-+      .get_frame_number       = ohci_get_frame,
-+
-+      .hub_status_data        = ohci_hub_status_data,
-+      .hub_control            = ohci_hub_control,
-+      .hub_irq_enable         = ohci_rhsc_enable,
-+      .bus_suspend            = ohci_bus_suspend,
-+      .bus_resume             = ohci_bus_resume,
-+
-+      .start_port_reset       = ohci_start_port_reset,
-+};
-+
-+static void ssb_ohci_detach(struct ssb_device *dev)
-+{
-+      struct usb_hcd *hcd = ssb_get_drvdata(dev);
-+
-+      usb_remove_hcd(hcd);
-+      iounmap(hcd->regs);
-+      usb_put_hcd(hcd);
-+      ssb_device_disable(dev, 0);
-+}
-+
-+static int ssb_ohci_attach(struct ssb_device *dev)
-+{
-+      struct ssb_ohci_device *ohcidev;
-+      struct usb_hcd *hcd;
-+      int err = -ENOMEM;
-+      u32 tmp, flags = 0;
-+
-+      if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
-+              flags |= SSB_OHCI_TMSLOW_HOSTMODE;
-+
-+      ssb_device_enable(dev, flags);
-+
-+      hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
-+                      dev->dev->bus_id);
-+      if (!hcd)
-+              goto err_dev_disable;
-+      ohcidev = hcd_to_ssb_ohci(hcd);
-+      ohcidev->enable_flags = flags;
-+
-+      tmp = ssb_read32(dev, SSB_ADMATCH0);
-+      hcd->rsrc_start = ssb_admatch_base(tmp);
-+      hcd->rsrc_len = ssb_admatch_size(tmp);
-+      hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-+      if (!hcd->regs)
-+              goto err_put_hcd;
-+      err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
-+      if (err)
-+              goto err_iounmap;
-+
-+      ssb_set_drvdata(dev, hcd);
-+
-+      return err;
-+
-+err_iounmap:
-+      iounmap(hcd->regs);
-+err_put_hcd:
-+      usb_put_hcd(hcd);
-+err_dev_disable:
-+      ssb_device_disable(dev, flags);
-+      return err;
-+}
-+
-+static int ssb_ohci_probe(struct ssb_device *dev,
-+              const struct ssb_device_id *id)
-+{
-+      int err;
-+      u16 chipid_top;
-+
-+      /* USBcores are only connected on embedded devices. */
-+      chipid_top = (dev->bus->chip_id & 0xFF00);
-+      if (chipid_top != 0x4700 && chipid_top != 0x5300)
-+              return -ENODEV;
-+
-+      /* TODO: Probably need checks here; is the core connected? */
-+
-+      if (usb_disabled())
-+              return -ENODEV;
-+
-+      /* We currently always attach SSB_DEV_USB11_HOSTDEV
-+       * as HOST OHCI. If we want to attach it as Client device,
-+       * we must branch here and call into the (yet to
-+       * be written) Client mode driver. Same for remove(). */
-+
-+      err = ssb_ohci_attach(dev);
-+
-+      return err;
-+}
-+
-+static void ssb_ohci_remove(struct ssb_device *dev)
-+{
-+      ssb_ohci_detach(dev);
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
-+{
-+      ssb_device_disable(dev, 0);
-+
-+      return 0;
-+}
-+
-+static int ssb_ohci_resume(struct ssb_device *dev)
-+{
-+      struct usb_hcd *hcd = ssb_get_drvdata(dev);
-+      struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-+
-+      ssb_device_enable(dev, ohcidev->enable_flags);
-+
-+      return 0;
-+}
-+
-+#else /* !CONFIG_PM */
-+#define ssb_ohci_suspend      NULL
-+#define ssb_ohci_resume       NULL
-+#endif /* CONFIG_PM */
-+
-+static const struct ssb_device_id ssb_ohci_table[] = {
-+      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
-+      SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
-+      SSB_DEVTABLE_END
-+};
-+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
-+
-+static struct ssb_driver ssb_ohci_driver = {
-+      .name           = KBUILD_MODNAME,
-+      .id_table       = ssb_ohci_table,
-+      .probe          = ssb_ohci_probe,
-+      .remove         = ssb_ohci_remove,
-+      .suspend        = ssb_ohci_suspend,
-+      .resume         = ssb_ohci_resume,
-+};
diff --git a/target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch b/target/linux/brcm47xx/patches-2.6.25/240-ohci-ssb-pm.patch
deleted file mode 100644 (file)
index 81ba45b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From: Al Viro <viro@ftp.linux.org.uk>
-Date: Sat, 13 Oct 2007 21:29:47 +0000 (+0100)
-Subject: Fix ohci-ssb with !CONFIG_PM
-X-Git-Tag: linux-2.6.24-rc1~57^2~38
-X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fralf%2Flinux.git;a=commitdiff_plain;h=4735b37cf434175c2b7b36b3b68f1e60e8ec8527;hp=d773b33972a663cfaf066e966f87922a74088a1e
-
-Fix ohci-ssb with !CONFIG_PM
-
-ohci_bus_{suspend,resume} exists only if we have CONFIG_PM; do the same
-thing as other subdrivers...
-
-Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
----
-
-diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
-index bc3e785..fe70e72 100644
---- a/drivers/usb/host/ohci-ssb.c
-+++ b/drivers/usb/host/ohci-ssb.c
-@@ -117,8 +117,10 @@ static const struct hc_driver ssb_ohci_hc_driver = {
-       .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,
- };
index 4549395..b4575c4 100644 (file)
@@ -1,6 +1,8 @@
---- a/drivers/usb/host/ohci-ssb.c      2007-11-05 07:56:56.000000000 -0800
-+++ b/drivers/usb/host/ohci-ssb.c      2007-11-05 08:26:15.000000000 -0800
-@@ -142,10 +142,59 @@
+Index: linux-2.6.25/drivers/usb/host/ohci-ssb.c
+===================================================================
+--- linux-2.6.25.orig/drivers/usb/host/ohci-ssb.c      2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/drivers/usb/host/ohci-ssb.c   2008-04-26 22:07:53.000000000 +0100
+@@ -142,10 +142,59 @@ static int ssb_ohci_attach(struct ssb_de
        int err = -ENOMEM;
        u32 tmp, flags = 0;
  
        int err = -ENOMEM;
        u32 tmp, flags = 0;
  
@@ -62,7 +64,7 @@
  
        hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
                        dev->dev->bus_id);
  
        hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
                        dev->dev->bus_id);
-@@ -235,6 +284,7 @@
+@@ -235,6 +284,7 @@ static int ssb_ohci_resume(struct ssb_de
  static const struct ssb_device_id ssb_ohci_table[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
  static const struct ssb_device_id ssb_ohci_table[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
index 5c2d522..afeeaa3 100644 (file)
@@ -1,6 +1,8 @@
---- linux-2.6.23.1/drivers/usb/host/ohci-ssb.c         2007-11-26 14:01:22.000000000 -0500
-+++ linux-2.6.23.1.new/drivers/usb/host/ohci-ssb.c     2007-11-26 14:16:08.000000000 -0500
-@@ -195,6 +195,11 @@
+Index: linux-2.6.25/drivers/usb/host/ohci-ssb.c
+===================================================================
+--- linux-2.6.25.orig/drivers/usb/host/ohci-ssb.c      2008-04-26 21:57:17.000000000 +0100
++++ linux-2.6.25/drivers/usb/host/ohci-ssb.c   2008-04-26 21:57:17.000000000 +0100
+@@ -195,6 +195,11 @@ static int ssb_ohci_attach(struct ssb_de
        else
                ssb_device_enable(dev, 0);
  
        else
                ssb_device_enable(dev, 0);
  
index 1620bf4..a13ba43 100644 (file)
@@ -1,7 +1,7 @@
-Index: linux-2.6.23/include/asm-mips/cacheflush.h
+Index: linux-2.6.25/include/asm-mips/cacheflush.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/cacheflush.h    2007-10-13 11:01:52.780284289 +0200
-+++ linux-2.6.23/include/asm-mips/cacheflush.h 2007-10-13 11:02:16.289624011 +0200
+--- linux-2.6.25.orig/include/asm-mips/cacheflush.h    2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/cacheflush.h 2008-04-26 21:57:18.000000000 +0100
 @@ -32,7 +32,7 @@
  extern void (*flush_cache_all)(void);
  extern void (*__flush_cache_all)(void);
 @@ -32,7 +32,7 @@
  extern void (*flush_cache_all)(void);
  extern void (*__flush_cache_all)(void);
index 16e7e3f..c43332b 100644 (file)
@@ -1,8 +1,8 @@
-Index: linux-2.6.23/arch/mips/mm/init.c
+Index: linux-2.6.25/arch/mips/mm/init.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/arch/mips/mm/init.c      2007-10-13 11:46:58.762489429 +0200
-+++ linux-2.6.23/arch/mips/mm/init.c   2007-10-13 11:47:36.092616749 +0200
-@@ -205,31 +205,6 @@
+--- linux-2.6.25.orig/arch/mips/mm/init.c      2008-04-26 21:57:15.000000000 +0100
++++ linux-2.6.25/arch/mips/mm/init.c   2008-04-26 21:57:19.000000000 +0100
+@@ -205,32 +205,6 @@ void kunmap_coherent(void)
        preempt_check_resched();
  }
  
        preempt_check_resched();
  }
  
@@ -12,7 +12,8 @@ Index: linux-2.6.23/arch/mips/mm/init.c
 -      void *vfrom, *vto;
 -
 -      vto = kmap_atomic(to, KM_USER1);
 -      void *vfrom, *vto;
 -
 -      vto = kmap_atomic(to, KM_USER1);
--      if (cpu_has_dc_aliases && cpu_use_kmap_coherent && !Page_dcache_dirty(from)) {
+-      if (cpu_has_dc_aliases && cpu_use_kmap_coherent &&
+-          page_mapped(from) && !Page_dcache_dirty(from)) {
 -              vfrom = kmap_coherent(from, vaddr);
 -              copy_page(vto, vfrom);
 -              kunmap_coherent();
 -              vfrom = kmap_coherent(from, vaddr);
 -              copy_page(vto, vfrom);
 -              kunmap_coherent();
@@ -34,11 +35,11 @@ Index: linux-2.6.23/arch/mips/mm/init.c
  void copy_to_user_page(struct vm_area_struct *vma,
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
  void copy_to_user_page(struct vm_area_struct *vma,
        struct page *page, unsigned long vaddr, void *dst, const void *src,
        unsigned long len)
-Index: linux-2.6.23/include/asm-mips/page.h
+Index: linux-2.6.25/include/asm-mips/page.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.orig/include/asm-mips/page.h  2007-10-13 11:45:50.518600430 +0200
-+++ linux-2.6.23/include/asm-mips/page.h       2007-10-13 11:47:26.472068504 +0200
-@@ -35,6 +35,7 @@
+--- linux-2.6.25.orig/include/asm-mips/page.h  2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/include/asm-mips/page.h       2008-04-26 21:57:19.000000000 +0100
+@@ -32,6 +32,7 @@
  #ifndef __ASSEMBLY__
  
  #include <linux/pfn.h>
  #ifndef __ASSEMBLY__
  
  #include <linux/pfn.h>
@@ -46,7 +47,7 @@ Index: linux-2.6.23/include/asm-mips/page.h
  #include <asm/io.h>
  
  /*
  #include <asm/io.h>
  
  /*
-@@ -67,13 +68,16 @@
+@@ -64,13 +65,16 @@ static inline void clear_user_page(void 
                flush_data_cache_page((unsigned long)addr);
  }
  
                flush_data_cache_page((unsigned long)addr);
  }
  
diff --git a/target/linux/brcm47xx/patches-2.6.25/400-arch-bcm47xx.patch b/target/linux/brcm47xx/patches-2.6.25/400-arch-bcm47xx.patch
new file mode 100644 (file)
index 0000000..df041da
--- /dev/null
@@ -0,0 +1,384 @@
+Index: linux-2.6.25.1/arch/mips/bcm47xx/irq.c
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/irq.c        2008-05-14 14:36:58.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/irq.c     2008-05-14 14:37:06.000000000 +0100
+@@ -1,5 +1,6 @@
+ /*
+  *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
++ *  Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
+  *
+  *  This program is free software; you can redistribute  it and/or modify it
+  *  under  the terms of  the GNU General  Public License as published by the
+@@ -23,10 +24,19 @@
+  */
+ #include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/init.h>
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
++#include <linux/pci.h>
++#include <linux/ssb/ssb.h>
++
+ #include <asm/irq_cpu.h>
++
++extern struct ssb_bus ssb_bcm47xx;
++
++
+ void plat_irq_dispatch(void)
+ {
+       u32 cause;
+@@ -53,3 +63,19 @@ void __init arch_init_irq(void)
+ {
+       mips_cpu_irq_init();
+ }
++
++int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++      int res;
++
++      res = ssb_pcibios_map_irq(dev, slot, pin);
++      if (res < 0) {
++              printk(KERN_ALERT "PCI: Failed to map IRQ of device %s\n",
++                     dev->dev.bus_id);
++              return 0;
++      }
++      /* IRQ-0 and IRQ-1 are software interrupts. */
++      WARN_ON((res == 0) || (res == 1));
++
++      return res;
++}
+Index: linux-2.6.25.1/arch/mips/bcm47xx/setup.c
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/setup.c      2008-05-14 14:36:58.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/setup.c   2008-05-14 14:37:06.000000000 +0100
+@@ -2,7 +2,7 @@
+  *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+  *  Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
+  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+- *  Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
++ *  Copyright (C) 2006-2008 Michael Buesch <mb@bu3sch.de>
+  *
+  *  This program is free software; you can redistribute  it and/or modify it
+  *  under  the terms of  the GNU General  Public License as published by the
+@@ -25,23 +25,52 @@
+  *  675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++#include <linux/init.h>
+ #include <linux/types.h>
+-#include <linux/ssb/ssb.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <linux/serial_8250.h>
+ #include <asm/bootinfo.h>
+-#include <asm/reboot.h>
+ #include <asm/time.h>
+-#include <bcm47xx.h>
++#include <asm/reboot.h>
+ #include <asm/fw/cfe/cfe_api.h>
++#include <linux/pm.h>
++#include <linux/ssb/ssb.h>
++#include <linux/ssb/ssb_embedded.h>
++
++#include "include/nvram.h"
+ struct ssb_bus ssb_bcm47xx;
+ EXPORT_SYMBOL(ssb_bcm47xx);
++extern void bcm47xx_pci_init(void);
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++      int err;
++
++      err = ssb_pcibios_plat_dev_init(dev);
++      if (err) {
++              printk(KERN_ALERT "PCI: Failed to init device %s\n",
++                     pci_name(dev));
++      }
++
++      return err;
++}
++
+ static void bcm47xx_machine_restart(char *command)
+ {
+       printk(KERN_ALERT "Please stand by while rebooting the system...\n");
+       local_irq_disable();
++      /* CFE has a reboot callback, but that does not work.
++       * Oopses with: Reserved instruction in kernel code.
++       */
++
+       /* Set the watchdog timer to reset immediately */
+-      ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1);
++      if (ssb_watchdog_timer_set(&ssb_bcm47xx, 1))
++              printk(KERN_EMERG "SSB watchdog-triggered reboot failed!\n");
+       while (1)
+               cpu_relax();
+ }
+@@ -50,12 +79,13 @@ static void bcm47xx_machine_halt(void)
+ {
+       /* Disable interrupts and watchdog and spin forever */
+       local_irq_disable();
+-      ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0);
++      if (ssb_watchdog_timer_set(&ssb_bcm47xx, 0))
++              printk(KERN_EMERG "Failed to disable SSB watchdog!\n");
+       while (1)
+               cpu_relax();
+ }
+-static void str2eaddr(char *str, char *dest)
++static void e_aton(char *str, char *dest)
+ {
+       int i = 0;
+@@ -72,52 +102,141 @@ static void str2eaddr(char *str, char *d
+       }
+ }
+-static int bcm47xx_get_invariants(struct ssb_bus *bus,
+-                                 struct ssb_init_invariants *iv)
++static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
+ {
+-      char buf[100];
++      char *s;
+-      /* Fill boardinfo structure */
+-      memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
++      memset(sprom, 0xFF, sizeof(struct ssb_sprom));
+-      if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0)
+-              iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
+-      if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
+-              iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
+-      if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
+-              iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
+-
+-      /* Fill sprom structure */
+-      memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
+-      iv->sprom.revision = 3;
+-
+-      if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+-              str2eaddr(buf, iv->sprom.et0mac);
+-      if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+-              str2eaddr(buf, iv->sprom.et1mac);
+-      if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
+-              iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10);
+-      if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
+-              iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10);
+-      if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
+-              iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
+-      if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
+-              iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
++      sprom->revision = 1;
++      if ((s = nvram_get("il0macaddr")))
++              e_aton(s, sprom->il0mac);
++      if ((s = nvram_get("et0macaddr")))
++              e_aton(s, sprom->et0mac);
++      if ((s = nvram_get("et1macaddr")))
++              e_aton(s, sprom->et1mac);
++      if ((s = nvram_get("et0phyaddr")))
++              sprom->et0phyaddr = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("et1phyaddr")))
++              sprom->et1phyaddr = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("et0mdcport")))
++              sprom->et0mdcport = !!simple_strtoul(s, NULL, 10);
++      if ((s = nvram_get("et1mdcport")))
++              sprom->et1mdcport = !!simple_strtoul(s, NULL, 10);
++      if ((s = nvram_get("pa0b0")))
++              sprom->pa0b0 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa0b1")))
++              sprom->pa0b1 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa0b2")))
++              sprom->pa0b2 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa1b0")))
++              sprom->pa1b0 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa1b1")))
++              sprom->pa1b1 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa1b2")))
++              sprom->pa1b2 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("wl0gpio0")))
++              sprom->gpio0 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("wl0gpio1")))
++              sprom->gpio1 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("wl0gpio2")))
++              sprom->gpio2 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("wl0gpio3")))
++              sprom->gpio3 = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa0maxpwr")))
++              sprom->maxpwr_bg = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa1maxpwr")))
++              sprom->maxpwr_a = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa0itssit")))
++              sprom->itssi_bg = simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("pa1itssit")))
++              sprom->itssi_a = simple_strtoul(s, NULL, 0);
++      sprom->boardflags_lo = 0;
++      if ((s = nvram_get("boardflags")))
++              sprom->boardflags_lo = simple_strtoul(s, NULL, 0);
++      sprom->boardflags_hi = 0;
++      if ((s = nvram_get("boardflags2")))
++              sprom->boardflags_hi = simple_strtoul(s, NULL, 0);
++}
++
++static int bcm47xx_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv)
++{
++      char *s;
++
++      iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
++      if ((s = nvram_get("boardtype")))
++              iv->boardinfo.type = (u16)simple_strtoul(s, NULL, 0);
++      if ((s = nvram_get("boardrev")))
++              iv->boardinfo.rev = (u16)simple_strtoul(s, NULL, 0);
++
++      bcm47xx_fill_sprom(&iv->sprom);
++
++      if ((s = nvram_get("cardbus")))
++              iv->has_cardbus_slot = !!simple_strtoul(s, NULL, 10);
+       return 0;
+ }
+ void __init plat_mem_setup(void)
+ {
+-      int err;
++      int i, err;
++      char *s;
++      struct ssb_mipscore *mcore;
++
++      err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE, bcm47xx_get_invariants);
++      if (err) {
++              const char *msg = "Failed to initialize SSB bus (err %d)\n";
++              printk(msg, err); /* Make sure the message gets out of the box. */
++              panic(msg, err);
++      }
++      mcore = &ssb_bcm47xx.mipscore;
++
++      s = nvram_get("kernel_args");
++      if (s && !strncmp(s, "console=ttyS1", 13)) {
++              struct ssb_serial_port port;
++
++              printk("Swapping serial ports!\n");
++              /* swap serial ports */
++              memcpy(&port, &mcore->serial_ports[0], sizeof(port));
++              memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1], sizeof(port));
++              memcpy(&mcore->serial_ports[1], &port, sizeof(port));
++      }
+-      err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
+-                                    bcm47xx_get_invariants);
+-      if (err)
+-              panic("Failed to initialize SSB bus (err %d)\n", err);
++      for (i = 0; i < mcore->nr_serial_ports; i++) {
++              struct ssb_serial_port *port = &(mcore->serial_ports[i]);
++              struct uart_port s;
++
++              memset(&s, 0, sizeof(s));
++              s.line = i;
++              s.membase = port->regs;
++              s.irq = port->irq + 2;
++              s.uartclk = port->baud_base;
++              s.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
++              s.iotype = SERIAL_IO_MEM;
++              s.regshift = port->reg_shift;
++
++              early_serial_setup(&s);
++      }
++      printk("Serial init done.\n");
+       _machine_restart = bcm47xx_machine_restart;
+       _machine_halt = bcm47xx_machine_halt;
+       pm_power_off = bcm47xx_machine_halt;
+ }
++static int __init bcm47xx_register_gpiodev(void)
++{
++      static struct resource res = {
++              .start = 0xFFFFFFFF,
++      };
++      struct platform_device *pdev;
++
++      pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
++      if (!pdev) {
++              printk(KERN_ERR "bcm47xx: GPIODEV init failed\n");
++              return -ENODEV;
++      }
++
++      return 0;
++}
++device_initcall(bcm47xx_register_gpiodev);
+Index: linux-2.6.25.1/arch/mips/bcm47xx/time.c
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/time.c       2008-05-14 14:36:58.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/time.c    2008-05-14 14:37:06.000000000 +0100
+@@ -22,11 +22,17 @@
+  *  675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+-
+ #include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/serial_reg.h>
++#include <linux/interrupt.h>
+ #include <linux/ssb/ssb.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
+ #include <asm/time.h>
+-#include <bcm47xx.h>
++
++extern struct ssb_bus ssb_bcm47xx;
+ void __init plat_time_init(void)
+ {
+Index: linux-2.6.25.1/arch/mips/bcm47xx/nvram.c
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/nvram.c      2008-05-14 14:36:58.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/nvram.c   2008-05-14 14:37:06.000000000 +0100
+@@ -24,10 +24,10 @@
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+-#include <nvram.h>
++#include "include/nvram.h"
+ #define MB * 1048576
+-extern struct ssb_bus ssb;
++extern struct ssb_bus ssb_bcm47xx;
+ static char nvram_buf[NVRAM_SPACE];
+ static int cfe_env;
+@@ -36,7 +36,7 @@ extern char *cfe_env_get(char *nv_buf, c
+ /* Probe for NVRAM header */
+ static void __init early_nvram_init(void)
+ {
+-      struct ssb_mipscore *mcore = &ssb.mipscore;
++      struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+       struct nvram_header *header;
+       int i;
+       u32 base, lim, off;
+Index: linux-2.6.25.1/arch/mips/bcm47xx/Makefile
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/Makefile     2008-05-14 14:36:58.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/Makefile  2008-05-14 14:37:06.000000000 +0100
+@@ -3,4 +3,4 @@
+ # under Linux.
+ #
+-obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o
++obj-y := cfe_env.o gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o
+Index: linux-2.6.25.1/arch/mips/Kconfig
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/Kconfig      2008-05-14 14:47:43.000000000 +0100
++++ linux-2.6.25.1/arch/mips/Kconfig   2008-05-14 14:48:15.000000000 +0100
+@@ -54,6 +54,7 @@ config BCM47XX
+       select SSB_DRIVER_MIPS
+       select SSB_DRIVER_EXTIF
+       select SSB_DRIVER_PCICORE
++      select SSB_B43_PCI_BRIDGE
+       select SSB_PCICORE_HOSTMODE if PCI
+       select GENERIC_GPIO
+       select SYS_HAS_EARLY_PRINTK
diff --git a/target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch b/target/linux/brcm47xx/patches-2.6.25/410-aec62xx_pci_enable.patch
deleted file mode 100644 (file)
index ae2be76..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-diff -Naur a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
---- a/drivers/ide/pci/aec62xx.c        2007-10-12 18:43:44.000000000 +0200
-+++ b/drivers/ide/pci/aec62xx.c        2007-11-14 14:12:51.000000000 +0100
-@@ -248,7 +248,14 @@
- static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d)
- {
--      unsigned long dma_base = pci_resource_start(dev, 4);
-+      unsigned long dma_base;
-+      int err;
-+
-+      err = pci_enable_device(dev);
-+      if (err)
-+              return err;
-+
-+      dma_base = pci_resource_start(dev, 4);
-       if (inb(dma_base + 2) & 0x10) {
-               d->name = (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) ?
-@@ -256,7 +263,11 @@
-               d->udma_mask = 0x7f; /* udma0-6 */
-       }
--      return ide_setup_pci_device(dev, d);
-+      err = ide_setup_pci_device(dev, d);
-+      if(err)
-+              pci_disable_device(dev);
-+
-+      return err;
- }
- static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
index b545bba..59c1d1d 100644 (file)
@@ -1,8 +1,8 @@
-Index: linux-2.6.23.1/scripts/gen_initramfs_list.sh
+Index: linux-2.6.25/scripts/gen_initramfs_list.sh
 ===================================================================
 ===================================================================
---- linux-2.6.23.1.orig/scripts/gen_initramfs_list.sh  2007-11-16 02:26:47.821227881 +0100
-+++ linux-2.6.23.1/scripts/gen_initramfs_list.sh       2007-11-16 02:45:42.753904007 +0100
-@@ -287,7 +287,7 @@
+--- linux-2.6.25.orig/scripts/gen_initramfs_list.sh    2008-04-26 21:57:00.000000000 +0100
++++ linux-2.6.25/scripts/gen_initramfs_list.sh 2008-04-26 21:57:20.000000000 +0100
+@@ -287,7 +287,7 @@ if [ ! -z ${output_file} ]; then
        if [ "${is_cpio_compressed}" = "compressed" ]; then
                cat ${cpio_tfile} > ${output_file}
        else
        if [ "${is_cpio_compressed}" = "compressed" ]; then
                cat ${cpio_tfile} > ${output_file}
        else
@@ -11,11 +11,11 @@ Index: linux-2.6.23.1/scripts/gen_initramfs_list.sh
        fi
        [ -z ${cpio_file} ] && rm ${cpio_tfile}
  fi
        fi
        [ -z ${cpio_file} ] && rm ${cpio_tfile}
  fi
-Index: linux-2.6.23.1/init/initramfs.c
+Index: linux-2.6.25/init/initramfs.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.1.orig/init/initramfs.c       2007-11-16 02:26:47.829228332 +0100
-+++ linux-2.6.23.1/init/initramfs.c    2007-11-16 03:03:09.661563882 +0100
-@@ -441,6 +441,69 @@
+--- linux-2.6.25.orig/init/initramfs.c 2008-04-26 21:56:21.000000000 +0100
++++ linux-2.6.25/init/initramfs.c      2008-04-26 21:57:20.000000000 +0100
+@@ -441,6 +441,69 @@ static void __init flush_window(void)
        outcnt = 0;
  }
  
        outcnt = 0;
  }
  
@@ -85,7 +85,7 @@ Index: linux-2.6.23.1/init/initramfs.c
  static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
  {
        int written;
  static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
  {
        int written;
-@@ -475,12 +538,28 @@
+@@ -475,12 +538,28 @@ static char * __init unpack_to_rootfs(ch
                inptr = 0;
                outcnt = 0;             /* bytes in output buffer */
                bytes_out = 0;
                inptr = 0;
                outcnt = 0;             /* bytes in output buffer */
                bytes_out = 0;
diff --git a/target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch b/target/linux/brcm47xx/patches-2.6.25/600-ssb-fix-pcidevices.patch
deleted file mode 100644 (file)
index 01bd9ff..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c  2008-02-16 17:55:20.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c       2008-02-16 17:55:35.000000000 +0100
-@@ -66,6 +66,7 @@ int pcibios_plat_dev_init(struct pci_dev
-                       base = &ssb_pcicore_pcibus_iobase;
-               else
-                       base = &ssb_pcicore_pcibus_membase;
-+              res->flags |= IORESOURCE_PCI_FIXED;
-               if (res->end) {
-                       size = res->end - res->start + 1;
-                       if (*base & (size - 1))
-@@ -88,10 +89,12 @@ int pcibios_plat_dev_init(struct pci_dev
- static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
- {
-+      u8 lat;
-+
-       if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
-               return;
--      ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
-+      ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
-       /* Enable PCI bridge bus mastering and memory space */
-       pci_set_master(dev);
-@@ -101,7 +104,10 @@ static void __init ssb_fixup_pcibridge(s
-       pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
-       /* Make sure our latency is high enough to handle the devices behind us */
--      pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
-+      lat = 168;
-+      ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
-+                 pci_name(dev), lat);
-+      pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
- }
- DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
-@@ -279,14 +285,14 @@ static struct resource ssb_pcicore_mem_r
-       .name   = "SSB PCIcore external memory",
-       .start  = SSB_PCI_DMA,
-       .end    = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
--      .flags  = IORESOURCE_MEM,
-+      .flags  = IORESOURCE_MEM | IORESOURCE_PCI_FIXED,
- };
- static struct resource ssb_pcicore_io_resource = {
-       .name   = "SSB PCIcore external I/O",
-       .start  = 0x100,
-       .end    = 0x7FF,
--      .flags  = IORESOURCE_IO,
-+      .flags  = IORESOURCE_IO | IORESOURCE_PCI_FIXED,
- };
- static struct pci_controller ssb_pcicore_controller = {
-@@ -344,7 +350,8 @@ static void ssb_pcicore_init_hostmode(st
-       /* Ok, ready to run, register it to the system.
-        * The following needs change, if we want to port hostmode
-        * to non-MIPS platform. */
--      set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
-+      ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000);
-+      set_io_port_base(ssb_pcicore_controller.io_map_base);
-       /* Give some time to the PCI controller to configure itself with the new
-        * values. Not waiting at this point causes crashes of the machine. */
-       mdelay(10);
index 8ab28a7..aa3ac25 100644 (file)
@@ -2,20 +2,23 @@ The SSB pcicore driver does create some MMIO resource collisions.
 However, the pcicore PCI-fixup routine fixes these collisions afterwards.
 Remove this sanity check for now until we find a better solution.
 --mb
 However, the pcicore PCI-fixup routine fixes these collisions afterwards.
 Remove this sanity check for now until we find a better solution.
 --mb
-Index: linux-2.6.23.16/arch/mips/pci/pci.c
+Index: linux-2.6.25.1/arch/mips/pci/pci.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/arch/mips/pci/pci.c   2008-02-16 17:55:20.000000000 +0100
-+++ linux-2.6.23.16/arch/mips/pci/pci.c        2008-02-16 17:57:39.000000000 +0100
-@@ -177,10 +177,8 @@ static int pcibios_enable_resources(stru
+--- linux-2.6.25.1.orig/arch/mips/pci/pci.c    2008-05-08 22:37:55.000000000 +0100
++++ linux-2.6.25.1/arch/mips/pci/pci.c 2008-05-09 07:39:55.000000000 +0100
+@@ -182,12 +182,10 @@ static int pcibios_enable_resources(stru
+               if ((idx == PCI_ROM_RESOURCE) &&
+                               (!(r->flags & IORESOURCE_ROM_ENABLE)))
                        continue;
                        continue;
-               r = &dev->resource[idx];
 -              if (!r->start && r->end) {
 -              if (!r->start && r->end) {
--                      printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+-                      printk(KERN_ERR "PCI: Device %s not available "
+-                             "because of resource collisions\n",
++              if (!r->start && r->end)
++                      printk(KERN_WARNING "PCI: Device %s resource"
++                             "collisions detected. Ignoring...\n",
+                              pci_name(dev));
 -                      return -EINVAL;
 -              }
 -                      return -EINVAL;
 -              }
-+              if (!r->start && r->end)
-+                      printk(KERN_WARNING "PCI: Device %s resource collisions detected. Ignoring...\n", pci_name(dev));
                if (r->flags & IORESOURCE_IO)
                        cmd |= PCI_COMMAND_IO;
                if (r->flags & IORESOURCE_MEM)
                if (r->flags & IORESOURCE_IO)
                        cmd |= PCI_COMMAND_IO;
                if (r->flags & IORESOURCE_MEM)
diff --git a/target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch b/target/linux/brcm47xx/patches-2.6.25/602-ssb-fix-serial-on-new-devices.patch
deleted file mode 100644 (file)
index d80b86e..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c       2008-02-19 14:37:26.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c    2008-02-19 14:37:27.000000000 +0100
-@@ -403,6 +403,7 @@ int ssb_chipco_serial_init(struct ssb_ch
-       unsigned int irq;
-       u32 baud_base, div;
-       u32 i, n;
-+      unsigned int ccrev = cc->dev->id.revision;
-       plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
-       irq = ssb_mips_irq(cc->dev);
-@@ -414,14 +415,39 @@ int ssb_chipco_serial_init(struct ssb_ch
-                                               chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
-               div = 1;
-       } else {
--              if (cc->dev->id.revision >= 11) {
-+              if (ccrev == 20) {
-+                      /* BCM5354 uses constant 25MHz clock */
-+                      baud_base = 25000000;
-+                      div = 48;
-+                      /* Set the override bit so we don't divide it */
-+                      chipco_write32(cc, SSB_CHIPCO_CORECTL,
-+                                     chipco_read32(cc, SSB_CHIPCO_CORECTL)
-+                                     | SSB_CHIPCO_CORECTL_UARTCLK0);
-+              } else if ((ccrev >= 11) && (ccrev != 15)) {
-                       /* Fixed ALP clock */
-                       baud_base = 20000000;
-+                      if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
-+                              /* FIXME: baud_base is different for devices with a PMU */
-+                              SSB_WARN_ON(1);
-+                      }
-                       div = 1;
-+                      if (ccrev >= 21) {
-+                              /* Turn off UART clock before switching clocksource. */
-+                              chipco_write32(cc, SSB_CHIPCO_CORECTL,
-+                                             chipco_read32(cc, SSB_CHIPCO_CORECTL)
-+                                             & ~SSB_CHIPCO_CORECTL_UARTCLKEN);
-+                      }
-                       /* Set the override bit so we don't divide it */
-                       chipco_write32(cc, SSB_CHIPCO_CORECTL,
--                                     SSB_CHIPCO_CORECTL_UARTCLK0);
--              } else if (cc->dev->id.revision >= 3) {
-+                                     chipco_read32(cc, SSB_CHIPCO_CORECTL)
-+                                     | SSB_CHIPCO_CORECTL_UARTCLK0);
-+                      if (ccrev >= 21) {
-+                              /* Re-enable the UART clock. */
-+                              chipco_write32(cc, SSB_CHIPCO_CORECTL,
-+                                             chipco_read32(cc, SSB_CHIPCO_CORECTL)
-+                                             | SSB_CHIPCO_CORECTL_UARTCLKEN);
-+                      }
-+              } else if (ccrev >= 3) {
-                       /* Internal backplane clock */
-                       baud_base = ssb_clockspeed(bus);
-                       div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
-@@ -433,7 +459,7 @@ int ssb_chipco_serial_init(struct ssb_ch
-               }
-               /* Clock source depends on strapping if UartClkOverride is unset */
--              if ((cc->dev->id.revision > 0) &&
-+              if ((ccrev > 0) &&
-                   !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
-                       if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
-                           SSB_CHIPCO_CAP_UARTCLK_INT) {
-@@ -455,7 +481,7 @@ int ssb_chipco_serial_init(struct ssb_ch
-               cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
-               uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
-               /* Offset changed at after rev 0 */
--              if (cc->dev->id.revision == 0)
-+              if (ccrev == 0)
-                       uart_regs += (i * 8);
-               else
-                       uart_regs += (i * 256);
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h     2008-02-19 14:37:26.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h  2008-02-19 14:37:27.000000000 +0100
-@@ -51,9 +51,12 @@
- #define  SSB_CHIPCO_CAP_JTAGM         0x00400000      /* JTAG master present */
- #define  SSB_CHIPCO_CAP_BROM          0x00800000      /* Internal boot ROM active */
- #define  SSB_CHIPCO_CAP_64BIT         0x08000000      /* 64-bit Backplane */
-+#define  SSB_CHIPCO_CAP_PMU           0x10000000      /* PMU available (rev >= 20) */
-+#define  SSB_CHIPCO_CAP_ECI           0x20000000      /* ECI available (rev >= 20) */
- #define SSB_CHIPCO_CORECTL            0x0008
- #define  SSB_CHIPCO_CORECTL_UARTCLK0  0x00000001      /* Drive UART with internal clock */
- #define        SSB_CHIPCO_CORECTL_SE          0x00000002      /* sync clk out enable (corerev >= 3) */
-+#define  SSB_CHIPCO_CORECTL_UARTCLKEN 0x00000008      /* UART clock enable (rev >= 21) */
- #define SSB_CHIPCO_BIST                       0x000C
- #define SSB_CHIPCO_OTPS                       0x0010          /* OTP status */
- #define        SSB_CHIPCO_OTPS_PROGFAIL       0x80000000
diff --git a/target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch b/target/linux/brcm47xx/patches-2.6.25/610-ssb-watchdog-fix.patch
deleted file mode 100644 (file)
index fecb8b5..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/Kconfig
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/Kconfig   2008-02-19 13:46:05.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/Kconfig        2008-02-19 13:46:33.000000000 +0100
-@@ -105,6 +105,12 @@ config SSB_DRIVER_MIPS
-         If unsure, say N
-+# Assumption: We are on embedded, if we compile the MIPS core.
-+config SSB_EMBEDDED
-+      bool
-+      depends on SSB_DRIVER_MIPS
-+      default y
-+
- config SSB_DRIVER_EXTIF
-       bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
-       depends on SSB_DRIVER_MIPS && EXPERIMENTAL
-Index: linux-2.6.23.16/drivers/ssb/Makefile
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/Makefile  2008-02-19 13:46:05.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/Makefile       2008-02-19 13:46:33.000000000 +0100
-@@ -1,5 +1,6 @@
- # core
- ssb-y                                 += main.o scan.o
-+ssb-$(CONFIG_SSB_EMBEDDED)            += embedded.o
- # host support
- ssb-$(CONFIG_SSB_PCIHOST)             += pci.o pcihost_wrapper.o
-Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c    2008-02-19 13:46:05.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 13:46:33.000000000 +0100
-@@ -37,6 +37,12 @@ static inline u32 extif_write32_masked(s
-       return value;
- }
-+void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
-+                                u32 ticks)
-+{
-+      extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
-+}
-+
- #ifdef CONFIG_SSB_SERIAL
- static bool serial_exists(u8 *regs)
- {
-Index: linux-2.6.23.16/drivers/ssb/embedded.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23.16/drivers/ssb/embedded.c     2008-02-19 13:46:33.000000000 +0100
-@@ -0,0 +1,26 @@
-+/*
-+ * Sonics Silicon Backplane
-+ * Embedded systems support code
-+ *
-+ * Copyright 2005-2008, Broadcom Corporation
-+ * Copyright 2006-2008, Michael Buesch <mb@bu3sch.de>
-+ *
-+ * Licensed under the GNU/GPL. See COPYING for details.
-+ */
-+
-+#include <linux/ssb/ssb.h>
-+#include <linux/ssb/ssb_embedded.h>
-+
-+
-+int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)
-+{
-+      if (ssb_chipco_available(&bus->chipco)) {
-+              ssb_chipco_watchdog_timer_set(&bus->chipco, ticks);
-+              return 0;
-+      }
-+      if (ssb_extif_available(&bus->extif)) {
-+              ssb_extif_watchdog_timer_set(&bus->extif, ticks);
-+              return 0;
-+      }
-+      return -ENODEV;
-+}
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_chipcommon.h     2008-02-19 13:46:29.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_chipcommon.h  2008-02-19 13:46:33.000000000 +0100
-@@ -360,6 +360,11 @@ struct ssb_chipcommon {
-       u16 fast_pwrup_delay;
- };
-+static inline bool ssb_chipco_available(struct ssb_chipcommon *cc)
-+{
-+      return (cc->dev != NULL);
-+}
-+
- extern void ssb_chipcommon_init(struct ssb_chipcommon *cc);
- #include <linux/pm.h>
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_extif.h  2008-02-19 13:46:05.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_extif.h       2008-02-19 13:46:33.000000000 +0100
-@@ -178,6 +178,9 @@ u32 ssb_extif_gpio_outen(struct ssb_exti
- u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value);
- u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value);
-+extern void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
-+                                       u32 ticks);
-+
- #ifdef CONFIG_SSB_SERIAL
- extern int ssb_extif_serial_init(struct ssb_extif *extif,
-                                struct ssb_serial_port *ports);
-@@ -201,5 +204,11 @@ void ssb_extif_get_clockcontrol(struct s
- {
- }
-+static inline
-+void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
-+                                u32 ticks)
-+{
-+}
-+
- #endif /* CONFIG_SSB_DRIVER_EXTIF */
- #endif /* LINUX_SSB_EXTIFCORE_H_ */
-Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h   2008-02-19 13:46:33.000000000 +0100
-@@ -0,0 +1,10 @@
-+#ifndef LINUX_SSB_EMBEDDED_H_
-+#define LINUX_SSB_EMBEDDED_H_
-+
-+#include <linux/types.h>
-+#include <linux/ssb/ssb.h>
-+
-+
-+extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks);
-+
-+#endif /* LINUX_SSB_EMBEDDED_H_ */
index a36c046..1efaf7c 100644 (file)
@@ -1,8 +1,8 @@
-Index: linux-2.6.23.16/drivers/ssb/main.c
+Index: linux-2.6.25.1/drivers/ssb/main.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-19 12:38:34.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 12:48:25.000000000 +0100
-@@ -1163,7 +1163,9 @@ static int __init ssb_modinit(void)
+--- linux-2.6.25.1.orig/drivers/ssb/main.c     2008-05-10 08:35:23.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/main.c  2008-05-10 09:04:53.000000000 +0100
+@@ -1173,7 +1173,9 @@ static int __init ssb_modinit(void)
  /* ssb must be initialized after PCI but before the ssb drivers.
   * That means we must use some initcall between subsys_initcall
   * and device_initcall. */
  /* ssb must be initialized after PCI but before the ssb drivers.
   * That means we must use some initcall between subsys_initcall
   * and device_initcall. */
diff --git a/target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch b/target/linux/brcm47xx/patches-2.6.25/621-ssb-common-gpio-api.patch
deleted file mode 100644 (file)
index d1debcf..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_chipcommon.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_chipcommon.c       2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_chipcommon.c    2008-02-19 15:50:44.000000000 +0100
-@@ -361,37 +361,31 @@ u32 ssb_chipco_gpio_in(struct ssb_chipco
- {
-       return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_in);
- u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
-       return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_out);
- u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
-       return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_outen);
- u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
-       return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_control);
- u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
-       return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_intmask);
- u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
- {
-       return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
- }
--EXPORT_SYMBOL(ssb_chipco_gpio_polarity);
- #ifdef CONFIG_SSB_SERIAL
- int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
-Index: linux-2.6.23.16/drivers/ssb/driver_extif.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_extif.c    2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_extif.c 2008-02-19 15:50:44.000000000 +0100
-@@ -122,30 +122,25 @@ u32 ssb_extif_gpio_in(struct ssb_extif *
- {
-       return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
- }
--EXPORT_SYMBOL(ssb_extif_gpio_in);
- u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
-                                  mask, value);
- }
--EXPORT_SYMBOL(ssb_extif_gpio_out);
- u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
-                                  mask, value);
- }
--EXPORT_SYMBOL(ssb_extif_gpio_outen);
- u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
- }
--EXPORT_SYMBOL(ssb_extif_gpio_polarity);
- u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
- {
-       return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
- }
--EXPORT_SYMBOL(ssb_extif_gpio_intmask);
-Index: linux-2.6.23.16/drivers/ssb/embedded.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/embedded.c        2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/embedded.c     2008-02-19 15:51:01.000000000 +0100
-@@ -11,6 +11,8 @@
- #include <linux/ssb/ssb.h>
- #include <linux/ssb/ssb_embedded.h>
-+#include "ssb_private.h"
-+
- int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks)
- {
-@@ -24,3 +26,107 @@ int ssb_watchdog_timer_set(struct ssb_bu
-       }
-       return -ENODEV;
- }
-+
-+u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_in(&bus->chipco, mask);
-+      else if (ssb_extif_available(&bus->extif))
-+              res = ssb_extif_gpio_in(&bus->extif, mask);
-+      else
-+              SSB_WARN_ON(1);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_in);
-+
-+u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_out(&bus->chipco, mask, value);
-+      else if (ssb_extif_available(&bus->extif))
-+              res = ssb_extif_gpio_out(&bus->extif, mask, value);
-+      else
-+              SSB_WARN_ON(1);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_out);
-+
-+u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_outen(&bus->chipco, mask, value);
-+      else if (ssb_extif_available(&bus->extif))
-+              res = ssb_extif_gpio_outen(&bus->extif, mask, value);
-+      else
-+              SSB_WARN_ON(1);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_outen);
-+
-+u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_control(&bus->chipco, mask, value);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_control);
-+
-+u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_intmask(&bus->chipco, mask, value);
-+      else if (ssb_extif_available(&bus->extif))
-+              res = ssb_extif_gpio_intmask(&bus->extif, mask, value);
-+      else
-+              SSB_WARN_ON(1);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_intmask);
-+
-+u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value)
-+{
-+      unsigned long flags;
-+      u32 res = 0;
-+
-+      spin_lock_irqsave(&bus->gpio_lock, flags);
-+      if (ssb_chipco_available(&bus->chipco))
-+              res = ssb_chipco_gpio_polarity(&bus->chipco, mask, value);
-+      else if (ssb_extif_available(&bus->extif))
-+              res = ssb_extif_gpio_polarity(&bus->extif, mask, value);
-+      else
-+              SSB_WARN_ON(1);
-+      spin_unlock_irqrestore(&bus->gpio_lock, flags);
-+
-+      return res;
-+}
-+EXPORT_SYMBOL(ssb_gpio_polarity);
-Index: linux-2.6.23.16/include/linux/ssb/ssb.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb.h       2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb.h    2008-02-19 15:50:44.000000000 +0100
-@@ -283,6 +283,11 @@ struct ssb_bus {
-       /* Contents of the SPROM. */
-       struct ssb_sprom sprom;
-+#ifdef CONFIG_SSB_EMBEDDED
-+      /* Lock for GPIO register access. */
-+      spinlock_t gpio_lock;
-+#endif /* EMBEDDED */
-+
-       /* Internal-only stuff follows. Do not touch. */
-       struct list_head list;
- #ifdef CONFIG_SSB_DEBUG
-Index: linux-2.6.23.16/include/linux/ssb/ssb_embedded.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_embedded.h      2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_embedded.h   2008-02-19 15:50:44.000000000 +0100
-@@ -7,4 +7,12 @@
- extern int ssb_watchdog_timer_set(struct ssb_bus *bus, u32 ticks);
-+/* Generic GPIO API */
-+u32 ssb_gpio_in(struct ssb_bus *bus, u32 mask);
-+u32 ssb_gpio_out(struct ssb_bus *bus, u32 mask, u32 value);
-+u32 ssb_gpio_outen(struct ssb_bus *bus, u32 mask, u32 value);
-+u32 ssb_gpio_control(struct ssb_bus *bus, u32 mask, u32 value);
-+u32 ssb_gpio_intmask(struct ssb_bus *bus, u32 mask, u32 value);
-+u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value);
-+
- #endif /* LINUX_SSB_EMBEDDED_H_ */
-Index: linux-2.6.23.16/drivers/ssb/main.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-19 15:50:42.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 15:50:44.000000000 +0100
-@@ -571,6 +571,9 @@ static int ssb_bus_register(struct ssb_b
-       spin_lock_init(&bus->bar_lock);
-       INIT_LIST_HEAD(&bus->list);
-+#ifdef CONFIG_SSB_EMBEDDED
-+      spin_lock_init(&bus->gpio_lock);
-+#endif
-       /* Powerup the bus */
-       err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
diff --git a/target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch b/target/linux/brcm47xx/patches-2.6.25/622-ssb-cardbus-fixes.patch
deleted file mode 100644 (file)
index 1d2779e..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c  2008-02-19 16:37:14.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c       2008-02-19 17:25:26.000000000 +0100
-@@ -11,6 +11,7 @@
- #include <linux/ssb/ssb.h>
- #include <linux/pci.h>
- #include <linux/delay.h>
-+#include <linux/ssb/ssb_embedded.h>
- #include "ssb_private.h"
-@@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore 
-       ssb_write32(pc->dev, offset, value);
- }
-+static inline
-+u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset)
-+{
-+      return ssb_read16(pc->dev, offset);
-+}
-+
-+static inline
-+void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value)
-+{
-+      ssb_write16(pc->dev, offset, value);
-+}
-+
- /**************************************************
-  * Code for hostmode operation.
-  **************************************************/
-@@ -123,8 +136,10 @@ static u32 get_cfgspace_addr(struct ssb_
-       u32 addr = 0;
-       u32 tmp;
--      if (unlikely(pc->cardbusmode && dev > 1))
-+      /* We do only have one cardbus device behind the bridge. */
-+      if (pc->cardbusmode && (dev >= 1))
-               goto out;
-+
-       if (bus == 0) {
-               /* Type 0 transaction */
-               if (unlikely(dev >= SSB_PCI_SLOT_MAX))
-@@ -324,7 +339,16 @@ static void ssb_pcicore_init_hostmode(st
-       pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
-       udelay(1); /* Assertion time demanded by the PCI standard */
--      /*TODO cardbus mode */
-+      if (pc->dev->bus->has_cardbus_slot) {
-+              ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
-+              pc->cardbusmode = 1;
-+              /* GPIO 1 resets the bridge */
-+              ssb_gpio_out(pc->dev->bus, 1, 1);
-+              ssb_gpio_outen(pc->dev->bus, 1, 1);
-+              pcicore_write16(pc, SSB_PCICORE_SPROM(0),
-+                              pcicore_read16(pc, SSB_PCICORE_SPROM(0))
-+                              | 0x0400);
-+      }
-       /* 64MB I/O window */
-       pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
-Index: linux-2.6.23.16/drivers/ssb/main.c
-===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-19 15:50:44.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-19 16:38:31.000000000 +0100
-@@ -559,6 +559,7 @@ static int ssb_fetch_invariants(struct s
-               goto out;
-       memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
-       memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
-+      bus->has_cardbus_slot = iv.has_cardbus_slot;
- out:
-       return err;
- }
-Index: linux-2.6.23.16/include/linux/ssb/ssb.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb.h       2008-02-19 15:50:44.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb.h    2008-02-19 16:38:31.000000000 +0100
-@@ -282,6 +282,8 @@ struct ssb_bus {
-       struct ssb_boardinfo boardinfo;
-       /* Contents of the SPROM. */
-       struct ssb_sprom sprom;
-+      /* If the board has a cardbus slot, this is set to true. */
-+      bool has_cardbus_slot;
- #ifdef CONFIG_SSB_EMBEDDED
-       /* Lock for GPIO register access. */
-@@ -299,8 +301,13 @@ struct ssb_bus {
- /* The initialization-invariants. */
- struct ssb_init_invariants {
-+      /* Versioning information about the PCB. */
-       struct ssb_boardinfo boardinfo;
-+      /* The SPROM information. That's either stored in an
-+       * EEPROM or NVRAM on the board. */
-       struct ssb_sprom sprom;
-+      /* If the board has a cardbus slot, this is set to true. */
-+      bool has_cardbus_slot;
- };
- /* Type of function to fetch the invariants. */
- typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus,
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
-===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h    2008-02-13 20:27:17.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-02-19 17:31:47.000000000 +0100
-@@ -51,6 +51,11 @@
- #define  SSB_PCICORE_SBTOPCI1_MASK    0xFC000000
- #define SSB_PCICORE_SBTOPCI2          0x0108  /* Backplane to PCI translation 2 (sbtopci2) */
- #define  SSB_PCICORE_SBTOPCI2_MASK    0xC0000000
-+#define SSB_PCICORE_PCICFG0           0x0400  /* PCI config space 0 (rev >= 8) */
-+#define SSB_PCICORE_PCICFG1           0x0500  /* PCI config space 1 (rev >= 8) */
-+#define SSB_PCICORE_PCICFG2           0x0600  /* PCI config space 2 (rev >= 8) */
-+#define SSB_PCICORE_PCICFG3           0x0700  /* PCI config space 3 (rev >= 8) */
-+#define SSB_PCICORE_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */
- /* SBtoPCIx */
- #define SSB_PCICORE_SBTOPCI_MEM               0x00000000
index 82b64a3..e3f7a6d 100644 (file)
@@ -1,9 +1,9 @@
 Add support for 8bit reads/writes to SSB.
 Add support for 8bit reads/writes to SSB.
-Index: linux-2.6.23.16/drivers/ssb/main.c
+Index: linux-2.6.25.1/drivers/ssb/main.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-20 14:10:07.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:34:48.000000000 +0100
-@@ -507,6 +507,14 @@ error:
+--- linux-2.6.25.1.orig/drivers/ssb/main.c     2008-05-10 09:04:53.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/main.c  2008-05-10 09:05:38.000000000 +0100
+@@ -508,6 +508,14 @@ error:
        return err;
  }
  
        return err;
  }
  
@@ -18,7 +18,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
  static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
  {
        struct ssb_bus *bus = dev->bus;
  static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
  {
        struct ssb_bus *bus = dev->bus;
-@@ -523,6 +531,14 @@ static u32 ssb_ssb_read32(struct ssb_dev
+@@ -524,6 +532,14 @@ static u32 ssb_ssb_read32(struct ssb_dev
        return readl(bus->mmio + offset);
  }
  
        return readl(bus->mmio + offset);
  }
  
@@ -33,7 +33,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
  static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
  {
        struct ssb_bus *bus = dev->bus;
  static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
  {
        struct ssb_bus *bus = dev->bus;
-@@ -541,8 +557,10 @@ static void ssb_ssb_write32(struct ssb_d
+@@ -542,8 +558,10 @@ static void ssb_ssb_write32(struct ssb_d
  
  /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
  static const struct ssb_bus_ops ssb_ssb_ops = {
  
  /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
  static const struct ssb_bus_ops ssb_ssb_ops = {
@@ -44,11 +44,11 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
        .write16        = ssb_ssb_write16,
        .write32        = ssb_ssb_write32,
  };
        .write16        = ssb_ssb_write16,
        .write32        = ssb_ssb_write32,
  };
-Index: linux-2.6.23.16/drivers/ssb/pci.c
+Index: linux-2.6.25.1/drivers/ssb/pci.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/pci.c     2008-02-20 14:10:03.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/pci.c  2008-02-20 14:10:07.000000000 +0100
-@@ -572,6 +572,19 @@ static inline int ssb_pci_assert_buspowe
+--- linux-2.6.25.1.orig/drivers/ssb/pci.c      2008-05-10 09:04:53.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/pci.c   2008-05-10 09:05:38.000000000 +0100
+@@ -577,6 +577,19 @@ static inline int ssb_pci_assert_buspowe
  }
  #endif /* DEBUG */
  
  }
  #endif /* DEBUG */
  
@@ -68,7 +68,7 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
  static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
  {
        struct ssb_bus *bus = dev->bus;
  static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
  {
        struct ssb_bus *bus = dev->bus;
-@@ -598,6 +611,19 @@ static u32 ssb_pci_read32(struct ssb_dev
+@@ -603,6 +616,19 @@ static u32 ssb_pci_read32(struct ssb_dev
        return ioread32(bus->mmio + offset);
  }
  
        return ioread32(bus->mmio + offset);
  }
  
@@ -88,7 +88,7 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
  static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
  {
        struct ssb_bus *bus = dev->bus;
  static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
  {
        struct ssb_bus *bus = dev->bus;
-@@ -626,8 +652,10 @@ static void ssb_pci_write32(struct ssb_d
+@@ -631,8 +657,10 @@ static void ssb_pci_write32(struct ssb_d
  
  /* Not "static", as it's used in main.c */
  const struct ssb_bus_ops ssb_pci_ops = {
  
  /* Not "static", as it's used in main.c */
  const struct ssb_bus_ops ssb_pci_ops = {
@@ -99,10 +99,10 @@ Index: linux-2.6.23.16/drivers/ssb/pci.c
        .write16        = ssb_pci_write16,
        .write32        = ssb_pci_write32,
  };
        .write16        = ssb_pci_write16,
        .write32        = ssb_pci_write32,
  };
-Index: linux-2.6.23.16/drivers/ssb/pcmcia.c
+Index: linux-2.6.25.1/drivers/ssb/pcmcia.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/pcmcia.c  2008-02-20 14:10:03.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/pcmcia.c       2008-02-20 14:10:07.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/ssb/pcmcia.c   2008-05-10 09:04:53.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/pcmcia.c        2008-05-10 09:05:38.000000000 +0100
 @@ -172,6 +172,22 @@ static int select_core_and_segment(struc
        return 0;
  }
 @@ -172,6 +172,22 @@ static int select_core_and_segment(struc
        return 0;
  }
@@ -158,10 +158,10 @@ Index: linux-2.6.23.16/drivers/ssb/pcmcia.c
        .write16        = ssb_pcmcia_write16,
        .write32        = ssb_pcmcia_write32,
  };
        .write16        = ssb_pcmcia_write16,
        .write32        = ssb_pcmcia_write32,
  };
-Index: linux-2.6.23.16/include/linux/ssb/ssb.h
+Index: linux-2.6.25.1/include/linux/ssb/ssb.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb.h       2008-02-20 14:10:07.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb.h    2008-02-20 18:33:21.000000000 +0100
+--- linux-2.6.25.1.orig/include/linux/ssb/ssb.h        2008-05-10 09:04:53.000000000 +0100
++++ linux-2.6.25.1/include/linux/ssb/ssb.h     2008-05-10 09:05:38.000000000 +0100
 @@ -72,8 +72,10 @@ struct ssb_device;
  /* Lowlevel read/write operations on the device MMIO.
   * Internal, don't use that outside of ssb. */
 @@ -72,8 +72,10 @@ struct ssb_device;
  /* Lowlevel read/write operations on the device MMIO.
   * Internal, don't use that outside of ssb. */
@@ -173,7 +173,7 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
        void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
        void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
  };
        void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
        void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
  };
-@@ -344,6 +346,10 @@ void ssb_device_disable(struct ssb_devic
+@@ -348,6 +350,10 @@ void ssb_device_disable(struct ssb_devic
  
  
  /* Device MMIO register read/write functions. */
  
  
  /* Device MMIO register read/write functions. */
@@ -184,7 +184,7 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
  static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
  {
        return dev->ops->read16(dev, offset);
  static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
  {
        return dev->ops->read16(dev, offset);
-@@ -352,6 +358,10 @@ static inline u32 ssb_read32(struct ssb_
+@@ -356,6 +362,10 @@ static inline u32 ssb_read32(struct ssb_
  {
        return dev->ops->read32(dev, offset);
  }
  {
        return dev->ops->read32(dev, offset);
  }
index 132b41d..0463da5 100644 (file)
@@ -1,10 +1,10 @@
 Allow registering PCI devices after early boot.
 
 This is an ugly hack and needs to be rewritten before going upstream.
 Allow registering PCI devices after early boot.
 
 This is an ugly hack and needs to be rewritten before going upstream.
-Index: linux-2.6.23.16/arch/mips/pci/pci.c
+Index: linux-2.6.25/arch/mips/pci/pci.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/arch/mips/pci/pci.c   2008-02-20 16:06:36.000000000 +0100
-+++ linux-2.6.23.16/arch/mips/pci/pci.c        2008-02-20 16:09:33.000000000 +0100
+--- linux-2.6.25.orig/arch/mips/pci/pci.c      2008-04-27 21:49:19.000000000 +0100
++++ linux-2.6.25/arch/mips/pci/pci.c   2008-04-27 21:58:31.000000000 +0100
 @@ -21,6 +21,17 @@
   */
  int pci_probe_only;
 @@ -21,6 +21,17 @@
   */
  int pci_probe_only;
@@ -146,11 +146,11 @@ Index: linux-2.6.23.16/arch/mips/pci/pci.c
  
        return 0;
  }
  
        return 0;
  }
-Index: linux-2.6.23.16/drivers/ssb/main.c
+Index: linux-2.6.25/drivers/ssb/main.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-02-20 16:06:36.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-02-20 18:33:21.000000000 +0100
-@@ -1185,9 +1185,7 @@ static int __init ssb_modinit(void)
+--- linux-2.6.25.orig/drivers/ssb/main.c       2008-04-27 21:55:32.000000000 +0100
++++ linux-2.6.25/drivers/ssb/main.c    2008-04-27 21:58:31.000000000 +0100
+@@ -1191,9 +1191,7 @@ static int __init ssb_modinit(void)
  /* ssb must be initialized after PCI but before the ssb drivers.
   * That means we must use some initcall between subsys_initcall
   * and device_initcall. */
  /* ssb must be initialized after PCI but before the ssb drivers.
   * That means we must use some initcall between subsys_initcall
   * and device_initcall. */
index 1b97d12..ec3f81d 100644 (file)
@@ -1,8 +1,8 @@
-Index: linux-2.6.23.16/drivers/ssb/Kconfig
+Index: linux-2.6.25.1/drivers/ssb/Kconfig
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/Kconfig   2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/Kconfig        2008-03-19 11:16:18.000000000 +0100
-@@ -120,4 +120,13 @@ config SSB_DRIVER_EXTIF
+--- linux-2.6.25.1.orig/drivers/ssb/Kconfig    2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/Kconfig 2008-05-07 22:57:40.000000000 +0100
+@@ -125,4 +125,13 @@ config SSB_DRIVER_EXTIF
  
          If unsure, say N
  
  
          If unsure, say N
  
@@ -16,10 +16,10 @@ Index: linux-2.6.23.16/drivers/ssb/Kconfig
 +        If unsure, say N
 +
  endmenu
 +        If unsure, say N
 +
  endmenu
-Index: linux-2.6.23.16/drivers/ssb/Makefile
+Index: linux-2.6.25.1/drivers/ssb/Makefile
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/Makefile  2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/Makefile       2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/ssb/Makefile   2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/Makefile        2008-05-07 22:57:40.000000000 +0100
 @@ -11,6 +11,7 @@ ssb-y                                        += driver_chipcommon.o
  ssb-$(CONFIG_SSB_DRIVER_MIPS)         += driver_mipscore.o
  ssb-$(CONFIG_SSB_DRIVER_EXTIF)                += driver_extif.o
 @@ -11,6 +11,7 @@ ssb-y                                        += driver_chipcommon.o
  ssb-$(CONFIG_SSB_DRIVER_MIPS)         += driver_mipscore.o
  ssb-$(CONFIG_SSB_DRIVER_EXTIF)                += driver_extif.o
@@ -28,10 +28,10 @@ Index: linux-2.6.23.16/drivers/ssb/Makefile
  
  # b43 pci-ssb-bridge driver
  # Not strictly a part of SSB, but kept here for convenience
  
  # b43 pci-ssb-bridge driver
  # Not strictly a part of SSB, but kept here for convenience
-Index: linux-2.6.23.16/drivers/ssb/driver_gige.c
+Index: linux-2.6.25.1/drivers/ssb/driver_gige.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23.16/drivers/ssb/driver_gige.c  2008-03-19 11:16:18.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/driver_gige.c   2008-05-07 22:57:40.000000000 +0100
 @@ -0,0 +1,294 @@
 +/*
 + * Sonics Silicon Backplane
 @@ -0,0 +1,294 @@
 +/*
 + * Sonics Silicon Backplane
@@ -327,10 +327,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_gige.c
 +{
 +      return ssb_driver_register(&ssb_gige_driver);
 +}
 +{
 +      return ssb_driver_register(&ssb_gige_driver);
 +}
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h
+Index: linux-2.6.25.1/include/linux/ssb/ssb_driver_gige.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h        2008-03-19 11:16:18.000000000 +0100
++++ linux-2.6.25.1/include/linux/ssb/ssb_driver_gige.h 2008-05-07 22:57:40.000000000 +0100
 @@ -0,0 +1,174 @@
 +#ifndef LINUX_SSB_DRIVER_GIGE_H_
 +#define LINUX_SSB_DRIVER_GIGE_H_
 @@ -0,0 +1,174 @@
 +#ifndef LINUX_SSB_DRIVER_GIGE_H_
 +#define LINUX_SSB_DRIVER_GIGE_H_
@@ -506,11 +506,11 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_gige.h
 +
 +#endif /* CONFIG_SSB_DRIVER_GIGE */
 +#endif /* LINUX_SSB_DRIVER_GIGE_H_ */
 +
 +#endif /* CONFIG_SSB_DRIVER_GIGE */
 +#endif /* LINUX_SSB_DRIVER_GIGE_H_ */
-Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
+Index: linux-2.6.25.1/drivers/ssb/driver_pcicore.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_pcicore.c  2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_pcicore.c       2008-03-19 11:16:18.000000000 +0100
-@@ -60,74 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock);
+--- linux-2.6.25.1.orig/drivers/ssb/driver_pcicore.c   2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/driver_pcicore.c        2008-05-07 22:57:40.000000000 +0100
+@@ -60,78 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock);
  /* Core to access the external PCI config space. Can only have one. */
  static struct ssb_pcicore *extpci_core;
  
  /* Core to access the external PCI config space. Can only have one. */
  static struct ssb_pcicore *extpci_core;
  
@@ -565,7 +565,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
 -
 -      /* Enable PCI bridge bus mastering and memory space */
 -      pci_set_master(dev);
 -
 -      /* Enable PCI bridge bus mastering and memory space */
 -      pci_set_master(dev);
--      pcibios_enable_device(dev, ~0);
+-      if (pcibios_enable_device(dev, ~0) < 0) {
+-              ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+-              return;
+-      }
 -
 -      /* Enable PCI bridge BAR1 prefetch and burst */
 -      pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
 -
 -      /* Enable PCI bridge BAR1 prefetch and burst */
 -      pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
@@ -582,10 +585,11 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
 -{
 -      return ssb_mips_irq(extpci_core->dev) + 2;
 -}
 -{
 -      return ssb_mips_irq(extpci_core->dev) + 2;
 -}
+-
  static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
                             unsigned int bus, unsigned int dev,
  static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
                             unsigned int bus, unsigned int dev,
-@@ -317,6 +249,92 @@ static struct pci_controller ssb_pcicore
+                            unsigned int func, unsigned int off)
+@@ -320,6 +248,95 @@ static struct pci_controller ssb_pcicore
        .mem_offset     = 0x24000000,
  };
  
        .mem_offset     = 0x24000000,
  };
  
@@ -652,7 +656,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
 +
 +      /* Enable PCI bridge bus mastering and memory space */
 +      pci_set_master(dev);
 +
 +      /* Enable PCI bridge bus mastering and memory space */
 +      pci_set_master(dev);
-+      pcibios_enable_device(dev, ~0);
++      if (pcibios_enable_device(dev, ~0) < 0) {
++              ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
++              return;
++      }
 +
 +      /* Enable PCI bridge BAR1 prefetch and burst */
 +      pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
 +
 +      /* Enable PCI bridge BAR1 prefetch and burst */
 +      pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
@@ -678,10 +685,10 @@ Index: linux-2.6.23.16/drivers/ssb/driver_pcicore.c
  static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
  {
        u32 val;
  static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
  {
        u32 val;
-Index: linux-2.6.23.16/drivers/ssb/embedded.c
+Index: linux-2.6.25.1/drivers/ssb/embedded.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/embedded.c        2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/embedded.c     2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/ssb/embedded.c 2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/embedded.c      2008-05-07 22:57:40.000000000 +0100
 @@ -10,6 +10,9 @@
  
  #include <linux/ssb/ssb.h>
 @@ -10,6 +10,9 @@
  
  #include <linux/ssb/ssb.h>
@@ -783,11 +790,11 @@ Index: linux-2.6.23.16/drivers/ssb/embedded.c
 +
 +      return -ENODEV;
 +}
 +
 +      return -ENODEV;
 +}
-Index: linux-2.6.23.16/include/linux/ssb/ssb.h
+Index: linux-2.6.25.1/include/linux/ssb/ssb.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb.h       2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb.h    2008-03-19 11:16:18.000000000 +0100
-@@ -422,5 +422,12 @@ extern int ssb_bus_powerup(struct ssb_bu
+--- linux-2.6.25.1.orig/include/linux/ssb/ssb.h        2008-05-07 22:45:33.000000000 +0100
++++ linux-2.6.25.1/include/linux/ssb/ssb.h     2008-05-07 22:57:40.000000000 +0100
+@@ -426,5 +426,12 @@ extern int ssb_bus_powerup(struct ssb_bu
  extern u32 ssb_admatch_base(u32 adm);
  extern u32 ssb_admatch_size(u32 adm);
  
  extern u32 ssb_admatch_base(u32 adm);
  extern u32 ssb_admatch_size(u32 adm);
  
@@ -800,10 +807,10 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb.h
 +#endif /* CONFIG_SSB_EMBEDDED */
  
  #endif /* LINUX_SSB_H_ */
 +#endif /* CONFIG_SSB_EMBEDDED */
  
  #endif /* LINUX_SSB_H_ */
-Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
+Index: linux-2.6.25.1/include/linux/ssb/ssb_driver_pci.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/include/linux/ssb/ssb_driver_pci.h    2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h 2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/include/linux/ssb/ssb_driver_pci.h     2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/include/linux/ssb/ssb_driver_pci.h  2008-05-07 22:57:40.000000000 +0100
 @@ -1,6 +1,11 @@
  #ifndef LINUX_SSB_PCICORE_H_
  #define LINUX_SSB_PCICORE_H_
 @@ -1,6 +1,11 @@
  #ifndef LINUX_SSB_PCICORE_H_
  #define LINUX_SSB_PCICORE_H_
@@ -843,10 +850,10 @@ Index: linux-2.6.23.16/include/linux/ssb/ssb_driver_pci.h
 +
  #endif /* CONFIG_SSB_DRIVER_PCICORE */
  #endif /* LINUX_SSB_PCICORE_H_ */
 +
  #endif /* CONFIG_SSB_DRIVER_PCICORE */
  #endif /* LINUX_SSB_PCICORE_H_ */
-Index: linux-2.6.23.16/drivers/ssb/main.c
+Index: linux-2.6.25.1/drivers/ssb/main.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/main.c    2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/main.c 2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/ssb/main.c     2008-05-07 22:45:33.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/main.c  2008-05-07 22:57:40.000000000 +0100
 @@ -14,6 +14,7 @@
  #include <linux/io.h>
  #include <linux/ssb/ssb.h>
 @@ -14,6 +14,7 @@
  #include <linux/io.h>
  #include <linux/ssb/ssb.h>
@@ -881,7 +888,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
  static struct ssb_device *ssb_device_get(struct ssb_device *dev)
  {
        if (dev)
  static struct ssb_device *ssb_device_get(struct ssb_device *dev)
  {
        if (dev)
-@@ -1175,7 +1195,14 @@ static int __init ssb_modinit(void)
+@@ -1181,7 +1201,14 @@ static int __init ssb_modinit(void)
        err = b43_pci_ssb_bridge_init();
        if (err) {
                ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
        err = b43_pci_ssb_bridge_init();
        if (err) {
                ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
@@ -897,7 +904,7 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
                /* don't fail SSB init because of this */
                err = 0;
        }
                /* don't fail SSB init because of this */
                err = 0;
        }
-@@ -1189,6 +1216,7 @@ fs_initcall(ssb_modinit);
+@@ -1195,6 +1222,7 @@ fs_initcall(ssb_modinit);
  
  static void __exit ssb_modexit(void)
  {
  
  static void __exit ssb_modexit(void)
  {
@@ -905,10 +912,10 @@ Index: linux-2.6.23.16/drivers/ssb/main.c
        b43_pci_ssb_bridge_exit();
        bus_unregister(&ssb_bustype);
  }
        b43_pci_ssb_bridge_exit();
        bus_unregister(&ssb_bustype);
  }
-Index: linux-2.6.23.16/drivers/ssb/ssb_private.h
+Index: linux-2.6.25.1/drivers/ssb/ssb_private.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/ssb_private.h     2008-03-19 11:16:15.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/ssb_private.h  2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/ssb/ssb_private.h      2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/ssb_private.h   2008-05-07 22:57:40.000000000 +0100
 @@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 pllty
  extern int ssb_devices_freeze(struct ssb_bus *bus);
  extern int ssb_devices_thaw(struct ssb_bus *bus);
 @@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 pllty
  extern int ssb_devices_freeze(struct ssb_bus *bus);
  extern int ssb_devices_thaw(struct ssb_bus *bus);
@@ -917,11 +924,11 @@ Index: linux-2.6.23.16/drivers/ssb/ssb_private.h
 +                        int (*func)(struct ssb_bus *bus, unsigned long data));
  
  /* b43_pci_bridge.c */
 +                        int (*func)(struct ssb_bus *bus, unsigned long data));
  
  /* b43_pci_bridge.c */
- #ifdef CONFIG_SSB_PCIHOST
-Index: linux-2.6.23.16/drivers/net/tg3.c
+ #ifdef CONFIG_SSB_B43_PCI_BRIDGE
+Index: linux-2.6.25.1/drivers/net/tg3.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/net/tg3.c     2008-03-19 11:16:15.000000000 +0100
-+++ linux-2.6.23.16/drivers/net/tg3.c  2008-03-19 11:16:18.000000000 +0100
+--- linux-2.6.25.1.orig/drivers/net/tg3.c      2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/net/tg3.c   2008-05-07 22:57:40.000000000 +0100
 @@ -38,6 +38,7 @@
  #include <linux/workqueue.h>
  #include <linux/prefetch.h>
 @@ -38,6 +38,7 @@
  #include <linux/workqueue.h>
  #include <linux/prefetch.h>
@@ -930,7 +937,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
  
  #include <net/checksum.h>
  #include <net/ip.h>
  
  #include <net/checksum.h>
  #include <net/ip.h>
-@@ -410,8 +411,9 @@ static void _tw32_flush(struct tg3 *tp, 
+@@ -425,8 +426,9 @@ static void _tw32_flush(struct tg3 *tp, 
  static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
  {
        tp->write32_mbox(tp, off, val);
  static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
  {
        tp->write32_mbox(tp, off, val);
@@ -942,7 +949,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
                tp->read32_mbox(tp, off);
  }
  
                tp->read32_mbox(tp, off);
  }
  
-@@ -623,7 +625,7 @@ static void tg3_switch_clocks(struct tg3
+@@ -706,7 +708,7 @@ static void tg3_switch_clocks(struct tg3
  
  #define PHY_BUSY_LOOPS        5000
  
  
  #define PHY_BUSY_LOOPS        5000
  
@@ -951,7 +958,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
  {
        u32 frame_val;
        unsigned int loops;
  {
        u32 frame_val;
        unsigned int loops;
-@@ -637,7 +639,7 @@ static int tg3_readphy(struct tg3 *tp, i
+@@ -720,7 +722,7 @@ static int tg3_readphy(struct tg3 *tp, i
  
        *val = 0x0;
  
  
        *val = 0x0;
  
@@ -960,7 +967,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
                      MI_COM_PHY_ADDR_MASK);
        frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
                      MI_COM_REG_ADDR_MASK);
                      MI_COM_PHY_ADDR_MASK);
        frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
                      MI_COM_REG_ADDR_MASK);
-@@ -672,7 +674,12 @@ static int tg3_readphy(struct tg3 *tp, i
+@@ -755,7 +757,12 @@ static int tg3_readphy(struct tg3 *tp, i
        return ret;
  }
  
        return ret;
  }
  
@@ -974,7 +981,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
  {
        u32 frame_val;
        unsigned int loops;
  {
        u32 frame_val;
        unsigned int loops;
-@@ -688,7 +695,7 @@ static int tg3_writephy(struct tg3 *tp, 
+@@ -771,7 +778,7 @@ static int tg3_writephy(struct tg3 *tp, 
                udelay(80);
        }
  
                udelay(80);
        }
  
@@ -983,8 +990,8 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
                      MI_COM_PHY_ADDR_MASK);
        frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
                      MI_COM_REG_ADDR_MASK);
                      MI_COM_PHY_ADDR_MASK);
        frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
                      MI_COM_REG_ADDR_MASK);
-@@ -721,6 +728,11 @@ static int tg3_writephy(struct tg3 *tp, 
-       return ret;
+@@ -810,6 +817,11 @@ static void tg3_phydsp_write(struct tg3 
+       tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
  }
  
 +static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
  }
  
 +static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
@@ -995,22 +1002,22 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
  static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
  {
        u32 phy;
  static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
  {
        u32 phy;
-@@ -1988,6 +2000,14 @@ static int tg3_setup_copper_phy(struct t
-               tp->link_config.active_duplex = current_duplex;
-       }
+@@ -2250,6 +2262,14 @@ static int tg3_setup_copper_phy(struct t
+                       }
+               }
  
  
-+      if (tp->tg3_flags3 & TG3_FLG3_ROBOSWITCH) {
-+              current_link_up = 1;
-+              current_speed = SPEED_1000; //FIXME
-+              current_duplex = DUPLEX_FULL;
-+              tp->link_config.active_speed = current_speed;
-+              tp->link_config.active_duplex = current_duplex;
-+      }
++              if (tp->tg3_flags & TG3_FLG3_ROBOSWITCH) {
++                      current_link_up = 1;
++                      current_speed = SPEED_1000; //FIXME
++                      current_duplex = DUPLEX_FULL;
++                      tp->link_config.active_speed = current_speed;
++                      tp->link_config.active_duplex = current_duplex;
++              }
 +
 +
-       if (current_link_up == 1 &&
-           (tp->link_config.active_duplex == DUPLEX_FULL) &&
-           (tp->link_config.autoneg == AUTONEG_ENABLE)) {
-@@ -4813,6 +4833,11 @@ static int tg3_poll_fw(struct tg3 *tp)
+               if (current_link_up == 1 &&
+                   tp->link_config.active_duplex == DUPLEX_FULL)
+                       tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+@@ -5197,6 +5217,11 @@ static int tg3_poll_fw(struct tg3 *tp)
        int i;
        u32 val;
  
        int i;
        u32 val;
  
@@ -1022,7 +1029,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                /* Wait up to 20ms for init done. */
                for (i = 0; i < 200; i++) {
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                /* Wait up to 20ms for init done. */
                for (i = 0; i < 200; i++) {
-@@ -5040,6 +5065,14 @@ static int tg3_chip_reset(struct tg3 *tp
+@@ -5435,6 +5460,14 @@ static int tg3_chip_reset(struct tg3 *tp
                tw32(0x5000, 0x400);
        }
  
                tw32(0x5000, 0x400);
        }
  
@@ -1037,7 +1044,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        tw32(GRC_MODE, tp->grc_mode);
  
        if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
        tw32(GRC_MODE, tp->grc_mode);
  
        if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
-@@ -5308,9 +5341,12 @@ static int tg3_halt_cpu(struct tg3 *tp, 
+@@ -5704,9 +5737,12 @@ static int tg3_halt_cpu(struct tg3 *tp, 
                return -ENODEV;
        }
  
                return -ENODEV;
        }
  
@@ -1053,7 +1060,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        return 0;
  }
  
        return 0;
  }
  
-@@ -5391,6 +5427,11 @@ static int tg3_load_5701_a0_firmware_fix
+@@ -5787,6 +5823,11 @@ static int tg3_load_5701_a0_firmware_fix
        struct fw_info info;
        int err, i;
  
        struct fw_info info;
        int err, i;
  
@@ -1065,7 +1072,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        info.text_base = TG3_FW_TEXT_ADDR;
        info.text_len = TG3_FW_TEXT_LEN;
        info.text_data = &tg3FwText[0];
        info.text_base = TG3_FW_TEXT_ADDR;
        info.text_len = TG3_FW_TEXT_LEN;
        info.text_data = &tg3FwText[0];
-@@ -5949,6 +5990,11 @@ static int tg3_load_tso_firmware(struct 
+@@ -6345,6 +6386,11 @@ static int tg3_load_tso_firmware(struct 
        unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
        int err, i;
  
        unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
        int err, i;
  
@@ -1077,7 +1084,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                return 0;
  
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                return 0;
  
-@@ -6850,6 +6896,11 @@ static void tg3_timer(unsigned long __op
+@@ -7306,6 +7352,11 @@ static void tg3_timer(unsigned long __op
  
        spin_lock(&tp->lock);
  
  
        spin_lock(&tp->lock);
  
@@ -1089,9 +1096,9 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
                /* All of this garbage is because when using non-tagged
                 * IRQ status the mailbox/status_block protocol the chip
        if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
                /* All of this garbage is because when using non-tagged
                 * IRQ status the mailbox/status_block protocol the chip
-@@ -8432,6 +8483,11 @@ static int tg3_test_nvram(struct tg3 *tp
-       u32 *buf, csum, magic;
-       int i, j, err = 0, size;
+@@ -8906,6 +8957,11 @@ static int tg3_test_nvram(struct tg3 *tp
+       __le32 *buf;
+       int i, j, k, err = 0, size;
  
 +      if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
 +              /* We don't have NVRAM. */
  
 +      if (tp->tg3_flags3 & TG3_FLG3_IS_SSB_CORE) {
 +              /* We don't have NVRAM. */
@@ -1101,7 +1108,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
                return -EIO;
  
        if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
                return -EIO;
  
-@@ -9154,7 +9210,7 @@ static int tg3_ioctl(struct net_device *
+@@ -9689,7 +9745,7 @@ static int tg3_ioctl(struct net_device *
                        return -EAGAIN;
  
                spin_lock_bh(&tp->lock);
                        return -EAGAIN;
  
                spin_lock_bh(&tp->lock);
@@ -1110,7 +1117,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
                spin_unlock_bh(&tp->lock);
  
                data->val_out = mii_regval;
                spin_unlock_bh(&tp->lock);
  
                data->val_out = mii_regval;
-@@ -9173,7 +9229,7 @@ static int tg3_ioctl(struct net_device *
+@@ -9708,7 +9764,7 @@ static int tg3_ioctl(struct net_device *
                        return -EAGAIN;
  
                spin_lock_bh(&tp->lock);
                        return -EAGAIN;
  
                spin_lock_bh(&tp->lock);
@@ -1119,7 +1126,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
                spin_unlock_bh(&tp->lock);
  
                return err;
                spin_unlock_bh(&tp->lock);
  
                return err;
-@@ -9571,6 +9627,12 @@ static void __devinit tg3_get_5906_nvram
+@@ -10177,6 +10233,12 @@ static void __devinit tg3_get_5906_nvram
  /* Chips other than 5700/5701 use the NVRAM for fetching info. */
  static void __devinit tg3_nvram_init(struct tg3 *tp)
  {
  /* Chips other than 5700/5701 use the NVRAM for fetching info. */
  static void __devinit tg3_nvram_init(struct tg3 *tp)
  {
@@ -1132,7 +1139,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        tw32_f(GRC_EEPROM_ADDR,
             (EEPROM_ADDR_FSM_RESET |
              (EEPROM_DEFAULT_CLOCK_PERIOD <<
        tw32_f(GRC_EEPROM_ADDR,
             (EEPROM_ADDR_FSM_RESET |
              (EEPROM_DEFAULT_CLOCK_PERIOD <<
-@@ -9706,6 +9768,9 @@ static int tg3_nvram_read(struct tg3 *tp
+@@ -10317,6 +10379,9 @@ static int tg3_nvram_read(struct tg3 *tp
  {
        int ret;
  
  {
        int ret;
  
@@ -1142,7 +1149,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
                return tg3_nvram_read_using_eeprom(tp, offset, val);
  
        if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
                return tg3_nvram_read_using_eeprom(tp, offset, val);
  
-@@ -9938,6 +10003,9 @@ static int tg3_nvram_write_block(struct 
+@@ -10563,6 +10628,9 @@ static int tg3_nvram_write_block(struct 
  {
        int ret;
  
  {
        int ret;
  
@@ -1152,7 +1159,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
                tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
                       ~GRC_LCLCTRL_GPIO_OUTPUT1);
        if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
                tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
                       ~GRC_LCLCTRL_GPIO_OUTPUT1);
-@@ -10804,7 +10872,6 @@ static int __devinit tg3_get_invariants(
+@@ -11610,7 +11678,6 @@ static int __devinit tg3_get_invariants(
                tp->write32 = tg3_write_flush_reg32;
        }
  
                tp->write32 = tg3_write_flush_reg32;
        }
  
@@ -1160,7 +1167,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
            (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
                tp->write32_tx_mbox = tg3_write32_tx_mbox;
        if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
            (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
                tp->write32_tx_mbox = tg3_write32_tx_mbox;
-@@ -10840,6 +10907,11 @@ static int __devinit tg3_get_invariants(
+@@ -11646,6 +11713,11 @@ static int __devinit tg3_get_invariants(
              GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
                tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
  
              GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
                tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
  
@@ -1172,7 +1179,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        /* Get eeprom hw config before calling tg3_set_power_state().
         * In particular, the TG3_FLG2_IS_NIC flag must be
         * determined before calling tg3_set_power_state() so that
        /* Get eeprom hw config before calling tg3_set_power_state().
         * In particular, the TG3_FLG2_IS_NIC flag must be
         * determined before calling tg3_set_power_state() so that
-@@ -11184,6 +11256,10 @@ static int __devinit tg3_get_device_addr
+@@ -12017,6 +12089,10 @@ static int __devinit tg3_get_device_addr
        }
  
        if (!is_valid_ether_addr(&dev->dev_addr[0])) {
        }
  
        if (!is_valid_ether_addr(&dev->dev_addr[0])) {
@@ -1180,10 +1187,10 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
 +                      ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
 +      }
 +      if (!is_valid_ether_addr(&dev->dev_addr[0])) {
 +                      ssb_gige_get_macaddr(tp->pdev, &dev->dev_addr[0]);
 +      }
 +      if (!is_valid_ether_addr(&dev->dev_addr[0])) {
- #ifdef CONFIG_SPARC64
+ #ifdef CONFIG_SPARC
                if (!tg3_get_default_macaddr_sparc(tp))
                        return 0;
                if (!tg3_get_default_macaddr_sparc(tp))
                        return 0;
-@@ -11675,6 +11751,7 @@ static char * __devinit tg3_phy_string(s
+@@ -12508,6 +12584,7 @@ static char * __devinit tg3_phy_string(s
        case PHY_ID_BCM5704:    return "5704";
        case PHY_ID_BCM5705:    return "5705";
        case PHY_ID_BCM5750:    return "5750";
        case PHY_ID_BCM5704:    return "5704";
        case PHY_ID_BCM5705:    return "5705";
        case PHY_ID_BCM5750:    return "5750";
@@ -1191,7 +1198,7 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
        case PHY_ID_BCM5752:    return "5752";
        case PHY_ID_BCM5714:    return "5714";
        case PHY_ID_BCM5780:    return "5780";
        case PHY_ID_BCM5752:    return "5752";
        case PHY_ID_BCM5714:    return "5714";
        case PHY_ID_BCM5780:    return "5780";
-@@ -11859,6 +11936,13 @@ static int __devinit tg3_init_one(struct
+@@ -12695,6 +12772,13 @@ static int __devinit tg3_init_one(struct
                tp->msg_enable = tg3_debug;
        else
                tp->msg_enable = TG3_DEF_MSG_ENABLE;
                tp->msg_enable = tg3_debug;
        else
                tp->msg_enable = TG3_DEF_MSG_ENABLE;
@@ -1205,44 +1212,42 @@ Index: linux-2.6.23.16/drivers/net/tg3.c
  
        /* The word/byte swap controls here control register access byte
         * swapping.  DMA data byte swapping is controlled in the GRC_MODE
  
        /* The word/byte swap controls here control register access byte
         * swapping.  DMA data byte swapping is controlled in the GRC_MODE
-Index: linux-2.6.23.16/drivers/net/tg3.h
+Index: linux-2.6.25.1/drivers/net/tg3.h
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/net/tg3.h     2008-03-19 11:16:15.000000000 +0100
-+++ linux-2.6.23.16/drivers/net/tg3.h  2008-03-19 11:16:18.000000000 +0100
-@@ -2279,6 +2279,10 @@ struct tg3 {
- #define TG3_FLG2_PHY_JITTER_BUG               0x20000000
- #define TG3_FLG2_NO_FWARE_REPORTED    0x40000000
- #define TG3_FLG2_PHY_ADJUST_TRIM      0x80000000
-+      u32                             tg3_flags3;
-+#define TG3_FLG3_IS_SSB_CORE          0x00000001
-+#define TG3_FLG3_FLUSH_POSTED_WRITES  0x00000002
-+#define TG3_FLG3_ROBOSWITCH           0x00000004
+--- linux-2.6.25.1.orig/drivers/net/tg3.h      2008-05-07 22:45:24.000000000 +0100
++++ linux-2.6.25.1/drivers/net/tg3.h   2008-05-07 23:02:12.000000000 +0100
+@@ -2477,6 +2477,9 @@ struct tg3 {
+ #define TG3_FLG3_ENABLE_APE           0x00000002
+ #define TG3_FLG3_5761_5784_AX_FIXES   0x00000004
+ #define TG3_FLG3_5701_DMA_BUG         0x00000008
++#define TG3_FLG3_IS_SSB_CORE          0x00000010
++#define TG3_FLG3_FLUSH_POSTED_WRITES  0x00000020
++#define TG3_FLG3_ROBOSWITCH           0x00000040
  
        struct timer_list               timer;
        u16                             timer_counter;
  
        struct timer_list               timer;
        u16                             timer_counter;
-@@ -2333,6 +2337,7 @@ struct tg3 {
+@@ -2532,6 +2535,7 @@ struct tg3 {
  #define PHY_ID_BCM5714                        0x60008340
  #define PHY_ID_BCM5780                        0x60008350
  #define PHY_ID_BCM5755                        0xbc050cc0
 +#define PHY_ID_BCM5750_2              0xbc050cd0
  #define PHY_ID_BCM5787                        0xbc050ce0
  #define PHY_ID_BCM5756                        0xbc050ed0
  #define PHY_ID_BCM5714                        0x60008340
  #define PHY_ID_BCM5780                        0x60008350
  #define PHY_ID_BCM5755                        0xbc050cc0
 +#define PHY_ID_BCM5750_2              0xbc050cd0
  #define PHY_ID_BCM5787                        0xbc050ce0
  #define PHY_ID_BCM5756                        0xbc050ed0
- #define PHY_ID_BCM5906                        0xdc00ac40
-@@ -2364,7 +2369,8 @@ struct tg3 {
-        (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
+ #define PHY_ID_BCM5784                        0xbc050fa0
+@@ -2568,7 +2572,7 @@ struct tg3 {
         (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
         (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
         (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
         (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
--       (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
-+       (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002 || \
-+       (X) == PHY_ID_BCM5750_2)
+        (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
+-       (X) == PHY_ID_BCM8002)
++       (X) == PHY_ID_BCM8002 || (X) == PHY_ID_BCM5750_2)
  
        struct tg3_hw_stats             *hw_stats;
        dma_addr_t                      stats_mapping;
  
        struct tg3_hw_stats             *hw_stats;
        dma_addr_t                      stats_mapping;
-Index: linux-2.6.23.16/drivers/ssb/driver_mipscore.c
+Index: linux-2.6.25.1/drivers/ssb/driver_mipscore.c
 ===================================================================
 ===================================================================
---- linux-2.6.23.16.orig/drivers/ssb/driver_mipscore.c 2008-03-19 11:16:18.000000000 +0100
-+++ linux-2.6.23.16/drivers/ssb/driver_mipscore.c      2008-03-19 11:16:18.000000000 +0100
-@@ -211,6 +211,7 @@ void ssb_mipscore_init(struct ssb_mipsco
+--- linux-2.6.25.1.orig/drivers/ssb/driver_mipscore.c  2008-05-07 22:45:33.000000000 +0100
++++ linux-2.6.25.1/drivers/ssb/driver_mipscore.c       2008-05-07 22:57:40.000000000 +0100
+@@ -212,6 +212,7 @@ void ssb_mipscore_init(struct ssb_mipsco
                        /* fallthrough */
                case SSB_DEV_PCI:
                case SSB_DEV_ETHERNET:
                        /* fallthrough */
                case SSB_DEV_PCI:
                case SSB_DEV_ETHERNET:
diff --git a/target/linux/brcm47xx/patches-2.6.25/800-cfe-workaround.patch b/target/linux/brcm47xx/patches-2.6.25/800-cfe-workaround.patch
new file mode 100644 (file)
index 0000000..361f006
--- /dev/null
@@ -0,0 +1,23 @@
+Index: linux-2.6.25.1/arch/mips/bcm47xx/prom.c
+===================================================================
+--- linux-2.6.25.1.orig/arch/mips/bcm47xx/prom.c       2008-05-14 14:46:44.000000000 +0100
++++ linux-2.6.25.1/arch/mips/bcm47xx/prom.c    2008-05-14 17:05:43.000000000 +0100
+@@ -83,9 +83,18 @@ static __init void prom_init_cfe(void)
+               }
+       }
++        if (((unsigned int)prom_vec == 0x80300000) ||
++          ((unsigned int)prom_vec == 0x80400000)) {
++              /* WRT54G series workaround */
++              cfe_eptseal = CFE_EPTSEAL;
++              cfe_ept = 0xBFC00500;
++              cfe_handle = (uint32_t)argc;
++        }
++
+       if (cfe_eptseal != CFE_EPTSEAL) {
+               /* too early for panic to do any good */
+               printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
++              *(unsigned int*)0xb8000064 = 0x1;
+               while (1) ;
+       }
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/gpio/gpio_dev.c b/target/linux/generic-2.6/files-2.6.25/drivers/gpio/gpio_dev.c
new file mode 100644 (file)
index 0000000..48ef76f
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * character device wrapper for generic gpio layer
+ *
+ * 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, MA02111-1307USA
+ *
+ * Feedback, Bugs...  blogic@openwrt.org
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/atomic.h>
+#include <linux/init.h>
+#include <linux/genhd.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_dev.h>
+
+#define DRVNAME                "gpiodev"
+#define DEVNAME                "gpio"
+
+static int dev_major;
+static unsigned int gpio_access_mask;
+static struct class *gpio_class;
+
+/* Counter is 1, if the device is not opened and zero (or less) if opened. */
+static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
+
+static int
+gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+
+       if (((1 << arg) & gpio_access_mask) != (1 << arg))
+       {
+               retval = -EINVAL;
+               goto out;
+       }
+
+       switch (cmd)
+       {
+       case GPIO_GET:
+               retval = gpio_get_value(arg);
+               break;
+
+       case GPIO_SET:
+               gpio_set_value(arg, 1);
+               break;
+
+       case GPIO_CLEAR:
+               gpio_set_value(arg, 0);
+               break;
+
+       case GPIO_DIR_IN:
+               gpio_direction_input(arg);
+               break;
+
+       case GPIO_DIR_OUT:
+               gpio_direction_output(arg, 0);
+               break;
+
+       default:
+               retval = -EINVAL;
+               break;
+       }
+
+out:
+       return retval;
+}
+
+static int
+gpio_open(struct inode *inode, struct file *file)
+{
+       int result = 0;
+       unsigned int dev_minor = MINOR(inode->i_rdev);
+
+       if (dev_minor != 0)
+       {
+               printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor);
+               result = -ENODEV;
+               goto out;
+       }
+
+       /* FIXME: We should really allow multiple applications to open the device
+        *        at the same time, as long as the apps access different IO pins.
+        *        The generic gpio-registration functions can be used for that.
+        *        Two new IOCTLs have to be introduced for that. Need to check userspace
+        *        compatibility first. --mb */
+       if (!atomic_dec_and_test(&gpio_open_cnt)) {
+               atomic_inc(&gpio_open_cnt);
+               printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
+               result = -EBUSY;
+               goto out;
+       }
+
+out:
+       return result;
+}
+
+static int
+gpio_close(struct inode * inode, struct file * file)
+{
+       smp_mb__before_atomic_inc();
+       atomic_inc(&gpio_open_cnt);
+
+       return 0;
+}
+
+struct file_operations gpio_fops = {
+       ioctl:          gpio_ioctl,
+       open:           gpio_open,
+       release:        gpio_close
+};
+
+static int
+gpio_probe(struct platform_device *dev)
+{
+       int result = 0;
+
+       dev_major = register_chrdev(0, DEVNAME, &gpio_fops);
+       if (!dev_major)
+       {
+               printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME);
+               result = -ENODEV;
+               goto out;
+       }
+
+       gpio_class = class_create(THIS_MODULE, DEVNAME);
+       class_device_create(gpio_class, NULL, MKDEV(dev_major, 0), NULL, DEVNAME);
+
+       printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major);
+
+       if (dev->num_resources != 1)
+       {
+               printk(KERN_ERR DRVNAME ": device may only have 1 resource\n");
+               result = -ENODEV;
+               goto out;
+       }
+
+       gpio_access_mask = dev->resource[0].start;
+
+       printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask);
+out:
+       return result;
+}
+
+static int
+gpio_remove(struct platform_device *dev)
+{
+       unregister_chrdev(dev_major, DEVNAME);
+       return 0;
+}
+
+static struct
+platform_driver gpio_driver = {
+       .probe = gpio_probe,
+       .remove = gpio_remove,
+       .driver = {
+               .name = "GPIODEV",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init
+gpio_mod_init(void)
+{
+       int ret = platform_driver_register(&gpio_driver);
+       if (ret)
+               printk(KERN_INFO DRVNAME ": Error registering platfom driver!");
+
+       return ret;
+}
+
+static void __exit
+gpio_mod_exit(void)
+{
+       platform_driver_unregister(&gpio_driver);
+}
+
+module_init (gpio_mod_init);
+module_exit (gpio_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin / OpenWrt");
+MODULE_DESCRIPTION("Character device for for generic gpio api");
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/input/misc/gpio_buttons.c b/target/linux/generic-2.6/files-2.6.25/drivers/input/misc/gpio_buttons.c
new file mode 100644 (file)
index 0000000..83a8178
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ *  Driver for buttons on GPIO lines not capable of generating interrupts
+ *
+ *  Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This file was based on: /drivers/input/misc/cobalt_btns.c
+ *     Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  also was based on: /drivers/input/keyboard/gpio_keys.c
+ *     Copyright 2005 Phil Blundell
+ *
+ *  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <linux/gpio_buttons.h>
+
+#include <asm/gpio.h>
+
+#define DRV_NAME       "gpio-buttons"
+#define DRV_VERSION    "0.1.1"
+#define PFX            DRV_NAME ": "
+
+struct gpio_buttons_dev {
+       struct input_polled_dev *poll_dev;
+       struct gpio_buttons_platform_data *pdata;
+};
+
+static void gpio_buttons_poll(struct input_polled_dev *dev)
+{
+       struct gpio_buttons_dev *bdev = dev->private;
+       struct gpio_buttons_platform_data *pdata = bdev->pdata;
+       struct input_dev *input = dev->input;
+       int i;
+
+       for (i = 0; i < bdev->pdata->nbuttons; i++) {
+               struct gpio_button *button = &pdata->buttons[i];
+               unsigned int type = button->type ?: EV_KEY;
+               int state;
+
+               state = gpio_get_value(button->gpio) ? 1 : 0;
+               state ^= button->active_low;
+
+               if (state) {
+                       button->count++;
+               } else {
+                       if (button->count >= button->threshold) {
+                               input_event(input, type, button->code, 1);
+                               input_sync(input);
+                       }
+                       button->count = 0;
+               }
+
+               if (button->count == button->threshold) {
+                       input_event(input, type, button->code, 0);
+                       input_sync(input);
+               }
+       }
+}
+
+static int __devinit gpio_buttons_probe(struct platform_device *pdev)
+{
+       struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_buttons_dev *bdev;
+       struct input_polled_dev *poll_dev;
+       struct input_dev *input;
+       int error, i;
+
+
+       if (!pdata)
+               return -ENXIO;
+
+       bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
+       if (!bdev) {
+               printk(KERN_ERR DRV_NAME "no memory for device\n");
+               return -ENOMEM;
+       }
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               printk(KERN_ERR DRV_NAME "no memory for polled device\n");
+               error = -ENOMEM;
+               goto err_free_bdev;
+       }
+
+       poll_dev->private = bdev;
+       poll_dev->poll = gpio_buttons_poll;
+       poll_dev->poll_interval = pdata->poll_interval;
+
+       input = poll_dev->input;
+
+       input->evbit[0] = BIT(EV_KEY);
+       input->name = pdev->name;
+       input->phys = "gpio-buttons/input0";
+       input->dev.parent = &pdev->dev;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               struct gpio_button *button = &pdata->buttons[i];
+               unsigned int gpio = button->gpio;
+               unsigned int type = button->type ?: EV_KEY;
+
+               error = gpio_request(gpio, button->desc ?
+                               button->desc : DRV_NAME);
+               if (error) {
+                       printk(KERN_ERR PFX "unable to claim gpio %u, "
+                               "error %d\n", gpio, error);
+                       goto err_free_gpio;
+               }
+
+               error = gpio_direction_input(gpio);
+               if (error) {
+                       printk(KERN_ERR PFX "unable to set direction on "
+                               "gpio %u, error %d\n", gpio, error);
+                       goto err_free_gpio;
+               }
+
+               input_set_capability(input, type, button->code);
+               button->count = 0;
+       }
+
+       bdev->poll_dev = poll_dev;
+       bdev->pdata = pdata;
+       platform_set_drvdata(pdev, bdev);
+
+       error = input_register_polled_device(poll_dev);
+       if (error) {
+               printk(KERN_ERR PFX "unable to register polled device, "
+                       "error %d\n", error);
+               goto err_free_gpio;
+       }
+
+       return 0;
+
+err_free_gpio:
+       for (i = i - 1; i >= 0; i--)
+               gpio_free(pdata->buttons[i].gpio);
+
+       input_free_polled_device(poll_dev);
+
+err_free_bdev:
+       kfree(bdev);
+
+       platform_set_drvdata(pdev, NULL);
+       return error;
+}
+
+static int __devexit gpio_buttons_remove(struct platform_device *pdev)
+{
+       struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
+       struct gpio_buttons_platform_data *pdata = bdev->pdata;
+       int i;
+
+       input_unregister_polled_device(bdev->poll_dev);
+
+       for (i = 0; i < pdata->nbuttons; i++)
+               gpio_free(pdata->buttons[i].gpio);
+
+       input_free_polled_device(bdev->poll_dev);
+
+       kfree(bdev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver gpio_buttons_driver = {
+       .probe  = gpio_buttons_probe,
+       .remove = __devexit_p(gpio_buttons_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init gpio_buttons_init(void)
+{
+       printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
+       return platform_driver_register(&gpio_buttons_driver);
+}
+
+static void __exit gpio_buttons_exit(void)
+{
+       platform_driver_unregister(&gpio_buttons_driver);
+}
+
+module_init(gpio_buttons_init);
+module_exit(gpio_buttons_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");
+
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/leds/leds-alix.c b/target/linux/generic-2.6/files-2.6.25/drivers/leds/leds-alix.c
new file mode 100644 (file)
index 0000000..103ca7d
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * LEDs driver for PCEngines ALIX 2/3 series
+ *
+ * Copyright (C) 2007 Petr Liebman
+ *
+ * Based on leds-wrap.c
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <asm/io.h>
+
+#define DRVNAME "alix-led"
+
+#define ALIX_LED1_PORT         (0x6100)
+#define ALIX_LED1_ON           (1<<22)
+#define ALIX_LED1_OFF          (1<<6)
+
+#define ALIX_LED2_PORT         (0x6180)
+#define ALIX_LED2_ON           (1<<25)
+#define ALIX_LED2_OFF          (1<<9)
+
+#define ALIX_LED3_PORT         (0x6180)
+#define ALIX_LED3_ON           (1<<27)
+#define ALIX_LED3_OFF          (1<<11)
+
+
+static struct platform_device *pdev;
+
+static void alix_led_set_1(struct led_classdev *led_cdev,
+               enum led_brightness value)
+{
+       if (value)
+               outl(ALIX_LED1_ON, ALIX_LED1_PORT);
+       else
+               outl(ALIX_LED1_OFF, ALIX_LED1_PORT);
+}
+
+static void alix_led_set_2(struct led_classdev *led_cdev,
+               enum led_brightness value)
+{
+       if (value)
+               outl(ALIX_LED2_ON, ALIX_LED2_PORT);
+       else
+               outl(ALIX_LED2_OFF, ALIX_LED2_PORT);
+}
+
+static void alix_led_set_3(struct led_classdev *led_cdev,
+               enum led_brightness value)
+{
+       if (value)
+               outl(ALIX_LED3_ON, ALIX_LED3_PORT);
+       else
+               outl(ALIX_LED3_OFF, ALIX_LED3_PORT);
+}
+
+static struct led_classdev alix_led_1 = {
+       .name           = "alix:1",
+       .brightness_set = alix_led_set_1,
+};
+
+static struct led_classdev alix_led_2 = {
+       .name           = "alix:2",
+       .brightness_set = alix_led_set_2,
+};
+
+static struct led_classdev alix_led_3 = {
+       .name           = "alix:3",
+       .brightness_set = alix_led_set_3,
+};
+
+
+#ifdef CONFIG_PM
+static int alix_led_suspend(struct platform_device *dev,
+               pm_message_t state)
+{
+       led_classdev_suspend(&alix_led_1);
+       led_classdev_suspend(&alix_led_2);
+       led_classdev_suspend(&alix_led_3);
+       return 0;
+}
+
+static int alix_led_resume(struct platform_device *dev)
+{
+       led_classdev_resume(&alix_led_1);
+       led_classdev_resume(&alix_led_2);
+       led_classdev_resume(&alix_led_3);
+       return 0;
+}
+#else
+#define alix_led_suspend NULL
+#define alix_led_resume NULL
+#endif
+
+static int alix_led_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = led_classdev_register(&pdev->dev, &alix_led_1);
+       if (ret >= 0)
+       {
+               ret = led_classdev_register(&pdev->dev, &alix_led_2);
+               if (ret >= 0)
+               {
+                       ret = led_classdev_register(&pdev->dev, &alix_led_3);
+                       if (ret < 0)
+                               led_classdev_unregister(&alix_led_2);
+               }
+               if (ret < 0)
+                       led_classdev_unregister(&alix_led_1);
+       }
+       return ret;
+}
+
+static int alix_led_remove(struct platform_device *pdev)
+{
+       led_classdev_unregister(&alix_led_1);
+       led_classdev_unregister(&alix_led_2);
+       led_classdev_unregister(&alix_led_3);
+       return 0;
+}
+
+static struct platform_driver alix_led_driver = {
+       .probe          = alix_led_probe,
+       .remove         = alix_led_remove,
+       .suspend        = alix_led_suspend,
+       .resume         = alix_led_resume,
+       .driver         = {
+               .name           = DRVNAME,
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init alix_led_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&alix_led_driver);
+       if (ret < 0)
+               goto out;
+
+       pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               platform_driver_unregister(&alix_led_driver);
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static void __exit alix_led_exit(void)
+{
+       platform_device_unregister(pdev);
+       platform_driver_unregister(&alix_led_driver);
+}
+
+module_init(alix_led_init);
+module_exit(alix_led_exit);
+
+MODULE_AUTHOR("Petr Liebman");
+MODULE_DESCRIPTION("PCEngines ALIX LED driver");
+MODULE_LICENSE("GPL");
+
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-default-on.c b/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-default-on.c
new file mode 100644 (file)
index 0000000..92995e4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * LED Kernel Default ON Trigger
+ *
+ * Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+static void defon_trig_activate(struct led_classdev *led_cdev)
+{
+       led_set_brightness(led_cdev, LED_FULL);
+}
+
+static struct led_trigger defon_led_trigger = {
+       .name     = "default-on",
+       .activate = defon_trig_activate,
+};
+
+static int __init defon_trig_init(void)
+{
+       return led_trigger_register(&defon_led_trigger);
+}
+
+static void __exit defon_trig_exit(void)
+{
+       led_trigger_unregister(&defon_led_trigger);
+}
+
+module_init(defon_trig_init);
+module_exit(defon_trig_exit);
+
+MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
+MODULE_DESCRIPTION("Default-ON LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-morse.c b/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-morse.c
new file mode 100644 (file)
index 0000000..cb47480
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *  LED Morse Trigger
+ *
+ *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This file was based on: drivers/led/ledtrig-timer.c
+ *     Copyright 2005-2006 Openedhand Ltd.
+ *     Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ *  also based on the patch '[PATCH] 2.5.59 morse code panics' posted
+ *  in the LKML by Tomas Szepe at Thu, 30 Jan 2003
+ *     Copyright (C) 2002 Andrew Rodland <arodland@noln.com>
+ *     Copyright (C) 2003 Tomas Szepe <szepe@pinerecords.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+
+#include "leds.h"
+
+#define MORSE_DELAY_BASE       (HZ/2)
+
+#define MORSE_STATE_BLINK_START        0
+#define MORSE_STATE_BLINK_STOP 1
+
+#define MORSE_DIT_LEN  1
+#define MORSE_DAH_LEN  3
+#define MORSE_SPACE_LEN        7
+
+struct morse_trig_data {
+       unsigned long delay;
+       char *msg;
+
+       unsigned char morse;
+       unsigned char state;
+       char *msgpos;
+       struct timer_list timer;
+};
+
+const unsigned char morsetable[] = {
+       0122, 0, 0310, 0, 0, 0163,                              /* "#$%&' */
+       055, 0155, 0, 0, 0163, 0141, 0152, 0051,                /* ()*+,-./ */
+       077, 076, 074, 070, 060, 040, 041, 043, 047, 057,       /* 0-9 */
+       0107, 0125, 0, 0061, 0, 0114, 0,                        /* :;<=>?@ */
+       006, 021, 025, 011, 002, 024, 013, 020, 004,            /* A-I */
+       036, 015, 022, 007, 005, 017, 026, 033, 012,            /* J-R */
+       010, 003, 014, 030, 016, 031, 035, 023,                 /* S-Z */
+       0, 0, 0, 0, 0154                                        /* [\]^_ */
+};
+
+static inline unsigned char tomorse(char c) {
+       if (c >= 'a' && c <= 'z')
+               c = c - 'a' + 'A';
+       if (c >= '"' && c <= '_') {
+               return morsetable[c - '"'];
+       } else
+               return 0;
+}
+
+static inline unsigned long dit_len(struct morse_trig_data *morse_data)
+{
+       return MORSE_DIT_LEN*morse_data->delay;
+}
+
+static inline unsigned long dah_len(struct morse_trig_data *morse_data)
+{
+       return MORSE_DAH_LEN*morse_data->delay;
+}
+
+static inline unsigned long space_len(struct morse_trig_data *morse_data)
+{
+       return MORSE_SPACE_LEN*morse_data->delay;
+}
+
+static void morse_timer_function(unsigned long data)
+{
+       struct led_classdev *led_cdev = (struct led_classdev *)data;
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+       unsigned long brightness = LED_OFF;
+       unsigned long delay = 0;
+
+       if (!morse_data->msg)
+               goto set_led;
+
+       switch (morse_data->state) {
+       case MORSE_STATE_BLINK_START:
+               /* Starting a new blink.  We have a valid code in morse. */
+               delay = (morse_data->morse & 001) ? dah_len(morse_data):
+                       dit_len(morse_data);
+               brightness = LED_FULL;
+               morse_data->state = MORSE_STATE_BLINK_STOP;
+               morse_data->morse >>= 1;
+               break;
+       case MORSE_STATE_BLINK_STOP:
+               /* Coming off of a blink. */
+               morse_data->state = MORSE_STATE_BLINK_START;
+
+               if (morse_data->morse > 1) {
+                       /* Not done yet, just a one-dit pause. */
+                       delay = dit_len(morse_data);
+                       break;
+               }
+
+               /* Get a new char, figure out how much space. */
+               /* First time through */
+               if (!morse_data->msgpos)
+                       morse_data->msgpos = (char *)morse_data->msg;
+
+               if (!*morse_data->msgpos) {
+                       /* Repeating */
+                       morse_data->msgpos = (char *)morse_data->msg;
+                       delay = space_len(morse_data);
+               } else {
+                       /* Inter-letter space */
+                       delay = dah_len(morse_data);
+               }
+
+               if (!(morse_data->morse = tomorse(*morse_data->msgpos))) {
+                       delay = space_len(morse_data);
+                       /* And get us back here */
+                       morse_data->state = MORSE_STATE_BLINK_STOP;
+               }
+               morse_data->msgpos++;
+               break;
+       }
+
+       mod_timer(&morse_data->timer, jiffies + msecs_to_jiffies(delay));
+
+set_led:
+       led_set_brightness(led_cdev, brightness);
+}
+
+static ssize_t _morse_delay_show(struct led_classdev *led_cdev, char *buf)
+{
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+
+       sprintf(buf, "%lu\n", morse_data->delay);
+
+       return strlen(buf) + 1;
+}
+
+static ssize_t _morse_delay_store(struct led_classdev *led_cdev,
+               const char *buf, size_t size)
+{
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+       char *after;
+       unsigned long state = simple_strtoul(buf, &after, 10);
+       size_t count = after - buf;
+       int ret = -EINVAL;
+
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               morse_data->delay = state;
+               mod_timer(&morse_data->timer, jiffies + 1);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static ssize_t _morse_msg_show(struct led_classdev *led_cdev, char *buf)
+{
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+
+       if (!morse_data->msg)
+               sprintf(buf, "<none>\n");
+       else
+               sprintf(buf, "%s\n", morse_data->msg);
+
+       return strlen(buf) + 1;
+}
+
+static ssize_t _morse_msg_store(struct led_classdev *led_cdev,
+               const char *buf, size_t size)
+{
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+       char *m;
+
+       m = kmalloc(size, GFP_KERNEL);
+       if (!m)
+               return -ENOMEM;
+
+       memcpy(m,buf,size);
+       m[size]='\0';
+
+       if (morse_data->msg)
+               kfree(morse_data->msg);
+
+       morse_data->msg = m;
+       morse_data->msgpos = NULL;
+       morse_data->state = MORSE_STATE_BLINK_STOP;
+
+       mod_timer(&morse_data->timer, jiffies + 1);
+
+       return size;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+static ssize_t morse_delay_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+       return _morse_delay_show(led_cdev, buf);
+}
+
+static ssize_t morse_delay_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+       return _morse_delay_store(led_cdev, buf, size);
+}
+
+static ssize_t morse_msg_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+       return _morse_msg_show(led_cdev, buf);
+}
+
+static ssize_t morse_msg_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+       return _morse_msg_store(led_cdev, buf, size);
+}
+
+static DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
+static DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
+
+#define led_device_create_file(leddev, attr) \
+       device_create_file(leddev->dev, &dev_attr_ ## attr)
+#define led_device_remove_file(leddev, attr) \
+       device_remove_file(leddev->dev, &dev_attr_ ## attr)
+
+#else
+static ssize_t morse_delay_show(struct class_device *dev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(dev);
+
+       return _morse_delay_show(led_cdev, buf);
+}
+
+static ssize_t morse_delay_store(struct class_device *dev, const char *buf,
+               size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(dev);
+
+       return _morse_delay_store(led_cdev, buf, size);
+}
+
+static ssize_t morse_msg_show(struct class_device *dev, char *buf)
+{
+       struct led_classdev *led_cdev = class_get_devdata(dev);
+
+       return _morse_msg_show(led_cdev, buf);
+}
+
+static ssize_t morse_msg_store(struct class_device *dev, const char *buf,
+                               size_t size)
+{
+       struct led_classdev *led_cdev = class_get_devdata(dev);
+
+       return _morse_msg_store(led_cdev, buf, size);
+}
+
+static CLASS_DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
+static CLASS_DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
+
+#define led_device_create_file(leddev, attr) \
+       class_device_create_file(leddev->class_dev, &class_device_attr_ ## attr)
+#define led_device_remove_file(leddev, attr) \
+       class_device_remove_file(leddev->class_dev, &class_device_attr_ ## attr)
+
+#endif
+
+static void morse_trig_activate(struct led_classdev *led_cdev)
+{
+       struct morse_trig_data *morse_data;
+       int rc;
+
+       morse_data = kzalloc(sizeof(*morse_data), GFP_KERNEL);
+       if (!morse_data)
+               return;
+
+       morse_data->delay = MORSE_DELAY_BASE;
+       init_timer(&morse_data->timer);
+       morse_data->timer.function = morse_timer_function;
+       morse_data->timer.data = (unsigned long)led_cdev;
+
+       rc = led_device_create_file(led_cdev, delay);
+       if (rc) goto err;
+
+       rc = led_device_create_file(led_cdev, message);
+       if (rc) goto err_delay;
+
+       led_cdev->trigger_data = morse_data;
+
+       return;
+
+err_delay:
+       led_device_remove_file(led_cdev, delay);
+err:
+       kfree(morse_data);
+}
+
+static void morse_trig_deactivate(struct led_classdev *led_cdev)
+{
+       struct morse_trig_data *morse_data = led_cdev->trigger_data;
+
+       if (!morse_data)
+               return;
+
+       led_device_remove_file(led_cdev, message);
+       led_device_remove_file(led_cdev, delay);
+
+       del_timer_sync(&morse_data->timer);
+       if (morse_data->msg)
+               kfree(morse_data->msg);
+
+       kfree(morse_data);
+}
+
+static struct led_trigger morse_led_trigger = {
+       .name           = "morse",
+       .activate       = morse_trig_activate,
+       .deactivate     = morse_trig_deactivate,
+};
+
+static int __init morse_trig_init(void)
+{
+       return led_trigger_register(&morse_led_trigger);
+}
+
+static void __exit morse_trig_exit(void)
+{
+       led_trigger_unregister(&morse_led_trigger);
+}
+
+module_init(morse_trig_init);
+module_exit(morse_trig_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
+MODULE_DESCRIPTION("Morse LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-netdev.c b/target/linux/generic-2.6/files-2.6.25/drivers/leds/ledtrig-netdev.c
new file mode 100644 (file)
index 0000000..285d0f7
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * LED Kernel Netdev Trigger
+ *
+ * Toggles the LED to reflect the link and traffic state of a named net device
+ *
+ * Copyright 2007 Oliver Jowett <oliver@opencloud.com>
+ *
+ * Derived from ledtrig-timer.c which is:
+ *  Copyright 2005-2006 Openedhand Ltd.
+ *  Author: Richard Purdie <rpurdie@openedhand.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+/*
+ * Configurable sysfs attributes:
+ *
+ * device_name - network device name to monitor
+ *
+ * interval - duration of LED blink, in milliseconds
+ *
+ * mode - either "none" (LED is off) or a space separated list of one or more of:
+ *   link: LED's normal state reflects whether the link is up (has carrier) or not
+ *   tx:   LED blinks on transmitted data
+ *   rx:   LED blinks on receive data
+ * 
+ * Some suggestions:
+ *
+ *  Simple link status LED:
+ *  $ echo netdev >someled/trigger
+ *  $ echo eth0 >someled/device_name
+ *  $ echo link >someled/mode
+ *
+ *  Ethernet-style link/activity LED:
+ *  $ echo netdev >someled/trigger
+ *  $ echo eth0 >someled/device_name
+ *  $ echo "link tx rx" >someled/mode
+ *
+ *  Modem-style tx/rx LEDs:
+ *  $ echo netdev >led1/trigger
+ *  $ echo ppp0 >led1/device_name
+ *  $ echo tx >led1/mode
+ *  $ echo netdev >led2/trigger
+ *  $ echo ppp0 >led2/device_name
+ *  $ echo rx >led2/mode
+ *
+ */
+
+#define MODE_LINK 1
+#define MODE_TX   2
+#define MODE_RX   4
+
+struct led_netdev_data {
+       rwlock_t lock;
+       
+       struct timer_list timer;
+       struct notifier_block notifier; 
+       
+       struct led_classdev *led_cdev;
+       struct net_device *net_dev;
+       
+       char device_name[IFNAMSIZ];
+       unsigned interval;
+       unsigned mode;
+       unsigned link_up;
+       unsigned last_activity;
+};
+
+static void set_baseline_state(struct led_netdev_data *trigger_data)
+{  
+       if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
+               led_set_brightness(trigger_data->led_cdev, LED_FULL);
+       else
+               led_set_brightness(trigger_data->led_cdev, LED_OFF);
+       
+       if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
+               mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
+       else
+               del_timer(&trigger_data->timer);    
+}  
+
+static ssize_t led_device_name_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+       
+       read_lock(&trigger_data->lock);
+       sprintf(buf, "%s\n", trigger_data->device_name);
+       read_unlock(&trigger_data->lock);
+       
+       return strlen(buf) + 1;
+}
+  
+static ssize_t led_device_name_store(struct device *dev, 
+                                    struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+       
+       if (size < 0 || size >= IFNAMSIZ)
+               return -EINVAL;
+       
+       write_lock(&trigger_data->lock);
+
+       strcpy(trigger_data->device_name, buf);
+       if (size > 0 && trigger_data->device_name[size-1] == '\n')
+               trigger_data->device_name[size-1] = 0;
+       
+       if (trigger_data->device_name[0] != 0) {
+               /* check for existing device to update from */
+               trigger_data->net_dev = dev_get_by_name(trigger_data->device_name);
+               if (trigger_data->net_dev != NULL)
+                       trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
+               set_baseline_state(trigger_data); /* updates LEDs, may start timers */
+       }
+       
+       write_unlock(&trigger_data->lock);      
+       return size;
+}
+
+static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
+
+static ssize_t led_mode_show(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+       
+       read_lock(&trigger_data->lock);
+       
+       if (trigger_data->mode == 0) {
+               strcpy(buf, "none\n");
+       } else {
+               if (trigger_data->mode & MODE_LINK) 
+                       strcat(buf, "link ");
+               if (trigger_data->mode & MODE_TX)
+                       strcat(buf, "tx ");
+               if (trigger_data->mode & MODE_RX)
+                       strcat(buf, "rx ");
+               strcat(buf, "\n");
+       }
+       
+       read_unlock(&trigger_data->lock);       
+
+       return strlen(buf)+1;
+}
+
+static ssize_t led_mode_store(struct device *dev, 
+                             struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;  
+       char copybuf[1024];
+       int new_mode = -1;
+       char *p, *token;
+
+       /* take a copy since we don't want to trash the inbound buffer when using strsep */
+       strncpy(copybuf, buf, sizeof(copybuf));
+       copybuf[1023] = 0;
+       p = copybuf;
+       
+       while ((token = strsep(&p, " \t\n")) != NULL) {
+               if (!*token)
+                       continue;
+               
+               if (new_mode == -1)
+                       new_mode = 0;
+               
+               if (!strcmp(token, "none"))
+                       new_mode = 0;
+               else if (!strcmp(token, "tx"))
+                       new_mode |= MODE_TX;
+               else if (!strcmp(token, "rx"))
+                       new_mode |= MODE_RX;
+               else if (!strcmp(token, "link"))
+                       new_mode |= MODE_LINK;
+               else
+                       return -EINVAL;
+       }
+       
+       if (new_mode == -1)
+               return -EINVAL;
+       
+       write_lock(&trigger_data->lock);        
+       trigger_data->mode = new_mode;  
+       set_baseline_state(trigger_data);
+       write_unlock(&trigger_data->lock);
+       
+       return size;
+}
+
+static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
+
+static ssize_t led_interval_show(struct device *dev, 
+                                struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+       
+       read_lock(&trigger_data->lock);
+       sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
+       read_unlock(&trigger_data->lock);
+       
+       return strlen(buf) + 1;
+}
+
+static ssize_t led_interval_store(struct device *dev, 
+                                 struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+       int ret = -EINVAL;
+       char *after;
+       unsigned long value = simple_strtoul(buf, &after, 10);
+       size_t count = after - buf;
+
+       if (*after && isspace(*after))
+               count++;
+
+       /* impose some basic bounds on the timer interval */
+       if (count == size && value >= 5 && value <= 10000) {
+               write_lock(&trigger_data->lock);
+               trigger_data->interval = msecs_to_jiffies(value);
+               set_baseline_state(trigger_data); // resets timer
+               write_unlock(&trigger_data->lock);
+               ret = count;
+       }
+       
+       return ret;
+}
+
+static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
+
+static int netdev_trig_notify(struct notifier_block *nb,
+                             unsigned long evt,
+                             void *dv)
+{
+       struct net_device *dev = dv;
+       struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
+       
+       if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
+               return NOTIFY_DONE;
+       
+       write_lock(&trigger_data->lock);
+
+       if (strcmp(dev->name, trigger_data->device_name))
+               goto done;
+       
+       if (evt == NETDEV_REGISTER) {
+               if (trigger_data->net_dev != NULL)
+                       dev_put(trigger_data->net_dev);
+               dev_hold(dev);
+               trigger_data->net_dev = dev;
+               trigger_data->link_up = 0;
+               goto done;
+       }
+       
+       if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
+               dev_put(trigger_data->net_dev);
+               trigger_data->net_dev = NULL;
+               goto done;
+       }
+       
+       /* UP / DOWN / CHANGE */
+       
+       trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
+       set_baseline_state(trigger_data);
+
+done:
+       write_unlock(&trigger_data->lock);  
+       return NOTIFY_DONE;
+}
+
+/* here's the real work! */
+static void netdev_trig_timer(unsigned long arg)
+{
+       struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
+       struct net_device_stats *dev_stats;
+       unsigned new_activity;
+       
+       write_lock(&trigger_data->lock);
+    
+       if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
+               /* we don't need to do timer work, just reflect link state. */
+               led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
+               goto no_restart;
+       }
+       
+       dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev);
+       new_activity =
+               ((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
+               ((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
+      
+       if (trigger_data->mode & MODE_LINK) {
+               /* base state is ON (link present) */
+               /* if there's no link, we don't get this far and the LED is off */
+               
+               /* OFF -> ON always */
+               /* ON -> OFF on activity */
+               if (trigger_data->led_cdev->brightness == LED_OFF) {
+                       led_set_brightness(trigger_data->led_cdev, LED_FULL);
+               } else if (trigger_data->last_activity != new_activity) {
+                       led_set_brightness(trigger_data->led_cdev, LED_OFF);
+               }
+       } else {
+               /* base state is OFF */
+               /* ON -> OFF always */
+               /* OFF -> ON on activity */
+               if (trigger_data->led_cdev->brightness == LED_FULL) {
+                       led_set_brightness(trigger_data->led_cdev, LED_OFF);
+               } else if (trigger_data->last_activity != new_activity) {
+                       led_set_brightness(trigger_data->led_cdev, LED_FULL);
+               }
+       }
+       
+       trigger_data->last_activity = new_activity;
+       mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
+
+no_restart:
+       write_unlock(&trigger_data->lock);
+}
+
+static void netdev_trig_activate(struct led_classdev *led_cdev)
+{
+       struct led_netdev_data *trigger_data;
+       int rc;
+
+       trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
+       if (!trigger_data)
+               return;
+
+       rwlock_init(&trigger_data->lock);
+
+       trigger_data->notifier.notifier_call = netdev_trig_notify;
+       trigger_data->notifier.priority = 10;
+
+       setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
+
+       trigger_data->led_cdev = led_cdev;
+       trigger_data->net_dev = NULL;
+       trigger_data->device_name[0] = 0;
+       
+       trigger_data->mode = 0;
+       trigger_data->interval = msecs_to_jiffies(50);
+       trigger_data->link_up = 0;
+       trigger_data->last_activity = 0;
+       
+       led_cdev->trigger_data = trigger_data;
+
+       rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
+       if (rc)
+               goto err_out;
+       rc = device_create_file(led_cdev->dev, &dev_attr_mode);
+       if (rc)
+               goto err_out_device_name;
+       rc = device_create_file(led_cdev->dev, &dev_attr_interval);
+       if (rc)
+               goto err_out_mode;
+
+       register_netdevice_notifier(&trigger_data->notifier);   
+       return;
+
+err_out_mode:
+       device_remove_file(led_cdev->dev, &dev_attr_mode);
+err_out_device_name:
+       device_remove_file(led_cdev->dev, &dev_attr_device_name);
+err_out:
+       led_cdev->trigger_data = NULL;
+       kfree(trigger_data);
+}
+
+static void netdev_trig_deactivate(struct led_classdev *led_cdev)
+{
+       struct led_netdev_data *trigger_data = led_cdev->trigger_data;
+
+       if (trigger_data) {       
+               unregister_netdevice_notifier(&trigger_data->notifier);
+
+               device_remove_file(led_cdev->dev, &dev_attr_device_name);
+               device_remove_file(led_cdev->dev, &dev_attr_mode);
+               device_remove_file(led_cdev->dev, &dev_attr_interval);
+
+               write_lock(&trigger_data->lock);
+               
+               if (trigger_data->net_dev) {
+                       dev_put(trigger_data->net_dev);
+                       trigger_data->net_dev = NULL;
+               }
+               
+               write_unlock(&trigger_data->lock);
+
+               del_timer_sync(&trigger_data->timer);
+
+               kfree(trigger_data);
+       }
+}
+
+static struct led_trigger netdev_led_trigger = {
+       .name     = "netdev",
+       .activate = netdev_trig_activate,
+       .deactivate = netdev_trig_deactivate,
+};
+
+static int __init netdev_trig_init(void)
+{
+       return led_trigger_register(&netdev_led_trigger);
+}
+
+static void __exit netdev_trig_exit(void)
+{
+       led_trigger_unregister(&netdev_led_trigger);
+}
+
+module_init(netdev_trig_init);
+module_exit(netdev_trig_exit);
+
+MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
+MODULE_DESCRIPTION("Netdev LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.c b/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.c
new file mode 100644 (file)
index 0000000..3033813
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * ADM6996 switch driver
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "adm6996.h"
+
+MODULE_DESCRIPTION("Infineon ADM6996 Switch");
+MODULE_AUTHOR("Felix Fietkau");
+MODULE_LICENSE("GPL");
+
+struct adm6996_priv {
+       /* use abstraction for regops, we want to add gpio support in the future */
+       u16 (*read)(struct phy_device *phydev, enum admreg reg);
+       void (*write)(struct phy_device *phydev, enum admreg reg, u16 val);
+};
+
+#define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv)
+
+
+static inline u16
+r16(struct phy_device *pdev, enum admreg reg)
+{
+       return to_adm(pdev)->read(pdev, reg);
+}
+
+static inline void
+w16(struct phy_device *pdev, enum admreg reg, u16 val)
+{
+       to_adm(pdev)->write(pdev, reg, val);
+}
+
+
+static u16
+adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg)
+{
+       return phydev->bus->read(phydev->bus, PHYADDR(reg));
+}
+
+static void
+adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val)
+{
+       phydev->bus->write(phydev->bus, PHYADDR(reg), val);
+}
+
+
+static int adm6996_config_init(struct phy_device *pdev)
+{
+       int i;
+
+       printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name);
+       pdev->supported = ADVERTISED_100baseT_Full;
+       pdev->advertising = ADVERTISED_100baseT_Full;
+
+       /* initialize port and vlan settings */
+       for (i = 0; i < ADM_PHY_PORTS; i++) {
+               w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT |
+                       ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0));
+       }
+       w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU);
+
+       /* reset all ports */
+       for (i = 0; i < ADM_PHY_PORTS; i++) {
+               w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT);
+       }
+
+       return 0;
+}
+
+static int adm6996_read_status(struct phy_device *phydev)
+{
+       phydev->speed = SPEED_100;
+       phydev->duplex = DUPLEX_FULL;
+       phydev->state = PHY_UP;
+       return 0;
+}
+
+static int adm6996_config_aneg(struct phy_device *phydev)
+{
+       return 0;
+}
+
+static int adm6996_probe(struct phy_device *pdev)
+{
+       struct adm6996_priv *priv;
+
+       priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       priv->read = adm6996_read_mii_reg;
+       priv->write = adm6996_write_mii_reg;
+       pdev->priv = priv;
+       return 0;
+}
+
+static void adm6996_remove(struct phy_device *pdev)
+{
+       kfree(pdev->priv);
+}
+
+static bool adm6996_detect(struct mii_bus *bus, int addr)
+{
+       u16 reg;
+
+       /* we only attach to phy id 0 */
+       if (addr != 0)
+               return false;
+
+       /* look for the switch on the bus */
+       reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK;
+       if (reg != ADM_SIG0_VAL)
+               return false;
+
+       reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK;
+       if (reg != ADM_SIG1_VAL)
+               return false;
+
+       return true;
+}
+
+static struct phy_driver adm6996_driver = {
+       .name           = "Infineon ADM6996",
+       .features       = PHY_BASIC_FEATURES,
+       .detect         = adm6996_detect,
+       .probe          = adm6996_probe,
+       .remove         = adm6996_remove,
+       .config_init    = &adm6996_config_init,
+       .config_aneg    = &adm6996_config_aneg,
+       .read_status    = &adm6996_read_status,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init adm6996_init(void)
+{
+       return phy_driver_register(&adm6996_driver);
+}
+
+static void __exit adm6996_exit(void)
+{
+       phy_driver_unregister(&adm6996_driver);
+}
+
+module_init(adm6996_init);
+module_exit(adm6996_exit);
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.h b/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/adm6996.h
new file mode 100644 (file)
index 0000000..e074901
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * ADM6996 switch driver
+ *
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __ADM6996_H
+#define __ADM6996_H
+
+#define ADM_PHY_PORTS  5
+#define ADM_CPU_PORT   5
+#define ADM_WAN_PORT   0 /* FIXME: dynamic ? */
+
+enum admreg {
+       ADM_EEPROM_BASE         = 0x0,
+               ADM_P0_CFG              = ADM_EEPROM_BASE + 1,
+               ADM_P1_CFG              = ADM_EEPROM_BASE + 3,
+               ADM_P2_CFG              = ADM_EEPROM_BASE + 5,
+               ADM_P3_CFG              = ADM_EEPROM_BASE + 7,
+               ADM_P4_CFG              = ADM_EEPROM_BASE + 8,
+               ADM_P5_CFG              = ADM_EEPROM_BASE + 9,
+       ADM_EEPROM_EXT_BASE     = 0x40,
+       ADM_COUNTER_BASE        = 0xa0,
+               ADM_SIG0                = ADM_COUNTER_BASE + 0,
+               ADM_SIG1                = ADM_COUNTER_BASE + 1,
+       ADM_PHY_BASE            = 0x200,
+#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
+};
+
+/* Chip identification patterns */
+#define        ADM_SIG0_MASK   0xfff0
+#define ADM_SIG0_VAL   0x1020
+#define ADM_SIG1_MASK  0xffff
+#define ADM_SIG1_VAL   0x0007
+
+enum {
+       ADM_PHYCFG_COLTST     = (1 << 7),       /* Enable collision test */
+       ADM_PHYCFG_DPLX       = (1 << 8),       /* Enable full duplex */
+       ADM_PHYCFG_ANEN_RST   = (1 << 9),       /* Restart auto negotiation (self clear) */
+       ADM_PHYCFG_ISO        = (1 << 10),      /* Isolate PHY */
+       ADM_PHYCFG_PDN        = (1 << 11),      /* Power down PHY */
+       ADM_PHYCFG_ANEN       = (1 << 12),      /* Enable auto negotiation */
+       ADM_PHYCFG_SPEED_100  = (1 << 13),      /* Enable 100 Mbit/s */
+       ADM_PHYCFG_LPBK       = (1 << 14),      /* Enable loopback operation */
+       ADM_PHYCFG_RST        = (1 << 15),      /* Reset the port (self clear) */
+       ADM_PHYCFG_INIT = (
+               ADM_PHYCFG_RST |
+               ADM_PHYCFG_SPEED_100 |
+               ADM_PHYCFG_ANEN |
+               ADM_PHYCFG_ANEN_RST
+       )
+};
+
+enum {
+       ADM_PORTCFG_FC        = (1 << 0),       /* Enable 802.x flow control */
+       ADM_PORTCFG_AN        = (1 << 1),       /* Enable auto-negotiation */
+       ADM_PORTCFG_SPEED_100 = (1 << 2),       /* Enable 100 Mbit/s */
+       ADM_PORTCFG_DPLX      = (1 << 3),       /* Enable full duplex */
+       ADM_PORTCFG_OT        = (1 << 4),       /* Output tagged packets */
+       ADM_PORTCFG_PD        = (1 << 5),       /* Port disable */
+       ADM_PORTCFG_TV_PRIO   = (1 << 6),       /* 0 = VLAN based priority
+                                                * 1 = TOS based priority */
+       ADM_PORTCFG_PPE       = (1 << 7),       /* Port based priority enable */
+       ADM_PORTCFG_PP_S      = (1 << 8),       /* Port based priority, 2 bits */
+       ADM_PORTCFG_PVID_BASE = (1 << 10),      /* Primary VLAN id, 4 bits */
+       ADM_PORTCFG_FSE       = (1 << 14),      /* Fx select enable */
+       ADM_PORTCFG_CAM       = (1 << 15),      /* Crossover Auto MDIX */
+
+       ADM_PORTCFG_INIT = (
+               ADM_PORTCFG_FC |
+               ADM_PORTCFG_AN |
+               ADM_PORTCFG_SPEED_100 |
+               ADM_PORTCFG_DPLX |
+               ADM_PORTCFG_CAM
+       ),
+       ADM_PORTCFG_CPU = (
+               ADM_PORTCFG_FC |
+               ADM_PORTCFG_SPEED_100 |
+               ADM_PORTCFG_OT |
+               ADM_PORTCFG_DPLX
+       ),
+};
+
+#define ADM_PORTCFG_PPID(N) ((n & 0x3) << 8)
+#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
+
+static const u8 adm_portcfg[] = {
+       [0] = ADM_P0_CFG,
+       [1] = ADM_P1_CFG,
+       [2] = ADM_P2_CFG,
+       [3] = ADM_P3_CFG,
+       [4] = ADM_P4_CFG,
+       [5] = ADM_P5_CFG,
+};
+
+/*
+ * Split the register address in phy id and register
+ * it will get combined again by the mdio bus op
+ */
+#define PHYADDR(_reg)  ((_reg >> 5) & 0xff), (_reg & 0x1f)
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c b/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.c
new file mode 100644 (file)
index 0000000..f28df43
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "mvswitch.h"
+
+/* Undefine this to use trailer mode instead.
+ * I don't know if header mode works with all chips */
+#define HEADER_MODE    1
+
+MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
+MODULE_AUTHOR("Felix Fietkau");
+MODULE_LICENSE("GPL");
+
+struct mvswitch_priv {
+       /* the driver's tx function */
+       int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
+       struct vlan_group *grp;
+       u8 vlans[16];
+};
+
+#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
+
+static inline u16
+r16(struct phy_device *phydev, int addr, int reg)
+{
+       return phydev->bus->read(phydev->bus, addr, reg);
+}
+
+static inline void
+w16(struct phy_device *phydev, int addr, int reg, u16 val)
+{
+       phydev->bus->write(phydev->bus, addr, reg, val);
+}
+
+
+static int
+mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       struct mvswitch_priv *priv;
+       char *buf = NULL;
+       u16 vid;
+
+       priv = dev->phy_ptr;
+       if (unlikely(!priv))
+               goto error;
+
+       if (unlikely(skb->len < 16))
+               goto error;
+
+#ifdef HEADER_MODE
+       if (__vlan_hwaccel_get_tag(skb, &vid))
+               goto error;
+
+       if ((skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
+               if (pskb_expand_head(skb, MV_HEADER_SIZE, 0, GFP_ATOMIC))
+                       goto error_expand;
+               if (skb->len < 62)
+                       skb->len = 62;
+       }
+       buf = skb_push(skb, MV_HEADER_SIZE);
+#else
+       if (__vlan_get_tag(skb, &vid))
+               goto error;
+
+       if (unlikely((vid > 15 || !priv->vlans[vid])))
+               goto error;
+
+       if (skb->len <= 64) {
+               if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
+                       goto error_expand;
+
+               buf = skb->data + 64;
+               skb->len = 64 + MV_TRAILER_SIZE;
+       } else {
+               if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
+                       if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
+                               goto error_expand;
+               }
+               buf = skb_put(skb, 4);
+       }
+
+       /* move the ethernet header 4 bytes forward, overwriting the vlan tag */
+       memmove(skb->data + 4, skb->data, 12);
+       skb->data += 4;
+       skb->len -= 4;
+       skb->mac_header += 4;
+#endif
+
+       if (!buf)
+               goto error;
+
+
+#ifdef HEADER_MODE
+       /* prepend the tag */
+       *((__be16 *) buf) = cpu_to_be16(
+               ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
+               ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
+       );
+#else
+       /* append the tag */
+       *((__be32 *) buf) = cpu_to_be32((
+               (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
+               ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
+       ));
+#endif
+
+       return priv->hardstart(skb, dev);
+
+error_expand:
+       if (net_ratelimit())
+               printk("%s: failed to expand/update skb for the switch\n", dev->name);
+
+error:
+       /* any errors? drop the packet! */
+       dev_kfree_skb_any(skb);
+       return 0;
+}
+
+static int
+mvswitch_mangle_rx(struct sk_buff *skb, int napi)
+{
+       struct mvswitch_priv *priv;
+       struct net_device *dev;
+       int vlan = -1;
+       unsigned char *buf;
+       int i;
+
+       dev = skb->dev;
+       if (!dev)
+               goto error;
+
+       priv = dev->phy_ptr;
+       if (!priv)
+               goto error;
+
+       if (!priv->grp)
+               goto error;
+
+#ifdef HEADER_MODE
+       buf = skb->data;
+       skb_pull(skb, MV_HEADER_SIZE);
+#else
+       buf = skb->data + skb->len - MV_TRAILER_SIZE;
+       if (buf[0] != 0x80)
+               goto error;
+#endif
+
+       /* look for the vlan matching the incoming port */
+       for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
+               if ((1 << buf[1]) & priv->vlans[i])
+                       vlan = i;
+       }
+
+       if (vlan == -1)
+               goto error;
+
+       skb->protocol = eth_type_trans(skb, skb->dev);
+
+       if (napi)
+               return vlan_hwaccel_receive_skb(skb, priv->grp, vlan);
+       else
+               return vlan_hwaccel_rx(skb, priv->grp, vlan);
+
+error:
+       /* no vlan? eat the packet! */
+       dev_kfree_skb_any(skb);
+       return 0;
+}
+
+
+static int
+mvswitch_netif_rx(struct sk_buff *skb)
+{
+       return mvswitch_mangle_rx(skb, 0);
+}
+
+static int
+mvswitch_netif_receive_skb(struct sk_buff *skb)
+{
+       return mvswitch_mangle_rx(skb, 1);
+}
+
+
+static void
+mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+       struct mvswitch_priv *priv = dev->phy_ptr;
+       priv->grp = grp;
+}
+
+
+static int
+mvswitch_config_init(struct phy_device *pdev)
+{
+       struct mvswitch_priv *priv = to_mvsw(pdev);
+       struct net_device *dev = pdev->attached_dev;
+       u8 vlmap = 0;
+       int i;
+
+       if (!dev)
+               return -EINVAL;
+
+       printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
+       pdev->supported = ADVERTISED_100baseT_Full;
+       pdev->advertising = ADVERTISED_100baseT_Full;
+       dev->phy_ptr = priv;
+
+       /* initialize default vlans */
+       for (i = 0; i < MV_PORTS; i++)
+               priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
+
+       /* before entering reset, disable all ports */
+       for (i = 0; i < MV_PORTS; i++)
+               w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
+
+       msleep(2); /* wait for the status change to settle in */
+
+       /* put the device in reset and set ATU flags */
+       w16(pdev, MV_SWITCHREG(ATU_CTRL),
+               MV_ATUCTL_RESET |
+               MV_ATUCTL_ATU_1K |
+               MV_ATUCTL_AGETIME(4080) /* maximum */
+       );
+
+       i = 100; /* timeout */
+       do {
+               if (!(r16(pdev, MV_SWITCHREG(ATU_CTRL)) & MV_ATUCTL_RESET))
+                       break;
+               msleep(1);
+       } while (--i > 0);
+
+       if (!i) {
+               printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+               return -ETIMEDOUT;
+       }
+
+       /* initialize the cpu port */
+       w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
+#ifdef HEADER_MODE
+               MV_PORTCTRL_HEADER |
+#else
+               MV_PORTCTRL_RXTR |
+               MV_PORTCTRL_TXTR |
+#endif
+               MV_PORTCTRL_ENABLED
+       );
+       /* wait for the phy change to settle in */
+       msleep(2);
+       for (i = 0; i < MV_PORTS; i++) {
+               u8 pvid = 0;
+               int j;
+
+               vlmap = 0;
+
+               /* look for the matching vlan */
+               for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
+                       if (priv->vlans[j] & (1 << i)) {
+                               vlmap = priv->vlans[j];
+                               pvid = j;
+                       }
+               }
+               /* leave port unconfigured if it's not part of a vlan */
+               if (!vlmap)
+                       break;
+
+               /* add the cpu port to the allowed destinations list */
+               vlmap |= (1 << MV_CPUPORT);
+
+               /* take port out of its own vlan destination map */
+               vlmap &= ~(1 << i);
+
+               /* apply vlan settings */
+               w16(pdev, MV_PORTREG(VLANMAP, i),
+                       MV_PORTVLAN_PORTS(vlmap) |
+                       MV_PORTVLAN_ID(pvid)
+               );
+
+               /* re-enable port */
+               w16(pdev, MV_PORTREG(CONTROL, i), MV_PORTCTRL_ENABLED);
+       }
+
+       /* build the target list for the cpu port */
+       for (i = 0; i < MV_PORTS; i++)
+               vlmap |= (1 << i);
+
+       w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
+               MV_PORTVLAN_PORTS(vlmap)
+       );
+
+       /* set the port association vector */
+       for (i = 0; i <= MV_PORTS; i++) {
+               w16(pdev, MV_PORTREG(ASSOC, i),
+                       MV_PORTASSOC_PORTS(1 << i)
+               );
+       }
+
+       /* init switch control */
+       w16(pdev, MV_SWITCHREG(CTRL),
+               MV_SWITCHCTL_MSIZE |
+               MV_SWITCHCTL_DROP
+       );
+
+       /* hook into the tx function */
+       priv->hardstart = dev->hard_start_xmit;
+       pdev->netif_receive_skb = mvswitch_netif_receive_skb;
+       pdev->netif_rx = mvswitch_netif_rx;
+       dev->hard_start_xmit = mvswitch_mangle_tx;
+       dev->vlan_rx_register = mvswitch_vlan_rx_register;
+#ifdef HEADER_MODE
+       dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
+#else
+       dev->features |= NETIF_F_HW_VLAN_RX;
+#endif
+
+       return 0;
+}
+
+static int
+mvswitch_read_status(struct phy_device *phydev)
+{
+       phydev->speed = SPEED_100;
+       phydev->duplex = DUPLEX_FULL;
+       phydev->state = PHY_UP;
+       return 0;
+}
+
+static int
+mvswitch_config_aneg(struct phy_device *phydev)
+{
+       return 0;
+}
+
+static void
+mvswitch_remove(struct phy_device *pdev)
+{
+       struct mvswitch_priv *priv = to_mvsw(pdev);
+       struct net_device *dev = pdev->attached_dev;
+
+       /* restore old xmit handler */
+       if (priv->hardstart && dev)
+               dev->hard_start_xmit = priv->hardstart;
+       dev->vlan_rx_register = NULL;
+       dev->vlan_rx_kill_vid = NULL;
+       dev->phy_ptr = NULL;
+       dev->features &= ~NETIF_F_HW_VLAN_RX;
+       kfree(priv);
+}
+
+static bool
+mvswitch_detect(struct mii_bus *bus, int addr)
+{
+       u16 reg;
+       int i;
+
+       /* we attach to phy id 31 to make sure that the late probe works */
+       if (addr != 31)
+               return false;
+
+       /* look for the switch on the bus */
+       reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+       if (reg != MV_IDENT_VALUE)
+               return false;
+
+       /* 
+        * Now that we've established that the switch actually exists, let's 
+        * get rid of the competition :)
+        */
+       for (i = 0; i < 31; i++) {
+               if (!bus->phy_map[i])
+                       continue;
+
+               device_unregister(&bus->phy_map[i]->dev);
+               kfree(bus->phy_map[i]);
+               bus->phy_map[i] = NULL;
+       }
+
+       return true;
+}
+
+static int
+mvswitch_probe(struct phy_device *pdev)
+{
+       struct mvswitch_priv *priv;
+
+       priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+
+       pdev->priv = priv;
+
+       return 0;
+}
+
+
+static struct phy_driver mvswitch_driver = {
+       .name           = "Marvell 88E6060",
+       .features       = PHY_BASIC_FEATURES,
+       .detect         = &mvswitch_detect,
+       .probe          = &mvswitch_probe,
+       .remove         = &mvswitch_remove,
+       .config_init    = &mvswitch_config_init,
+       .config_aneg    = &mvswitch_config_aneg,
+       .read_status    = &mvswitch_read_status,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+static int __init
+mvswitch_init(void)
+{
+       return phy_driver_register(&mvswitch_driver);
+}
+
+static void __exit
+mvswitch_exit(void)
+{
+       phy_driver_unregister(&mvswitch_driver);
+}
+
+module_init(mvswitch_init);
+module_exit(mvswitch_exit);
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h b/target/linux/generic-2.6/files-2.6.25/drivers/net/phy/mvswitch.h
new file mode 100644 (file)
index 0000000..81516b7
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __MVSWITCH_H
+#define __MVSWITCH_H
+
+#define MV_HEADER_SIZE 2
+#define MV_HEADER_PORTS_M      0x001f
+#define MV_HEADER_PORTS_S      0
+#define MV_HEADER_VLAN_M       0xf000
+#define MV_HEADER_VLAN_S       12
+
+#define MV_TRAILER_SIZE        4
+#define MV_TRAILER_PORTS_M     0x1f
+#define MV_TRAILER_PORTS_S     16
+#define MV_TRAILER_FLAGS_S     24
+#define MV_TRAILER_OVERRIDE    0x80
+
+
+#define MV_PORTS       5
+#define MV_WANPORT     4
+#define MV_CPUPORT     5
+
+#define MV_BASE                0x10
+
+#define MV_PHYPORT_BASE                (MV_BASE + 0x0)
+#define MV_PHYPORT(_n)         (MV_PHYPORT_BASE + (_n))
+#define MV_SWITCHPORT_BASE     (MV_BASE + 0x8)
+#define MV_SWITCHPORT(_n)      (MV_SWITCHPORT_BASE + (_n))
+#define MV_SWITCHREGS          (MV_BASE + 0xf)
+
+enum {
+       MV_PHY_CONTROL      = 0x00,
+       MV_PHY_STATUS       = 0x01,
+       MV_PHY_IDENT0       = 0x02,
+       MV_PHY_IDENT1       = 0x03,
+       MV_PHY_ANEG         = 0x04,
+       MV_PHY_LINK_ABILITY = 0x05,
+       MV_PHY_ANEG_EXPAND  = 0x06,
+       MV_PHY_XMIT_NEXTP   = 0x07,
+       MV_PHY_LINK_NEXTP   = 0x08,
+       MV_PHY_CONTROL1     = 0x10,
+       MV_PHY_STATUS1      = 0x11,
+       MV_PHY_INTR_EN      = 0x12,
+       MV_PHY_INTR_STATUS  = 0x13,
+       MV_PHY_INTR_PORT    = 0x14,
+       MV_PHY_RECV_COUNTER = 0x16,
+       MV_PHY_LED_PARALLEL = 0x16,
+       MV_PHY_LED_STREAM   = 0x17,
+       MV_PHY_LED_CTRL     = 0x18,
+       MV_PHY_LED_OVERRIDE = 0x19,
+       MV_PHY_VCT_CTRL     = 0x1a,
+       MV_PHY_VCT_STATUS   = 0x1b,
+       MV_PHY_CONTROL2     = 0x1e
+};
+#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
+
+enum {
+       MV_PORT_STATUS      = 0x00,
+       MV_PORT_IDENT       = 0x03,
+       MV_PORT_CONTROL     = 0x04,
+       MV_PORT_VLANMAP     = 0x06,
+       MV_PORT_ASSOC       = 0x0b,
+       MV_PORT_RXCOUNT     = 0x10,
+       MV_PORT_TXCOUNT     = 0x11,
+};
+#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
+
+enum {
+       MV_PORTCTRL_BLOCK   =  (1 << 0),
+       MV_PORTCTRL_LEARN   =  (2 << 0),
+       MV_PORTCTRL_ENABLED =  (3 << 0),
+       MV_PORTCTRL_VLANTUN =  (1 << 7),        /* Enforce VLANs on packets */
+       MV_PORTCTRL_RXTR    =  (1 << 8),        /* Enable Marvell packet trailer for ingress */
+       MV_PORTCTRL_HEADER      = (1 << 11),    /* Enable Marvell packet header mode for port */
+       MV_PORTCTRL_TXTR    = (1 << 14),        /* Enable Marvell packet trailer for egress */
+       MV_PORTCTRL_FORCEFL = (1 << 15),        /* force flow control */
+};
+
+#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
+#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
+
+#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
+#define MV_PORTASSOC_MONITOR   (1 << 15)
+
+enum {
+       MV_SWITCH_MAC0      = 0x01,
+       MV_SWITCH_MAC1      = 0x02,
+       MV_SWITCH_MAC2      = 0x03,
+       MV_SWITCH_CTRL      = 0x04,
+       MV_SWITCH_ATU_CTRL  = 0x0a,
+       MV_SWITCH_ATU_OP    = 0x0b,
+       MV_SWITCH_ATU_DATA  = 0x0c,
+       MV_SWITCH_ATU_MAC0  = 0x0d,
+       MV_SWITCH_ATU_MAC1  = 0x0e,
+       MV_SWITCH_ATU_MAC2  = 0x0f,
+};
+#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
+
+enum {
+       MV_SWITCHCTL_EEIE   =  (1 << 0),        /* EEPROM interrupt enable */
+       MV_SWITCHCTL_PHYIE  =  (1 << 1),        /* PHY interrupt enable */
+       MV_SWITCHCTL_ATUDONE=  (1 << 2),        /* ATU done interrupt enable */
+       MV_SWITCHCTL_ATUIE  =  (1 << 3),        /* ATU interrupt enable */
+       MV_SWITCHCTL_CTRMODE=  (1 << 8),        /* statistics for rx and tx errors */
+       MV_SWITCHCTL_RELOAD =  (1 << 9),        /* reload registers from eeprom */
+       MV_SWITCHCTL_MSIZE  = (1 << 10),        /* increase maximum frame size */
+       MV_SWITCHCTL_DROP   = (1 << 13),        /* discard frames with excessive collisions */
+};
+
+enum {
+#define MV_ATUCTL_AGETIME(_n)  ((((_n) / 16) & 0xff) << 4)
+       MV_ATUCTL_ATU_256   = (0 << 12),
+       MV_ATUCTL_ATU_512   = (1 << 12),
+       MV_ATUCTL_ATU_1K        = (2 << 12),
+       MV_ATUCTL_ATUMASK   = (3 << 12),
+       MV_ATUCTL_NO_LEARN  = (1 << 14),
+       MV_ATUCTL_RESET     = (1 << 15),
+}
+
+#define MV_IDENT_MASK          0xfff0
+#define MV_IDENT_VALUE         0x0600
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/drivers/spi/spi_gpio.c b/target/linux/generic-2.6/files-2.6.25/drivers/spi/spi_gpio.c
new file mode 100644 (file)
index 0000000..31048ac
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Bitbanging SPI bus driver using GPIO API
+ *
+ * Copyright (c) 2008 Piotr Skamruk
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * based on spi_s3c2410_gpio.c
+ *   Copyright (c) 2006 Ben Dooks
+ *   Copyright (c) 2006 Simtec Electronics
+ * and on i2c-gpio.c
+ *   Copyright (C) 2007 Atmel 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include "linux/spi/spi_gpio.h" //XXX
+#include <asm/gpio.h>
+
+
+struct spi_gpio {
+       struct spi_bitbang bitbang;
+       struct spi_gpio_platform_data *info;
+       struct platform_device *pdev;
+       struct spi_board_info bi;
+};
+
+
+static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
+{
+       return dev->controller_data;
+}
+
+static inline void setsck(struct spi_device *dev, int val)
+{
+       struct spi_gpio *sp = spidev_to_sg(dev);
+       gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
+}
+
+static inline void setmosi(struct spi_device *dev, int val )
+{
+       struct spi_gpio *sp = spidev_to_sg(dev);
+       gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+       struct spi_gpio *sp = spidev_to_sg(dev);
+       return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
+}
+
+static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
+{
+       struct spi_gpio *sp = spidev_to_sg(dev);
+
+       if (!sp->info->no_spi_delay)
+               ndelay(nsecs);
+}
+
+#define spidelay(nsecs) do {                                   \
+       /* Steal the spi_device pointer from our caller.        \
+        * The bitbang-API should probably get fixed here... */ \
+       do_spidelay(spi, nsecs);                                \
+  } while (0)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+{
+        return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+{
+        return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+{
+        return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
+                              unsigned nsecs, u32 word, u8 bits)
+{
+        return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void spi_gpio_chipselect(struct spi_device *dev, int on)
+{
+       struct spi_gpio *sp = spidev_to_sg(dev);
+
+       if (sp->info->cs_activelow)
+               on = !on;
+       gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
+}
+
+static int spi_gpio_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct spi_gpio_platform_data *pdata;
+       struct spi_gpio *sp;
+       struct spi_device *spidev;
+       int err;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata)
+               return -ENXIO;
+
+       err = -ENOMEM;
+       master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
+       if (!master)
+               goto err_alloc_master;
+
+       sp = spi_master_get_devdata(master);
+       platform_set_drvdata(pdev, sp);
+       sp->info = pdata;
+
+       err = gpio_request(pdata->pin_clk, "spi_clock");
+       if (err)
+               goto err_request_clk;
+       err = gpio_request(pdata->pin_mosi, "spi_mosi");
+       if (err)
+               goto err_request_mosi;
+       err = gpio_request(pdata->pin_miso, "spi_miso");
+       if (err)
+               goto err_request_miso;
+       err = gpio_request(pdata->pin_cs, "spi_cs");
+       if (err)
+               goto err_request_cs;
+
+       sp->bitbang.master = spi_master_get(master);
+       sp->bitbang.master->bus_num = -1;
+       sp->bitbang.master->num_chipselect = 1;
+       sp->bitbang.chipselect = spi_gpio_chipselect;
+       sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
+       sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
+       sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
+       sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
+
+       gpio_direction_output(pdata->pin_clk, 0);
+       gpio_direction_output(pdata->pin_mosi, 0);
+       gpio_direction_output(pdata->pin_cs,
+                             pdata->cs_activelow ? 1 : 0);
+       gpio_direction_input(pdata->pin_miso);
+
+       err = spi_bitbang_start(&sp->bitbang);
+       if (err)
+               goto err_no_bitbang;
+       err = pdata->boardinfo_setup(&sp->bi, master,
+                                    pdata->boardinfo_setup_data);
+       if (err)
+               goto err_bi_setup;
+       sp->bi.controller_data = sp;
+       spidev = spi_new_device(master, &sp->bi);
+       if (!spidev)
+               goto err_new_dev;
+
+       return 0;
+
+err_new_dev:
+err_bi_setup:
+       spi_bitbang_stop(&sp->bitbang);
+err_no_bitbang:
+       spi_master_put(sp->bitbang.master);
+       gpio_free(pdata->pin_cs);
+err_request_cs:
+       gpio_free(pdata->pin_miso);
+err_request_miso:
+       gpio_free(pdata->pin_mosi);
+err_request_mosi:
+       gpio_free(pdata->pin_clk);
+err_request_clk:
+       kfree(master);
+
+err_alloc_master:
+       return err;
+}
+
+static int __devexit spi_gpio_remove(struct platform_device *pdev)
+{
+       struct spi_gpio *sp;
+       struct spi_gpio_platform_data *pdata;
+
+       pdata = pdev->dev.platform_data;
+       sp = platform_get_drvdata(pdev);
+
+       gpio_free(pdata->pin_clk);
+       gpio_free(pdata->pin_mosi);
+       gpio_free(pdata->pin_miso);
+       gpio_free(pdata->pin_cs);
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+
+       return 0;
+}
+
+static struct platform_driver spi_gpio_driver = {
+       .driver         = {
+               .name   = "spi-gpio",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = spi_gpio_probe,
+       .remove         = __devexit_p(spi_gpio_remove),
+};
+
+static int __init spi_gpio_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&spi_gpio_driver);
+       if (err)
+               printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
+
+       return err;
+}
+module_init(spi_gpio_init);
+
+static void __exit spi_gpio_exit(void)
+{
+       platform_driver_unregister(&spi_gpio_driver);
+}
+module_exit(spi_gpio_exit);
+
+MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_DESCRIPTION("Platform independent GPIO bitbangling SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Kconfig b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Kconfig
new file mode 100644 (file)
index 0000000..f55b3c5
--- /dev/null
@@ -0,0 +1,175 @@
+#
+# YAFFS file system configurations
+#
+
+config YAFFS_FS
+       tristate "YAFFS2 file system support"
+       default n
+       depends on MTD
+       select YAFFS_YAFFS1
+       select YAFFS_YAFFS2
+       help
+         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.
+
+         If unsure, say N.
+
+         Further information on YAFFS2 is available at
+         <http://www.aleph1.co.uk/yaffs/>.
+
+config YAFFS_YAFFS1
+       bool "512 byte / page devices"
+       depends on YAFFS_FS
+       default y
+       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
+       default n
+       help
+         This enables Yaffs to use its own ECC functions instead of using
+         the ones from the generic MTD-NAND driver.
+
+         If unsure, say N.
+
+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
+       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.
+
+         If unsure, say N.
+
+config YAFFS_YAFFS2
+       bool "2048 byte (or larger) / page devices"
+       depends on YAFFS_FS
+       default y
+       help
+         Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
+
+         If unsure, say Y.
+
+config YAFFS_AUTO_YAFFS2
+       bool "Autoselect yaffs2 format"
+       depends on YAFFS_YAFFS2
+       default y
+       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).
+
+         If unsure, say Y.
+
+config YAFFS_DISABLE_LAZY_LOAD
+       bool "Disable lazy loading"
+       depends on YAFFS_YAFFS2
+       default n
+       help
+         "Lazy loading" defers loading file details until they are
+         required. This saves mount time, but makes the first look-up
+         a bit longer.
+
+         Lazy loading will only happen if enabled by this option being 'n'
+         and if the appropriate tags are available, else yaffs2 will
+         automatically fall back to immediate loading and do the right
+         thing.
+
+         Lazy laoding will be required by checkpointing.
+
+         Setting this to 'y' will disable lazy loading.
+
+         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
+         searching.
+
+         Setting this to 'y' will force tnode width to 16 bits and save
+         memory but make large arrays slower.
+
+         If unsure, say N.
+
+config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+       bool "Force chunk erase check"
+       depends on YAFFS_FS
+       default n
+       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.  
+
+         If unsure, say Y.
+
+config YAFFS_SHORT_NAMES_IN_RAM
+       bool "Cache short names in RAM"
+       depends on YAFFS_FS
+       default y
+       help
+         If this config is set, then short names are stored with the
+         yaffs_Object.  This costs an extra 16 bytes of RAM per object,
+         but makes look-ups faster.
+
+         If unsure, say Y.
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Makefile b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/Makefile
new file mode 100644 (file)
index 0000000..73f4658
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux YAFFS 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
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/devextras.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/devextras.h
new file mode 100644 (file)
index 0000000..9635c7a
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations used during development.
+ * Most of these are from kernel includes placed here so we can use them in 
+ * applications.
+ *
+ */
+
+#ifndef __EXTRAS_H__
+#define __EXTRAS_H__
+
+#if defined WIN32
+#define __inline__ __inline
+#define new newHack
+#endif
+
+#if !(defined __KERNEL__) || (defined WIN32)
+
+/* User space defines */
+
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#define prefetch(x) 1
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+       (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+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;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new,
+                                    struct list_head *head)
+{
+       __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head *prev,
+                                 struct list_head *next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+       return head->next == head;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static __inline__ void list_splice(struct list_head *list,
+                                  struct list_head *head)
+{
+       struct list_head *first = list->next;
+
+       if (first != list) {
+               struct list_head *last = list->prev;
+               struct list_head *at = head->next;
+
+               first->prev = head;
+               head->next = first;
+
+               last->next = at;
+               at->prev = last;
+       }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+               pos = pos->next, prefetch(pos->next))
+
+/**
+ * list_for_each_safe  -       iterate over a list safe against removal
+ *                              of list entry
+ * @pos:       the &struct list_head to use as a loop counter.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN     0
+#define DT_FIFO                1
+#define DT_CHR         2
+#define DT_DIR         4
+#define DT_BLK         6
+#define DT_REG         8
+#define DT_LNK         10
+#define DT_SOCK                12
+#define DT_WHT         14
+
+#ifndef WIN32
+#include <sys/stat.h>
+#endif
+
+/*
+ * Attribute flags.  These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE      1
+#define ATTR_UID       2
+#define ATTR_GID       4
+#define ATTR_SIZE      8
+#define ATTR_ATIME     16
+#define ATTR_MTIME     32
+#define ATTR_CTIME     64
+#define ATTR_ATIME_SET 128
+#define ATTR_MTIME_SET 256
+#define ATTR_FORCE     512     /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG 1024
+
+struct iattr {
+       unsigned int ia_valid;
+       unsigned ia_mode;
+       unsigned ia_uid;
+       unsigned ia_gid;
+       unsigned ia_size;
+       unsigned ia_atime;
+       unsigned ia_mtime;
+       unsigned ia_ctime;
+       unsigned int ia_attr_flags;
+};
+
+#define KERN_DEBUG
+
+#else
+
+#ifndef WIN32
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#endif
+
+#endif
+
+#if defined WIN32
+#undef new
+#endif
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/moduleconfig.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/moduleconfig.h
new file mode 100644 (file)
index 0000000..8eb1ca3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 <Martin.Fouts@palmsource.com> 
+ *
+ * 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_CONFIG_H__
+#define __YAFFS_CONFIG_H__
+
+#ifdef YAFFS_OUT_OF_TREE
+
+/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
+#define CONFIG_YAFFS_FS
+#define CONFIG_YAFFS_YAFFS1
+#define CONFIG_YAFFS_YAFFS2
+
+/* These options are independent of each other.  Select those that matter. */
+
+/* Default: Not selected */
+/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
+//#define CONFIG_YAFFS_DOES_ECC
+
+/* Default: Not selected */
+/* Meaning: ECC byte order is 'wrong'.  Only meaningful if */
+/*          CONFIG_YAFFS_DOES_ECC is set */
+//#define CONFIG_YAFFS_ECC_WRONG_ORDER
+
+/* Default: Selected */
+/* Meaning: Disables testing whether chunks are erased before writing to them*/
+#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
+
+/* Default: Selected */
+/* Meaning: Cache short names, taking more RAM, but faster look-ups */
+#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+
+/* 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
+
+#endif /* YAFFS_OUT_OF_TREE */
+
+#endif /* __YAFFS_CONFIG_H__ */
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.c
new file mode 100644 (file)
index 0000000..2f3f875
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_checkptrw_c_version =
+    "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
+
+
+#include "yaffs_checkptrw.h"
+
+
+static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
+{
+
+       int blocksAvailable = dev->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)      
+               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){
+                       T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
+                       if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
+                               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+                               dev->nErasedBlocks++;
+                               dev->nFreeChunks += dev->nChunksPerBlock;
+                       }
+                       else {
+                               dev->markNANDBlockBad(dev,i);
+                               bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+                       }
+               }
+       }
+       
+       dev->blocksInCheckpoint = 0;
+       
+       return 1;
+}
+
+
+static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
+{
+       int  i;
+       int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
+       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){
+                               dev->checkpointNextBlock = i + 1;
+                               dev->checkpointCurrentBlock = i;
+                               T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
+                               return;
+                       }
+               }
+       }
+       T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
+       
+       dev->checkpointNextBlock = -1;
+       dev->checkpointCurrentBlock = -1;
+}
+
+static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
+{
+       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) 
+               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), 
+                               i, tags.objectId,tags.sequenceNumber,tags.eccResult));
+                                                     
+                       if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
+                               /* Right kind of block */
+                               dev->checkpointNextBlock = tags.objectId;
+                               dev->checkpointCurrentBlock = i;
+                               dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
+                               dev->blocksInCheckpoint++;
+                               T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
+                               return;
+                       }
+               }
+
+       T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
+
+       dev->checkpointNextBlock = -1;
+       dev->checkpointCurrentBlock = -1;
+}
+
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
+{
+       
+       /* Got the functions we need? */
+       if (!dev->writeChunkWithTagsToNAND ||
+           !dev->readChunkWithTagsFromNAND ||
+           !dev->eraseBlockInNAND ||
+           !dev->markNANDBlockBad)
+               return 0;
+
+       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 */
+               dev->checkpointByteOffset = dev->nDataBytesPerChunk;
+               /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
+                * going to be way more than we need */
+               dev->blocksInCheckpoint = 0;
+               dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
+               dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+               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;
+}
+
+static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
+{
+
+       int chunk;
+       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;
+       tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;
+       tags.byteCount = dev->nDataBytesPerChunk;
+       if(dev->checkpointCurrentChunk == 0){
+               /* First chunk we write for the block? Set block state to
+                  checkpoint */
+               yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
+               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)); 
+       
+       realignedChunk = chunk - dev->chunkOffset;
+       
+       dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
+       dev->checkpointByteOffset = 0;
+       dev->checkpointPageSequence++;     
+       dev->checkpointCurrentChunk++;
+       if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
+               dev->checkpointCurrentChunk = 0;
+               dev->checkpointCurrentBlock = -1;
+       }
+       memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
+       
+       return 1;
+}
+
+
+int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
+{
+       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->checkpointByteOffset++;
+               i++;
+               dataBytes++;
+               dev->checkpointByteCount++;
+               
+               
+               if(dev->checkpointByteOffset < 0 ||
+                  dev->checkpointByteOffset >= dev->nDataBytesPerChunk) 
+                       ok = yaffs_CheckpointFlushBuffer(dev);
+
+       }
+       
+       return  i;
+}
+
+int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
+{
+       int i=0;
+       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 + 
+                                         dev->checkpointCurrentChunk;
+
+                               realignedChunk = chunk - dev->chunkOffset;
+
+                               /* read in the next chunk */
+                               /* printf("read checkpoint page %d\n",dev->checkpointPage); */
+                               dev->readChunkWithTagsFromNAND(dev, realignedChunk, 
+                                                              dev->checkpointBuffer,
+                                                             &tags);
+                                                     
+                               if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
+                                  tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+                                  ok = 0;
+
+                               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->checkpointByteOffset != 0)
+                       yaffs_CheckpointFlushBuffer(dev);
+       } else {
+               int i;
+               for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
+                       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
+                       if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
+                               bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
+                       else {
+                               // Todo this looks odd...
+                       }
+               }
+               YFREE(dev->checkpointBlockList);
+               dev->checkpointBlockList = NULL;
+       }
+
+       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 */   
+               YFREE(dev->checkpointBuffer);
+               dev->checkpointBuffer = NULL;
+               return 1;
+       }
+       else
+               return 0;
+       
+}
+
+int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
+{
+       /* Erase the first checksum block */
+
+       T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
+
+       if(!yaffs_CheckpointSpaceOk(dev))
+               return 0;
+
+       return yaffs_CheckpointErase(dev);
+}
+
+
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_checkptrw.h
new file mode 100644 (file)
index 0000000..f4b0c7d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
+
+int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
+
+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);
+
+
+#endif
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.c
new file mode 100644 (file)
index 0000000..be860d0
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. 
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC 
+ * blocks are used on a 512-byte NAND page.
+ *
+ */
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
+ * this bytes influence on the line parity.
+ */
+
+const char *yaffs_ecc_c_version =
+    "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+static const unsigned char column_parity_table[] = {
+       0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+       0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+       0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+       0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+       0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+       0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+       0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+       0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+       0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+       0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+       0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+       0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+       0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+       0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+       0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+       0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+       0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+       0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+       0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+       0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+       0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+       0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+       0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+       0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+       0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+       0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+       0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+       0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+       0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+       0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+       0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+       0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+/* Count the bits in an unsigned char or a U32 */
+
+static int yaffs_CountBits(unsigned char x)
+{
+       int r = 0;
+       while (x) {
+               if (x & 1)
+                       r++;
+               x >>= 1;
+       }
+       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)
+{
+       unsigned int i;
+
+       unsigned char col_parity = 0;
+       unsigned char line_parity = 0;
+       unsigned char line_parity_prime = 0;
+       unsigned char t;
+       unsigned char b;
+
+       for (i = 0; i < 256; i++) {
+               b = column_parity_table[*data++];
+               col_parity ^= b;
+
+               if (b & 0x01)   // odd number of bits in the byte
+               {
+                       line_parity ^= i;
+                       line_parity_prime ^= ~i;
+               }
+
+       }
+
+       ecc[2] = (~col_parity) | 0x03;
+
+       t = 0;
+       if (line_parity & 0x80)
+               t |= 0x80;
+       if (line_parity_prime & 0x80)
+               t |= 0x40;
+       if (line_parity & 0x40)
+               t |= 0x20;
+       if (line_parity_prime & 0x40)
+               t |= 0x10;
+       if (line_parity & 0x20)
+               t |= 0x08;
+       if (line_parity_prime & 0x20)
+               t |= 0x04;
+       if (line_parity & 0x10)
+               t |= 0x02;
+       if (line_parity_prime & 0x10)
+               t |= 0x01;
+       ecc[1] = ~t;
+
+       t = 0;
+       if (line_parity & 0x08)
+               t |= 0x80;
+       if (line_parity_prime & 0x08)
+               t |= 0x40;
+       if (line_parity & 0x04)
+               t |= 0x20;
+       if (line_parity_prime & 0x04)
+               t |= 0x10;
+       if (line_parity & 0x02)
+               t |= 0x08;
+       if (line_parity_prime & 0x02)
+               t |= 0x04;
+       if (line_parity & 0x01)
+               t |= 0x02;
+       if (line_parity_prime & 0x01)
+               t |= 0x01;
+       ecc[0] = ~t;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+       // Swap the bytes into the wrong order
+       t = ecc[0];
+       ecc[0] = ecc[1];
+       ecc[1] = t;
+#endif
+}
+
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
+                    const unsigned char *test_ecc)
+{
+       unsigned char d0, d1, d2;       /* deltas */
+
+       d0 = read_ecc[0] ^ test_ecc[0];
+       d1 = read_ecc[1] ^ test_ecc[1];
+       d2 = read_ecc[2] ^ test_ecc[2];
+
+       if ((d0 | d1 | d2) == 0)
+               return 0; /* no error */
+
+       if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+           ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+           ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+               /* Single bit (recoverable) error in data */
+
+               unsigned byte;
+               unsigned bit;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+               // swap the bytes to correct for the wrong order
+               unsigned char t;
+
+               t = d0;
+               d0 = d1;
+               d1 = t;
+#endif
+
+               bit = byte = 0;
+
+               if (d1 & 0x80)
+                       byte |= 0x80;
+               if (d1 & 0x20)
+                       byte |= 0x40;
+               if (d1 & 0x08)
+                       byte |= 0x20;
+               if (d1 & 0x02)
+                       byte |= 0x10;
+               if (d0 & 0x80)
+                       byte |= 0x08;
+               if (d0 & 0x20)
+                       byte |= 0x04;
+               if (d0 & 0x08)
+                       byte |= 0x02;
+               if (d0 & 0x02)
+                       byte |= 0x01;
+
+               if (d2 & 0x80)
+                       bit |= 0x04;
+               if (d2 & 0x20)
+                       bit |= 0x02;
+               if (d2 & 0x08)
+                       bit |= 0x01;
+
+               data[byte] ^= (1 << bit);
+
+               return 1; /* Corrected the error */
+       }
+
+       if ((yaffs_CountBits(d0) + 
+            yaffs_CountBits(d1) + 
+            yaffs_CountBits(d2)) ==  1) {
+               /* Reccoverable error in ecc */
+
+               read_ecc[0] = test_ecc[0];
+               read_ecc[1] = test_ecc[1];
+               read_ecc[2] = test_ecc[2];
+
+               return 1; /* Corrected the error */
+       }
+       
+       /* Unrecoverable error */
+
+       return -1;
+
+}
+
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+                            yaffs_ECCOther * eccOther)
+{
+       unsigned int i;
+
+       unsigned char col_parity = 0;
+       unsigned line_parity = 0;
+       unsigned line_parity_prime = 0;
+       unsigned char b;
+
+       for (i = 0; i < nBytes; i++) {
+               b = column_parity_table[*data++];
+               col_parity ^= b;
+
+               if (b & 0x01)    {
+                       /* odd number of bits in the byte */
+                       line_parity ^= i;
+                       line_parity_prime ^= ~i;
+               }
+
+       }
+
+       eccOther->colParity = (col_parity >> 2) & 0x3f;
+       eccOther->lineParity = line_parity;
+       eccOther->lineParityPrime = line_parity_prime;
+}
+
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+                         yaffs_ECCOther * read_ecc,
+                         const yaffs_ECCOther * test_ecc)
+{
+       unsigned char cDelta;   /* column parity delta */
+       unsigned lDelta;        /* line parity delta */
+       unsigned lDeltaPrime;   /* line parity delta */
+       unsigned bit;
+
+       cDelta = read_ecc->colParity ^ test_ecc->colParity;
+       lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
+       lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
+
+       if ((cDelta | lDelta | lDeltaPrime) == 0)
+               return 0; /* no error */
+
+       if (lDelta == ~lDeltaPrime && 
+           (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
+       {
+               /* Single bit (recoverable) error in data */
+
+               bit = 0;
+
+               if (cDelta & 0x20)
+                       bit |= 0x04;
+               if (cDelta & 0x08)
+                       bit |= 0x02;
+               if (cDelta & 0x02)
+                       bit |= 0x01;
+
+               if(lDelta >= nBytes)
+                       return -1;
+                       
+               data[lDelta] ^= (1 << bit);
+
+               return 1; /* corrected */
+       }
+
+       if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
+            yaffs_CountBits(cDelta)) == 1) {
+               /* Reccoverable error in ecc */
+
+               *read_ecc = *test_ecc;
+               return 1; /* corrected */
+       }
+
+       /* Unrecoverable error */
+
+       return -1;
+
+}
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_ecc.h
new file mode 100644 (file)
index 0000000..40fd02b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+ /*
+  * This code implements the ECC algorithm used in SmartMedia.
+  *
+  * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. 
+  * The two unused bit are set to 1.
+  * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC 
+  * blocks are used on a 512-byte NAND page.
+  *
+  */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+typedef struct {
+       unsigned char colParity;
+       unsigned lineParity;
+       unsigned lineParityPrime;
+} yaffs_ECCOther;
+
+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);
+
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+                            yaffs_ECCOther * ecc);
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+                         yaffs_ECCOther * read_ecc,
+                         const yaffs_ECCOther * test_ecc);
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_fs.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_fs.c
new file mode 100644 (file)
index 0000000..e572301
--- /dev/null
@@ -0,0 +1,2299 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * 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 is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * 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
+ *         superblock
+ * >> inode->u.generic_ip points to the associated yaffs_Object.
+ */
+
+const char *yaffs_fs_c_version =
+    "$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $";
+extern const char *yaffs_guts_c_version;
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+#include <linux/statfs.h>      /* Added NCB 15-8-2003 */
+#include <asm/statfs.h>
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page)    test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
+
+#else
+
+#include <linux/locks.h>
+#define        BDEVNAME_SIZE           0
+#define        yaffs_devname(sb, buf)  kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#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 <asm/uaccess.h>
+
+#include "yportenv.h"
+#include "yaffs_guts.h"
+
+#include <linux/mtd/mtd.h>
+#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");
+#endif
+
+/*#define T(x) printk x */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
+#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
+#else
+#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
+#endif
+
+#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->s_fs_info)
+#else
+#define yaffs_SuperToDevice(sb)        ((yaffs_Device *)sb->u.generic_sbp)
+#endif
+
+static void yaffs_put_super(struct super_block *sb);
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+                               loff_t * pos);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id);
+#else
+static int yaffs_file_flush(struct file *file);
+#endif
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+                            int datasync);
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+                       struct nameidata *n);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+                                  struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
+#endif
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+                     struct dentry *dentry);
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+                        const char *symname);
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                      dev_t dev);
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                      int dev);
+#endif
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                       struct inode *new_dir, struct dentry *new_dentry);
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_sync_fs(struct super_block *sb, int wait);
+static void yaffs_write_super(struct super_block *sb);
+#else
+static int yaffs_sync_fs(struct super_block *sb);
+static int yaffs_write_super(struct super_block *sb);
+#endif
+
+#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))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+static void yaffs_read_inode(struct inode *inode);
+
+static void yaffs_put_inode(struct inode *inode);
+static void yaffs_delete_inode(struct inode *);
+static void yaffs_clear_inode(struct inode *);
+
+static int yaffs_readpage(struct file *file, struct page *page);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
+#else
+static int yaffs_writepage(struct page *page);
+#endif
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+                              unsigned offset, unsigned to);
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+                             unsigned to);
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+                         int buflen);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#endif
+
+static struct address_space_operations yaffs_file_address_operations = {
+       .readpage = yaffs_readpage,
+       .writepage = yaffs_writepage,
+       .prepare_write = yaffs_prepare_write,
+       .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 = {
+       .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,
+       .mmap = generic_file_mmap,
+       .flush = yaffs_file_flush,
+       .fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+       .sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+static struct inode_operations yaffs_file_inode_operations = {
+       .setattr = yaffs_setattr,
+};
+
+static struct inode_operations yaffs_symlink_inode_operations = {
+       .readlink = yaffs_readlink,
+       .follow_link = yaffs_follow_link,
+       .setattr = yaffs_setattr,
+};
+
+static struct inode_operations yaffs_dir_inode_operations = {
+       .create = yaffs_create,
+       .lookup = yaffs_lookup,
+       .link = yaffs_link,
+       .unlink = yaffs_unlink,
+       .symlink = yaffs_symlink,
+       .mkdir = yaffs_mkdir,
+       .rmdir = yaffs_unlink,
+       .mknod = yaffs_mknod,
+       .rename = yaffs_rename,
+       .setattr = yaffs_setattr,
+};
+
+static struct file_operations yaffs_dir_operations = {
+       .read = generic_read_dir,
+       .readdir = yaffs_readdir,
+       .fsync = yaffs_sync_object,
+};
+
+static struct super_operations yaffs_super_ops = {
+       .statfs = yaffs_statfs,
+       .read_inode = yaffs_read_inode,
+       .put_inode = yaffs_put_inode,
+       .put_super = yaffs_put_super,
+       .delete_inode = yaffs_delete_inode,
+       .clear_inode = yaffs_clear_inode,
+       .sync_fs = yaffs_sync_fs,
+       .write_super = yaffs_write_super,
+};
+
+static void yaffs_GrossLock(yaffs_Device * dev)
+{
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n"));
+
+       down(&dev->grossLock);
+}
+
+static void yaffs_GrossUnlock(yaffs_Device * dev)
+{
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n"));
+       up(&dev->grossLock);
+
+}
+
+static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
+                         int buflen)
+{
+       unsigned char *alias;
+       int ret;
+
+       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+       yaffs_GrossLock(dev);
+
+       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+       yaffs_GrossUnlock(dev);
+
+       if (!alias)
+               return -ENOMEM;
+
+       ret = vfs_readlink(dentry, buffer, buflen, alias);
+       kfree(alias);
+       return ret;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#endif
+{
+       unsigned char *alias;
+       int ret;
+       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+       yaffs_GrossLock(dev);
+
+       alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+       yaffs_GrossUnlock(dev);
+
+       if (!alias)
+        {
+               ret = -ENOMEM;
+               goto out;
+        }
+
+       ret = vfs_follow_link(nd, alias);
+       kfree(alias);
+out:
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+       return ERR_PTR (ret);
+#else
+       return ret;
+#endif
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+                             yaffs_Object * obj);
+
+/*
+ * Lookup is used to find objects in the fs
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+                                  struct nameidata *n)
+#else
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+       yaffs_Object *obj;
+       struct inode *inode = NULL;     /* NCB 2.5/2.6 needs NULL here */
+
+       yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
+
+       yaffs_GrossLock(dev);
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_lookup for %d:%s\n",
+          yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
+
+       obj =
+           yaffs_FindObjectByName(yaffs_InodeToObject(dir),
+                                  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);
+
+       if (obj) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_lookup found %d\n", obj->objectId));
+
+               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+
+               if (inode) {
+                       T(YAFFS_TRACE_OS,
+                         (KERN_DEBUG "yaffs_loookup dentry \n"));
+/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
+ * d_add even if NULL inode */
+#if 0
+                       /*dget(dentry); // try to solve directory bug */
+                       d_add(dentry, inode);
+
+                       /* return dentry; */
+                       return NULL;
+#endif
+               }
+
+       } else {
+               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_lookup not found\n"));
+
+       }
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+       d_add(dentry, inode);
+
+       return NULL;
+       /*      return (ERR_PTR(-EIO)); */
+
+}
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+       T(YAFFS_TRACE_OS,
+         ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
+          atomic_read(&inode->i_count)));
+
+}
+
+/* clear is called to tell the fs to release any per-inode data it holds */
+static void yaffs_clear_inode(struct inode *inode)
+{
+       yaffs_Object *obj;
+       yaffs_Device *dev;
+
+       obj = yaffs_InodeToObject(inode);
+
+       T(YAFFS_TRACE_OS,
+         ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+          atomic_read(&inode->i_count),
+          obj ? "object exists" : "null object"));
+
+       if (obj) {
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+
+               /* Clear the association between the inode and
+                * the yaffs_Object.
+                */
+               obj->myInode = NULL;
+               yaffs_InodeToObjectLV(inode) = NULL;
+
+               /* If the object freeing was deferred, then the real
+                * free happens now.
+                * This should fix the inode inconsistency problem.
+                */
+
+               yaffs_HandleDeferedFree(obj);
+
+               yaffs_GrossUnlock(dev);
+       }
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+       yaffs_Object *obj = yaffs_InodeToObject(inode);
+       yaffs_Device *dev;
+
+       T(YAFFS_TRACE_OS,
+         ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+          atomic_read(&inode->i_count),
+          obj ? "object exists" : "null object"));
+
+       if (obj) {
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+               yaffs_DeleteFile(obj);
+               yaffs_GrossUnlock(dev);
+       }
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
+        truncate_inode_pages (&inode->i_data, 0);
+#endif
+       clear_inode(inode);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+       yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
+
+       yaffs_Device *dev = obj->myDev;
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_file_flush object %d (%s)\n", obj->objectId,
+          obj->dirty ? "dirty" : "clean"));
+
+       yaffs_GrossLock(dev);
+
+       yaffs_FlushFile(obj, 1);
+
+       yaffs_GrossUnlock(dev);
+
+       return 0;
+}
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+       /* Lifted from jffs2 */
+
+       yaffs_Object *obj;
+       unsigned char *pg_buf;
+       int ret;
+
+       yaffs_Device *dev;
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage at %08x, size %08x\n",
+                          (unsigned)(pg->index << PAGE_CACHE_SHIFT),
+                          (unsigned)PAGE_CACHE_SIZE));
+
+       obj = yaffs_DentryToObject(f->f_dentry);
+
+       dev = obj->myDev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+       BUG_ON(!PageLocked(pg));
+#else
+       if (!PageLocked(pg))
+               PAGE_BUG(pg);
+#endif
+
+       pg_buf = kmap(pg);
+       /* FIXME: Can kmap fail? */
+
+       yaffs_GrossLock(dev);
+
+       ret =
+           yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT,
+                                  PAGE_CACHE_SIZE);
+
+       yaffs_GrossUnlock(dev);
+
+       if (ret >= 0)
+               ret = 0;
+
+       if (ret) {
+               ClearPageUptodate(pg);
+               SetPageError(pg);
+       } else {
+               SetPageUptodate(pg);
+               ClearPageError(pg);
+       }
+
+       flush_dcache_page(pg);
+       kunmap(pg);
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage done\n"));
+       return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+       int ret = yaffs_readpage_nolock(f, pg);
+       UnlockPage(pg);
+       return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+       return yaffs_readpage_unlock(f, pg);
+}
+
+/* writepage inspired by/stolen from smbfs */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+       struct address_space *mapping = page->mapping;
+       loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
+       struct inode *inode;
+       unsigned long end_index;
+       char *buffer;
+       yaffs_Object *obj;
+       int nWritten = 0;
+       unsigned nBytes;
+
+       if (!mapping)
+               BUG();
+       inode = mapping->host;
+       if (!inode)
+               BUG();
+
+       if (offset > inode->i_size) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG
+                  "yaffs_writepage at %08x, inode size = %08x!!!\n",
+                  (unsigned)(page->index << PAGE_CACHE_SHIFT),
+                  (unsigned)inode->i_size));
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "                -> don't care!!\n"));
+               unlock_page(page);
+               return 0;
+       }
+
+       end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+       /* easy case */
+       if (page->index < end_index) {
+               nBytes = PAGE_CACHE_SIZE;
+       } else {
+               nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
+       }
+
+       get_page(page);
+
+       buffer = kmap(page);
+
+       obj = yaffs_InodeToObject(inode);
+       yaffs_GrossLock(obj->myDev);
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_writepage at %08x, size %08x\n",
+          (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "writepag0: obj = %05x, ino = %05x\n",
+          (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+       nWritten =
+           yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT,
+                                 nBytes, 0);
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "writepag1: obj = %05x, ino = %05x\n",
+          (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+       yaffs_GrossUnlock(obj->myDev);
+
+       kunmap(page);
+       SetPageUptodate(page);
+       UnlockPage(page);
+       put_page(page);
+
+       return (nWritten == nBytes) ? 0 : -ENOSPC;
+}
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+                              unsigned offset, unsigned to)
+{
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
+       if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
+               return yaffs_readpage_nolock(f, pg);
+
+       return 0;
+
+}
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+                             unsigned to)
+{
+
+       void *addr = page_address(pg) + offset;
+       loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+       int nBytes = to - offset;
+       int nWritten;
+
+       unsigned spos = pos;
+       unsigned saddr = (unsigned)addr;
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
+          spos, nBytes));
+
+       nWritten = yaffs_file_write(f, addr, nBytes, &pos);
+
+       if (nWritten != nBytes) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG
+                  "yaffs_commit_write not same size nWritten %d  nBytes %d\n",
+                  nWritten, nBytes));
+               SetPageError(pg);
+               ClearPageUptodate(pg);
+       } else {
+               SetPageUptodate(pg);
+       }
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_commit_write returning %d\n",
+          nWritten == nBytes ? 0 : nWritten));
+
+       return nWritten == nBytes ? 0 : nWritten;
+
+}
+
+static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
+{
+       if (inode && obj) {
+
+
+               /* Check mode against the variant type and attempt to repair if broken. */
+               __u32 mode = obj->yst_mode;
+               switch( obj->variantType ){
+               case YAFFS_OBJECT_TYPE_FILE :
+                       if( ! S_ISREG(mode) ){
+                               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 :
+               case YAFFS_OBJECT_TYPE_SPECIAL :
+               default:
+                       /* TODO? */
+                       break;
+               }
+
+               inode->i_ino = obj->objectId;
+               inode->i_mode = obj->yst_mode;
+               inode->i_uid = obj->yst_uid;
+               inode->i_gid = obj->yst_gid;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+               inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+
+               inode->i_rdev = old_decode_dev(obj->yst_rdev);
+               inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+               inode->i_atime.tv_nsec = 0;
+               inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+               inode->i_mtime.tv_nsec = 0;
+               inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+               inode->i_ctime.tv_nsec = 0;
+#else
+               inode->i_rdev = obj->yst_rdev;
+               inode->i_atime = obj->yst_atime;
+               inode->i_mtime = obj->yst_mtime;
+               inode->i_ctime = obj->yst_ctime;
+#endif
+               inode->i_size = yaffs_GetObjectFileLength(obj);
+               inode->i_blocks = (inode->i_size + 511) >> 9;
+
+               inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG
+                  "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
+                  inode->i_mode, inode->i_uid, inode->i_gid,
+                  (int)inode->i_size, atomic_read(&inode->i_count)));
+
+               switch (obj->yst_mode & S_IFMT) {
+               default:        /* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+                       init_special_inode(inode, obj->yst_mode,
+                                          old_decode_dev(obj->yst_rdev));
+#else
+                       init_special_inode(inode, obj->yst_mode,
+                                          (dev_t) (obj->yst_rdev));
+#endif
+                       break;
+               case S_IFREG:   /* file */
+                       inode->i_op = &yaffs_file_inode_operations;
+                       inode->i_fop = &yaffs_file_operations;
+                       inode->i_mapping->a_ops =
+                           &yaffs_file_address_operations;
+                       break;
+               case S_IFDIR:   /* directory */
+                       inode->i_op = &yaffs_dir_inode_operations;
+                       inode->i_fop = &yaffs_dir_operations;
+                       break;
+               case S_IFLNK:   /* symlink */
+                       inode->i_op = &yaffs_symlink_inode_operations;
+                       break;
+               }
+
+               yaffs_InodeToObjectLV(inode) = obj;
+
+               obj->myInode = inode;
+
+       } else {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_FileInode invalid parameters\n"));
+       }
+
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+                             yaffs_Object * obj)
+{
+       struct inode *inode;
+
+       if (!sb) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n"));
+               return NULL;
+
+       }
+
+       if (!obj) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_get_inode for NULL object!!\n"));
+               return NULL;
+
+       }
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
+
+       inode = iget(sb, obj->objectId);
+
+       /* NB Side effect: iget calls back to yaffs_read_inode(). */
+       /* iget also increments the inode's i_count */
+       /* NB You can't be holding grossLock or deadlock will happen! */
+
+       return inode;
+}
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+                               loff_t * pos)
+{
+       yaffs_Object *obj;
+       int nWritten, ipos;
+       struct inode *inode;
+       yaffs_Device *dev;
+
+       obj = yaffs_DentryToObject(f->f_dentry);
+
+       dev = obj->myDev;
+
+       yaffs_GrossLock(dev);
+
+       inode = f->f_dentry->d_inode;
+
+       if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
+               ipos = inode->i_size;
+       } else {
+               ipos = *pos;
+       }
+
+       if (!obj) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_file_write: hey obj is null!\n"));
+       } else {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG
+                  "yaffs_file_write about to write writing %d bytes"
+                  "to object %d at %d\n",
+                  n, obj->objectId, ipos));
+       }
+
+       nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n",
+          n, nWritten, ipos));
+       if (nWritten > 0) {
+               ipos += nWritten;
+               *pos = ipos;
+               if (ipos > inode->i_size) {
+                       inode->i_size = ipos;
+                       inode->i_blocks = (ipos + 511) >> 9;
+
+                       T(YAFFS_TRACE_OS,
+                         (KERN_DEBUG
+                          "yaffs_file_write size updated to %d bytes, "
+                          "%d blocks\n",
+                          ipos, (int)(inode->i_blocks)));
+               }
+
+       }
+       yaffs_GrossUnlock(dev);
+       return nWritten == 0 ? -ENOSPC : nWritten;
+}
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+       yaffs_Object *obj;
+       yaffs_Device *dev;
+       struct inode *inode = f->f_dentry->d_inode;
+       unsigned long offset, curoffs;
+       struct list_head *i;
+       yaffs_Object *l;
+
+       char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+       obj = yaffs_DentryToObject(f->f_dentry);
+       dev = obj->myDev;
+
+       yaffs_GrossLock(dev);
+
+       offset = f->f_pos;
+
+       T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
+
+       if (offset == 0) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_readdir: entry . ino %d \n",
+                  (int)inode->i_ino));
+               if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
+                   < 0) {
+                       goto out;
+               }
+               offset++;
+               f->f_pos++;
+       }
+       if (offset == 1) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n",
+                  (int)f->f_dentry->d_parent->d_inode->i_ino));
+               if (filldir
+                   (dirent, "..", 2, offset,
+                    f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+                       goto out;
+               }
+               offset++;
+               f->f_pos++;
+       }
+
+       curoffs = 1;
+
+       /* If the directory has changed since the open or last call to
+          readdir, rewind to after the 2 canned entries. */
+
+       if (f->f_version != inode->i_version) {
+               offset = 2;
+               f->f_pos = offset;
+               f->f_version = inode->i_version;
+       }
+
+       list_for_each(i, &obj->variant.directoryVariant.children) {
+               curoffs++;
+               if (curoffs >= offset) {
+                       l = list_entry(i, yaffs_Object, siblings);
+
+                       yaffs_GetObjectName(l, name,
+                                           YAFFS_MAX_NAME_LENGTH + 1);
+                       T(YAFFS_TRACE_OS,
+                         (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
+                          yaffs_GetObjectInode(l)));
+
+                       if (filldir(dirent,
+                                   name,
+                                   strlen(name),
+                                   offset,
+                                   yaffs_GetObjectInode(l),
+                                   yaffs_GetObjectType(l))
+                           < 0) {
+                               goto up_and_out;
+                       }
+
+                       offset++;
+                       f->f_pos++;
+               }
+       }
+
+      up_and_out:
+      out:
+
+       yaffs_GrossUnlock(dev);
+
+       return 0;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                      dev_t rdev)
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+                      int rdev)
+#endif
+{
+       struct inode *inode;
+
+       yaffs_Object *obj = NULL;
+       yaffs_Device *dev;
+
+       yaffs_Object *parent = yaffs_InodeToObject(dir);
+
+       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;
+
+       if (parent) {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n",
+                  parent->objectId, parent->variantType));
+       } else {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_mknod: could not get parent object\n"));
+               return -EPERM;
+       }
+
+       T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
+                          "mode %x dev %x\n",
+                          dentry->d_name.name, mode, rdev));
+
+       dev = parent->myDev;
+
+       yaffs_GrossLock(dev);
+
+       switch (mode & S_IFMT) {
+       default:
+               /* Special (socket, fifo, device...) */
+               T(YAFFS_TRACE_OS, (KERN_DEBUG
+                                  "yaffs_mknod: making special\n"));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+               obj =
+                   yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+                                      gid, old_encode_dev(rdev));
+#else
+               obj =
+                   yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+                                      gid, rdev);
+#endif
+               break;
+       case S_IFREG:           /* file          */
+               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
+               obj =
+                   yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
+                                   gid);
+               break;
+       case S_IFDIR:           /* directory */
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_mknod: making directory\n"));
+               obj =
+                   yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
+                                        uid, gid);
+               break;
+       case S_IFLNK:           /* symlink */
+               T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
+               obj = NULL;     /* Do we ever get here? */
+               break;
+       }
+       
+       /* Can not call yaffs_get_inode() with gross lock held */
+       yaffs_GrossUnlock(dev);
+
+       if (obj) {
+               inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+               d_instantiate(dentry, inode);
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
+                  obj->objectId, atomic_read(&inode->i_count)));
+               error = 0;
+       } else {
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_mknod failed making object\n"));
+               error = -ENOMEM;
+       }
+
+       return error;
+}
+
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       int retVal;
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
+       retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+#if 0
+       /* attempt to fix dir bug - didn't work */
+       if (!retVal) {
+               dget(dentry);
+       }
+#endif
+       return retVal;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+                       struct nameidata *n)
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
+       return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       int retVal;
+
+       yaffs_Device *dev;
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
+          dentry->d_name.name));
+
+       dev = yaffs_InodeToObject(dir)->myDev;
+
+       yaffs_GrossLock(dev);
+
+       retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
+
+       if (retVal == YAFFS_OK) {
+               dentry->d_inode->i_nlink--;
+               dir->i_version++;
+               yaffs_GrossUnlock(dev);
+               mark_inode_dirty(dentry->d_inode);
+               return 0;
+       }
+       yaffs_GrossUnlock(dev);
+       return -ENOTEMPTY;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+                     struct dentry *dentry)
+{
+       struct inode *inode = old_dentry->d_inode;
+       yaffs_Object *obj = NULL;
+       yaffs_Object *link = NULL;
+       yaffs_Device *dev;
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n"));
+
+       obj = yaffs_InodeToObject(inode);
+       dev = obj->myDev;
+
+       yaffs_GrossLock(dev);
+
+       if (!S_ISDIR(inode->i_mode))    /* Don't link directories */
+       {
+               link =
+                   yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
+                              obj);
+       }
+
+       if (link) {
+               old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+               d_instantiate(dentry, old_dentry->d_inode);
+               atomic_inc(&old_dentry->d_inode->i_count);
+               T(YAFFS_TRACE_OS,
+                 (KERN_DEBUG "yaffs_link link count %d i_count %d\n",
+                  old_dentry->d_inode->i_nlink,
+                  atomic_read(&old_dentry->d_inode->i_count)));
+
+       }
+
+       yaffs_GrossUnlock(dev);
+
+       if (link) {
+
+               return 0;
+       }
+
+       return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+                        const char *symname)
+{
+       yaffs_Object *obj;
+       yaffs_Device *dev;
+       uid_t uid = current->fsuid;
+       gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n"));
+
+       dev = yaffs_InodeToObject(dir)->myDev;
+       yaffs_GrossLock(dev);
+       obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
+                                S_IFLNK | S_IRWXUGO, uid, gid, symname);
+       yaffs_GrossUnlock(dev);
+
+       if (obj) {
+
+               struct inode *inode;
+
+               inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+               d_instantiate(dentry, inode);
+               T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n"));
+               return 0;
+       } else {
+               T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n"));
+
+       }
+
+       return -ENOMEM;
+}
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+                            int datasync)
+{
+
+       yaffs_Object *obj;
+       yaffs_Device *dev;
+
+       obj = yaffs_DentryToObject(dentry);
+
+       dev = obj->myDev;
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n"));
+       yaffs_GrossLock(dev);
+       yaffs_FlushFile(obj, 1);
+       yaffs_GrossUnlock(dev);
+       return 0;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                       struct inode *new_dir, struct dentry *new_dentry)
+{
+       yaffs_Device *dev;
+       int retVal = YAFFS_FAIL;
+       yaffs_Object *target;
+
+        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n"));
+       dev = yaffs_InodeToObject(old_dir)->myDev;
+
+       yaffs_GrossLock(dev);
+
+       /* Check if the target is an existing directory that is not empty. */
+       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;
+       } else {
+
+               /* 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,
+                                      yaffs_InodeToObject(new_dir),
+                                      new_dentry->d_name.name);
+
+       }
+       yaffs_GrossUnlock(dev);
+
+       if (retVal == YAFFS_OK) {
+               if(target) {
+                       new_dentry->d_inode->i_nlink--;
+                       mark_inode_dirty(new_dentry->d_inode);
+               }
+
+               return 0;
+       } else {
+               return -ENOTEMPTY;
+       }
+
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+       yaffs_Device *dev;
+
+       T(YAFFS_TRACE_OS,
+         (KERN_DEBUG "yaffs_setattr of object %d\n",
+          yaffs_InodeToObject(inode)->objectId));
+
+       if ((error = inode_change_ok(inode, attr)) == 0) {
+
+               dev = yaffs_InodeToObject(inode)->myDev;
+               yaffs_GrossLock(dev);
+               if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
+                   YAFFS_OK) {
+                       error = 0;
+               } else {
+                       error = -EPERM;
+               }
+               yaffs_GrossUnlock(dev);
+               if (!error)
+                       error = inode_setattr(inode, attr);
+       }
+       return error;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+       struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+       yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+       yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#endif
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
+
+       yaffs_GrossLock(dev);
+
+       buf->f_type = YAFFS_MAGIC;
+       buf->f_bsize = sb->s_blocksize;
+       buf->f_namelen = 255;
+       if (sb->s_blocksize > dev->nDataBytesPerChunk) {
+
+               buf->f_blocks =
+                   (dev->endBlock - dev->startBlock +
+                    1) * dev->nChunksPerBlock / (sb->s_blocksize /
+                                                 dev->nDataBytesPerChunk);
+               buf->f_bfree =
+                   yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
+                                                       dev->nDataBytesPerChunk);
+       } else {
+
+               buf->f_blocks =
+                   (dev->endBlock - dev->startBlock +
+                    1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
+                                                 sb->s_blocksize);
+               buf->f_bfree =
+                   yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
+                                                       sb->s_blocksize);
+       }
+       buf->f_files = 0;
+       buf->f_ffree = 0;
+       buf->f_bavail = buf->f_bfree;
+
+       yaffs_GrossUnlock(dev);
+       return 0;
+}
+
+
+/**
+static int yaffs_do_sync_fs(struct super_block *sb)
+{
+
+       yaffs_Device *dev = yaffs_SuperToDevice(sb);
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
+
+       if(sb->s_dirt) {
+               yaffs_GrossLock(dev);
+
+               if(dev)
+                       yaffs_CheckpointSave(dev);
+               
+               yaffs_GrossUnlock(dev);
+
+               sb->s_dirt = 0;
+       }
+       return 0;
+}
+**/
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+       return 0; /* yaffs_do_sync_fs(sb);*/
+#endif
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+
+       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 
+        * need to lock again.
+        */
+
+       yaffs_Object *obj;
+       yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
+
+       T(YAFFS_TRACE_OS,
+         (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);
+
+       yaffs_GrossUnlock(dev);
+}
+
+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, 
+                       (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name ));
+       }
+       return 0;
+}
+#endif
+
+static void yaffs_put_super(struct super_block *sb)
+{
+       yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+       T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n"));
+
+       yaffs_GrossLock(dev);
+       
+       yaffs_FlushEntireDeviceCache(dev);
+
+       yaffs_CheckpointSave(dev);
+
+       if (dev->putSuperFunc) {
+               dev->putSuperFunc(sb);
+       }
+
+       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;
+       }
+
+       kfree(dev);
+}
+
+
+static void yaffs_MTDPutSuper(struct super_block *sb)
+{
+
+       struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+       if (mtd->sync) {
+               mtd->sync(mtd);
+       }
+
+       put_mtd_device(mtd);
+}
+
+
+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)
+{
+       int nBlocks;
+       struct inode *inode = NULL;
+       struct dentry *root;
+       yaffs_Device *dev = 0;
+       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;
+
+       if (!sb)
+               printk(KERN_INFO "yaffs: sb is NULL\n");
+       else if (!sb->s_dev)
+               printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+       else if (!yaffs_devname(sb, devname_buf))
+               printk(KERN_INFO "yaffs: devname is NULL\n");
+       else
+               printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
+                      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));
+       T(YAFFS_TRACE_OS,
+         ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
+
+#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
+       T(YAFFS_TRACE_OS,
+         ("yaffs: Write verification disabled. All guarantees "
+          "null and void\n"));
+#endif
+
+       T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
+                              "\"%s\"\n",
+                              MAJOR(sb->s_dev), MINOR(sb->s_dev),
+                              yaffs_devname(sb, devname_buf)));
+
+       /* Check it's an mtd device..... */
+       if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
+               return NULL;    /* This isn't an mtd device */
+       }
+       /* Get the device */
+       mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+       if (!mtd) {
+               T(YAFFS_TRACE_ALWAYS,
+                 ("yaffs: MTD device #%u doesn't appear to exist\n",
+                  MINOR(sb->s_dev)));
+               return NULL;
+       }
+       /* Check it's NAND */
+       if (mtd->type != MTD_NANDFLASH) {
+               T(YAFFS_TRACE_ALWAYS,
+                 ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
+               return NULL;
+       }
+
+       T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
+       T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
+       T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
+       T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
+       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)));
+       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));
+       
+#ifdef CONFIG_YAFFS_AUTO_YAFFS2
+
+       if (yaffsVersion == 1 && 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+           mtd->writesize >= 2048) {
+#else
+           mtd->oobblock >= 2048) {
+#endif
+           T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
+           yaffsVersion = 2;
+       }       
+       
+       /* Added NCB 26/5/2006 for completeness */
+       if (yaffsVersion == 2 && 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+           mtd->writesize == 512) {
+#else
+           mtd->oobblock == 512) {
+#endif
+           T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
+           yaffsVersion = 1;
+       }       
+
+#endif
+
+       if (yaffsVersion == 2) {
+               /* Check for version 2 style functions */
+               if (!mtd->erase ||
+                   !mtd->block_isbad ||
+                   !mtd->block_markbad ||
+                   !mtd->read ||
+                   !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+                   !mtd->read_oob || !mtd->write_oob) {
+#else
+                   !mtd->write_ecc ||
+                   !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+                       T(YAFFS_TRACE_ALWAYS,
+                         ("yaffs: MTD device does not support required "
+                          "functions\n"));;
+                       return NULL;
+               }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+               if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+#else
+               if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+#endif
+                   mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
+                       T(YAFFS_TRACE_ALWAYS,
+                         ("yaffs: MTD device does not have the "
+                          "right page sizes\n"));
+                       return NULL;
+               }
+       } else {
+               /* Check for V1 style functions */
+               if (!mtd->erase ||
+                   !mtd->read ||
+                   !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+                   !mtd->read_oob || !mtd->write_oob) {
+#else
+                   !mtd->write_ecc ||
+                   !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+                       T(YAFFS_TRACE_ALWAYS,
+                         ("yaffs: MTD device does not support required "
+                          "functions\n"));;
+                       return NULL;
+               }
+
+               if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+                   mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+                       T(YAFFS_TRACE_ALWAYS,
+                         ("yaffs: MTD device does not support have the "
+                          "right page sizes\n"));
+                       return NULL;
+               }
+       }
+
+       /* OK, so if we got here, we have an MTD that's NAND and looks
+        * like it has the right capabilities
+        * Set the yaffs_Device up for mtd
+        */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+       sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#else
+       sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#endif
+       if (!dev) {
+               /* Deep shit could not allocate device structure */
+               T(YAFFS_TRACE_ALWAYS,
+                 ("yaffs_read_super: Failed trying to allocate "
+                  "yaffs_Device. \n"));
+               return NULL;
+       }
+
+       memset(dev, 0, sizeof(yaffs_Device));
+       dev->genericDevice = mtd;
+       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;
+
+       /* ... and the functions. */
+       if (yaffsVersion == 2) {
+               dev->writeChunkWithTagsToNAND =
+                   nandmtd2_WriteChunkWithTagsToNAND;
+               dev->readChunkWithTagsFromNAND =
+                   nandmtd2_ReadChunkWithTagsFromNAND;
+               dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+               dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
+               dev->spareBuffer = YMALLOC(mtd->oobsize);
+               dev->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+               dev->nDataBytesPerChunk = mtd->writesize;
+               dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+               dev->nDataBytesPerChunk = mtd->oobblock;
+               dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+               nBlocks = mtd->size / mtd->erasesize;
+
+               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
+               dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
+               dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
+#endif
+               dev->isYaffs2 = 0;
+       }
+       /* ... and common functions */
+       dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+       dev->initialiseNAND = nandmtd_InitialiseNAND;
+
+       dev->putSuperFunc = yaffs_MTDPutSuper;
+       
+       dev->superBlock = (void *)sb;
+       dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
+       
+
+#ifndef CONFIG_YAFFS_DOES_ECC
+       dev->useNANDECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
+       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);
+
+       init_MUTEX(&dev->grossLock);
+
+       yaffs_GrossLock(dev);
+
+       err = yaffs_GutsInitialise(dev);
+
+       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);
+
+       /* Create root inode */
+       if (err == YAFFS_OK)
+               inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
+                                       yaffs_Root(dev));
+
+       if (!inode)
+               return NULL;
+
+       inode->i_op = &yaffs_dir_inode_operations;
+       inode->i_fop = &yaffs_dir_operations;
+
+       T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
+
+       root = d_alloc_root(inode);
+
+       T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
+
+       if (!root) {
+               iput(inode);
+               return NULL;
+       }
+       sb->s_root = root;
+
+       T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
+       return sb;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+                                        int silent)
+{
+       return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs_read_super(struct file_system_type *fs,
+                           int flags, const char *dev_name,
+                           void *data, struct vfsmount *mnt)
+{
+
+       return get_sb_bdev(fs, flags, dev_name, data,
+                          yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+                                           int flags, const char *dev_name,
+                                           void *data)
+{
+
+       return get_sb_bdev(fs, flags, dev_name, data,
+                          yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+       .owner = THIS_MODULE,
+       .name = "yaffs",
+       .get_sb = yaffs_read_super,
+       .kill_sb = kill_block_super,
+       .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+                                           int silent)
+{
+       return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+                     FS_REQUIRES_DEV);
+#endif
+
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+                                         int silent)
+{
+       return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static int yaffs2_read_super(struct file_system_type *fs,
+                       int flags, const char *dev_name, void *data,
+                       struct vfsmount *mnt)
+{
+       return get_sb_bdev(fs, flags, dev_name, data,
+                       yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+                                            int flags, const char *dev_name,
+                                            void *data)
+{
+
+       return get_sb_bdev(fs, flags, dev_name, data,
+                          yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+       .owner = THIS_MODULE,
+       .name = "yaffs2",
+       .get_sb = yaffs2_read_super,
+       .kill_sb = kill_block_super,
+       .fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+                                            void *data, int silent)
+{
+       return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+                     FS_REQUIRES_DEV);
+#endif
+
+#endif                         /* CONFIG_YAFFS_YAFFS2 */
+
+static struct proc_dir_entry *my_proc_entry;
+
+static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
+{
+       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);
+       buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
+       buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
+       buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
+       buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
+       buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
+       buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
+       buf +=
+           sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
+       buf +=
+           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);
+       buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
+       buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
+       buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
+       buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
+       buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
+       buf +=
+           sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
+       buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
+       buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
+
+       return buf;
+}
+
+static int yaffs_proc_read(char *page,
+                          char **start,
+                          off_t offset, int count, int *eof, void *data)
+{
+       struct list_head *item;
+       char *buf = page;
+       int step = offset;
+       int n = 0;
+
+       /* Get proc_file_read() to step 'offset' by one on each sucessive call.
+        * We use 'offset' (*ppos) to indicate where we are in devList.
+        * This also assumes the user has posted a read buffer large
+        * enough to hold the complete output; but that's life in /proc.
+        */
+
+       *(int *)start = 1;
+
+       /* Print header first */
+       if (step == 0) {
+               buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
+                              "\n%s\n%s\n", yaffs_fs_c_version,
+                              yaffs_guts_c_version);
+       }
+
+       /* hold lock_kernel while traversing yaffs_dev_list */
+       lock_kernel();
+
+       /* Locate and print the Nth entry.  Order N-squared but N is small. */
+       list_for_each(item, &yaffs_dev_list) {
+               yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
+               if (n < step) {
+                       n++;
+                       continue;
+               }
+               buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
+               buf = yaffs_dump_dev(buf, dev);
+               break;
+       }
+       unlock_kernel();
+
+       return buf - page < count ? buf - page : count;
+}
+
+/**
+ * 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 {
+       char *mask_name;
+       unsigned mask_bitfield;
+} mask_flags[] = {
+       {"allocate", YAFFS_TRACE_ALLOCATE},
+       {"always", YAFFS_TRACE_ALWAYS},
+       {"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},
+       {"gc_detail", YAFFS_TRACE_GC_DETAIL},
+       {"gc", YAFFS_TRACE_GC},
+       {"mtd", YAFFS_TRACE_MTD},
+       {"nandaccess", YAFFS_TRACE_NANDACCESS},
+       {"os", YAFFS_TRACE_OS},
+       {"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];
+       int i;
+       int done = 0;
+       int add, len = 0;
+       int pos = 0;
+
+       rg = yaffs_traceMask;
+
+       while (!done && (pos < count)) {
+               done = 1;
+               while ((pos < count) && isspace(buf[pos])) {
+                       pos++;
+               }
+
+               switch (buf[pos]) {
+               case '+':
+               case '-':
+               case '=':
+                       add = buf[pos];
+                       pos++;
+                       break;
+
+               default:
+                       add = ' ';
+                       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 <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+                           substring[i] = *x;
+                       substring[i] = '\0';
+                       
+                       for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+                               if(strcmp(substring,mask_flags[i].mask_name) == 0){
+                                       mask_name = mask_flags[i].mask_name;
+                                       mask_bitfield = mask_flags[i].mask_bitfield;
+                                       done = 0;
+                                       break;
+                               }
+                       }
+               }
+
+               if (mask_name != NULL) {
+                       done = 0;
+                       switch(add) {
+                       case '-':
+                               rg &= ~mask_bitfield;
+                               break;
+                       case '+':
+                               rg |= mask_bitfield;
+                               break;
+                       case '=':
+                               rg = mask_bitfield;
+                               break;
+                       default:
+                               rg |= mask_bitfield;
+                               break;
+                       }
+               }
+       }
+
+       yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
+       
+       printk("new trace = 0x%08X\n",yaffs_traceMask);
+       
+       if (rg & YAFFS_TRACE_ALWAYS) {
+               for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+                       char flag;
+                       flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
+                       printk("%c%s\n", flag, mask_flags[i].mask_name);
+               }
+       }
+
+       return count;
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+       struct file_system_type *fst;
+       int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+//#ifdef CONFIG_YAFFS_YAFFS1
+       {&yaffs_fs_type, 0},
+//#endif
+//#ifdef CONFIG_YAFFS_YAFFS2
+       {&yaffs2_fs_type, 0},
+//#endif
+       {NULL, 0}
+};
+
+static int __init init_yaffs_fs(void)
+{
+       int error = 0;
+       struct file_system_to_install *fsinst;
+
+       T(YAFFS_TRACE_ALWAYS,
+         ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
+
+       /* Install the proc_fs entry */
+       my_proc_entry = create_proc_entry("yaffs",
+                                              S_IRUGO | S_IFREG,
+                                              &proc_root);
+
+       if (my_proc_entry) {
+               my_proc_entry->write_proc = yaffs_proc_write;
+               my_proc_entry->read_proc = yaffs_proc_read;
+               my_proc_entry->data = NULL;
+       } else {
+               return -ENOMEM;
+       }
+
+       /* Now add the file system entries */
+
+       fsinst = fs_to_install;
+
+       while (fsinst->fst && !error) {
+               error = register_filesystem(fsinst->fst);
+               if (!error) {
+                       fsinst->installed = 1;
+               }
+               fsinst++;
+       }
+
+       /* Any errors? uninstall  */
+       if (error) {
+               fsinst = fs_to_install;
+
+               while (fsinst->fst) {
+                       if (fsinst->installed) {
+                               unregister_filesystem(fsinst->fst);
+                               fsinst->installed = 0;
+                       }
+                       fsinst++;
+               }
+       }
+
+       return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+       struct file_system_to_install *fsinst;
+
+       T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
+                              " removing. \n"));
+
+       remove_proc_entry("yaffs", &proc_root);
+
+       fsinst = fs_to_install;
+
+       while (fsinst->fst) {
+               if (fsinst->installed) {
+                       unregister_filesystem(fsinst->fst);
+                       fsinst->installed = 0;
+               }
+               fsinst++;
+       }
+
+}
+
+module_init(init_yaffs_fs)
+module_exit(exit_yaffs_fs)
+
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.c
new file mode 100644 (file)
index 0000000..006820c
--- /dev/null
@@ -0,0 +1,7469 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_guts_c_version =
+    "$Id: yaffs_guts.c,v 1.49 2007-05-15 20:07:40 charles Exp $";
+
+#include "yportenv.h"
+
+#include "yaffsinterface.h"
+#include "yaffs_guts.h"
+#include "yaffs_tagsvalidity.h"
+
+#include "yaffs_tagscompat.h"
+#ifndef  CONFIG_YAFFS_USE_OWN_SORT
+#include "yaffs_qsort.h"
+#endif
+#include "yaffs_nand.h"
+
+#include "yaffs_checkptrw.h"
+
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+
+
+#ifdef CONFIG_YAFFS_WINCE
+void yfsd_LockYAFFS(BOOL fsLockOnly);
+void yfsd_UnlockYAFFS(BOOL fsLockOnly);
+#endif
+
+#define YAFFS_PASSIVE_GC_CHUNKS 2
+
+#include "yaffs_ecc.h"
+
+
+/* Robustification (if it ever comes about...) */
+static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND);
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk);
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+                                    const __u8 * data,
+                                    const yaffs_ExtendedTags * tags);
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+                                   const yaffs_ExtendedTags * tags);
+
+/* Other local prototypes */
+static int yaffs_UnlinkObject( yaffs_Object *obj);
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
+
+static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev,
+                                            const __u8 * buffer,
+                                            yaffs_ExtendedTags * tags,
+                                            int useReserve);
+static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
+                                 int chunkInNAND, int inScan);
+
+static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
+                                          yaffs_ObjectType type);
+static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
+                                      yaffs_Object * obj);
+static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name,
+                                   int force, int isShrink, int shadows);
+static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj);
+static int yaffs_CheckStructures(void);
+static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
+                             int chunkOffset, int *limit);
+static int yaffs_DoGenericObjectDeletion(yaffs_Object * in);
+
+static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo);
+
+static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo);
+static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
+                                   int lineNo);
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+                                 int chunkInNAND);
+
+static int yaffs_UnlinkWorker(yaffs_Object * obj);
+static void yaffs_DestroyObject(yaffs_Object * obj);
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
+                          int chunkInObject);
+
+loff_t yaffs_GetFileSize(yaffs_Object * obj);
+
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr);
+
+static void yaffs_VerifyFreeChunks(yaffs_Device * dev);
+
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
+
+#ifdef YAFFS_PARANOID
+static int yaffs_CheckFileSanity(yaffs_Object * in);
+#else
+#define yaffs_CheckFileSanity(in)
+#endif
+
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in);
+static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId);
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
+
+static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
+                                yaffs_ExtendedTags * tags);
+
+static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos);
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
+                                         yaffs_FileStructure * fStruct,
+                                         __u32 chunkId);
+
+
+/* Function to calculate chunk and offset */
+
+static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset)
+{
+       if(dev->chunkShift){
+               /* Easy-peasy power of 2 case */
+               *chunk  = (__u32)(addr >> dev->chunkShift);
+               *offset = (__u32)(addr & dev->chunkMask);
+       }
+       else if(dev->crumbsPerChunk)
+       {
+               /* Case where we're using "crumbs" */
+               *offset = (__u32)(addr & dev->crumbMask);
+               addr >>= dev->crumbShift;
+               *chunk = ((__u32)addr)/dev->crumbsPerChunk;
+               *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift);
+       }
+       else
+               YBUG();
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or equal 
+ * to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+static __u32 ShiftsGE(__u32 x)
+{
+       int extraBits;
+       int nShifts;
+       
+       nShifts = extraBits = 0;
+       
+       while(x>1){
+               if(x & 1) extraBits++;
+               x>>=1;
+               nShifts++;
+       }
+
+       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;
+       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+               if (dev->tempBuffer[i].line == 0) {
+                       dev->tempBuffer[i].line = lineNo;
+                       if ((i + 1) > dev->maxTemp) {
+                               dev->maxTemp = i + 1;
+                               for (j = 0; j <= i; j++)
+                                       dev->tempBuffer[j].maxLine =
+                                           dev->tempBuffer[j].line;
+                       }
+
+                       return dev->tempBuffer[i].buffer;
+               }
+       }
+
+       T(YAFFS_TRACE_BUFFERS,
+         (TSTR("Out of temp buffers at line %d, other held by lines:"),
+          lineNo));
+       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+               T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
+       }
+       T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
+
+       /*
+        * If we got here then we have to allocate an unmanaged one
+        * This is not good.
+        */
+
+       dev->unmanagedTempAllocations++;
+       return YMALLOC(dev->nDataBytesPerChunk);
+
+}
+
+static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer,
+                                   int lineNo)
+{
+       int i;
+       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+               if (dev->tempBuffer[i].buffer == buffer) {
+                       dev->tempBuffer[i].line = 0;
+                       return;
+               }
+       }
+
+       if (buffer) {
+               /* assume it is an unmanaged one. */
+               T(YAFFS_TRACE_BUFFERS,
+                 (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
+                  lineNo));
+               YFREE(buffer);
+               dev->unmanagedTempDeallocations++;
+       }
+
+}
+
+/*
+ * Determine if we have a managed buffer.
+ */
+int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer)
+{
+       int i;
+       for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+               if (dev->tempBuffer[i].buffer == buffer)
+                       return 1;
+
+       }
+
+    for (i = 0; i < dev->nShortOpCaches; i++) {
+        if( dev->srCache[i].data == buffer )
+            return 1;
+
+    }
+
+    if (buffer == dev->checkpointBuffer)
+      return 1;
+
+    T(YAFFS_TRACE_ALWAYS,
+         (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
+    return 0;
+}
+
+
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk)
+{
+       if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+               T(YAFFS_TRACE_ERROR,
+                 (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
+                  blk));
+               YBUG();
+       }
+       return dev->chunkBits +
+           (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);
+
+       memset(blkBits, 0, dev->chunkBitmapStride);
+}
+
+static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+       yaffs_VerifyChunkBitId(dev,blk,chunk);
+
+       blkBits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk)
+{
+       __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;
+}
+
+static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev, blk);
+       int i;
+       for (i = 0; i < dev->chunkBitmapStride; i++) {
+               if (*blkBits)
+                       return 1;
+               blkBits++;
+       }
+       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<<YAFFS_TNODES_INTERNAL_BITS) + i);
+                               }
+                       }
+               } else if (level == 0) {
+                       int i;
+                       yaffs_ExtendedTags tags;
+                       __u32 objectId = obj->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);
+       return (n % YAFFS_NOBJECT_BUCKETS);
+}
+
+/*
+ * Access functions to useful fake objects
+ */
+yaffs_Object *yaffs_Root(yaffs_Device * dev)
+{
+       return dev->rootDir;
+}
+
+yaffs_Object *yaffs_LostNFound(yaffs_Device * dev)
+{
+       return dev->lostNFoundDir;
+}
+
+
+/*
+ *  Erased NAND checking functions
+ */
+int yaffs_CheckFF(__u8 * buffer, int nBytes)
+{
+       /* Horrible, slow implementation */
+       while (nBytes--) {
+               if (*buffer != 0xFF)
+                       return 0;
+               buffer++;
+       }
+       return 1;
+}
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+                                 int chunkInNAND)
+{
+
+       int retval = YAFFS_OK;
+       __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
+       yaffs_ExtendedTags tags;
+       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,
+                 (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
+               retval = YAFFS_FAIL;
+       }
+
+       yaffs_ReleaseTempBuffer(dev, data, __LINE__);
+
+       return retval;
+
+}
+
+
+static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+                                            const __u8 * data,
+                                            yaffs_ExtendedTags * tags,
+                                            int useReserve)
+{
+       int attempts = 0;
+       int writeOk = 0;
+       int chunk;
+
+       yaffs_InvalidateCheckpoint(dev);
+
+       do {
+               yaffs_BlockInfo *bi = 0;
+               int erasedOk = 0;
+
+               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;
+               }
+
+               /* let's give it a try */
+               attempts++;
+
+#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));
+
+                               /* try another chunk */
+                               continue;
+                       }
+                       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);
+
+       if (attempts > 1) {
+               T(YAFFS_TRACE_ERROR,
+                       (TSTR("**>> yaffs write required %d attempts" TENDSTR),
+                       attempts));
+
+               dev->nRetriedWrites += (attempts - 1);
+       }
+
+       return chunk;
+}
+
+/*
+ * 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;
+       bi->gcPrioritise = 0;
+       bi->needsRetiring = 0;
+
+       dev->nRetiredBlocks++;
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+                                    const __u8 * data,
+                                    const yaffs_ExtendedTags * tags)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+                                   const yaffs_ExtendedTags * tags)
+{
+}
+
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
+{
+       if(!bi->gcPrioritise){
+               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_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk)
+{
+
+       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 ------------*/ 
+
+static __u16 yaffs_CalcNameSum(const YCHAR * name)
+{
+       __u16 sum = 0;
+       __u16 i = 1;
+
+       YUCHAR *bname = (YUCHAR *) name;
+       if (bname) {
+               while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+                       sum += yaffs_toupper(*bname) * i;
+#else
+                       sum += (*bname) * i;
+#endif
+                       i++;
+                       bname++;
+               }
+       }
+       return sum;
+}
+
+static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name)
+{
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+       if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) {
+               yaffs_strcpy(obj->shortName, name);
+       } else {
+               obj->shortName[0] = _Y('\0');
+       }
+#endif
+       obj->sum = yaffs_CalcNameSum(name);
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * 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
+ */
+
+static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes)
+{
+       int i;
+       int tnodeSize;
+       yaffs_Tnode *newTnodes;
+       __u8 *mem;
+       yaffs_Tnode *curr;
+       yaffs_Tnode *next;
+       yaffs_TnodeList *tnl;
+
+       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;
+
+       /* make these things */
+
+       newTnodes = YMALLOC(nTnodes * tnodeSize);
+       mem = (__u8 *)newTnodes;
+
+       if (!newTnodes) {
+               T(YAFFS_TRACE_ERROR,
+                 (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       /* Hook them into the free list */
+#if 0
+       for (i = 0; i < nTnodes - 1; i++) {
+               newTnodes[i].internal[0] = &newTnodes[i + 1];
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+               newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+       }
+
+       newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+       dev->freeTnodes = newTnodes;
+#else
+       /* New hookup for wide tnodes */
+       for(i = 0; i < nTnodes -1; i++) {
+               curr = (yaffs_Tnode *) &mem[i * tnodeSize];
+               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;
+
+#endif
+
+
+       dev->nFreeTnodes += nTnodes;
+       dev->nTnodesCreated += nTnodes;
+
+       /* Now add this bunch of tnodes to a list for freeing up.
+        * NB If we can't add this to the management list it isn't fatal
+        * but it just means we can't free this bunch of tnodes later.
+        */
+        
+       tnl = 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;
+               tnl->next = dev->allocatedTnodeList;
+               dev->allocatedTnodeList = tnl;
+       }
+
+       T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
+
+       return YAFFS_OK;
+}
+
+/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
+
+static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev)
+{
+       yaffs_Tnode *tn = NULL;
+
+       /* If there are none left make more */
+       if (!dev->freeTnodes) {
+               yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
+       }
+
+       if (dev->freeTnodes) {
+               tn = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+               if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
+                       /* Hoosterman, this thing looks like it isn't in the list */
+                       T(YAFFS_TRACE_ALWAYS,
+                         (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
+               }
+#endif
+               dev->freeTnodes = dev->freeTnodes->internal[0];
+               dev->nFreeTnodes--;
+       }
+
+       return tn;
+}
+
+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;      
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn)
+{
+       if (tn) {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+               if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
+                       /* Hoosterman, this thing looks like it is already in the list */
+                       T(YAFFS_TRACE_ALWAYS,
+                         (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
+               }
+               tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+               tn->internal[0] = dev->freeTnodes;
+               dev->freeTnodes = tn;
+               dev->nFreeTnodes++;
+       }
+}
+
+static void yaffs_DeinitialiseTnodes(yaffs_Device * dev)
+{
+       /* Free the list of allocated tnodes */
+       yaffs_TnodeList *tmp;
+
+       while (dev->allocatedTnodeList) {
+               tmp = dev->allocatedTnodeList->next;
+
+               YFREE(dev->allocatedTnodeList->tnodes);
+               YFREE(dev->allocatedTnodeList);
+               dev->allocatedTnodeList = tmp;
+
+       }
+
+       dev->freeTnodes = NULL;
+       dev->nFreeTnodes = 0;
+}
+
+static void yaffs_InitialiseTnodes(yaffs_Device * dev)
+{
+       dev->allocatedTnodeList = NULL;
+       dev->freeTnodes = NULL;
+       dev->nFreeTnodes = 0;
+       dev->nTnodesCreated = 0;
+
+}
+
+
+void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val)
+{
+  __u32 *map = (__u32 *)tn;
+  __u32 bitInMap;
+  __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++;;
+    mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
+    map[wordInMap] &= ~mask;
+    map[wordInMap] |= (mask & (val >> bitInWord));
+  }
+}
+
+static __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;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of topLevel
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,
+                                         yaffs_FileStructure * fStruct,
+                                         __u32 chunkId)
+{
+
+       yaffs_Tnode *tn = fStruct->top;
+       __u32 i;
+       int requiredTallness;
+       int level = fStruct->topLevel;
+
+       /* Check sane level and chunk Id */
+       if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) {
+               return NULL;
+       }
+
+       if (chunkId > YAFFS_MAX_CHUNK_ID) {
+               return NULL;
+       }
+
+       /* First check we're tall enough (ie enough topLevel) */
+
+       i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+       requiredTallness = 0;
+       while (i) {
+               i >>= YAFFS_TNODES_INTERNAL_BITS;
+               requiredTallness++;
+       }
+
+       if (requiredTallness > fStruct->topLevel) {
+               /* Not tall enough, so we can't find it, return NULL. */
+               return NULL;
+       }
+
+       /* Traverse down to level 0 */
+       while (level > 0 && tn) {
+               tn = tn->
+                   internal[(chunkId >>
+                              ( YAFFS_TNODES_LEVEL0_BITS + 
+                                (level - 1) *
+                                YAFFS_TNODES_INTERNAL_BITS)
+                             ) &
+                            YAFFS_TNODES_INTERNAL_MASK];
+               level--;
+
+       }
+
+       return tn;
+}
+
+/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
+ * This happens in two steps:
+ *  1. If the tree isn't tall enough, then make it taller.
+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
+ *  be plugged into the ttree.
+ */
+static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev,
+                                              yaffs_FileStructure * fStruct,
+                                              __u32 chunkId,
+                                              yaffs_Tnode *passedTn)
+{
+
+       int requiredTallness;
+       int i;
+       int l;
+       yaffs_Tnode *tn;
+
+       __u32 x;
+
+
+       /* Check sane level and page Id */
+       if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) {
+               return NULL;
+       }
+
+       if (chunkId > YAFFS_MAX_CHUNK_ID) {
+               return NULL;
+       }
+
+       /* First check we're tall enough (ie enough topLevel) */
+
+       x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+       requiredTallness = 0;
+       while (x) {
+               x >>= YAFFS_TNODES_INTERNAL_BITS;
+               requiredTallness++;
+       }
+
+
+       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) {
+                               tn->internal[0] = fStruct->top;
+                               fStruct->top = tn;
+                       } else {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR("yaffs: no more tnodes" TENDSTR)));
+                       }
+               }
+
+               fStruct->topLevel = requiredTallness;
+       }
+
+       /* Traverse down to level 0, adding anything we need */
+
+       l = fStruct->topLevel;
+       tn = fStruct->top;
+       
+       if(l > 0) {
+               while (l > 0 && tn) {
+                       x = (chunkId >>
+                            ( YAFFS_TNODES_LEVEL0_BITS +
+                             (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+                           YAFFS_TNODES_INTERNAL_MASK;
+
+
+                       if((l>1) && !tn->internal[x]){
+                               /* Add missing non-level-zero tnode */
+                               tn->internal[x] = yaffs_GetTnode(dev);
+
+                       } else if(l == 1) {
+                               /* Looking from level 1 at level 0 */
+                               if (passedTn) {
+                                       /* If we already have one, then release it.*/
+                                       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--;
+               }
+       } else {
+               /* top is level 0 */
+               if(passedTn) {
+                       memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
+                       yaffs_FreeTnode(dev,passedTn);
+               }
+       }
+
+       return tn;
+}
+
+static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk,
+                                 yaffs_ExtendedTags * tags, int objectId,
+                                 int chunkInInode)
+{
+       int j;
+
+       for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
+               if (yaffs_CheckChunkBit
+                   (dev, theChunk / dev->nChunksPerBlock,
+                    theChunk % dev->nChunksPerBlock)) {
+                       yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+                                                       tags);
+                       if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+                               /* found it; */
+                               return theChunk;
+
+                       }
+               }
+               theChunk++;
+       }
+       return -1;
+}
+
+
+/* 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 0 if it stopped early due to hitting the limit and the delete is incomplete.
+ */
+
+static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level,
+                             int chunkOffset, int *limit)
+{
+       int i;
+       int chunkInInode;
+       int theChunk;
+       yaffs_ExtendedTags tags;
+       int foundChunk;
+       yaffs_Device *dev = in->myDev;
+
+       int allDone = 1;
+
+       if (tn) {
+               if (level > 0) {
+
+                       for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+                            i--) {
+                               if (tn->internal[i]) {
+                                       if (limit && (*limit) < 0) {
+                                               allDone = 0;
+                                       } else {
+                                               allDone =
+                                                   yaffs_DeleteWorker(in,
+                                                                      tn->
+                                                                      internal
+                                                                      [i],
+                                                                      level -
+                                                                      1,
+                                                                      (chunkOffset
+                                                                       <<
+                                                                       YAFFS_TNODES_INTERNAL_BITS)
+                                                                      + i,
+                                                                      limit);
+                                       }
+                                       if (allDone) {
+                                               yaffs_FreeTnode(dev,
+                                                               tn->
+                                                               internal[i]);
+                                               tn->internal[i] = NULL;
+                                       }
+                               }
+
+                       }
+                       return (allDone) ? 1 : 0;
+               } else if (level == 0) {
+                       int hitLimit = 0;
+
+                       for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
+                            i--) {
+                               theChunk = yaffs_GetChunkGroupBase(dev,tn,i);
+                               if (theChunk) {
+
+                                       chunkInInode =
+                                           (chunkOffset <<
+                                            YAFFS_TNODES_LEVEL0_BITS) + i;
+
+                                       foundChunk =
+                                           yaffs_FindChunkInGroup(dev,
+                                                                  theChunk,
+                                                                  &tags,
+                                                                  in->objectId,
+                                                                  chunkInInode);
+
+                                       if (foundChunk > 0) {
+                                               yaffs_DeleteChunk(dev,
+                                                                 foundChunk, 1,
+                                                                 __LINE__);
+                                               in->nDataChunks--;
+                                               if (limit) {
+                                                       *limit = *limit - 1;
+                                                       if (*limit <= 0) {
+                                                               hitLimit = 1;
+                                                       }
+                                               }
+
+                                       }
+
+                                       yaffs_PutLevel0Tnode(dev,tn,i,0);
+                               }
+
+                       }
+                       return (i < 0) ? 1 : 0;
+
+               }
+
+       }
+
+       return 1;
+
+}
+
+static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk)
+{
+
+       yaffs_BlockInfo *theBlock;
+
+       T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
+
+       theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
+       if (theBlock) {
+               theBlock->softDeletions++;
+               dev->nFreeChunks++;
+       }
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
+ * of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
+ */
+static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn,
+                                 __u32 level, int chunkOffset)
+{
+       int i;
+       int theChunk;
+       int allDone = 1;
+       yaffs_Device *dev = in->myDev;
+
+       if (tn) {
+               if (level > 0) {
+
+                       for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+                            i--) {
+                               if (tn->internal[i]) {
+                                       allDone =
+                                           yaffs_SoftDeleteWorker(in,
+                                                                  tn->
+                                                                  internal[i],
+                                                                  level - 1,
+                                                                  (chunkOffset
+                                                                   <<
+                                                                   YAFFS_TNODES_INTERNAL_BITS)
+                                                                  + i);
+                                       if (allDone) {
+                                               yaffs_FreeTnode(dev,
+                                                               tn->
+                                                               internal[i]);
+                                               tn->internal[i] = NULL;
+                                       } else {
+                                               /* Hoosterman... how could this happen? */
+                                       }
+                               }
+                       }
+                       return (allDone) ? 1 : 0;
+               } else if (level == 0) {
+
+                       for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+                               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 
+                                        * a block.
+                                        */
+                                       yaffs_SoftDeleteChunk(dev, theChunk);
+                                       yaffs_PutLevel0Tnode(dev,tn,i,0);
+                               }
+
+                       }
+                       return 1;
+
+               }
+
+       }
+
+       return 1;
+
+}
+
+static void yaffs_SoftDeleteFile(yaffs_Object * obj)
+{
+       if (obj->deleted &&
+           obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
+               if (obj->nDataChunks <= 0) {
+                       /* Empty file with no duplicate object headers, just delete it immediately */
+                       yaffs_FreeTnode(obj->myDev,
+                                       obj->variant.fileVariant.top);
+                       obj->variant.fileVariant.top = NULL;
+                       T(YAFFS_TRACE_TRACING,
+                         (TSTR("yaffs: Deleting empty file %d" TENDSTR),
+                          obj->objectId));
+                       yaffs_DoGenericObjectDeletion(obj);
+               } else {
+                       yaffs_SoftDeleteWorker(obj,
+                                              obj->variant.fileVariant.top,
+                                              obj->variant.fileVariant.
+                                              topLevel, 0);
+                       obj->softDeleted = 1;
+               }
+       }
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ */
+
+static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn,
+                                     __u32 level, int del0)
+{
+       int i;
+       int hasData;
+
+       if (tn) {
+               hasData = 0;
+
+               for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+                       if (tn->internal[i] && level > 0) {
+                               tn->internal[i] =
+                                   yaffs_PruneWorker(dev, tn->internal[i],
+                                                     level - 1,
+                                                     (i == 0) ? del0 : 1);
+                       }
+
+                       if (tn->internal[i]) {
+                               hasData++;
+                       }
+               }
+
+               if (hasData == 0 && del0) {
+                       /* Free and return NULL */
+
+                       yaffs_FreeTnode(dev, tn);
+                       tn = NULL;
+               }
+
+       }
+
+       return tn;
+
+}
+
+static int yaffs_PruneFileStructure(yaffs_Device * dev,
+                                   yaffs_FileStructure * fStruct)
+{
+       int i;
+       int hasData;
+       int done = 0;
+       yaffs_Tnode *tn;
+
+       if (fStruct->topLevel > 0) {
+               fStruct->top =
+                   yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
+
+               /* Now we have a tree with all the non-zero branches NULL but the height
+                * is the same as it was.
+                * Let's see if we can trim internal tnodes to shorten the tree.
+                * We can do this if only the 0th element in the tnode is in use 
+                * (ie all the non-zero are NULL)
+                */
+
+               while (fStruct->topLevel && !done) {
+                       tn = fStruct->top;
+
+                       hasData = 0;
+                       for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+                               if (tn->internal[i]) {
+                                       hasData++;
+                               }
+                       }
+
+                       if (!hasData) {
+                               fStruct->top = tn->internal[0];
+                               fStruct->topLevel--;
+                               yaffs_FreeTnode(dev, tn);
+                       } else {
+                               done = 1;
+                       }
+               }
+       }
+
+       return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* yaffs_CreateFreeObjects creates a bunch more objects and
+ * adds them to the object free list.
+ */
+static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects)
+{
+       int i;
+       yaffs_Object *newObjects;
+       yaffs_ObjectList *list;
+
+       if (nObjects < 1)
+               return YAFFS_OK;
+
+       /* 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);
+               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 =
+                   (struct list_head *)(&newObjects[i + 1]);
+       }
+
+       newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
+       dev->freeObjects = newObjects;
+       dev->nFreeObjects += nObjects;
+       dev->nObjectsCreated += nObjects;
+
+       /* Now add this bunch of Objects to a list for freeing up. */
+
+       list->objects = newObjects;
+       list->next = dev->allocatedObjectList;
+       dev->allocatedObjectList = list;
+
+       return YAFFS_OK;
+}
+
+
+/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
+static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev)
+{
+       yaffs_Object *tn = NULL;
+
+       /* If there are none left make more */
+       if (!dev->freeObjects) {
+               yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
+       }
+
+       if (dev->freeObjects) {
+               tn = dev->freeObjects;
+               dev->freeObjects =
+                   (yaffs_Object *) (dev->freeObjects->siblings.next);
+               dev->nFreeObjects--;
+
+               /* Now sweeten it up... */
+
+               memset(tn, 0, sizeof(yaffs_Object));
+               tn->myDev = dev;
+               tn->chunkId = -1;
+               tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
+               INIT_LIST_HEAD(&(tn->hardLinks));
+               INIT_LIST_HEAD(&(tn->hashLink));
+               INIT_LIST_HEAD(&tn->siblings);
+
+               /* Add it to the lost and found directory.
+                * NB Can't put root or lostNFound in lostNFound so
+                * check if lostNFound exists first
+                */
+               if (dev->lostNFoundDir) {
+                       yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
+               }
+       }
+
+       return tn;
+}
+
+static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number,
+                                              __u32 mode)
+{
+
+       yaffs_Object *obj =
+           yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+       if (obj) {
+               obj->fake = 1;          /* it is fake so it has no NAND presence... */
+               obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */
+               obj->unlinkAllowed = 0; /* ... or unlink it */
+               obj->deleted = 0;
+               obj->unlinked = 0;
+               obj->yst_mode = mode;
+               obj->myDev = dev;
+               obj->chunkId = 0;       /* Not a valid chunk. */
+       }
+
+       return obj;
+
+}
+
+static void yaffs_UnhashObject(yaffs_Object * tn)
+{
+       int bucket;
+       yaffs_Device *dev = tn->myDev;
+
+       /* If it is still linked into the bucket list, free from the list */
+       if (!list_empty(&tn->hashLink)) {
+               list_del_init(&tn->hashLink);
+               bucket = yaffs_HashFunction(tn->objectId);
+               dev->objectBucket[bucket].count--;
+       }
+
+}
+
+/*  FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_FreeObject(yaffs_Object * tn)
+{
+
+       yaffs_Device *dev = tn->myDev;
+
+#ifdef  __KERNEL__
+       if (tn->myInode) {
+               /* We're still hooked up to a cached inode.
+                * Don't delete now, but mark for later deletion
+                */
+               tn->deferedFree = 1;
+               return;
+       }
+#endif
+
+       yaffs_UnhashObject(tn);
+
+       /* Link into the free list. */
+       tn->siblings.next = (struct list_head *)(dev->freeObjects);
+       dev->freeObjects = tn;
+       dev->nFreeObjects++;
+}
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object * obj)
+{
+       if (obj->deferedFree) {
+               yaffs_FreeObject(obj);
+       }
+}
+
+#endif
+
+static void yaffs_DeinitialiseObjects(yaffs_Device * dev)
+{
+       /* Free the list of allocated Objects */
+
+       yaffs_ObjectList *tmp;
+
+       while (dev->allocatedObjectList) {
+               tmp = dev->allocatedObjectList->next;
+               YFREE(dev->allocatedObjectList->objects);
+               YFREE(dev->allocatedObjectList);
+
+               dev->allocatedObjectList = tmp;
+       }
+
+       dev->freeObjects = NULL;
+       dev->nFreeObjects = 0;
+}
+
+static void yaffs_InitialiseObjects(yaffs_Device * dev)
+{
+       int i;
+
+       dev->allocatedObjectList = NULL;
+       dev->freeObjects = NULL;
+       dev->nFreeObjects = 0;
+
+       for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+               INIT_LIST_HEAD(&dev->objectBucket[i].list);
+               dev->objectBucket[i].count = 0;
+       }
+
+}
+
+static int yaffs_FindNiceObjectBucket(yaffs_Device * dev)
+{
+       static int x = 0;
+       int i;
+       int l = 999;
+       int lowest = 999999;
+
+       /* First let's see if we can find one that's empty. */
+
+       for (i = 0; i < 10 && lowest > 0; i++) {
+               x++;
+               x %= YAFFS_NOBJECT_BUCKETS;
+               if (dev->objectBucket[x].count < lowest) {
+                       lowest = dev->objectBucket[x].count;
+                       l = x;
+               }
+
+       }
+
+       /* If we didn't find an empty list, then try
+        * looking a bit further for a short one
+        */
+
+       for (i = 0; i < 10 && lowest > 3; i++) {
+               x++;
+               x %= YAFFS_NOBJECT_BUCKETS;
+               if (dev->objectBucket[x].count < lowest) {
+                       lowest = dev->objectBucket[x].count;
+                       l = x;
+               }
+
+       }
+
+       return l;
+}
+
+static int yaffs_CreateNewObjectNumber(yaffs_Device * dev)
+{
+       int bucket = yaffs_FindNiceObjectBucket(dev);
+
+       /* Now find an object value that has not already been taken
+        * by scanning the list.
+        */
+
+       int found = 0;
+       struct list_head *i;
+
+       __u32 n = (__u32) bucket;
+
+       /* yaffs_CheckObjectHashSanity();  */
+
+       while (!found) {
+               found = 1;
+               n += YAFFS_NOBJECT_BUCKETS;
+               if (1 || dev->objectBucket[bucket].count > 0) {
+                       list_for_each(i, &dev->objectBucket[bucket].list) {
+                               /* If there is already one in the list */
+                               if (i
+                                   && list_entry(i, yaffs_Object,
+                                                 hashLink)->objectId == n) {
+                                       found = 0;
+                               }
+                       }
+               }
+       }
+
+
+       return n;
+}
+
+static void yaffs_HashObject(yaffs_Object * in)
+{
+       int bucket = yaffs_HashFunction(in->objectId);
+       yaffs_Device *dev = in->myDev;
+
+       list_add(&in->hashLink, &dev->objectBucket[bucket].list);
+       dev->objectBucket[bucket].count++;
+
+}
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number)
+{
+       int bucket = yaffs_HashFunction(number);
+       struct list_head *i;
+       yaffs_Object *in;
+
+       list_for_each(i, &dev->objectBucket[bucket].list) {
+               /* Look if it is in the list */
+               if (i) {
+                       in = list_entry(i, yaffs_Object, hashLink);
+                       if (in->objectId == number) {
+#ifdef __KERNEL__
+                               /* Don't tell the VFS about this one if it is defered free */
+                               if (in->deferedFree)
+                                       return NULL;
+#endif
+
+                               return in;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,
+                                   yaffs_ObjectType type)
+{
+
+       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;
+               theObject->renameAllowed = 1;
+               theObject->unlinkAllowed = 1;
+               theObject->objectId = number;
+               yaffs_HashObject(theObject);
+               theObject->variantType = type;
+#ifdef CONFIG_YAFFS_WINCE
+               yfsd_WinFileTimeNow(theObject->win_atime);
+               theObject->win_ctime[0] = theObject->win_mtime[0] =
+                   theObject->win_atime[0];
+               theObject->win_ctime[1] = theObject->win_mtime[1] =
+                   theObject->win_atime[1];
+
+#else
+
+               theObject->yst_atime = theObject->yst_mtime =
+                   theObject->yst_ctime = Y_CURRENT_TIME;
+#endif
+               switch (type) {
+               case YAFFS_OBJECT_TYPE_FILE:
+                       theObject->variant.fileVariant.fileSize = 0;
+                       theObject->variant.fileVariant.scannedFileSize = 0;
+                       theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */
+                       theObject->variant.fileVariant.topLevel = 0;
+                       theObject->variant.fileVariant.top = tn;
+                       break;
+               case YAFFS_OBJECT_TYPE_DIRECTORY:
+                       INIT_LIST_HEAD(&theObject->variant.directoryVariant.
+                                      children);
+                       break;
+               case YAFFS_OBJECT_TYPE_SYMLINK:
+               case YAFFS_OBJECT_TYPE_HARDLINK:
+               case YAFFS_OBJECT_TYPE_SPECIAL:
+                       /* No action required */
+                       break;
+               case YAFFS_OBJECT_TYPE_UNKNOWN:
+                       /* todo this should not happen */
+                       break;
+               }
+       }
+
+       return theObject;
+}
+
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev,
+                                                     int number,
+                                                     yaffs_ObjectType type)
+{
+       yaffs_Object *theObject = NULL;
+
+       if (number > 0) {
+               theObject = yaffs_FindObjectByNumber(dev, number);
+       }
+
+       if (!theObject) {
+               theObject = yaffs_CreateNewObject(dev, number, type);
+       }
+
+       return theObject;
+
+}
+                       
+
+static YCHAR *yaffs_CloneString(const YCHAR * str)
+{
+       YCHAR *newStr = NULL;
+
+       if (str && *str) {
+               newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
+               if(newStr)
+                       yaffs_strcpy(newStr, str);
+       }
+
+       return newStr;
+
+}
+
+/*
+ * Mknod (create) a new object.
+ * equivalentObject only has meaning for a hard link;
+ * 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,
+                                      __u32 mode,
+                                      __u32 uid,
+                                      __u32 gid,
+                                      yaffs_Object * equivalentObject,
+                                      const YCHAR * aliasString, __u32 rdev)
+{
+       yaffs_Object *in;
+       YCHAR *str;
+
+       yaffs_Device *dev = parent->myDev;
+
+       /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
+       if (yaffs_FindObjectByName(parent, name)) {
+               return NULL;
+       }
+
+       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;
+               in->variantType = type;
+
+               in->yst_mode = mode;
+
+#ifdef CONFIG_YAFFS_WINCE
+               yfsd_WinFileTimeNow(in->win_atime);
+               in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
+               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
+
+#else
+               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
+
+               in->yst_rdev = rdev;
+               in->yst_uid = uid;
+               in->yst_gid = gid;
+#endif
+               in->nDataChunks = 0;
+
+               yaffs_SetObjectName(in, name);
+               in->dirty = 1;
+
+               yaffs_AddObjectToDirectory(parent, in);
+
+               in->myDev = parent->myDev;
+
+               switch (type) {
+               case YAFFS_OBJECT_TYPE_SYMLINK:
+                       in->variant.symLinkVariant.alias = str;
+                       break;
+               case YAFFS_OBJECT_TYPE_HARDLINK:
+                       in->variant.hardLinkVariant.equivalentObject =
+                           equivalentObject;
+                       in->variant.hardLinkVariant.equivalentObjectId =
+                           equivalentObject->objectId;
+                       list_add(&in->hardLinks, &equivalentObject->hardLinks);
+                       break;
+               case YAFFS_OBJECT_TYPE_FILE:    
+               case YAFFS_OBJECT_TYPE_DIRECTORY:
+               case YAFFS_OBJECT_TYPE_SPECIAL:
+               case YAFFS_OBJECT_TYPE_UNKNOWN:
+                       /* do nothing */
+                       break;
+               }
+
+               if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
+                       /* Could not create the object header, fail the creation */
+                       yaffs_DestroyObject(in);
+                       in = NULL;
+               }
+
+       }
+
+       return in;
+}
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
+                             __u32 mode, __u32 uid, __u32 gid)
+{
+       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+                                uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
+                                  __u32 mode, __u32 uid, __u32 gid)
+{
+       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+                                mode, uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
+                                __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
+{
+       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+                                uid, gid, NULL, NULL, rdev);
+}
+
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
+                                __u32 mode, __u32 uid, __u32 gid,
+                                const YCHAR * alias)
+{
+       return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+                                uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_Link returns the object id of the equivalent object.*/
+yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
+                        yaffs_Object * equivalentObject)
+{
+       /* Get the real object in case we were fed a hard link as an equivalent object */
+       equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
+
+       if (yaffs_MknodObject
+           (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
+            equivalentObject, NULL, 0)) {
+               return equivalentObject;
+       } else {
+               return NULL;
+       }
+
+}
+
+static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir,
+                                 const YCHAR * newName, int force, int shadows)
+{
+       int unlinkOp;
+       int deleteOp;
+
+       yaffs_Object *existingTarget;
+
+       if (newDir == NULL) {
+               newDir = obj->parent;   /* use the old directory */
+       }
+
+       if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragendy: yaffs_ChangeObjectName: newDir is not a directory"
+                   TENDSTR)));
+               YBUG();
+       }
+       
+       /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
+       if (obj->myDev->isYaffs2) {
+               unlinkOp = (newDir == obj->myDev->unlinkedDir);
+       } else {
+               unlinkOp = (newDir == obj->myDev->unlinkedDir
+                           && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
+       }
+
+       deleteOp = (newDir == obj->myDev->deletedDir);
+
+       existingTarget = yaffs_FindObjectByName(newDir, newName);
+
+       /* 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 
+        *   it into a directory.
+        */
+       if ((unlinkOp ||
+            deleteOp ||
+            force ||
+            (shadows > 0) ||
+            !existingTarget) &&
+           newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
+               yaffs_SetObjectName(obj, newName);
+               obj->dirty = 1;
+
+               yaffs_AddObjectToDirectory(newDir, obj);
+
+               if (unlinkOp)
+                       obj->unlinked = 1;
+
+               /* If it is a deletion then we mark it as a shrink for gc purposes. */
+               if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0)
+                       return YAFFS_OK;
+       }
+
+       return YAFFS_FAIL;
+}
+
+int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
+                      yaffs_Object * newDir, const YCHAR * newName)
+{
+       yaffs_Object *obj;
+       yaffs_Object *existingTarget;
+       int force = 0;
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+       /* Special case for case insemsitive systems (eg. WinCE).
+        * While look-up is case insensitive, the name isn't.
+        * Therefore we might want to change x.txt to X.txt
+       */
+       if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) {
+               force = 1;
+       }
+#endif
+
+       obj = yaffs_FindObjectByName(oldDir, oldName);
+       /* Check new name to long. */
+       if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK &&
+           yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH)
+         /* ENAMETOOLONG */
+         return YAFFS_FAIL;
+       else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK &&
+                yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+         /* ENAMETOOLONG */
+         return YAFFS_FAIL;
+
+       if (obj && obj->renameAllowed) {
+
+               /* Now do the handling for an existing target, if there is one */
+
+               existingTarget = yaffs_FindObjectByName(newDir, newName);
+               if (existingTarget &&
+                   existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+                   !list_empty(&existingTarget->variant.directoryVariant.children)) {
+                       /* 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, 
+                        * but only if it isn't the same object
+                        */
+                       yaffs_ChangeObjectName(obj, newDir, newName, force,
+                                              existingTarget->objectId);
+                       yaffs_UnlinkObject(existingTarget);
+               }
+
+               return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+       }
+       return YAFFS_FAIL;
+}
+
+/*------------------------- Block Management and Page Allocation ----------------*/
+
+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 */
+       dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
+       if(!dev->blockInfo){
+               dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
+               dev->blockInfoAlt = 1;
+       }
+       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;
+       }
+       
+       if (dev->blockInfo && dev->chunkBits) {
+               memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
+               memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
+               return YAFFS_OK;
+       }
+
+       return YAFFS_FAIL;
+
+}
+
+static void yaffs_DeinitialiseBlocks(yaffs_Device * dev)
+{
+       if(dev->blockInfoAlt && dev->blockInfo)
+               YFREE_ALT(dev->blockInfo);
+       else if(dev->blockInfo)
+               YFREE(dev->blockInfo);
+
+       dev->blockInfoAlt = 0;
+
+       dev->blockInfo = NULL;
+       
+       if(dev->chunkBitsAlt && dev->chunkBits)
+               YFREE_ALT(dev->chunkBits);
+       else if(dev->chunkBits)
+               YFREE(dev->chunkBits);
+       dev->chunkBitsAlt = 0;
+       dev->chunkBits = NULL;
+}
+
+static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev,
+                                           yaffs_BlockInfo * bi)
+{
+       int i;
+       __u32 seq;
+       yaffs_BlockInfo *b;
+
+       if (!dev->isYaffs2)
+               return 1;       /* disqualification only applies to yaffs2. */
+
+       if (!bi->hasShrinkHeader)
+               return 1;       /* can gc */
+
+       /* Find the oldest dirty sequence number if we don't know it and save it
+        * so we don't have to keep recomputing it.
+        */
+       if (!dev->oldestDirtySequence) {
+               seq = dev->sequenceNumber;
+
+               for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
+                    i++) {
+                       b = yaffs_GetBlockInfo(dev, i);
+                       if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
+                           (b->pagesInUse - b->softDeletions) <
+                           dev->nChunksPerBlock && b->sequenceNumber < seq) {
+                               seq = b->sequenceNumber;
+                       }
+               }
+               dev->oldestDirtySequence = seq;
+       }
+
+       /* Can't do gc of this block if there are any blocks older than this one that have
+        * discarded pages.
+        */
+       return (bi->sequenceNumber <= dev->oldestDirtySequence);
+
+}
+
+/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev,
+                                              int aggressive)
+{
+
+       int b = dev->currentDirtyChecker;
+
+       int i;
+       int iterations;
+       int dirtiest = -1;
+       int pagesInUse = 0;
+       int prioritised=0;
+       yaffs_BlockInfo *bi;
+       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 &&
+                                  yaffs_BlockNotDisqualifiedFromGC(dev, bi)){
+                                       pagesInUse = (bi->pagesInUse - bi->softDeletions);
+                                       dirtiest = i;
+                                       prioritised = 1;
+                                       aggressive = 1; /* Fool the non-aggressive skip logiv below */
+                               }
+                       }
+               }
+               
+               if(!pendingPrioritisedExist) /* None found, so we can clear this */
+                       dev->hasPendingPrioritisedGCs = 0;
+       }
+
+       /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
+        * search harder.
+        * else (we're doing a leasurely gc), then we only bother to do this if the
+        * block has only a few pages in use.
+        */
+
+       dev->nonAggressiveSkip--;
+
+       if (!aggressive && (dev->nonAggressiveSkip > 0)) {
+               return -1;
+       }
+
+       if(!prioritised)
+               pagesInUse =
+                       (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
+       if (aggressive) {
+               iterations =
+                   dev->internalEndBlock - dev->internalStartBlock + 1;
+       } else {
+               iterations =
+                   dev->internalEndBlock - dev->internalStartBlock + 1;
+               iterations = iterations / 16;
+               if (iterations > 200) {
+                       iterations = 200;
+               }
+       }
+
+       for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
+               b++;
+               if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+                       b = dev->internalStartBlock;
+               }
+
+               if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+                       T(YAFFS_TRACE_ERROR,
+                         (TSTR("**>> Block %d is not valid" TENDSTR), b));
+                       YBUG();
+               }
+
+               bi = yaffs_GetBlockInfo(dev, b);
+
+#if 0
+               if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
+                       dirtiest = b;
+                       pagesInUse = 0;
+               }
+               else 
+#endif
+
+               if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
+                      (bi->pagesInUse - bi->softDeletions) < pagesInUse &&
+                       yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+                       dirtiest = b;
+                       pagesInUse = (bi->pagesInUse - bi->softDeletions);
+               }
+       }
+
+       dev->currentDirtyChecker = b;
+
+       if (dirtiest > 0) {
+               T(YAFFS_TRACE_GC,
+                 (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
+                  dev->nChunksPerBlock - pagesInUse,prioritised));
+       }
+
+       dev->oldestDirtySequence = 0;
+
+       if (dirtiest > 0) {
+               dev->nonAggressiveSkip = 4;
+       }
+
+       return dirtiest;
+}
+
+static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo)
+{
+       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
+
+       int erasedOk = 0;
+
+       /* 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) {
+               yaffs_InvalidateCheckpoint(dev);
+               erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
+               if (!erasedOk) {
+                       dev->nErasureFailures++;
+                       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+                         (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
+               }
+       }
+
+       if (erasedOk && 
+           ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
+               int i;
+               for (i = 0; i < dev->nChunksPerBlock; i++) {
+                       if (!yaffs_CheckChunkErased
+                           (dev, blockNo * dev->nChunksPerBlock + i)) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  (">>Block %d erasure supposedly OK, but chunk %d not erased"
+                                   TENDSTR), blockNo, i));
+                       }
+               }
+       }
+
+       if (erasedOk) {
+               /* Clean it up... */
+               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+               dev->nErasedBlocks++;
+               bi->pagesInUse = 0;
+               bi->softDeletions = 0;
+               bi->hasShrinkHeader = 0;
+               bi->skipErasedCheck = 1;  /* This is clean, so no need to check */
+               bi->gcPrioritise = 0;
+               yaffs_ClearChunkBits(dev, blockNo);
+
+               T(YAFFS_TRACE_ERASE,
+                 (TSTR("Erased block %d" TENDSTR), blockNo));
+       } else {
+               dev->nFreeChunks -= dev->nChunksPerBlock;       /* We lost a block of free space */
+
+               yaffs_RetireBlock(dev, blockNo);
+               T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+                 (TSTR("**>> Block %d retired" TENDSTR), blockNo));
+       }
+}
+
+static int yaffs_FindBlockForAllocation(yaffs_Device * dev)
+{
+       int i;
+
+       yaffs_BlockInfo *bi;
+
+       if (dev->nErasedBlocks < 1) {
+               /* Hoosterman we've got a problem.
+                * Can't get space to gc
+                */
+               T(YAFFS_TRACE_ERROR,
+                 (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
+
+               return -1;
+       }
+       
+       /* Find an empty block. */
+
+       for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+               dev->allocationBlockFinder++;
+               if (dev->allocationBlockFinder < dev->internalStartBlock
+                   || dev->allocationBlockFinder > dev->internalEndBlock) {
+                       dev->allocationBlockFinder = dev->internalStartBlock;
+               }
+
+               bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
+
+               if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
+                       bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
+                       dev->sequenceNumber++;
+                       bi->sequenceNumber = dev->sequenceNumber;
+                       dev->nErasedBlocks--;
+                       T(YAFFS_TRACE_ALLOCATE,
+                         (TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),
+                          dev->allocationBlockFinder, dev->sequenceNumber,
+                          dev->nErasedBlocks));
+                       return dev->allocationBlockFinder;
+               }
+       }
+
+       T(YAFFS_TRACE_ALWAYS,
+         (TSTR
+          ("yaffs tragedy: no more eraased blocks, but there should have been %d"
+           TENDSTR), dev->nErasedBlocks));
+
+       return -1;
+}
+
+
+// Check if there's space to allocate...
+// Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
+static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev)
+{
+       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);
+}
+
+static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr)
+{
+       int retVal;
+       yaffs_BlockInfo *bi;
+
+       if (dev->allocationBlock < 0) {
+               /* Get next block to allocate off */
+               dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
+               dev->allocationPage = 0;
+       }
+
+       if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
+               /* Not enough space to allocate unless we're allowed to use the reserve. */
+               return -1;
+       }
+
+       if (dev->nErasedBlocks < dev->nReservedBlocks
+           && dev->allocationPage == 0) {
+               T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
+       }
+
+       /* Next page please.... */
+       if (dev->allocationBlock >= 0) {
+               bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
+
+               retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
+                   dev->allocationPage;
+               bi->pagesInUse++;
+               yaffs_SetChunkBit(dev, dev->allocationBlock,
+                                 dev->allocationPage);
+
+               dev->allocationPage++;
+
+               dev->nFreeChunks--;
+
+               /* If the block is full set the state to full */
+               if (dev->allocationPage >= dev->nChunksPerBlock) {
+                       bi->blockState = YAFFS_BLOCK_STATE_FULL;
+                       dev->allocationBlock = -1;
+               }
+
+               if(blockUsedPtr)
+                       *blockUsedPtr = bi;
+                       
+               return retVal;
+       }
+       
+       T(YAFFS_TRACE_ERROR,
+         (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
+
+       return -1;
+}
+
+static int yaffs_GetErasedChunks(yaffs_Device * dev)
+{
+       int n;
+
+       n = dev->nErasedBlocks * dev->nChunksPerBlock;
+
+       if (dev->allocationBlock > 0) {
+               n += (dev->nChunksPerBlock - dev->allocationPage);
+       }
+
+       return n;
+
+}
+
+static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block)
+{
+       int oldChunk;
+       int newChunk;
+       int chunkInBlock;
+       int markNAND;
+       int retVal = YAFFS_OK;
+       int cleanups = 0;
+       int i;
+       int isCheckpointBlock;
+       int matchingChunk;
+
+       int chunksBefore = yaffs_GetErasedChunks(dev);
+       int chunksAfter;
+
+       yaffs_ExtendedTags tags;
+
+       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
+
+       yaffs_Object *object;
+
+       isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
+       
+       bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
+       T(YAFFS_TRACE_TRACING,
+         (TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR), block,
+          bi->pagesInUse, bi->hasShrinkHeader));
+
+       /*yaffs_VerifyFreeChunks(dev); */
+
+       bi->hasShrinkHeader = 0;        /* clear the flag so that the block can erase */
+
+       /* Take off the number of soft deleted entries because
+        * they're going to get really deleted during GC.
+        */
+       dev->nFreeChunks -= bi->softDeletions;
+
+       dev->isDoingGC = 1;
+
+       if (isCheckpointBlock ||
+           !yaffs_StillSomeChunkBits(dev, block)) {
+               T(YAFFS_TRACE_TRACING,
+                 (TSTR
+                  ("Collecting block %d that has no chunks in use" TENDSTR),
+                  block));
+               yaffs_BlockBecameDirty(dev, block);
+       } else {
+
+               __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);
+                    chunkInBlock++, oldChunk++) {
+                       if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) {
+
+                               /* This page is in use and might need to be copied off */
+
+                               markNAND = 1;
+
+                               yaffs_InitialiseTags(&tags);
+
+                               yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
+                                                               buffer, &tags);
+
+                               object =
+                                   yaffs_FindObjectByNumber(dev,
+                                                            tags.objectId);
+
+                               T(YAFFS_TRACE_GC_DETAIL,
+                                 (TSTR
+                                  ("Collecting page %d, %d %d %d " TENDSTR),
+                                  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));
+                               }
+
+                               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 
+                                        * fix up the object.
+                                        */
+
+                                       object->nDataChunks--;
+
+                                       if (object->nDataChunks <= 0) {
+                                               /* remeber to clean up the object */
+                                               dev->gcCleanupList[cleanups] =
+                                                   tags.objectId;
+                                               cleanups++;
+                                       }
+                                       markNAND = 0;
+                               } else if (0
+                                          /* Todo object && object->deleted && object->nDataChunks == 0 */
+                                          ) {
+                                       /* Deleted object header with no data chunks.
+                                        * Can be discarded and the file deleted.
+                                        */
+                                       object->chunkId = 0;
+                                       yaffs_FreeTnode(object->myDev,
+                                                       object->variant.
+                                                       fileVariant.top);
+                                       object->variant.fileVariant.top = NULL;
+                                       yaffs_DoGenericObjectDeletion(object);
+
+                               } else if (object) {
+                                       /* It's either a data chunk in a live file or
+                                        * an ObjectHeader, so we're interested in it.
+                                        * NB Need to keep the ObjectHeaders of deleted files
+                                        * until the whole file has been deleted off
+                                        */
+                                       tags.serialNumber++;
+
+                                       dev->nGCCopies++;
+
+                                       if (tags.chunkId == 0) {
+                                               /* It is an object Id,
+                                                * We need to nuke the shrinkheader flags first
+                                                * We no longer want the shrinkHeader flag since its work is done
+                                                * and if it is left in place it will mess up scanning.
+                                                * Also, clear out any shadowing stuff
+                                                */
+
+                                               yaffs_ObjectHeader *oh;
+                                               oh = (yaffs_ObjectHeader *)buffer;
+                                               oh->isShrink = 0;
+                                               oh->shadowsObject = -1;
+                                               tags.extraShadows = 0;
+                                               tags.extraIsShrinkHeader = 0;
+                                               
+                                               yaffs_VerifyObjectHeader(object,oh,&tags,1);
+                                       }
+
+                                       newChunk =
+                                           yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
+
+                                       if (newChunk < 0) {
+                                               retVal = YAFFS_FAIL;
+                                       } else {
+
+                                               /* Ok, now fix up the Tnodes etc. */
+
+                                               if (tags.chunkId == 0) {
+                                                       /* It's a header */
+                                                       object->chunkId =  newChunk;
+                                                       object->serial =   tags.serialNumber;
+                                               } else {
+                                                       /* It's a data chunk */
+                                                       yaffs_PutChunkIntoFile
+                                                           (object,
+                                                            tags.chunkId,
+                                                            newChunk, 0);
+                                               }
+                                       }
+                               }
+
+                               yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
+
+                       }
+               }
+
+               yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+
+               /* Do any required cleanups */
+               for (i = 0; i < cleanups; i++) {
+                       /* Time to delete the file too */
+                       object =
+                           yaffs_FindObjectByNumber(dev,
+                                                    dev->gcCleanupList[i]);
+                       if (object) {
+                               yaffs_FreeTnode(dev,
+                                               object->variant.fileVariant.
+                                               top);
+                               object->variant.fileVariant.top = NULL;
+                               T(YAFFS_TRACE_GC,
+                                 (TSTR
+                                  ("yaffs: About to finally delete object %d"
+                                   TENDSTR), object->objectId));
+                               yaffs_DoGenericObjectDeletion(object);
+                               object->myDev->nDeletedFiles--;
+                       }
+
+               }
+
+       }
+
+       yaffs_VerifyCollectedBlock(dev,bi,block);
+         
+       if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) {
+               T(YAFFS_TRACE_GC,
+                 (TSTR
+                  ("gc did not increase free chunks before %d after %d"
+                   TENDSTR), chunksBefore, chunksAfter));
+       }
+
+       dev->isDoingGC = 0;
+
+       return YAFFS_OK;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_CheckGarbageCollection(yaffs_Device * dev)
+{
+       int block;
+       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)) {
+                       /* We need a block soon...*/
+                       aggressive = 1;
+               } else {
+                       /* We're in no hurry */
+                       aggressive = 0;
+               }
+
+               block = yaffs_FindBlockForGarbageCollection(dev, aggressive);
+
+               if (block > 0) {
+                       dev->garbageCollections++;
+                       if (!aggressive) {
+                               dev->passiveGarbageCollections++;
+                       }
+
+                       T(YAFFS_TRACE_GC,
+                         (TSTR
+                          ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
+                          dev->nErasedBlocks, aggressive));
+
+                       gcOk = yaffs_GarbageCollectBlock(dev, block);
+               }
+
+               if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
+                       T(YAFFS_TRACE_GC,
+                         (TSTR
+                          ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
+                           TENDSTR), dev->nErasedBlocks, maxTries, block));
+               }
+       } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0)
+                && (maxTries < 2));
+
+       return aggressive ? gcOk : YAFFS_OK;
+}
+
+/*-------------------------  TAGS --------------------------------*/
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
+                          int chunkInObject)
+{
+       return (tags->chunkId == chunkInObject &&
+               tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
+
+}
+
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
+                                yaffs_ExtendedTags * tags)
+{
+       /*Get the Tnode, then get the level 0 offset chunk offset */
+       yaffs_Tnode *tn;
+       int theChunk = -1;
+       yaffs_ExtendedTags localTags;
+       int retVal = -1;
+
+       yaffs_Device *dev = in->myDev;
+
+       if (!tags) {
+               /* Passed a NULL, so use our own tags space */
+               tags = &localTags;
+       }
+
+       tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+       if (tn) {
+               theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+               retVal =
+                   yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+                                          chunkInInode);
+       }
+       return retVal;
+}
+
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode,
+                                         yaffs_ExtendedTags * tags)
+{
+       /* Get the Tnode, then get the level 0 offset chunk offset */
+       yaffs_Tnode *tn;
+       int theChunk = -1;
+       yaffs_ExtendedTags localTags;
+
+       yaffs_Device *dev = in->myDev;
+       int retVal = -1;
+
+       if (!tags) {
+               /* Passed a NULL, so use our own tags space */
+               tags = &localTags;
+       }
+
+       tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+       if (tn) {
+
+               theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+               retVal =
+                   yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+                                          chunkInInode);
+
+               /* Delete the entry in the filestructure (if found) */
+               if (retVal != -1) {
+                       yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0);
+               }
+       } else {
+               /*T(("No level 0 found for %d\n", chunkInInode)); */
+       }
+
+       if (retVal == -1) {
+               /* T(("Could not find %d to delete\n",chunkInInode)); */
+       }
+       return retVal;
+}
+
+#ifdef YAFFS_PARANOID
+
+static int yaffs_CheckFileSanity(yaffs_Object * in)
+{
+       int chunk;
+       int nChunks;
+       int fSize;
+       int failed = 0;
+       int objId;
+       yaffs_Tnode *tn;
+       yaffs_Tags localTags;
+       yaffs_Tags *tags = &localTags;
+       int theChunk;
+       int chunkDeleted;
+
+       if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+               /* T(("Object not a file\n")); */
+               return YAFFS_FAIL;
+       }
+
+       objId = in->objectId;
+       fSize = in->variant.fileVariant.fileSize;
+       nChunks =
+           (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
+
+       for (chunk = 1; chunk <= nChunks; chunk++) {
+               tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
+                                          chunk);
+
+               if (tn) {
+
+                       theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk);
+
+                       if (yaffs_CheckChunkBits
+                           (dev, theChunk / dev->nChunksPerBlock,
+                            theChunk % dev->nChunksPerBlock)) {
+
+                               yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
+                                                           tags,
+                                                           &chunkDeleted);
+                               if (yaffs_TagsMatch
+                                   (tags, in->objectId, chunk, chunkDeleted)) {
+                                       /* found it; */
+
+                               }
+                       } else {
+
+                               failed = 1;
+                       }
+
+               } else {
+                       /* T(("No level 0 found for %d\n", chunk)); */
+               }
+       }
+
+       return failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+#endif
+
+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; 
+        * for backward scanning inScan is < 0
+        */
+        
+       yaffs_Tnode *tn;
+       yaffs_Device *dev = in->myDev;
+       int existingChunk;
+       yaffs_ExtendedTags existingTags;
+       yaffs_ExtendedTags newTags;
+       unsigned existingSerial, newSerial;
+
+       if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+               /* Just ignore an attempt at putting a chunk into a non-file during scanning
+                * If it is not during Scanning then something went wrong!
+                */
+               if (!inScan) {
+                       T(YAFFS_TRACE_ERROR,
+                         (TSTR
+                          ("yaffs tragedy:attempt to put data chunk into a non-file"
+                           TENDSTR)));
+                       YBUG();
+               }
+
+               yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+               return YAFFS_OK;
+       }
+
+       tn = yaffs_AddOrFindLevel0Tnode(dev, 
+                                       &in->variant.fileVariant,
+                                       chunkInInode,
+                                       NULL);
+       if (!tn) {
+               return YAFFS_FAIL;
+       }
+
+       existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
+
+       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 
+                * happen when the power fails during a write, then only one
+                * chunk should ever be affected.
+                *
+                * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
+                * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
+                */
+
+               if (existingChunk != 0) {
+                       /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
+                        *    thus we have to do a FindChunkInFile to get the real chunk id.
+                        *
+                        * We have a duplicate now we need to decide which one to use:
+                        *
+                        * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
+                        * Forward scanning YAFFS2: The new one is what we use, dump the old one.
+                        * YAFFS1: Get both sets of tags and compare serial numbers.
+                        */
+
+                       if (inScan > 0) {
+                               /* Only do this for forward scanning */
+                               yaffs_ReadChunkWithTagsFromNAND(dev,
+                                                               chunkInNAND,
+                                                               NULL, &newTags);
+
+                               /* Do a proper find */
+                               existingChunk =
+                                   yaffs_FindChunkInFile(in, chunkInInode,
+                                                         &existingTags);
+                       }
+
+                       if (existingChunk <= 0) {
+                               /*Hoosterman - how did this happen? */
+
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("yaffs tragedy: existing chunk < 0 in scan"
+                                   TENDSTR)));
+
+                       }
+
+                       /* NB The deleted flags should be false, otherwise the chunks will 
+                        * not be loaded during a scan
+                        */
+
+                       newSerial = newTags.serialNumber;
+                       existingSerial = existingTags.serialNumber;
+
+                       if ((inScan > 0) &&
+                           (in->myDev->isYaffs2 ||
+                            existingChunk <= 0 ||
+                            ((existingSerial + 1) & 3) == newSerial)) {
+                               /* Forward scanning.                            
+                                * Use new
+                                * Delete the old one and drop through to update the tnode
+                                */
+                               yaffs_DeleteChunk(dev, existingChunk, 1,
+                                                 __LINE__);
+                       } else {
+                               /* Backward scanning or we want to use the existing one
+                                * Use existing.
+                                * Delete the new one and return early so that the tnode isn't changed
+                                */
+                               yaffs_DeleteChunk(dev, chunkInNAND, 1,
+                                                 __LINE__);
+                               return YAFFS_OK;
+                       }
+               }
+
+       }
+
+       if (existingChunk == 0) {
+               in->nDataChunks++;
+       }
+
+       yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);
+
+       return YAFFS_OK;
+}
+
+static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,
+                                        __u8 * buffer)
+{
+       int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
+
+       if (chunkInNAND >= 0) {
+               return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
+                                                      buffer,NULL);
+       } else {
+               T(YAFFS_TRACE_NANDACCESS,
+                 (TSTR("Chunk %d not found zero instead" TENDSTR),
+                  chunkInNAND));
+               /* get sane (zero) data if you read a hole */
+               memset(buffer, 0, in->myDev->nDataBytesPerChunk);       
+               return 0;
+       }
+
+}
+
+void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)
+{
+       int block;
+       int page;
+       yaffs_ExtendedTags tags;
+       yaffs_BlockInfo *bi;
+
+       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,
+         (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
+
+       if (markNAND &&
+           bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
+
+               yaffs_InitialiseTags(&tags);
+
+               tags.chunkDeleted = 1;
+
+               yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
+               yaffs_HandleUpdateChunk(dev, chunkId, &tags);
+       } else {
+               dev->nUnmarkedDeletions++;
+       }
+
+       /* Pull out of the management area.
+        * If the whole block became dirty, this will kick off an erasure.
+        */
+       if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
+           bi->blockState == YAFFS_BLOCK_STATE_FULL ||
+           bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+           bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+               dev->nFreeChunks++;
+
+               yaffs_ClearChunkBit(dev, block, page);
+
+               bi->pagesInUse--;
+
+               if (bi->pagesInUse == 0 &&
+                   !bi->hasShrinkHeader &&
+                   bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
+                   bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+                       yaffs_BlockBecameDirty(dev, block);
+               }
+
+       } else {
+               /* T(("Bad news deleting chunk %d\n",chunkId)); */
+       }
+
+}
+
+static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode,
+                                       const __u8 * buffer, int nBytes,
+                                       int useReserve)
+{
+       /* Find old chunk Need to do this to get serial number
+        * Write new one and patch into tree.
+        * Invalidate old tags.
+        */
+
+       int prevChunkId;
+       yaffs_ExtendedTags prevTags;
+
+       int newChunkId;
+       yaffs_ExtendedTags newTags;
+
+       yaffs_Device *dev = in->myDev;
+
+       yaffs_CheckGarbageCollection(dev);
+
+       /* Get the previous chunk at this location in the file if it exists */
+       prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
+
+       /* Set up new tags */
+       yaffs_InitialiseTags(&newTags);
+
+       newTags.chunkId = chunkInInode;
+       newTags.objectId = in->objectId;
+       newTags.serialNumber =
+           (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+       newTags.byteCount = nBytes;
+
+       newChunkId =
+           yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
+                                             useReserve);
+
+       if (newChunkId >= 0) {
+               yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
+
+               if (prevChunkId >= 0) {
+                       yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
+
+               }
+
+               yaffs_CheckFileSanity(in);
+       }
+       return newChunkId;
+
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force,
+                            int isShrink, int shadows)
+{
+
+       yaffs_BlockInfo *bi;
+
+       yaffs_Device *dev = in->myDev;
+
+       int prevChunkId;
+       int retVal = 0;
+       int result = 0;
+
+       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;
+
+               prevChunkId = in->chunkId;
+
+               if (prevChunkId >= 0) {
+                       result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
+                                                       buffer, &oldTags);
+                       
+                       yaffs_VerifyObjectHeader(in,oh,&oldTags,0);
+                                                                               
+                       memcpy(oldName, oh->name, sizeof(oh->name));
+               }
+
+               memset(buffer, 0xFF, dev->nDataBytesPerChunk);
+
+               oh->type = in->variantType;
+               oh->yst_mode = in->yst_mode;
+               oh->shadowsObject = shadows;
+
+#ifdef CONFIG_YAFFS_WINCE
+               oh->win_atime[0] = in->win_atime[0];
+               oh->win_ctime[0] = in->win_ctime[0];
+               oh->win_mtime[0] = in->win_mtime[0];
+               oh->win_atime[1] = in->win_atime[1];
+               oh->win_ctime[1] = in->win_ctime[1];
+               oh->win_mtime[1] = in->win_mtime[1];
+#else
+               oh->yst_uid = in->yst_uid;
+               oh->yst_gid = in->yst_gid;
+               oh->yst_atime = in->yst_atime;
+               oh->yst_mtime = in->yst_mtime;
+               oh->yst_ctime = in->yst_ctime;
+               oh->yst_rdev = in->yst_rdev;
+#endif
+               if (in->parent) {
+                       oh->parentObjectId = in->parent->objectId;
+               } else {
+                       oh->parentObjectId = 0;
+               }
+
+               if (name && *name) {
+                       memset(oh->name, 0, sizeof(oh->name));
+                       yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
+               } else if (prevChunkId>=0) {
+                       memcpy(oh->name, oldName, sizeof(oh->name));
+               } else {
+                       memset(oh->name, 0, sizeof(oh->name));
+               }
+
+               oh->isShrink = isShrink;
+
+               switch (in->variantType) {
+               case YAFFS_OBJECT_TYPE_UNKNOWN:
+                       /* Should not happen */
+                       break;
+               case YAFFS_OBJECT_TYPE_FILE:
+                       oh->fileSize =
+                           (oh->parentObjectId == YAFFS_OBJECTID_DELETED
+                            || oh->parentObjectId ==
+                            YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
+                           fileVariant.fileSize;
+                       break;
+               case YAFFS_OBJECT_TYPE_HARDLINK:
+                       oh->equivalentObjectId =
+                           in->variant.hardLinkVariant.equivalentObjectId;
+                       break;
+               case YAFFS_OBJECT_TYPE_SPECIAL:
+                       /* Do nothing */
+                       break;
+               case YAFFS_OBJECT_TYPE_DIRECTORY:
+                       /* Do nothing */
+                       break;
+               case YAFFS_OBJECT_TYPE_SYMLINK:
+                       yaffs_strncpy(oh->alias,
+                                     in->variant.symLinkVariant.alias,
+                                     YAFFS_MAX_ALIAS_LENGTH);
+                       oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+                       break;
+               }
+
+               /* Tags */
+               yaffs_InitialiseTags(&newTags);
+               in->serial++;
+               newTags.chunkId = 0;
+               newTags.objectId = in->objectId;
+               newTags.serialNumber = in->serial;
+
+               /* Add extra info for file header */
+
+               newTags.extraHeaderInfoAvailable = 1;
+               newTags.extraParentObjectId = oh->parentObjectId;
+               newTags.extraFileLength = oh->fileSize;
+               newTags.extraIsShrinkHeader = oh->isShrink;
+               newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+               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,
+                                                     (prevChunkId >= 0) ? 1 : 0);
+
+               if (newChunkId >= 0) {
+
+                       in->chunkId = newChunkId;
+
+                       if (prevChunkId >= 0) {
+                               yaffs_DeleteChunk(dev, prevChunkId, 1,
+                                                 __LINE__);
+                       }
+
+                       if(!yaffs_ObjectHasCachedWriteData(in))
+                               in->dirty = 0;
+
+                       /* If this was a shrink, then mark the block that the chunk lives on */
+                       if (isShrink) {
+                               bi = yaffs_GetBlockInfo(in->myDev,
+                                                       newChunkId /in->myDev-> nChunksPerBlock);
+                               bi->hasShrinkHeader = 1;
+                       }
+
+               }
+
+               retVal = newChunkId;
+
+       }
+
+       if (buffer)
+               yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+       return retVal;
+}
+
+/*------------------------ 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 
+ *   sequential writes. eg. scanning/writing a jpeg file.
+ *   In these cases, a short read/write cache can provide a huge perfomance benefit 
+ *   with dumb-as-a-rock code.
+ *   In Linux, the page cache provides read buffering aand the short op cache provides write 
+ *   buffering.
+ *
+ *   There are a limited number (~10) of cache chunks per device so that we don't
+ *   need a very intelligent search.
+ */
+
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
+{
+       yaffs_Device *dev = obj->myDev;
+       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;
+}
+
+
+static void yaffs_FlushFilesChunkCache(yaffs_Object * obj)
+{
+       yaffs_Device *dev = obj->myDev;
+       int lowest = -99;       /* Stop compiler whining. */
+       int i;
+       yaffs_ChunkCache *cache;
+       int chunkWritten = 0;
+       int nCaches = obj->myDev->nShortOpCaches;
+
+       if (nCaches > 0) {
+               do {
+                       cache = NULL;
+
+                       /* Find the dirty cache for this object with the lowest chunk id. */
+                       for (i = 0; i < nCaches; i++) {
+                               if (dev->srCache[i].object == obj &&
+                                   dev->srCache[i].dirty) {
+                                       if (!cache
+                                           || dev->srCache[i].chunkId <
+                                           lowest) {
+                                               cache = &dev->srCache[i];
+                                               lowest = cache->chunkId;
+                                       }
+                               }
+                       }
+
+                       if (cache && !cache->locked) {
+                               /* Write it out and free it up */
+
+                               chunkWritten =
+                                   yaffs_WriteChunkDataToObject(cache->object,
+                                                                cache->chunkId,
+                                                                cache->data,
+                                                                cache->nBytes,
+                                                                1);
+                               cache->dirty = 0;
+                               cache->object = NULL;
+                       }
+
+               } while (cache && chunkWritten > 0);
+
+               if (cache) {
+                       /* Hoosterman, disk full while writing cache out. */
+                       T(YAFFS_TRACE_ERROR,
+                         (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
+
+               }
+       }
+
+}
+
+/*yaffs_FlushEntireDeviceCache(dev)
+ *
+ *
+ */
+
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
+{
+       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.
+        */
+       do {
+               obj = NULL;
+               for( i = 0; i < nCaches && !obj; i++) {
+                       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. 
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev)
+{
+       int i;
+       int usage;
+       int theOne;
+
+       if (dev->nShortOpCaches > 0) {
+               for (i = 0; i < dev->nShortOpCaches; i++) {
+                       if (!dev->srCache[i].object) 
+                               return &dev->srCache[i];
+               }
+
+               return NULL;
+
+               theOne = -1;
+               usage = 0;      /* just to stop the compiler grizzling */
+
+               for (i = 0; i < dev->nShortOpCaches; i++) {
+                       if (!dev->srCache[i].dirty &&
+                           ((dev->srCache[i].lastUse < usage && theOne >= 0) ||
+                            theOne < 0)) {
+                               usage = dev->srCache[i].lastUse;
+                               theOne = i;
+                       }
+               }
+
+
+               return theOne >= 0 ? &dev->srCache[theOne] : NULL;
+       } else {
+               return NULL;
+       }
+
+}
+
+static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
+{
+       yaffs_ChunkCache *cache;
+       yaffs_Object *theObj;
+       int usage;
+       int i;
+       int pushout;
+
+       if (dev->nShortOpCaches > 0) {
+               /* Try find a non-dirty one... */
+
+               cache = yaffs_GrabChunkCacheWorker(dev);
+
+               if (!cache) {
+                       /* They were all dirty, find the last recently used object and flush
+                        * its cache, then  find again.
+                        * NB what's here is not very accurate, we actually flush the object
+                        * the last recently used page.
+                        */
+
+                       /* With locking we can't assume we can use entry zero */
+
+                       theObj = NULL;
+                       usage = -1;
+                       cache = NULL;
+                       pushout = -1;
+
+                       for (i = 0; i < dev->nShortOpCaches; i++) {
+                               if (dev->srCache[i].object &&
+                                   !dev->srCache[i].locked &&
+                                   (dev->srCache[i].lastUse < usage || !cache))
+                               {
+                                       usage = dev->srCache[i].lastUse;
+                                       theObj = dev->srCache[i].object;
+                                       cache = &dev->srCache[i];
+                                       pushout = i;
+                               }
+                       }
+
+                       if (!cache || cache->dirty) {
+                               /* Flush and try again */
+                               yaffs_FlushFilesChunkCache(theObj);
+                               cache = yaffs_GrabChunkCacheWorker(dev);
+                       }
+
+               }
+               return cache;
+       } else
+               return NULL;
+
+}
+
+/* Find a cached chunk */
+static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj,
+                                             int chunkId)
+{
+       yaffs_Device *dev = obj->myDev;
+       int i;
+       if (dev->nShortOpCaches > 0) {
+               for (i = 0; i < dev->nShortOpCaches; i++) {
+                       if (dev->srCache[i].object == obj &&
+                           dev->srCache[i].chunkId == chunkId) {
+                               dev->cacheHits++;
+
+                               return &dev->srCache[i];
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache,
+                               int isAWrite)
+{
+
+       if (dev->nShortOpCaches > 0) {
+               if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
+                       /* Reset the cache usages */
+                       int i;
+                       for (i = 1; i < dev->nShortOpCaches; i++) {
+                               dev->srCache[i].lastUse = 0;
+                       }
+                       dev->srLastUse = 0;
+               }
+
+               dev->srLastUse++;
+
+               cache->lastUse = dev->srLastUse;
+
+               if (isAWrite) {
+                       cache->dirty = 1;
+               }
+       }
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId)
+{
+       if (object->myDev->nShortOpCaches > 0) {
+               yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
+
+               if (cache) {
+                       cache->object = NULL;
+               }
+       }
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in)
+{
+       int i;
+       yaffs_Device *dev = in->myDev;
+
+       if (dev->nShortOpCaches > 0) {
+               /* Invalidate it. */
+               for (i = 0; i < dev->nShortOpCaches; i++) {
+                       if (dev->srCache[i].object == in) {
+                               dev->srCache[i].object = NULL;
+                       }
+               }
+       }
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+
+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;
+}
+
+static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+       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) &&
+                    (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+                    (cp.head == ((head) ? 1 : 0));
+       return ok ? 1 : 0;
+}
+
+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,
+                                          yaffs_CheckpointDevice *cp)
+{
+       dev->nErasedBlocks = cp->nErasedBlocks;
+       dev->allocationBlock = cp->allocationBlock;
+       dev->allocationPage = cp->allocationPage;
+       dev->nFreeChunks = cp->nFreeChunks;
+       
+       dev->nDeletedFiles = cp->nDeletedFiles;
+       dev->nUnlinkedFiles = cp->nUnlinkedFiles;
+       dev->nBackgroundDeletions = cp->nBackgroundDeletions;
+       dev->sequenceNumber = cp->sequenceNumber;
+       dev->oldestDirtySequence = cp->oldestDirtySequence;
+}
+
+
+static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
+{
+       yaffs_CheckpointDevice cp;
+       __u32 nBytes;
+       __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 */          
+       if(ok) {
+               nBytes = nBlocks * dev->chunkBitmapStride;
+               ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes);
+       }
+       return   ok ? 1 : 0;
+
+}
+
+static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
+{
+       yaffs_CheckpointDevice cp;
+       __u32 nBytes;
+       __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+       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;
+}
+
+static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
+                                          yaffs_Object *obj)
+{
+
+       cp->objectId = obj->objectId;
+       cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
+       cp->chunkId = obj->chunkId;
+       cp->variantType = obj->variantType;                     
+       cp->deleted = obj->deleted;
+       cp->softDeleted = obj->softDeleted;
+       cp->unlinked = obj->unlinked;
+       cp->fake = obj->fake;
+       cp->renameAllowed = obj->renameAllowed;
+       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)
+               cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
+}
+
+static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
+{
+
+       yaffs_Object *parent;
+       
+       obj->objectId = cp->objectId;
+       
+       if(cp->parentId)
+               parent = yaffs_FindOrCreateObjectByNumber(
+                                       obj->myDev,
+                                       cp->parentId,
+                                       YAFFS_OBJECT_TYPE_DIRECTORY);
+       else
+               parent = NULL;
+               
+       if(parent)
+               yaffs_AddObjectToDirectory(parent, obj);
+               
+       obj->chunkId = cp->chunkId;
+       obj->variantType = cp->variantType;                     
+       obj->deleted = cp->deleted;
+       obj->softDeleted = cp->softDeleted;
+       obj->unlinked = cp->unlinked;
+       obj->fake = cp->fake;
+       obj->renameAllowed = cp->renameAllowed;
+       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;
+}
+
+
+
+static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn,
+                                       __u32 level, int chunkOffset)
+{
+       int i;
+       yaffs_Device *dev = in->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_CheckpointTnodeWorker(in,
+                                                       tn->internal[i],
+                                                       level - 1,
+                                                       (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
+                               }
+                       }
+               } else if (level == 0) {
+                       __u32 baseOffset = chunkOffset <<  YAFFS_TNODES_LEVEL0_BITS;
+                       /* printf("write tnode at %d\n",baseOffset); */
+                       ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset));
+                       if(ok)
+                               ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes);
+               }
+       }
+
+       return ok;
+
+}
+
+static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
+{
+       __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)) == 
+                               sizeof(endMarker));
+       }
+       
+       return ok ? 1 : 0;
+}
+
+static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
+{
+       __u32 baseChunk;
+       int ok = 1;
+       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)
+                       ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) ==
+                             (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;      
+}
+
+static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
+{
+       yaffs_Object *obj;
+       yaffs_CheckpointObject cp;
+       int i;
+       int ok = 1;
+       struct list_head *lh;
+
+       
+       /* Iterate through the objects in each hash entry,
+        * dumping them to the checkpointing stream.
+        */
+        
+        for(i = 0; ok &&  i <  YAFFS_NOBJECT_BUCKETS; i++){
+               list_for_each(lh, &dev->objectBucket[i].list) {
+                       if (lh) {
+                               obj = list_entry(lh, yaffs_Object, hashLink);
+                               if (!obj->deferedFree) {
+                                       yaffs_ObjectToCheckpointObject(&cp,obj);
+                                       cp.structType = sizeof(cp);
+
+                                       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);
+                                       }
+                               }
+                       }
+               }
+        }
+        
+        /* 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;
+}
+
+static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
+{
+       yaffs_Object *obj;
+       yaffs_CheckpointObject cp;
+       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));
+                       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);
+                       if(obj) {
+                               yaffs_CheckpointObjectToObject(obj,&cp);
+                               if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+                                       ok = yaffs_ReadCheckpointTnodes(obj);
+                               } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+                                       obj->hardLinks.next =
+                                                   (struct list_head *)
+                                                   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;
+       }
+               
+       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)));
+               ok = yaffs_WriteCheckpointDevice(dev);
+       }
+       if(ok){
+               T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR)));
+               ok = yaffs_WriteCheckpointObjects(dev);
+       }
+       if(ok){
+               T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
+               ok = yaffs_WriteCheckpointValidityMarker(dev,0);
+       }
+       
+       if(ok){
+               ok = yaffs_WriteCheckpointSum(dev);
+       }
+       
+       
+       if(!yaffs_CheckpointClose(dev))
+                ok = 0;
+                
+       if(ok)
+               dev->isCheckpointed = 1;
+        else 
+               dev->isCheckpointed = 0;
+
+       return dev->isCheckpointed;
+}
+
+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;
+       }
+       
+       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)));
+               ok = yaffs_ReadCheckpointDevice(dev);
+       }
+       if(ok){
+               T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR)));    
+               ok = yaffs_ReadCheckpointObjects(dev);
+       }
+       if(ok){
+               T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
+               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 
+               dev->isCheckpointed = 0;
+
+       return ok ? 1 : 0;
+
+}
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
+{
+       if(dev->isCheckpointed || 
+          dev->blocksInCheckpoint > 0){
+               dev->isCheckpointed = 0;
+               yaffs_CheckpointInvalidateStream(dev);
+               if(dev->superBlock && dev->markSuperBlockDirty)
+                       dev->markSuperBlockDirty(dev->superBlock);
+       }
+}
+
+
+int yaffs_CheckpointSave(yaffs_Device *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);
+               yaffs_WriteCheckpointData(dev);
+       }
+       
+       T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
+
+       return dev->isCheckpointed;
+}
+
+int yaffs_CheckpointRestore(yaffs_Device *dev)
+{
+       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));
+       
+       return retval;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
+                          int nBytes)
+{
+
+       int chunk;
+       int start;
+       int nToCopy;
+       int n = nBytes;
+       int nDone = 0;
+       yaffs_ChunkCache *cache;
+
+       yaffs_Device *dev;
+
+       dev = in->myDev;
+
+       while (n > 0) {
+               //chunk = offset / dev->nDataBytesPerChunk + 1;
+               //start = offset % dev->nDataBytesPerChunk;
+               yaffs_AddrToChunk(dev,offset,&chunk,&start);
+               chunk++;
+
+               /* OK now check for the curveball where the start and end are in
+                * the same chunk.      
+                */
+               if ((start + n) < dev->nDataBytesPerChunk) {
+                       nToCopy = n;
+               } else {
+                       nToCopy = dev->nDataBytesPerChunk - start;
+               }
+
+               cache = yaffs_FindChunkCache(in, chunk);
+
+               /* If the chunk is already in the cache or it is less than a whole chunk
+                * then use the cache (if there is caching)
+                * else bypass the cache.
+                */
+               if (cache || nToCopy != dev->nDataBytesPerChunk) {
+                       if (dev->nShortOpCaches > 0) {
+
+                               /* If we can't find the data in the cache, then load it up. */
+
+                               if (!cache) {
+                                       cache = yaffs_GrabChunkCache(in->myDev);
+                                       cache->object = in;
+                                       cache->chunkId = chunk;
+                                       cache->dirty = 0;
+                                       cache->locked = 0;
+                                       yaffs_ReadChunkDataFromObject(in, chunk,
+                                                                     cache->
+                                                                     data);
+                                       cache->nBytes = 0;
+                               }
+
+                               yaffs_UseChunkCache(dev, cache, 0);
+
+                               cache->locked = 1;
+
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_UnlockYAFFS(TRUE);
+#endif
+                               memcpy(buffer, &cache->data[start], nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_LockYAFFS(TRUE);
+#endif
+                               cache->locked = 0;
+                       } else {
+                               /* Read into the local buffer then copy..*/
+
+                               __u8 *localBuffer =
+                                   yaffs_GetTempBuffer(dev, __LINE__);
+                               yaffs_ReadChunkDataFromObject(in, chunk,
+                                                             localBuffer);
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_UnlockYAFFS(TRUE);
+#endif
+                               memcpy(buffer, &localBuffer[start], nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_LockYAFFS(TRUE);
+#endif
+                               yaffs_ReleaseTempBuffer(dev, localBuffer,
+                                                       __LINE__);
+                       }
+
+               } else {
+#ifdef CONFIG_YAFFS_WINCE
+                       __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+                       /* Under WinCE can't do direct transfer. Need to use a local buffer.
+                        * This is because we otherwise screw up WinCE's memory mapper
+                        */
+                       yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
+
+#ifdef CONFIG_YAFFS_WINCE
+                       yfsd_UnlockYAFFS(TRUE);
+#endif
+                       memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
+
+#ifdef CONFIG_YAFFS_WINCE
+                       yfsd_LockYAFFS(TRUE);
+                       yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+#endif
+
+#else
+                       /* A full chunk. Read directly into the supplied buffer. */
+                       yaffs_ReadChunkDataFromObject(in, chunk, buffer);
+#endif
+               }
+
+               n -= nToCopy;
+               offset += nToCopy;
+               buffer += nToCopy;
+               nDone += nToCopy;
+
+       }
+
+       return nDone;
+}
+
+int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
+                         int nBytes, int writeThrough)
+{
+
+       int chunk;
+       int start;
+       int nToCopy;
+       int n = nBytes;
+       int nDone = 0;
+       int nToWriteBack;
+       int startOfWrite = offset;
+       int chunkWritten = 0;
+       int nBytesRead;
+
+       yaffs_Device *dev;
+
+       dev = in->myDev;
+
+       while (n > 0 && chunkWritten >= 0) {
+               //chunk = offset / dev->nDataBytesPerChunk + 1;
+               //start = offset % dev->nDataBytesPerChunk;
+               yaffs_AddrToChunk(dev,offset,&chunk,&start);
+               chunk++;
+
+               /* OK now check for the curveball where the start and end are in
+                * the same chunk.
+                */
+
+               if ((start + n) < dev->nDataBytesPerChunk) {
+                       nToCopy = n;
+
+                       /* Now folks, to calculate how many bytes to write back....
+                        * If we're overwriting and not writing to then end of file then
+                        * we need to write back as much as was there before.
+                        */
+
+                       nBytesRead =
+                           in->variant.fileVariant.fileSize -
+                           ((chunk - 1) * dev->nDataBytesPerChunk);
+
+                       if (nBytesRead > dev->nDataBytesPerChunk) {
+                               nBytesRead = dev->nDataBytesPerChunk;
+                       }
+
+                       nToWriteBack =
+                           (nBytesRead >
+                            (start + n)) ? nBytesRead : (start + n);
+
+               } else {
+                       nToCopy = dev->nDataBytesPerChunk - start;
+                       nToWriteBack = dev->nDataBytesPerChunk;
+               }
+
+               if (nToCopy != dev->nDataBytesPerChunk) {
+                       /* An incomplete start or end chunk (or maybe both start and end chunk) */
+                       if (dev->nShortOpCaches > 0) {
+                               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)) {
+                                       cache = yaffs_GrabChunkCache(in->myDev);
+                                       cache->object = in;
+                                       cache->chunkId = chunk;
+                                       cache->dirty = 0;
+                                       cache->locked = 0;
+                                       yaffs_ReadChunkDataFromObject(in, chunk,
+                                                                     cache->
+                                                                     data);
+                               }
+                               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;
+                               }
+
+                               if (cache) {
+                                       yaffs_UseChunkCache(dev, cache, 1);
+                                       cache->locked = 1;
+#ifdef CONFIG_YAFFS_WINCE
+                                       yfsd_UnlockYAFFS(TRUE);
+#endif
+
+                                       memcpy(&cache->data[start], buffer,
+                                              nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+                                       yfsd_LockYAFFS(TRUE);
+#endif
+                                       cache->locked = 0;
+                                       cache->nBytes = nToWriteBack;
+
+                                       if (writeThrough) {
+                                               chunkWritten =
+                                                   yaffs_WriteChunkDataToObject
+                                                   (cache->object,
+                                                    cache->chunkId,
+                                                    cache->data, cache->nBytes,
+                                                    1);
+                                               cache->dirty = 0;
+                                       }
+
+                               } else {
+                                       chunkWritten = -1;      /* fail the write */
+                               }
+                       } else {
+                               /* An incomplete start or end chunk (or maybe both start and end chunk)
+                                * Read into the local buffer then copy, then copy over and write back.
+                                */
+
+                               __u8 *localBuffer =
+                                   yaffs_GetTempBuffer(dev, __LINE__);
+
+                               yaffs_ReadChunkDataFromObject(in, chunk,
+                                                             localBuffer);
+
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_UnlockYAFFS(TRUE);
+#endif
+
+                               memcpy(&localBuffer[start], buffer, nToCopy);
+
+#ifdef CONFIG_YAFFS_WINCE
+                               yfsd_LockYAFFS(TRUE);
+#endif
+                               chunkWritten =
+                                   yaffs_WriteChunkDataToObject(in, chunk,
+                                                                localBuffer,
+                                                                nToWriteBack,
+                                                                0);
+
+                               yaffs_ReleaseTempBuffer(dev, localBuffer,
+                                                       __LINE__);
+
+                       }
+
+               } else {
+
+#ifdef CONFIG_YAFFS_WINCE
+                       /* Under WinCE can't do direct transfer. Need to use a local buffer.
+                        * This is because we otherwise screw up WinCE's memory mapper
+                        */
+                       __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+#ifdef CONFIG_YAFFS_WINCE
+                       yfsd_UnlockYAFFS(TRUE);
+#endif
+                       memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
+#ifdef CONFIG_YAFFS_WINCE
+                       yfsd_LockYAFFS(TRUE);
+#endif
+                       chunkWritten =
+                           yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
+                                                        dev->nDataBytesPerChunk,
+                                                        0);
+                       yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+#else
+                       /* A full chunk. Write directly from the supplied buffer. */
+                       chunkWritten =
+                           yaffs_WriteChunkDataToObject(in, chunk, buffer,
+                                                        dev->nDataBytesPerChunk,
+                                                        0);
+#endif
+                       /* Since we've overwritten the cached data, we better invalidate it. */
+                       yaffs_InvalidateChunkCache(in, chunk);
+               }
+
+               if (chunkWritten >= 0) {
+                       n -= nToCopy;
+                       offset += nToCopy;
+                       buffer += nToCopy;
+                       nDone += nToCopy;
+               }
+
+       }
+
+       /* Update file object */
+
+       if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
+               in->variant.fileVariant.fileSize = (startOfWrite + nDone);
+       }
+
+       in->dirty = 1;
+
+       return nDone;
+}
+
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize)
+{
+
+       yaffs_Device *dev = in->myDev;
+       int oldFileSize = in->variant.fileVariant.fileSize;
+
+       int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
+
+       int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
+           dev->nDataBytesPerChunk;
+       int i;
+       int chunkId;
+
+       /* Delete backwards so that we don't end up with holes if
+        * power is lost part-way through the operation.
+        */
+       for (i = lastDel; i >= startDel; i--) {
+               /* NB this could be optimised somewhat,
+                * eg. could retrieve the tags and write them without
+                * using yaffs_DeleteChunk
+                */
+
+               chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
+               if (chunkId > 0) {
+                       if (chunkId <
+                           (dev->internalStartBlock * dev->nChunksPerBlock)
+                           || chunkId >=
+                           ((dev->internalEndBlock +
+                             1) * dev->nChunksPerBlock)) {
+                               T(YAFFS_TRACE_ALWAYS,
+                                 (TSTR("Found daft chunkId %d for %d" TENDSTR),
+                                  chunkId, i));
+                       } else {
+                               in->nDataChunks--;
+                               yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
+                       }
+               }
+       }
+
+}
+
+int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize)
+{
+
+       int oldFileSize = in->variant.fileVariant.fileSize;
+       int newSizeOfPartialChunk;
+       int newFullChunks;
+       
+       yaffs_Device *dev = in->myDev;
+
+       yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
+
+       yaffs_FlushFilesChunkCache(in);
+       yaffs_InvalidateWholeChunkCache(in);
+
+       yaffs_CheckGarbageCollection(dev);
+
+       if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+               return yaffs_GetFileSize(in);
+       }
+
+       if (newSize == oldFileSize) {
+               return oldFileSize;
+       }
+
+       if (newSize < oldFileSize) {
+
+               yaffs_PruneResizedChunks(in, newSize);
+
+               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 */
+                       yaffs_ReadChunkDataFromObject(in, lastChunk,
+                                                     localBuffer);
+
+                       memset(localBuffer + newSizeOfPartialChunk, 0,
+                              dev->nDataBytesPerChunk - newSizeOfPartialChunk);
+
+                       yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
+                                                    newSizeOfPartialChunk, 1);
+
+                       yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+               }
+
+               in->variant.fileVariant.fileSize = newSize;
+
+               yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
+       } else {
+               /* newsSize > oldFileSize */
+               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.
+        */
+       if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+           in->parent->objectId != YAFFS_OBJECTID_DELETED) {
+               yaffs_UpdateObjectHeader(in, NULL, 0,
+                                        (newSize < oldFileSize) ? 1 : 0, 0);
+       }
+
+       return newSize;
+}
+
+loff_t yaffs_GetFileSize(yaffs_Object * obj)
+{
+       obj = yaffs_GetEquivalentObject(obj);
+
+       switch (obj->variantType) {
+       case YAFFS_OBJECT_TYPE_FILE:
+               return obj->variant.fileVariant.fileSize;
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+               return yaffs_strlen(obj->variant.symLinkVariant.alias);
+       default:
+               return 0;
+       }
+}
+
+
+
+int yaffs_FlushFile(yaffs_Object * in, int updateTime)
+{
+       int retVal;
+       if (in->dirty) {
+               yaffs_FlushFilesChunkCache(in);
+               if (updateTime) {
+#ifdef CONFIG_YAFFS_WINCE
+                       yfsd_WinFileTimeNow(in->win_mtime);
+#else
+
+                       in->yst_mtime = Y_CURRENT_TIME;
+
+#endif
+               }
+
+               retVal =
+                   (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+                    0) ? YAFFS_OK : YAFFS_FAIL;
+       } else {
+               retVal = YAFFS_OK;
+       }
+
+       return retVal;
+
+}
+
+static int yaffs_DoGenericObjectDeletion(yaffs_Object * in)
+{
+
+       /* First off, invalidate the file's data in the cache, without flushing. */
+       yaffs_InvalidateWholeChunkCache(in);
+
+       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_RemoveObjectFromDirectory(in);
+       yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__);
+       in->chunkId = -1;
+
+       yaffs_FreeObject(in);
+       return YAFFS_OK;
+
+}
+
+/* yaffs_DeleteFile deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_UnlinkFile(yaffs_Object * in)
+{
+
+       int retVal;
+       int immediateDeletion = 0;
+
+       if (1) {
+#ifdef __KERNEL__
+               if (!in->myInode) {
+                       immediateDeletion = 1;
+
+               }
+#else
+               if (in->inUse <= 0) {
+                       immediateDeletion = 1;
+
+               }
+#endif
+               if (immediateDeletion) {
+                       retVal =
+                           yaffs_ChangeObjectName(in, in->myDev->deletedDir,
+                                                  "deleted", 0, 0);
+                       T(YAFFS_TRACE_TRACING,
+                         (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
+                          in->objectId));
+                       in->deleted = 1;
+                       in->myDev->nDeletedFiles++;
+                       if (0 && in->myDev->isYaffs2) {
+                               yaffs_ResizeFile(in, 0);
+                       }
+                       yaffs_SoftDeleteFile(in);
+               } else {
+                       retVal =
+                           yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
+                                                  "unlinked", 0, 0);
+               }
+
+       }
+       return retVal;
+}
+
+int yaffs_DeleteFile(yaffs_Object * in)
+{
+       int retVal = YAFFS_OK;
+
+       if (in->nDataChunks > 0) {
+               /* Use soft deletion if there is data in the file */
+               if (!in->unlinked) {
+                       retVal = yaffs_UnlinkFile(in);
+               }
+               if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
+                       in->deleted = 1;
+                       in->myDev->nDeletedFiles++;
+                       yaffs_SoftDeleteFile(in);
+               }
+               return in->deleted ? YAFFS_OK : YAFFS_FAIL;
+       } else {
+               /* The file has no data chunks so we toss it immediately */
+               yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
+               in->variant.fileVariant.top = NULL;
+               yaffs_DoGenericObjectDeletion(in);
+
+               return YAFFS_OK;
+       }
+}
+
+static int yaffs_DeleteDirectory(yaffs_Object * in)
+{
+       /* First check that the directory is empty. */
+       if (list_empty(&in->variant.directoryVariant.children)) {
+               return yaffs_DoGenericObjectDeletion(in);
+       }
+
+       return YAFFS_FAIL;
+
+}
+
+static int yaffs_DeleteSymLink(yaffs_Object * in)
+{
+       YFREE(in->variant.symLinkVariant.alias);
+
+       return yaffs_DoGenericObjectDeletion(in);
+}
+
+static int yaffs_DeleteHardLink(yaffs_Object * in)
+{
+       /* remove this hardlink from the list assocaited with the equivalent
+        * object
+        */
+       list_del(&in->hardLinks);
+       return yaffs_DoGenericObjectDeletion(in);
+}
+
+static void yaffs_DestroyObject(yaffs_Object * obj)
+{
+       switch (obj->variantType) {
+       case YAFFS_OBJECT_TYPE_FILE:
+               yaffs_DeleteFile(obj);
+               break;
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               yaffs_DeleteDirectory(obj);
+               break;
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+               yaffs_DeleteSymLink(obj);
+               break;
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+               yaffs_DeleteHardLink(obj);
+               break;
+       case YAFFS_OBJECT_TYPE_SPECIAL:
+               yaffs_DoGenericObjectDeletion(obj);
+               break;
+       case YAFFS_OBJECT_TYPE_UNKNOWN:
+               break;          /* should not happen. */
+       }
+}
+
+static int yaffs_UnlinkWorker(yaffs_Object * obj)
+{
+
+       if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+               return yaffs_DeleteHardLink(obj);
+       } else if (!list_empty(&obj->hardLinks)) {
+               /* Curve ball: We're unlinking an object that has a hardlink.
+                *
+                * This problem arises because we are not strictly following
+                * The Linux link/inode model.
+                *
+                * We can't really delete the object.
+                * Instead, we do the following:
+                * - Select a hardlink.
+                * - Unhook it from the hard links
+                * - Unhook it from its parent directory (so that the rename can work)
+                * - Rename the object to the hardlink's name.
+                * - Delete the hardlink
+                */
+
+               yaffs_Object *hl;
+               int retVal;
+               YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+               hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
+
+               list_del_init(&hl->hardLinks);
+               list_del_init(&hl->siblings);
+
+               yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+
+               retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
+
+               if (retVal == YAFFS_OK) {
+                       retVal = yaffs_DoGenericObjectDeletion(hl);
+               }
+               return retVal;
+
+       } else {
+               switch (obj->variantType) {
+               case YAFFS_OBJECT_TYPE_FILE:
+                       return yaffs_UnlinkFile(obj);
+                       break;
+               case YAFFS_OBJECT_TYPE_DIRECTORY:
+                       return yaffs_DeleteDirectory(obj);
+                       break;
+               case YAFFS_OBJECT_TYPE_SYMLINK:
+                       return yaffs_DeleteSymLink(obj);
+                       break;
+               case YAFFS_OBJECT_TYPE_SPECIAL:
+                       return yaffs_DoGenericObjectDeletion(obj);
+                       break;
+               case YAFFS_OBJECT_TYPE_HARDLINK:
+               case YAFFS_OBJECT_TYPE_UNKNOWN:
+               default:
+                       return YAFFS_FAIL;
+               }
+       }
+}
+
+
+static int yaffs_UnlinkObject( yaffs_Object *obj)
+{
+
+       if (obj && obj->unlinkAllowed) {
+               return yaffs_UnlinkWorker(obj);
+       }
+
+       return YAFFS_FAIL;
+
+}
+int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name)
+{
+       yaffs_Object *obj;
+
+       obj = yaffs_FindObjectByName(dir, name);
+       return yaffs_UnlinkObject(obj);
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId,
+                                      int backwardScanning)
+{
+       yaffs_Object *obj;
+
+       if (!backwardScanning) {
+               /* Handle YAFFS1 forward scanning case
+                * For YAFFS1 we always do the deletion
+                */
+
+       } else {
+               /* Handle YAFFS2 case (backward scanning)
+                * If the shadowed object exists then ignore.
+                */
+               if (yaffs_FindObjectByNumber(dev, objId)) {
+                       return;
+               }
+       }
+
+       /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+        * We put it in unlinked dir to be cleaned up after the scanning
+        */
+       obj =
+           yaffs_FindOrCreateObjectByNumber(dev, objId,
+                                            YAFFS_OBJECT_TYPE_FILE);
+       yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
+       obj->variant.fileVariant.shrinkSize = 0;
+       obj->valid = 1;         /* So that we don't read any other info for this file */
+
+}
+
+typedef struct {
+       int seq;
+       int block;
+} yaffs_BlockIndex;
+
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
+{
+       yaffs_Object *hl;
+       yaffs_Object *in;
+       
+       while (hardList) {
+               hl = hardList;
+               hardList = (yaffs_Object *) (hardList->hardLinks.next);
+
+               in = yaffs_FindObjectByNumber(dev,
+                                             hl->variant.hardLinkVariant.
+                                             equivalentObjectId);
+
+               if (in) {
+                       /* Add the hardlink pointers */
+                       hl->variant.hardLinkVariant.equivalentObject = in;
+                       list_add(&hl->hardLinks, &in->hardLinks);
+               } else {
+                       /* Todo Need to report/handle this better.
+                        * Got a problem... hardlink to a non-existant object
+                        */
+                       hl->variant.hardLinkVariant.equivalentObject = NULL;
+                       INIT_LIST_HEAD(&hl->hardLinks);
+
+               }
+
+       }
+
+}
+
+
+
+
+
+static int ybicmp(const void *a, const void *b){
+    register int aseq = ((yaffs_BlockIndex *)a)->seq;
+    register int bseq = ((yaffs_BlockIndex *)b)->seq;
+    register int ablock = ((yaffs_BlockIndex *)a)->block;
+    register int bblock = ((yaffs_BlockIndex *)b)->block;
+    if( aseq == bseq )
+        return ablock - bblock;
+    else
+        return aseq - bseq;
+
+}
+
+static int yaffs_Scan(yaffs_Device * dev)
+{
+       yaffs_ExtendedTags tags;
+       int blk;
+       int blockIterator;
+       int startIterator;
+       int endIterator;
+       int nBlocksToScan = 0;
+       int result;
+
+       int chunk;
+       int c;
+       int deleted;
+       yaffs_BlockState state;
+       yaffs_Object *hardList = NULL;
+       yaffs_BlockInfo *bi;
+       int sequenceNumber;
+       yaffs_ObjectHeader *oh;
+       yaffs_Object *in;
+       yaffs_Object *parent;
+       int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+       
+       int alloc_failed = 0;
+       
+
+       __u8 *chunkData;
+
+       yaffs_BlockIndex *blockIndex = NULL;
+
+       if (dev->isYaffs2) {
+               T(YAFFS_TRACE_SCAN,
+                 (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));
+
+       chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+       dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+       if (dev->isYaffs2) {
+               blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+               if(!blockIndex)
+                       return YAFFS_FAIL;
+       }
+
+       /* Scan all the blocks to determine their state */
+       for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+               bi = yaffs_GetBlockInfo(dev, blk);
+               yaffs_ClearChunkBits(dev, blk);
+               bi->pagesInUse = 0;
+               bi->softDeletions = 0;
+
+               yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+               bi->blockState = state;
+               bi->sequenceNumber = sequenceNumber;
+
+               T(YAFFS_TRACE_SCAN_DEBUG,
+                 (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+                  state, sequenceNumber));
+
+               if (state == YAFFS_BLOCK_STATE_DEAD) {
+                       T(YAFFS_TRACE_BAD_BLOCKS,
+                         (TSTR("block %d is bad" TENDSTR), blk));
+               } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+                       T(YAFFS_TRACE_SCAN_DEBUG,
+                         (TSTR("Block empty " TENDSTR)));
+                       dev->nErasedBlocks++;
+                       dev->nFreeChunks += dev->nChunksPerBlock;
+               } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+                       /* Determine the highest sequence number */
+                       if (dev->isYaffs2 &&
+                           sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+                           sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+                               blockIndex[nBlocksToScan].seq = sequenceNumber;
+                               blockIndex[nBlocksToScan].block = blk;
+
+                               nBlocksToScan++;
+
+                               if (sequenceNumber >= dev->sequenceNumber) {
+                                       dev->sequenceNumber = sequenceNumber;
+                               }
+                       } else if (dev->isYaffs2) {
+                               /* TODO: Nasty sequence number! */
+                               T(YAFFS_TRACE_SCAN,
+                                 (TSTR
+                                  ("Block scanning block %d has bad sequence number %d"
+                                   TENDSTR), blk, sequenceNumber));
+
+                       }
+               }
+       }
+
+       /* Sort the blocks
+        * Dungy old bubble sort for now...
+        */
+       if (dev->isYaffs2) {
+               yaffs_BlockIndex temp;
+               int i;
+               int j;
+
+               for (i = 0; i < nBlocksToScan; i++)
+                       for (j = i + 1; j < nBlocksToScan; j++)
+                               if (blockIndex[i].seq > blockIndex[j].seq) {
+                                       temp = blockIndex[j];
+                                       blockIndex[j] = blockIndex[i];
+                                       blockIndex[i] = temp;
+                               }
+       }
+
+       /* Now scan the blocks looking at the data. */
+       if (dev->isYaffs2) {
+               startIterator = 0;
+               endIterator = nBlocksToScan - 1;
+               T(YAFFS_TRACE_SCAN_DEBUG,
+                 (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+       } else {
+               startIterator = dev->internalStartBlock;
+               endIterator = dev->internalEndBlock;
+       }
+
+       /* For each block.... */
+       for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
+            blockIterator++) {
+
+               if (dev->isYaffs2) {
+                       /* get the block to scan in the correct order */
+                       blk = blockIndex[blockIterator].block;
+               } else {
+                       blk = blockIterator;
+               }
+
+               bi = yaffs_GetBlockInfo(dev, blk);
+               state = bi->blockState;
+
+               deleted = 0;
+
+               /* For each chunk in each block that needs scanning....*/
+               for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
+                    state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
+                       /* Read the tags and decide what to do */
+                       chunk = blk * dev->nChunksPerBlock + c;
+
+                       result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+                                                       &tags);
+
+                       /* Let's have a good look at this chunk... */
+
+                       if (!dev->isYaffs2 && tags.chunkDeleted) {
+                               /* YAFFS1 only...
+                                * A deleted chunk
+                                */
+                               deleted++;
+                               dev->nFreeChunks++;
+                               /*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 is the one being allocated from
+                                */
+
+                               if (c == 0) {
+                                       /* We're looking at the first chunk in the block so the block is unused */
+                                       state = YAFFS_BLOCK_STATE_EMPTY;
+                                       dev->nErasedBlocks++;
+                               } else {
+                                       /* this is the block being allocated from */
+                                       T(YAFFS_TRACE_SCAN,
+                                         (TSTR
+                                          (" Allocating from %d %d" TENDSTR),
+                                          blk, c));
+                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
+                                       dev->allocationBlock = blk;
+                                       dev->allocationPage = c;
+                                       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
+                                        */
+                                       if (dev->isYaffs2
+                                           && (dev->sequenceNumber !=
+                                               bi->sequenceNumber)) {
+                                               T(YAFFS_TRACE_ALWAYS,
+                                                 (TSTR
+                                                  ("yaffs: Allocation block %d was not highest sequence id:"
+                                                   " block seq = %d, dev seq = %d"
+                                                   TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber));
+                                       }
+                               }
+
+                               dev->nFreeChunks += (dev->nChunksPerBlock - c);
+                       } else if (tags.chunkId > 0) {
+                               /* chunkId > 0 so it is a data chunk... */
+                               unsigned int endpos;
+
+                               yaffs_SetChunkBit(dev, blk, c);
+                               bi->pagesInUse++;
+
+                               in = yaffs_FindOrCreateObjectByNumber(dev,
+                                                                     tags.
+                                                                     objectId,
+                                                                     YAFFS_OBJECT_TYPE_FILE);
+                               /* 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;
+                               }
+                               
+                               endpos =
+                                   (tags.chunkId - 1) * dev->nDataBytesPerChunk +
+                                   tags.byteCount;
+                               if (in && 
+                                   in->variantType == YAFFS_OBJECT_TYPE_FILE
+                                   && in->variant.fileVariant.scannedFileSize <
+                                   endpos) {
+                                       in->variant.fileVariant.
+                                           scannedFileSize = endpos;
+                                       if (!dev->useHeaderFileSize) {
+                                               in->variant.fileVariant.
+                                                   fileSize =
+                                                   in->variant.fileVariant.
+                                                   scannedFileSize;
+                                       }
+
+                               }
+                               /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));   */
+                       } else {
+                               /* chunkId == 0, so it is an ObjectHeader.
+                                * Thus, we read in the object header and make the object
+                                */
+                               yaffs_SetChunkBit(dev, blk, c);
+                               bi->pagesInUse++;
+
+                               result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
+                                                               chunkData,
+                                                               NULL);
+
+                               oh = (yaffs_ObjectHeader *) chunkData;
+
+                               in = yaffs_FindObjectByNumber(dev,
+                                                             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 
+                                        * deleted, and worse still it has changed type. Delete the old object.
+                                        */
+
+                                       yaffs_DestroyObject(in);
+
+                                       in = 0;
+                               }
+
+                               in = yaffs_FindOrCreateObjectByNumber(dev,
+                                                                     tags.
+                                                                     objectId,
+                                                                     oh->type);
+
+                               if(!in)
+                                       alloc_failed = 1;
+                                       
+                               if (in && oh->shadowsObject > 0) {
+                                       yaffs_HandleShadowedObject(dev,
+                                                                  oh->
+                                                                  shadowsObject,
+                                                                  0);
+                               }
+
+                               if (in && in->valid) {
+                                       /* We have already filled this one. We have a duplicate and need to resolve it. */
+
+                                       unsigned existingSerial = in->serial;
+                                       unsigned newSerial = tags.serialNumber;
+
+                                       if (dev->isYaffs2 ||
+                                           ((existingSerial + 1) & 3) ==
+                                           newSerial) {
+                                               /* Use new one - destroy the exisiting one */
+                                               yaffs_DeleteChunk(dev,
+                                                                 in->chunkId,
+                                                                 1, __LINE__);
+                                               in->valid = 0;
+                                       } else {
+                                               /* Use existing - destroy this one. */
+                                               yaffs_DeleteChunk(dev, chunk, 1,
+                                                                 __LINE__);
+                                       }
+                               }
+
+                               if (in && !in->valid &&
+                                   (tags.objectId == YAFFS_OBJECTID_ROOT ||
+                                    tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
+                                       /* We only load some info, don't fiddle with directory structure */
+                                       in->valid = 1;
+                                       in->variantType = oh->type;
+
+                                       in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+                                       in->win_atime[0] = oh->win_atime[0];
+                                       in->win_ctime[0] = oh->win_ctime[0];
+                                       in->win_mtime[0] = oh->win_mtime[0];
+                                       in->win_atime[1] = oh->win_atime[1];
+                                       in->win_ctime[1] = oh->win_ctime[1];
+                                       in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                       in->yst_uid = oh->yst_uid;
+                                       in->yst_gid = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
+#endif
+                                       in->chunkId = chunk;
+
+                               } else if (in && !in->valid) {
+                                       /* we need to load this info */
+
+                                       in->valid = 1;
+                                       in->variantType = oh->type;
+
+                                       in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+                                       in->win_atime[0] = oh->win_atime[0];
+                                       in->win_ctime[0] = oh->win_ctime[0];
+                                       in->win_mtime[0] = oh->win_mtime[0];
+                                       in->win_atime[1] = oh->win_atime[1];
+                                       in->win_ctime[1] = oh->win_ctime[1];
+                                       in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                       in->yst_uid = oh->yst_uid;
+                                       in->yst_gid = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
+#endif
+                                       in->chunkId = chunk;
+
+                                       yaffs_SetObjectName(in, oh->name);
+                                       in->dirty = 0;
+
+                                       /* directory stuff...
+                                        * hook up to parent
+                                        */
+
+                                       parent =
+                                           yaffs_FindOrCreateObjectByNumber
+                                           (dev, oh->parentObjectId,
+                                            YAFFS_OBJECT_TYPE_DIRECTORY);
+                                       if (parent->variantType ==
+                                           YAFFS_OBJECT_TYPE_UNKNOWN) {
+                                               /* Set up as a directory */
+                                               parent->variantType =
+                                                   YAFFS_OBJECT_TYPE_DIRECTORY;
+                                               INIT_LIST_HEAD(&parent->variant.
+                                                              directoryVariant.
+                                                              children);
+                                       } else if (parent->variantType !=
+                                                  YAFFS_OBJECT_TYPE_DIRECTORY)
+                                       {
+                                               /* Hoosterman, another problem....
+                                                * We're trying to use a non-directory as a directory
+                                                */
+
+                                               T(YAFFS_TRACE_ERROR,
+                                                 (TSTR
+                                                  ("yaffs tragedy: attempting to use non-directory as"
+                                                   " a directory in scan. Put in lost+found."
+                                                   TENDSTR)));
+                                               parent = dev->lostNFoundDir;
+                                       }
+
+                                       yaffs_AddObjectToDirectory(parent, in);
+
+                                       if (0 && (parent == dev->deletedDir ||
+                                                 parent == dev->unlinkedDir)) {
+                                               in->deleted = 1;        /* If it is unlinked at start up then it wants deleting */
+                                               dev->nDeletedFiles++;
+                                       }
+                                       /* Note re hardlinks.
+                                        * Since we might scan a hardlink before its equivalent object is scanned
+                                        * we put them all in a list.
+                                        * After scanning is complete, we should have all the objects, so we run through this
+                                        * list and fix up all the chains.              
+                                        */
+
+                                       switch (in->variantType) {
+                                       case YAFFS_OBJECT_TYPE_UNKNOWN: 
+                                               /* Todo got a problem */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_FILE:
+                                               if (dev->isYaffs2
+                                                   && oh->isShrink) {
+                                                       /* Prune back the shrunken chunks */
+                                                       yaffs_PruneResizedChunks
+                                                           (in, oh->fileSize);
+                                                       /* Mark the block as having a shrinkHeader */
+                                                       bi->hasShrinkHeader = 1;
+                                               }
+
+                                               if (dev->useHeaderFileSize)
+
+                                                       in->variant.fileVariant.
+                                                           fileSize =
+                                                           oh->fileSize;
+
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_HARDLINK:
+                                               in->variant.hardLinkVariant.
+                                                   equivalentObjectId =
+                                                   oh->equivalentObjectId;
+                                               in->hardLinks.next =
+                                                   (struct list_head *)
+                                                   hardList;
+                                               hardList = in;
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_DIRECTORY:
+                                               /* Do nothing */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_SPECIAL:
+                                               /* Do nothing */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_SYMLINK: 
+                                               in->variant.symLinkVariant.alias =
+                                                   yaffs_CloneString(oh->alias);
+                                               if(!in->variant.symLinkVariant.alias)
+                                                       alloc_failed = 1;
+                                               break;
+                                       }
+
+                                       if (parent == dev->deletedDir) {
+                                               yaffs_DestroyObject(in);
+                                               bi->hasShrinkHeader = 1;
+                                       }
+                               }
+                       }
+               }
+
+               if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+                       /* If we got this far while scanning, then the block is fully allocated.*/
+                       state = YAFFS_BLOCK_STATE_FULL;
+               }
+
+               bi->blockState = state;
+
+               /* Now let's see if it was dirty */
+               if (bi->pagesInUse == 0 &&
+                   !bi->hasShrinkHeader &&
+                   bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+                       yaffs_BlockBecameDirty(dev, blk);
+               }
+
+       }
+
+       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 
+        * hardlinks.
+        */
+
+       yaffs_HardlinkFixup(dev,hardList);
+
+       /* Handle the unlinked files. Since they were left in an unlinked state we should
+        * just delete them.
+        */
+       {
+               struct list_head *i;
+               struct list_head *n;
+
+               yaffs_Object *l;
+               /* Soft delete all the unlinked files */
+               list_for_each_safe(i, n,
+                                  &dev->unlinkedDir->variant.directoryVariant.
+                                  children) {
+                       if (i) {
+                               l = list_entry(i, yaffs_Object, siblings);
+                               yaffs_DestroyObject(l);
+                       }
+               }
+       }
+
+       yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+       if(alloc_failed){
+               return YAFFS_FAIL;
+       }
+       
+       T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
+       
+
+       return YAFFS_OK;
+}
+
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
+{
+       __u8 *chunkData;
+       yaffs_ObjectHeader *oh;
+       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;          
+
+               in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+               in->win_atime[0] = oh->win_atime[0];
+               in->win_ctime[0] = oh->win_ctime[0];
+               in->win_mtime[0] = oh->win_mtime[0];
+               in->win_atime[1] = oh->win_atime[1];
+               in->win_ctime[1] = oh->win_ctime[1];
+               in->win_mtime[1] = oh->win_mtime[1];
+#else
+               in->yst_uid = oh->yst_uid;
+               in->yst_gid = oh->yst_gid;
+               in->yst_atime = oh->yst_atime;
+               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){
+                        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__);
+       }
+}
+
+static int yaffs_ScanBackwards(yaffs_Device * dev)
+{
+       yaffs_ExtendedTags tags;
+       int blk;
+       int blockIterator;
+       int startIterator;
+       int endIterator;
+       int nBlocksToScan = 0;
+
+       int chunk;
+       int result;
+       int c;
+       int deleted;
+       yaffs_BlockState state;
+       yaffs_Object *hardList = NULL;
+       yaffs_BlockInfo *bi;
+       int sequenceNumber;
+       yaffs_ObjectHeader *oh;
+       yaffs_Object *in;
+       yaffs_Object *parent;
+       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;
+
+       if (!dev->isYaffs2) {
+               T(YAFFS_TRACE_SCAN,
+                 (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       T(YAFFS_TRACE_SCAN,
+         (TSTR
+          ("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..."
+           TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
+
+
+       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 */
+       for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+               bi = yaffs_GetBlockInfo(dev, blk);
+               yaffs_ClearChunkBits(dev, blk);
+               bi->pagesInUse = 0;
+               bi->softDeletions = 0;
+
+               yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+               bi->blockState = state;
+               bi->sequenceNumber = sequenceNumber;
+
+               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++;
+                       
+               } else if (state == YAFFS_BLOCK_STATE_DEAD) {
+                       T(YAFFS_TRACE_BAD_BLOCKS,
+                         (TSTR("block %d is bad" TENDSTR), blk));
+               } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+                       T(YAFFS_TRACE_SCAN_DEBUG,
+                         (TSTR("Block empty " TENDSTR)));
+                       dev->nErasedBlocks++;
+                       dev->nFreeChunks += dev->nChunksPerBlock;
+               } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+                       /* Determine the highest sequence number */
+                       if (dev->isYaffs2 &&
+                           sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+                           sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+                               blockIndex[nBlocksToScan].seq = sequenceNumber;
+                               blockIndex[nBlocksToScan].block = blk;
+
+                               nBlocksToScan++;
+
+                               if (sequenceNumber >= dev->sequenceNumber) {
+                                       dev->sequenceNumber = sequenceNumber;
+                               }
+                       } else if (dev->isYaffs2) {
+                               /* TODO: Nasty sequence number! */
+                               T(YAFFS_TRACE_SCAN,
+                                 (TSTR
+                                  ("Block scanning block %d has bad sequence number %d"
+                                   TENDSTR), blk, sequenceNumber));
+
+                       }
+               }
+       }
+
+       T(YAFFS_TRACE_SCAN,
+       (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
+
+
+
+       YYIELD();
+
+       /* Sort the blocks */
+#ifndef CONFIG_YAFFS_USE_OWN_SORT
+       yaffs_qsort(blockIndex, nBlocksToScan,
+               sizeof(yaffs_BlockIndex), ybicmp);
+#else
+       {
+               /* Dungy old bubble sort... */
+               
+               yaffs_BlockIndex temp;
+               int i;
+               int j;
+
+               for (i = 0; i < nBlocksToScan; i++)
+                       for (j = i + 1; j < nBlocksToScan; j++)
+                               if (blockIndex[i].seq > blockIndex[j].seq) {
+                                       temp = blockIndex[j];
+                                       blockIndex[j] = blockIndex[i];
+                                       blockIndex[i] = temp;
+                               }
+       }
+#endif
+
+       YYIELD();
+
+       T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
+
+       /* Now scan the blocks looking at the data. */
+       startIterator = 0;
+       endIterator = nBlocksToScan - 1;
+       T(YAFFS_TRACE_SCAN_DEBUG,
+         (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+
+       /* For each block.... backwards */
+       for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
+            blockIterator--) {
+               /* Cooperative multitasking! This loop can run for so
+                  long that watchdog timers expire. */
+               YYIELD();
+
+               /* get the block to scan in the correct order */
+               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 &&
+                    (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+                     state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
+                       /* Scan backwards... 
+                        * Read the tags and decide what to do
+                        */
+                       
+                       chunk = blk * dev->nChunksPerBlock + c;
+
+                       result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+                                                       &tags);
+
+                       /* Let's have a good look at this chunk... */
+
+                       if (!tags.chunkUsed) {
+                               /* An unassigned chunk in the block.
+                                * If there are used chunks after this one, then
+                                * it is a chunk that was skipped due to failing the erased
+                                * check. Just skip it so that it can be deleted.
+                                * But, more typically, We get here when this is an unallocated
+                                * chunk and his means that either the block is empty or 
+                                * this is the one being allocated from
+                                */
+
+                               if(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;
+                                       dev->nErasedBlocks++;
+                               } else {
+                                       if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+                                           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"
+                                                           TENDSTR), blk, c));
+
+                                                       state = YAFFS_BLOCK_STATE_ALLOCATING;
+                                                       dev->allocationBlock = blk;
+                                                       dev->allocationPage = c;
+                                                       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;
+
+
+                               yaffs_SetChunkBit(dev, blk, c);
+                               bi->pagesInUse++;
+
+                               in = yaffs_FindOrCreateObjectByNumber(dev,
+                                                                     tags.
+                                                                     objectId,
+                                                                     YAFFS_OBJECT_TYPE_FILE);
+                               if(!in){
+                                       /* Out of memory */
+                                       alloc_failed = 1;
+                               }
+                               
+                               if (in &&
+                                   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;
+                                       }
+
+                                       /* 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) {
+                                               in->variant.fileVariant.
+                                                   scannedFileSize = endpos;
+                                               in->variant.fileVariant.
+                                                   fileSize =
+                                                   in->variant.fileVariant.
+                                                   scannedFileSize;
+                                       }
+
+                               } else if(in) {
+                                       /* This chunk has been invalidated by a resize, so delete */
+                                       yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+                               }
+                       } else {
+                               /* chunkId == 0, so it is an ObjectHeader.
+                                * Thus, we read in the object header and make the object
+                                */
+                               foundChunksInBlock = 1;
+
+                               yaffs_SetChunkBit(dev, blk, c);
+                               bi->pagesInUse++;
+
+                               oh = NULL;
+                               in = NULL;
+
+                               if (tags.extraHeaderInfoAvailable) {
+                                       in = yaffs_FindOrCreateObjectByNumber
+                                           (dev, tags.objectId,
+                                            tags.extraObjectType);
+                               }
+
+                               if (!in ||
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+                                   !in->valid ||
+#endif
+                                   tags.extraShadows ||
+                                   (!in->valid &&
+                                   (tags.objectId == YAFFS_OBJECTID_ROOT ||
+                                    tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
+                                   ) {
+
+                                       /* If we don't have  valid info then we need to read the chunk
+                                        * TODO In future we can probably defer reading the chunk and 
+                                        * living with invalid data until needed.
+                                        */
+
+                                       result = yaffs_ReadChunkWithTagsFromNAND(dev,
+                                                                       chunk,
+                                                                       chunkData,
+                                                                       NULL);
+
+                                       oh = (yaffs_ObjectHeader *) chunkData;
+
+                                       if (!in)
+                                               in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
+
+                               }
+
+                               if (!in) {
+                                       /* TODO Hoosterman we have a problem! */
+                                       T(YAFFS_TRACE_ERROR,
+                                         (TSTR
+                                          ("yaffs tragedy: Could not make object for object  %d  "
+                                           "at chunk %d during scan"
+                                           TENDSTR), tags.objectId, chunk));
+
+                               }
+
+                               if (in->valid) {
+                                       /* We have already filled this one.
+                                        * We have a duplicate that will be discarded, but 
+                                        * we first have to suck out resize info if it is a file.
+                                        */
+
+                                       if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && 
+                                            ((oh && 
+                                              oh-> type == YAFFS_OBJECT_TYPE_FILE)||
+                                             (tags.extraHeaderInfoAvailable  &&
+                                              tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))
+                                           ) {
+                                               __u32 thisSize =
+                                                   (oh) ? oh->fileSize : tags.
+                                                   extraFileLength;
+                                               __u32 parentObjectId =
+                                                   (oh) ? oh->
+                                                   parentObjectId : tags.
+                                                   extraParentObjectId;
+                                               unsigned isShrink =
+                                                   (oh) ? oh->isShrink : tags.
+                                                   extraIsShrinkHeader;
+
+                                               /* If it is deleted (unlinked at start also means deleted)
+                                                * we treat the file size as being zeroed at this point.
+                                                */
+                                               if (parentObjectId ==
+                                                   YAFFS_OBJECTID_DELETED
+                                                   || parentObjectId ==
+                                                   YAFFS_OBJECTID_UNLINKED) {
+                                                       thisSize = 0;
+                                                       isShrink = 1;
+                                               }
+
+                                               if (isShrink &&
+                                                   in->variant.fileVariant.
+                                                   shrinkSize > thisSize) {
+                                                       in->variant.fileVariant.
+                                                           shrinkSize =
+                                                           thisSize;
+                                               }
+
+                                               if (isShrink) {
+                                                       bi->hasShrinkHeader = 1;
+                                               }
+
+                                       }
+                                       /* Use existing - destroy this one. */
+                                       yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+                               }
+
+                               if (!in->valid &&
+                                   (tags.objectId == YAFFS_OBJECTID_ROOT ||
+                                    tags.objectId ==
+                                    YAFFS_OBJECTID_LOSTNFOUND)) {
+                                       /* We only load some info, don't fiddle with directory structure */
+                                       in->valid = 1;
+                                       
+                                       if(oh) {
+                                               in->variantType = oh->type;
+
+                                               in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+                                               in->win_atime[0] = oh->win_atime[0];
+                                               in->win_ctime[0] = oh->win_ctime[0];
+                                               in->win_mtime[0] = oh->win_mtime[0];
+                                               in->win_atime[1] = oh->win_atime[1];
+                                               in->win_ctime[1] = oh->win_ctime[1];
+                                               in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                               in->yst_uid = oh->yst_uid;
+                                               in->yst_gid = oh->yst_gid;
+                                               in->yst_atime = oh->yst_atime;
+                                               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) {
+                                       /* we need to load this info */
+
+                                       in->valid = 1;
+                                       in->chunkId = chunk;
+                                       
+                                       if(oh) {
+                                               in->variantType = oh->type;
+
+                                               in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+                                               in->win_atime[0] = oh->win_atime[0];
+                                               in->win_ctime[0] = oh->win_ctime[0];
+                                               in->win_mtime[0] = oh->win_mtime[0];
+                                               in->win_atime[1] = oh->win_atime[1];
+                                               in->win_ctime[1] = oh->win_ctime[1];
+                                               in->win_mtime[1] = oh->win_mtime[1];
+#else
+                                               in->yst_uid = oh->yst_uid;
+                                               in->yst_gid = oh->yst_gid;
+                                               in->yst_atime = oh->yst_atime;
+                                               in->yst_mtime = oh->yst_mtime;
+                                               in->yst_ctime = oh->yst_ctime;
+                                               in->yst_rdev = oh->yst_rdev;
+#endif
+
+                                               if (oh->shadowsObject > 0) 
+                                                       yaffs_HandleShadowedObject(dev,
+                                                                          oh->
+                                                                          shadowsObject,
+                                                                          1);
+                                       
+
+                                               yaffs_SetObjectName(in, oh->name);
+                                               parent =
+                                                   yaffs_FindOrCreateObjectByNumber
+                                                       (dev, oh->parentObjectId,
+                                                        YAFFS_OBJECT_TYPE_DIRECTORY);
+
+                                                fileSize = oh->fileSize;
+                                                isShrink = oh->isShrink;
+                                                equivalentObjectId = oh->equivalentObjectId;
+
+                                       }
+                                       else {
+                                               in->variantType = tags.extraObjectType;
+                                               parent =
+                                                   yaffs_FindOrCreateObjectByNumber
+                                                       (dev, tags.extraParentObjectId,
+                                                        YAFFS_OBJECT_TYPE_DIRECTORY);
+                                                fileSize = tags.extraFileLength;
+                                                isShrink = tags.extraIsShrinkHeader;
+                                                equivalentObjectId = tags.extraEquivalentObjectId;
+                                               in->lazyLoaded = 1;
+
+                                       }
+                                       in->dirty = 0;
+
+                                       /* directory stuff...
+                                        * hook up to parent
+                                        */
+
+                                       if (parent->variantType ==
+                                           YAFFS_OBJECT_TYPE_UNKNOWN) {
+                                               /* Set up as a directory */
+                                               parent->variantType =
+                                                   YAFFS_OBJECT_TYPE_DIRECTORY;
+                                               INIT_LIST_HEAD(&parent->variant.
+                                                              directoryVariant.
+                                                              children);
+                                       } else if (parent->variantType !=
+                                                  YAFFS_OBJECT_TYPE_DIRECTORY)
+                                       {
+                                               /* Hoosterman, another problem....
+                                                * We're trying to use a non-directory as a directory
+                                                */
+
+                                               T(YAFFS_TRACE_ERROR,
+                                                 (TSTR
+                                                  ("yaffs tragedy: attempting to use non-directory as"
+                                                   " a directory in scan. Put in lost+found."
+                                                   TENDSTR)));
+                                               parent = dev->lostNFoundDir;
+                                       }
+
+                                       yaffs_AddObjectToDirectory(parent, in);
+
+                                       itsUnlinked = (parent == dev->deletedDir) ||
+                                                     (parent == dev->unlinkedDir);
+
+                                       if (isShrink) {
+                                               /* Mark the block as having a shrinkHeader */
+                                               bi->hasShrinkHeader = 1;
+                                       }
+
+                                       /* Note re hardlinks.
+                                        * Since we might scan a hardlink before its equivalent object is scanned
+                                        * we put them all in a list.
+                                        * After scanning is complete, we should have all the objects, so we run
+                                        * through this list and fix up all the chains.              
+                                        */
+
+                                       switch (in->variantType) {
+                                       case YAFFS_OBJECT_TYPE_UNKNOWN: 
+                                               /* Todo got a problem */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_FILE:
+
+                                               if (in->variant.fileVariant.
+                                                   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 
+                                                        * than its current data extents.
+                                                        */
+                                                       in->variant.fileVariant.fileSize = fileSize;
+                                                       in->variant.fileVariant.scannedFileSize =
+                                                           in->variant.fileVariant.fileSize;
+                                               }
+
+                                               if (isShrink &&
+                                                   in->variant.fileVariant.shrinkSize > fileSize) {
+                                                       in->variant.fileVariant.shrinkSize = fileSize;
+                                               }
+
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_HARDLINK:
+                                               if(!itsUnlinked) {
+                                                 in->variant.hardLinkVariant.equivalentObjectId =
+                                                   equivalentObjectId;
+                                                 in->hardLinks.next =
+                                                   (struct list_head *) hardList;
+                                                 hardList = in;
+                                               }
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_DIRECTORY:
+                                               /* Do nothing */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_SPECIAL:
+                                               /* Do nothing */
+                                               break;
+                                       case YAFFS_OBJECT_TYPE_SYMLINK:
+                                               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. */
+                       state = YAFFS_BLOCK_STATE_FULL;
+               }
+
+               bi->blockState = state;
+
+               /* Now let's see if it was dirty */
+               if (bi->pagesInUse == 0 &&
+                   !bi->hasShrinkHeader &&
+                   bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+                       yaffs_BlockBecameDirty(dev, blk);
+               }
+
+       }
+
+       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 
+        * hardlinks.
+        */
+       yaffs_HardlinkFixup(dev,hardList);
+       
+       
+       /*
+       *  Sort out state of unlinked and deleted objects.
+       */
+       {
+               struct list_head *i;
+               struct list_head *n;
+
+               yaffs_Object *l;
+
+               /* Soft delete all the unlinked files */
+               list_for_each_safe(i, n,
+                                  &dev->unlinkedDir->variant.directoryVariant.
+                                  children) {
+                       if (i) {
+                               l = list_entry(i, yaffs_Object, siblings);
+                               yaffs_DestroyObject(l);
+                       }
+               }
+
+               /* Soft delete all the deletedDir files */
+               list_for_each_safe(i, n,
+                                  &dev->deletedDir->variant.directoryVariant.
+                                  children) {
+                       if (i) {
+                               l = list_entry(i, yaffs_Object, siblings);
+                               yaffs_DestroyObject(l);
+
+                       }
+               }
+       }
+
+       yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+       
+       if(alloc_failed){
+               return YAFFS_FAIL;
+       }
+
+       T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
+
+       return YAFFS_OK;
+}
+
+/*------------------------------  Directory Functions ----------------------------- */
+
+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;
+}
+
+
+static void yaffs_AddObjectToDirectory(yaffs_Object * directory,
+                                      yaffs_Object * obj)
+{
+
+       if (!directory) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: Trying to add an object to a null pointer directory"
+                   TENDSTR)));
+               YBUG();
+       }
+       if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: Trying to add an object to a non-directory"
+                   TENDSTR)));
+               YBUG();
+       }
+
+       if (obj->siblings.prev == NULL) {
+               /* Not initialised */
+               INIT_LIST_HEAD(&obj->siblings);
+
+       } else if (!list_empty(&obj->siblings)) {
+               /* If it is holed up somewhere else, un hook it */
+               yaffs_RemoveObjectFromDirectory(obj);
+       }
+       /* Now add it */
+       list_add(&obj->siblings, &directory->variant.directoryVariant.children);
+       obj->parent = directory;
+
+       if (directory == obj->myDev->unlinkedDir
+           || directory == obj->myDev->deletedDir) {
+               obj->unlinked = 1;
+               obj->myDev->nUnlinkedFiles++;
+               obj->renameAllowed = 0;
+       }
+}
+
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory,
+                                    const YCHAR * name)
+{
+       int sum;
+
+       struct list_head *i;
+       YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+
+       yaffs_Object *l;
+
+       if (!name) {
+               return NULL;
+       }
+
+       if (!directory) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: yaffs_FindObjectByName: null pointer directory"
+                   TENDSTR)));
+               YBUG();
+       }
+       if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+               YBUG();
+       }
+
+       sum = yaffs_CalcNameSum(name);
+
+       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 */
+                       if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+                               if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) {
+                                       return l;
+                               }
+                       } 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) {
+                                       return l;
+                               }
+
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+
+#if 0
+int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
+                                  int (*fn) (yaffs_Object *))
+{
+       struct list_head *i;
+       yaffs_Object *l;
+
+       if (!theDir) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: yaffs_FindObjectByName: null pointer directory"
+                   TENDSTR)));
+               YBUG();
+       }
+       if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+               YBUG();
+       }
+
+       list_for_each(i, &theDir->variant.directoryVariant.children) {
+               if (i) {
+                       l = list_entry(i, yaffs_Object, siblings);
+                       if (l && !fn(l)) {
+                               return YAFFS_FAIL;
+                       }
+               }
+       }
+
+       return YAFFS_OK;
+
+}
+#endif
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj)
+{
+       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;
+
+}
+
+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) {
+               yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
+       } else if (obj->chunkId <= 0) {
+               YCHAR locName[20];
+               /* make up a name */
+               yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX,
+                             obj->objectId);
+               yaffs_strncpy(name, locName, buffSize - 1);
+
+       }
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+       else if (obj->shortName[0]) {
+               yaffs_strcpy(name, obj->shortName);
+       }
+#endif
+       else {
+               int result;
+               __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
+
+               yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
+
+               memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
+
+               if (obj->chunkId >= 0) {
+                       result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
+                                                       obj->chunkId, buffer,
+                                                       NULL);
+               }
+               yaffs_strncpy(name, oh->name, buffSize - 1);
+
+               yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
+       }
+
+       return yaffs_strlen(name);
+}
+
+int yaffs_GetObjectFileLength(yaffs_Object * obj)
+{
+
+       /* Dereference any hard linking */
+       obj = yaffs_GetEquivalentObject(obj);
+
+       if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+               return obj->variant.fileVariant.fileSize;
+       }
+       if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+               return yaffs_strlen(obj->variant.symLinkVariant.alias);
+       } else {
+               /* Only a directory should drop through to here */
+               return obj->myDev->nDataBytesPerChunk;
+       }
+}
+
+int yaffs_GetObjectLinkCount(yaffs_Object * obj)
+{
+       int count = 0;
+       struct list_head *i;
+
+       if (!obj->unlinked) {
+               count++;        /* the object itself */
+       }
+       list_for_each(i, &obj->hardLinks) {
+               count++;        /* add the hard links; */
+       }
+       return count;
+
+}
+
+int yaffs_GetObjectInode(yaffs_Object * obj)
+{
+       obj = yaffs_GetEquivalentObject(obj);
+
+       return obj->objectId;
+}
+
+unsigned yaffs_GetObjectType(yaffs_Object * obj)
+{
+       obj = yaffs_GetEquivalentObject(obj);
+
+       switch (obj->variantType) {
+       case YAFFS_OBJECT_TYPE_FILE:
+               return DT_REG;
+               break;
+       case YAFFS_OBJECT_TYPE_DIRECTORY:
+               return DT_DIR;
+               break;
+       case YAFFS_OBJECT_TYPE_SYMLINK:
+               return DT_LNK;
+               break;
+       case YAFFS_OBJECT_TYPE_HARDLINK:
+               return DT_REG;
+               break;
+       case YAFFS_OBJECT_TYPE_SPECIAL:
+               if (S_ISFIFO(obj->yst_mode))
+                       return DT_FIFO;
+               if (S_ISCHR(obj->yst_mode))
+                       return DT_CHR;
+               if (S_ISBLK(obj->yst_mode))
+                       return DT_BLK;
+               if (S_ISSOCK(obj->yst_mode))
+                       return DT_SOCK;
+       default:
+               return DT_REG;
+               break;
+       }
+}
+
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj)
+{
+       obj = yaffs_GetEquivalentObject(obj);
+       if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+               return yaffs_CloneString(obj->variant.symLinkVariant.alias);
+       } else {
+               return yaffs_CloneString(_Y(""));
+       }
+}
+
+#ifndef CONFIG_YAFFS_WINCE
+
+int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr)
+{
+       unsigned int valid = attr->ia_valid;
+
+       if (valid & ATTR_MODE)
+               obj->yst_mode = attr->ia_mode;
+       if (valid & ATTR_UID)
+               obj->yst_uid = attr->ia_uid;
+       if (valid & ATTR_GID)
+               obj->yst_gid = attr->ia_gid;
+
+       if (valid & ATTR_ATIME)
+               obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+       if (valid & ATTR_CTIME)
+               obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+       if (valid & ATTR_MTIME)
+               obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+       if (valid & ATTR_SIZE)
+               yaffs_ResizeFile(obj, attr->ia_size);
+
+       yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+
+       return YAFFS_OK;
+
+}
+int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr)
+{
+       unsigned int valid = 0;
+
+       attr->ia_mode = obj->yst_mode;
+       valid |= ATTR_MODE;
+       attr->ia_uid = obj->yst_uid;
+       valid |= ATTR_UID;
+       attr->ia_gid = obj->yst_gid;
+       valid |= ATTR_GID;
+
+       Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+       valid |= ATTR_ATIME;
+       Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+       valid |= ATTR_CTIME;
+       Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+       valid |= ATTR_MTIME;
+
+       attr->ia_size = yaffs_GetFileSize(obj);
+       valid |= ATTR_SIZE;
+
+       attr->ia_valid = valid;
+
+       return YAFFS_OK;
+
+}
+
+#endif
+
+#if 0
+int yaffs_DumpObject(yaffs_Object * obj)
+{
+       YCHAR name[257];
+
+       yaffs_GetObjectName(obj, name, 256);
+
+       T(YAFFS_TRACE_ALWAYS,
+         (TSTR
+          ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
+           " chunk %d type %d size %d\n"
+           TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
+          obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId,
+          yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
+
+       return YAFFS_OK;
+}
+#endif
+
+/*---------------------------- Initialisation code -------------------------------------- */
+
+static int yaffs_CheckDevFunctions(const yaffs_Device * dev)
+{
+
+       /* Common functions, gotta have */
+       if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
+               return 0;
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+       /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
+       if (dev->writeChunkWithTagsToNAND &&
+           dev->readChunkWithTagsFromNAND &&
+           !dev->writeChunkToNAND &&
+           !dev->readChunkFromNAND &&
+           dev->markNANDBlockBad && dev->queryNANDBlock)
+               return 1;
+#endif
+
+       /* Can use the "spare" style interface for yaffs1 */
+       if (!dev->isYaffs2 &&
+           !dev->writeChunkWithTagsToNAND &&
+           !dev->readChunkWithTagsFromNAND &&
+           dev->writeChunkToNAND &&
+           dev->readChunkFromNAND &&
+           !dev->markNANDBlockBad && !dev->queryNANDBlock)
+               return 1;
+
+       return 0;               /* bad */
+}
+
+
+static int 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);
+
+       dev->rootDir =
+           yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
+                                     YAFFS_ROOT_MODE | S_IFDIR);
+       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;
+}
+
+int yaffs_GutsInitialise(yaffs_Device * dev)
+{
+       int init_failed = 0;
+       unsigned x;
+       int bits;
+
+       T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
+
+       /* Check stuff that must be set */
+
+       if (!dev) {
+               T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       dev->internalStartBlock = dev->startBlock;
+       dev->internalEndBlock = dev->endBlock;
+       dev->blockOffset = 0;
+       dev->chunkOffset = 0;
+       dev->nFreeChunks = 0;
+
+       if (dev->startBlock == 0) {
+               dev->internalStartBlock = dev->startBlock + 1;
+               dev->internalEndBlock = dev->endBlock + 1;
+               dev->blockOffset = 1;
+               dev->chunkOffset = dev->nChunksPerBlock;
+       }
+
+       /* 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 || 
+            dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)      // otherwise it is too small
+           ) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s "
+                   TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : ""));
+               return YAFFS_FAIL;
+       }
+
+       if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       /* Got the right mix of functions? */
+       if (!yaffs_CheckDevFunctions(dev)) {
+               /* Function missing */
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR
+                  ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
+
+               return YAFFS_FAIL;
+       }
+
+       /* This is really a compilation check. */
+       if (!yaffs_CheckStructures()) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       if (dev->isMounted) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR("yaffs: device already mounted\n" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       /* Finished with most checks. One or two more checks happen later on too. */
+
+       dev->isMounted = 1;
+
+
+
+       /* OK now calculate a few things for the device */
+       
+       /*
+        *  Calculate all the chunk size manipulation numbers: 
+        */
+        /* Start off assuming it is a power of 2 */
+        dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk);
+        dev->chunkMask = (1<<dev->chunkShift) - 1;
+
+        if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){
+               /* Yes it is a power of 2, disable crumbs */
+               dev->crumbMask = 0;
+               dev->crumbShift = 0;
+               dev->crumbsPerChunk = 0;
+        } else {
+               /* Not a power of 2, use crumbs instead */
+               dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart));
+               dev->crumbMask = (1<<dev->crumbShift)-1;
+               dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift);
+               dev->chunkShift = 0;
+               dev->chunkMask = 0;
+       }
+               
+
+       /*
+        * Calculate chunkGroupBits.
+        * We need to find the next power of 2 > than internalEndBlock
+        */
+
+       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 */
+               if(bits & 1)
+                       bits++;
+               if(bits < 16)
+                       dev->tnodeWidth = 16;
+               else
+                       dev->tnodeWidth = bits;
+       }
+       else
+               dev->tnodeWidth = 16;
+       dev->tnodeMask = (1<<dev->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;
+
+       if (dev->nChunksPerBlock < dev->chunkGroupSize) {
+               /* We have a problem because the soft delete won't work if
+                * the chunk group size > chunks per block.
+                * This can be remedied by using larger "virtual blocks".
+                */
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR("yaffs: chunk group too large\n" TENDSTR)));
+
+               return YAFFS_FAIL;
+       }
+
+       /* OK, we've finished verifying the device, lets continue with initialisation */
+
+       /* More device initialisation */
+       dev->garbageCollections = 0;
+       dev->passiveGarbageCollections = 0;
+       dev->currentDirtyChecker = 0;
+       dev->bufferedBlock = -1;
+       dev->doingBufferedBlockRewrite = 0;
+       dev->nDeletedFiles = 0;
+       dev->nBackgroundDeletions = 0;
+       dev->nUnlinkedFiles = 0;
+       dev->eccFixed = 0;
+       dev->eccUnfixed = 0;
+       dev->tagsEccFixed = 0;
+       dev->tagsEccUnfixed = 0;
+       dev->nErasureFailures = 0;
+       dev->nErasedBlocks = 0;
+       dev->isDoingGC = 0;
+       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;
+               __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);
+                   
+               if(dev->srCache)
+                       memset(dev->srCache,0,srCacheBytes);
+                  
+               for (i = 0; i < dev->nShortOpCaches && buf; 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);
+               }
+               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;
+       }
+
+       if (dev->isYaffs2) {
+               dev->useHeaderFileSize = 1;
+       }
+       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){
+               /* 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;
+
+                               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;
+       }
+               
+       if(init_failed){
+               /* Clean up the mess */
+               T(YAFFS_TRACE_TRACING,
+                 (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
+
+               yaffs_Deinitialise(dev);
+               return YAFFS_FAIL;
+       }
+
+       /* Zero out stats */
+       dev->nPageReads = 0;
+       dev->nPageWrites = 0;
+       dev->nBlockErasures = 0;
+       dev->nGCCopies = 0;
+       dev->nRetriedWrites = 0;
+
+       dev->nRetiredBlocks = 0;
+
+       yaffs_VerifyFreeChunks(dev);
+       yaffs_VerifyBlocks(dev);
+       
+
+       T(YAFFS_TRACE_TRACING,
+         (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
+       return YAFFS_OK;
+
+}
+
+void yaffs_Deinitialise(yaffs_Device * dev)
+{
+       if (dev->isMounted) {
+               int i;
+
+               yaffs_DeinitialiseBlocks(dev);
+               yaffs_DeinitialiseTnodes(dev);
+               yaffs_DeinitialiseObjects(dev);
+               if (dev->nShortOpCaches > 0 &&
+                   dev->srCache) {
+
+                       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);
+                       dev->srCache = NULL;
+               }
+
+               YFREE(dev->gcCleanupList);
+
+               for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+                       YFREE(dev->tempBuffer[i].buffer);
+               }
+
+               dev->isMounted = 0;
+       }
+
+}
+
+static int yaffs_CountFreeChunks(yaffs_Device * dev)
+{
+       int nFree;
+       int b;
+
+       yaffs_BlockInfo *blk;
+
+       for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
+            b++) {
+               blk = yaffs_GetBlockInfo(dev, b);
+
+               switch (blk->blockState) {
+               case YAFFS_BLOCK_STATE_EMPTY:
+               case YAFFS_BLOCK_STATE_ALLOCATING:
+               case YAFFS_BLOCK_STATE_COLLECTING:
+               case YAFFS_BLOCK_STATE_FULL:
+                       nFree +=
+                           (dev->nChunksPerBlock - blk->pagesInUse +
+                            blk->softDeletions);
+                       break;
+               default:
+                       break;
+               }
+
+       }
+
+       return nFree;
+}
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev)
+{
+       /* This is what we report to the outside world */
+
+       int nFree;
+       int nDirtyCacheChunks;
+       int blocksForCheckpoint;
+
+#if 1
+       nFree = dev->nFreeChunks;
+#else
+       nFree = yaffs_CountFreeChunks(dev);
+#endif
+
+       nFree += dev->nDeletedFiles;
+       
+       /* Now count the number of dirty chunks in the cache and subtract those */
+
+       {
+               int i;
+               for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
+                       if (dev->srCache[i].dirty)
+                               nDirtyCacheChunks++;
+               }
+       }
+
+       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)
+               nFree = 0;
+
+       return nFree;
+
+}
+
+static int yaffs_freeVerificationFailures;
+
+static void yaffs_VerifyFreeChunks(yaffs_Device * dev)
+{
+       int counted;
+       int difference;
+       
+       if(yaffs_SkipVerification(dev))
+               return;
+       
+       counted = yaffs_CountFreeChunks(dev);
+
+       difference = dev->nFreeChunks - counted;
+
+       if (difference) {
+               T(YAFFS_TRACE_ALWAYS,
+                 (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
+                  dev->nFreeChunks, counted, difference));
+               yaffs_freeVerificationFailures++;
+       }
+}
+
+/*---------------------------------------- YAFFS test code ----------------------*/
+
+#define yaffs_CheckStruct(structure,syze, name) \
+           if(sizeof(structure) != syze) \
+              { \
+                T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\
+                name,syze,sizeof(structure))); \
+                return YAFFS_FAIL; \
+               }
+
+static int yaffs_CheckStructures(void)
+{
+/*      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */
+/*      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */
+/*      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */
+#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode")
+#endif
+           yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader")
+
+           return YAFFS_OK;
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_guts.h
new file mode 100644 (file)
index 0000000..59c6e75
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "devextras.h"
+#include "yportenv.h"
+
+#define YAFFS_OK       1
+#define YAFFS_FAIL  0
+
+/* Give us a  Y=0x59, 
+ * Give us an A=0x41, 
+ * Give us an FF=0xFF 
+ * Give us an S=0x53
+ * And what have we got... 
+ */
+#define YAFFS_MAGIC                    0x5941FF53
+
+#define YAFFS_NTNODES_LEVEL0           16
+#define YAFFS_TNODES_LEVEL0_BITS       4
+#define YAFFS_TNODES_LEVEL0_MASK       0xf
+
+#define YAFFS_NTNODES_INTERNAL                 (YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS     (YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK     0x7
+#define YAFFS_TNODES_MAX_LEVEL         6
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+#define YAFFS_BYTES_PER_SPARE          16
+#define YAFFS_BYTES_PER_CHUNK          512
+#define YAFFS_CHUNK_SIZE_SHIFT         9
+#define YAFFS_CHUNKS_PER_BLOCK         32
+#define YAFFS_BYTES_PER_BLOCK          (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+#endif
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE    1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE    32
+
+#define YAFFS_MAX_CHUNK_ID             0x000FFFFF
+
+#define YAFFS_UNUSED_OBJECT_ID         0x0003FFFF
+
+#define YAFFS_ALLOCATION_NOBJECTS      100
+#define YAFFS_ALLOCATION_NTNODES       100
+#define YAFFS_ALLOCATION_NLINKS                100
+
+#define YAFFS_NOBJECT_BUCKETS          256
+
+
+#define YAFFS_OBJECT_SPACE             0x40000
+
+#define YAFFS_CHECKPOINT_VERSION       3
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH          127
+#define YAFFS_MAX_ALIAS_LENGTH         79
+#else
+#define YAFFS_MAX_NAME_LENGTH          255
+#define YAFFS_MAX_ALIAS_LENGTH         159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH                15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT            1
+#define YAFFS_OBJECTID_LOSTNFOUND      2
+#define YAFFS_OBJECTID_UNLINKED                3
+#define YAFFS_OBJECTID_DELETED         4
+
+/* Sseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_SB_HEADER       0x10
+#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA  0x21
+
+/* */
+
+#define YAFFS_MAX_SHORT_OP_CACHES      20
+
+#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, 
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER   0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER  0xEFFFFF00
+
+/* ChunkCache is used for short read/write operations.*/
+typedef struct {
+       struct yaffs_ObjectStruct *object;
+       int chunkId;
+       int lastUse;
+       int dirty;
+       int nBytes;             /* Only valid if the cache is dirty */
+       int locked;             /* Can't push out or flush while locked. */
+#ifdef CONFIG_YAFFS_YAFFS2
+       __u8 *data;
+#else
+       __u8 data[YAFFS_BYTES_PER_CHUNK];
+#endif
+} yaffs_ChunkCache;
+
+
+
+/* Tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
+ * the structure size will get blown out.
+ */
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+typedef struct {
+       unsigned chunkId:20;
+       unsigned serialNumber:2;
+       unsigned byteCount:10;
+       unsigned objectId:18;
+       unsigned ecc:12;
+       unsigned unusedStuff:2;
+
+} yaffs_Tags;
+
+typedef union {
+       yaffs_Tags asTags;
+       __u8 asBytes[8];
+} yaffs_TagsUnion;
+
+#endif
+
+/* Stuff used for extended tags in YAFFS2 */
+
+typedef enum {
+       YAFFS_ECC_RESULT_UNKNOWN,
+       YAFFS_ECC_RESULT_NO_ERROR,
+       YAFFS_ECC_RESULT_FIXED,
+       YAFFS_ECC_RESULT_UNFIXED
+} yaffs_ECCResult;
+
+typedef enum {
+       YAFFS_OBJECT_TYPE_UNKNOWN,
+       YAFFS_OBJECT_TYPE_FILE,
+       YAFFS_OBJECT_TYPE_SYMLINK,
+       YAFFS_OBJECT_TYPE_DIRECTORY,
+       YAFFS_OBJECT_TYPE_HARDLINK,
+       YAFFS_OBJECT_TYPE_SPECIAL
+} yaffs_ObjectType;
+
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
+typedef struct {
+
+       unsigned validMarker0;
+       unsigned chunkUsed;     /*  Status of the chunk: used or unused */
+       unsigned objectId;      /* If 0 then this is not part of an object (unused) */
+       unsigned chunkId;       /* If 0 then this is a header, else a data chunk */
+       unsigned byteCount;     /* Only valid for data chunks */
+
+       /* The following stuff only has meaning when we read */
+       yaffs_ECCResult eccResult;
+       unsigned blockBad;      
+
+       /* YAFFS 1 stuff */
+       unsigned chunkDeleted;  /* The chunk is marked deleted */
+       unsigned serialNumber;  /* Yaffs1 2-bit serial number */
+
+       /* YAFFS2 stuff */
+       unsigned sequenceNumber;        /* The sequence number of this block */
+
+       /* Extra info if this is an object header (YAFFS2 only) */
+
+       unsigned extraHeaderInfoAvailable;      /* There is extra info available if this is not zero */
+       unsigned extraParentObjectId;   /* The parent object */
+       unsigned extraIsShrinkHeader;   /* Is it a shrink header? */
+       unsigned extraShadows;          /* Does this shadow another object? */
+
+       yaffs_ObjectType extraObjectType;       /* What object type? */
+
+       unsigned extraFileLength;               /* Length if it is a file */
+       unsigned extraEquivalentObjectId;       /* Equivalent object Id if it is a hard link */
+
+       unsigned validMarker1;
+
+} yaffs_ExtendedTags;
+
+/* Spare structure for YAFFS1 */
+typedef struct {
+       __u8 tagByte0;
+       __u8 tagByte1;
+       __u8 tagByte2;
+       __u8 tagByte3;
+       __u8 pageStatus;        /* set to 0 to delete the chunk */
+       __u8 blockStatus;
+       __u8 tagByte4;
+       __u8 tagByte5;
+       __u8 ecc1[3];
+       __u8 tagByte6;
+       __u8 tagByte7;
+       __u8 ecc2[3];
+} yaffs_Spare;
+
+/*Special structure for passing through to mtd */
+struct yaffs_NANDSpare {
+       yaffs_Spare spare;
+       int eccres1;
+       int eccres2;
+};
+
+/* Block data in RAM */
+
+typedef enum {
+       YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+       YAFFS_BLOCK_STATE_SCANNING,
+       YAFFS_BLOCK_STATE_NEEDS_SCANNING,
+       /* The block might have something on it (ie it is allocating or full, perhaps empty)
+        * but it needs to be scanned to determine its true state.
+        * This state is only valid during yaffs_Scan.
+        * NB We tolerate empty because the pre-scanner might be incapable of deciding
+        * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
+        */
+
+       YAFFS_BLOCK_STATE_EMPTY,
+       /* This block is empty */
+
+       YAFFS_BLOCK_STATE_ALLOCATING,
+       /* This block is partially allocated. 
+        * At least one page holds valid data.
+        * This is the one currently being used for page
+        * allocation. Should never be more than one of these
+        */
+
+       YAFFS_BLOCK_STATE_FULL, 
+       /* All the pages in this block have been allocated.
+        */
+
+       YAFFS_BLOCK_STATE_DIRTY,
+       /* All pages have been allocated and deleted. 
+        * Erase me, reuse me.
+        */
+
+       YAFFS_BLOCK_STATE_CHECKPOINT,   
+       /* This block is assigned to holding checkpoint data.
+        */
+
+       YAFFS_BLOCK_STATE_COLLECTING,   
+       /* This block is being garbage collected */
+
+       YAFFS_BLOCK_STATE_DEAD  
+       /* This block has failed and is not in use */
+} yaffs_BlockState;
+
+#define        YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+
+typedef struct {
+
+       int softDeletions:10;   /* number of soft deleted pages */
+       int pagesInUse:10;      /* number of pages in use */
+       yaffs_BlockState blockState:4;  /* One of the above block states */
+       __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. 
+                                  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 */
+
+#ifdef CONFIG_YAFFS_YAFFS2
+       __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
+       __u32 sequenceNumber;    /* block sequence number for yaffs2 */
+#endif
+
+} yaffs_BlockInfo;
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+typedef struct {
+       yaffs_ObjectType type;
+
+       /* Apply to everything  */
+       int parentObjectId;
+       __u16 sum__NoLongerUsed;        /* checksum of name. No longer used */
+       YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+       /* Thes following apply to directories, files, symlinks - not hard links */
+       __u32 yst_mode;         /* protection */
+
+#ifdef CONFIG_YAFFS_WINCE
+       __u32 notForWinCE[5];
+#else
+       __u32 yst_uid;
+       __u32 yst_gid;
+       __u32 yst_atime;
+       __u32 yst_mtime;
+       __u32 yst_ctime;
+#endif
+
+       /* File size  applies to files only */
+       int fileSize;
+
+       /* Equivalent object id applies to hard links only. */
+       int equivalentObjectId;
+
+       /* Alias is for symlinks only. */
+       YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+       __u32 yst_rdev;         /* device stuff for block and char devices (major/min) */
+
+#ifdef CONFIG_YAFFS_WINCE
+       __u32 win_ctime[2];
+       __u32 win_atime[2];
+       __u32 win_mtime[2];
+       __u32 roomToGrow[4];
+#else
+       __u32 roomToGrow[10];
+#endif
+
+       int shadowsObject;      /* This object header shadows the specified object if > 0 */
+
+       /* isShrink applies to object headers written when we shrink the file (ie resize) */
+       __u32 isShrink;
+
+} yaffs_ObjectHeader;
+
+/*--------------------------- Tnode -------------------------- */
+
+union yaffs_Tnode_union {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
+#else
+       union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
+#endif
+/*     __u16 level0[YAFFS_NTNODES_LEVEL0]; */
+
+};
+
+typedef union yaffs_Tnode_union yaffs_Tnode;
+
+struct yaffs_TnodeList_struct {
+       struct yaffs_TnodeList_struct *next;
+       yaffs_Tnode *tnodes;
+};
+
+typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
+
+/*------------------------  Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+typedef struct {
+       __u32 fileSize;
+       __u32 scannedFileSize;
+       __u32 shrinkSize;
+       int topLevel;
+       yaffs_Tnode *top;
+} yaffs_FileStructure;
+
+typedef struct {
+       struct list_head children;      /* list of child links */
+} yaffs_DirectoryStructure;
+
+typedef struct {
+       YCHAR *alias;
+} yaffs_SymLinkStructure;
+
+typedef struct {
+       struct yaffs_ObjectStruct *equivalentObject;
+       __u32 equivalentObjectId;
+} yaffs_HardLinkStructure;
+
+typedef union {
+       yaffs_FileStructure fileVariant;
+       yaffs_DirectoryStructure directoryVariant;
+       yaffs_SymLinkStructure symLinkVariant;
+       yaffs_HardLinkStructure hardLinkVariant;
+} yaffs_ObjectVariant;
+
+struct yaffs_ObjectStruct {
+       __u8 deleted:1;         /* This should only apply to unlinked files. */
+       __u8 softDeleted:1;     /* it has also been soft deleted */
+       __u8 unlinked:1;        /* An unlinked file. The file should be in the unlinked directory.*/
+       __u8 fake:1;            /* A fake object has no presence on NAND. */
+       __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 
+                                * object might be created before the data
+                                * is available (ie. file data records appear before the header).
+                                */
+       __u8 lazyLoaded:1;      /* This object has been lazy loaded and is missing some detail */
+
+       __u8 deferedFree:1;     /* For Linux kernel. Object is removed from NAND, but is
+                                * still in the inode cache. Free of object is defered.
+                                * until the inode is released.
+                                */
+
+       __u8 serial;            /* serial number of chunk in NAND. Cached here */
+       __u16 sum;              /* sum of the name to speed searching */
+
+       struct yaffs_DeviceStruct *myDev;       /* The device I'm on */
+
+       struct list_head hashLink;      /* list of objects in this hash bucket */
+
+       struct list_head hardLinks;     /* all the equivalent hard linked objects */
+
+       /* directory structure stuff */
+       /* also used for linking up the free list */
+       struct yaffs_ObjectStruct *parent; 
+       struct list_head siblings;
+
+       /* Where's my object header in NAND? */
+       int chunkId;            
+
+       int nDataChunks;        /* Number of data chunks attached to the file. */
+
+       __u32 objectId;         /* the object id value */
+
+       __u32 yst_mode;
+
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+       YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
+#endif
+
+#ifndef __KERNEL__
+       __u32 inUse;
+#endif
+
+#ifdef CONFIG_YAFFS_WINCE
+       __u32 win_ctime[2];
+       __u32 win_mtime[2];
+       __u32 win_atime[2];
+#else
+       __u32 yst_uid;
+       __u32 yst_gid;
+       __u32 yst_atime;
+       __u32 yst_mtime;
+       __u32 yst_ctime;
+#endif
+
+       __u32 yst_rdev;
+
+#ifdef __KERNEL__
+       struct inode *myInode;
+
+#endif
+
+       yaffs_ObjectType variantType;
+
+       yaffs_ObjectVariant variant;
+
+};
+
+typedef struct yaffs_ObjectStruct yaffs_Object;
+
+struct yaffs_ObjectList_struct {
+       yaffs_Object *objects;
+       struct yaffs_ObjectList_struct *next;
+};
+
+typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
+
+typedef struct {
+       struct list_head list;
+       int count;
+} yaffs_ObjectBucket;
+
+
+/* yaffs_CheckpointObject holds the definition of an object as dumped 
+ * by checkpointing.
+ */
+
+typedef struct {
+        int structType;
+       __u32 objectId;         
+       __u32 parentId;
+       int chunkId;
+                       
+       yaffs_ObjectType variantType:3;
+       __u8 deleted:1;         
+       __u8 softDeleted:1;     
+       __u8 unlinked:1;        
+       __u8 fake:1;            
+       __u8 renameAllowed:1;
+       __u8 unlinkAllowed:1;
+       __u8 serial;            
+       
+       int nDataChunks;        
+       __u32 fileSizeOrEquivalentObjectId;
+
+}yaffs_CheckpointObject;
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few
+ */
+
+typedef struct {
+       __u8 *buffer;
+       int line;       /* track from whence this buffer was allocated */
+       int maxLine;
+} yaffs_TempBuffer;
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_DeviceStruct {
+       struct list_head devList;
+       const char *name;
+
+       /* Entry parameters set up way early. Yaffs sets up the rest.*/
+       int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
+       int nChunksPerBlock;    /* does not need to be a power of 2 */
+       int nBytesPerSpare;     /* spare area size */
+       int startBlock;         /* Start block we're allowed to use */
+       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 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
+                                * the number of short op caches (don't use too many)
+                                */
+
+       int useHeaderFileSize;  /* Flag to determine if we should use file sizes from the header */
+
+       int useNANDECC;         /* Flag to decide whether or not to use NANDECC */
+
+       void *genericDevice;    /* Pointer to device context
+                                * 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,
+                                int chunkInNAND, const __u8 * data,
+                                const yaffs_Spare * spare);
+       int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
+                                 int chunkInNAND, __u8 * data,
+                                 yaffs_Spare * spare);
+       int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
+                                int blockInNAND);
+       int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
+
+#ifdef CONFIG_YAFFS_YAFFS2
+       int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
+                                        int chunkInNAND, const __u8 * data,
+                                        const yaffs_ExtendedTags * tags);
+       int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
+                                         int chunkInNAND, __u8 * data,
+                                         yaffs_ExtendedTags * tags);
+       int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
+       int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
+                              yaffs_BlockState * state, int *sequenceNumber);
+#endif
+
+       int isYaffs2;
+       
+       /* 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 
+                                * at compile time so we have to allocate it.
+                                */
+       void (*putSuperFunc) (struct super_block * sb);
+#endif
+
+       int isMounted;
+       
+       int isCheckpointed;
+
+
+       /* Stuff to support block offsetting to support start block zero */
+       int internalStartBlock;
+       int internalEndBlock;
+       int blockOffset;
+       int chunkOffset;
+       
+
+       /* Runtime checkpointing stuff */
+       int checkpointPageSequence;   /* running sequence number of checkpoint pages */
+       int checkpointByteCount;
+       int checkpointByteOffset;
+       __u8 *checkpointBuffer;
+       int checkpointOpenForWrite;
+       int blocksInCheckpoint;
+       int checkpointCurrentChunk;
+       int checkpointCurrentBlock;
+       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. 
+                                * Must be consistent with nChunksPerBlock.
+                                */
+
+       int nErasedBlocks;
+       int allocationBlock;    /* Current block being allocated off */
+       __u32 allocationPage;
+       int allocationBlockFinder;      /* Used to search for next allocation block */
+
+       /* Runtime state */
+       int nTnodesCreated;
+       yaffs_Tnode *freeTnodes;
+       int nFreeTnodes;
+       yaffs_TnodeList *allocatedTnodeList;
+
+       int isDoingGC;
+
+       int nObjectsCreated;
+       yaffs_Object *freeObjects;
+       int nFreeObjects;
+
+       yaffs_ObjectList *allocatedObjectList;
+
+       yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
+
+       int nFreeChunks;
+
+       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;
+       int nPageReads;
+       int nBlockErasures;
+       int nErasureFailures;
+       int nGCCopies;
+       int garbageCollections;
+       int passiveGarbageCollections;
+       int nRetriedWrites;
+       int nRetiredBlocks;
+       int eccFixed;
+       int eccUnfixed;
+       int tagsEccFixed;
+       int tagsEccUnfixed;
+       int nDeletions;
+       int nUnmarkedDeletions;
+       
+       int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
+
+       /* Special directories */
+       yaffs_Object *rootDir;
+       yaffs_Object *lostNFoundDir;
+
+       /* Buffer areas for storing data to recover from write failures TODO
+        *      __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;
+
+       yaffs_ChunkCache *srCache;
+       int srLastUse;
+
+       int cacheHits;
+
+       /* Stuff for background deletion and unlinked files.*/
+       yaffs_Object *unlinkedDir;      /* Directory where unlinked and deleted files live. */
+       yaffs_Object *deletedDir;       /* Directory where deleted objects are sent to disappear. */
+       yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
+       int nDeletedFiles;              /* Count of files awaiting deletion;*/
+       int nUnlinkedFiles;             /* Count of unlinked files. */
+       int nBackgroundDeletions;       /* Count of background deletions. */
+
+
+       yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
+       int maxTemp;
+       int unmanagedTempAllocations;
+       int unmanagedTempDeallocations;
+
+       /* yaffs2 runtime stuff */
+       unsigned sequenceNumber;        /* Sequence number of currently allocating block */
+       unsigned oldestDirtySequence;
+
+};
+
+typedef struct yaffs_DeviceStruct yaffs_Device;
+
+/* The static layout of bllock usage etc is stored in the super block header */
+typedef struct {
+        int StructType;
+       int version;
+       int checkpointStartBlock;
+       int checkpointEndBlock;
+       int startBlock;
+       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.
+ */
+typedef struct {
+        int structType;
+       int nErasedBlocks;
+       int allocationBlock;    /* Current block being allocated off */
+       __u32 allocationPage;
+       int nFreeChunks;
+
+       int nDeletedFiles;              /* Count of files awaiting deletion;*/
+       int nUnlinkedFiles;             /* Count of unlinked files. */
+       int nBackgroundDeletions;       /* Count of background deletions. */
+
+       /* yaffs2 runtime stuff */
+       unsigned sequenceNumber;        /* Sequence number of currently allocating block */
+       unsigned oldestDirtySequence;
+
+} yaffs_CheckpointDevice;
+
+
+typedef struct {
+    int structType;
+    __u32 magic;
+    __u32 version;
+    __u32 head;
+} yaffs_CheckpointValidity;
+
+/* Function to manipulate block info */
+static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
+{
+       if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+               T(YAFFS_TRACE_ERROR,
+                 (TSTR
+                  ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
+                  blk));
+               YBUG();
+       }
+       return &dev->blockInfo[blk - dev->internalStartBlock];
+}
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_GutsInitialise(yaffs_Device * dev);
+void yaffs_Deinitialise(yaffs_Device * dev);
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
+
+int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
+                      yaffs_Object * newDir, const YCHAR * newName);
+
+int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
+int yaffs_DeleteFile(yaffs_Object * obj);
+
+int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
+int yaffs_GetObjectFileLength(yaffs_Object * obj);
+int yaffs_GetObjectInode(yaffs_Object * obj);
+unsigned yaffs_GetObjectType(yaffs_Object * obj);
+int yaffs_GetObjectLinkCount(yaffs_Object * obj);
+
+int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
+int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
+
+/* File operations */
+int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
+                          int nBytes);
+int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
+                         int nBytes, int writeThrough);
+int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
+                             __u32 mode, __u32 uid, __u32 gid);
+int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
+
+/* Flushing and checkpointing */
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
+
+int yaffs_CheckpointSave(yaffs_Device *dev);
+int yaffs_CheckpointRestore(yaffs_Device *dev);
+
+/* Directory operations */
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
+                                  __u32 mode, __u32 uid, __u32 gid);
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
+int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
+                                  int (*fn) (yaffs_Object *));
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
+
+/* Link operations */
+yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
+                        yaffs_Object * equivalentObject);
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
+
+/* Symlink operations */
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
+                                __u32 mode, __u32 uid, __u32 gid,
+                                const YCHAR * alias);
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
+
+/* Special inodes (fifos, sockets and devices) */
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
+                                __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
+
+/* Special directories */
+yaffs_Object *yaffs_Root(yaffs_Device * dev);
+yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
+
+#ifdef CONFIG_YAFFS_WINCE
+/* CONFIG_YAFFS_WINCE special stuff */
+void yfsd_WinFileTimeNow(__u32 target[2]);
+#endif
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object * obj);
+#endif
+
+/* Debug dump  */
+int yaffs_DumpObject(yaffs_Object * obj);
+
+void yaffs_GutsTest(yaffs_Device * dev);
+
+/* A few useful functions */
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
+void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
+int yaffs_CheckFF(__u8 * buffer, int nBytes);
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.c
new file mode 100644 (file)
index 0000000..6e2a9de
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+const char *yaffs_mtdif_c_version =
+    "$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
+
+#include "yportenv.h"
+
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
+static struct nand_oobinfo yaffs_oobinfo = {
+       .useecc = 1,
+       .eccbytes = 6,
+       .eccpos = {8, 9, 10, 13, 14, 15}
+};
+
+static struct nand_oobinfo yaffs_noeccinfo = {
+       .useecc = 0,
+};
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
+{
+       oob[0] = spare->tagByte0;
+       oob[1] = spare->tagByte1;
+       oob[2] = spare->tagByte2;
+       oob[3] = spare->tagByte3;
+       oob[4] = spare->tagByte4;
+       oob[5] = spare->tagByte5 & 0x3f;
+       oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
+       oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
+       oob[6] = spare->tagByte6;
+       oob[7] = spare->tagByte7;
+}
+
+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];
+       spare->tagByte3 = oob[3];
+       spare->tagByte4 = oob[4];
+       spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
+       spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
+       spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
+       spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
+       spare->tagByte6 = oob[6];
+       spare->tagByte7 = oob[7];
+       spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
+
+       nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
+}
+#endif
+
+int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
+                            const __u8 * data, const yaffs_Spare * spare)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       struct mtd_oob_ops ops;
+#endif
+       size_t dummy;
+       int retval = 0;
+
+       loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       __u8 spareAsBytes[8]; /* OOB */
+
+       if (data && !spare)
+               retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
+                               &dummy, data);
+       else if (spare) {
+               if (dev->useNANDECC) {
+                       translate_spare2oob(spare, spareAsBytes);
+                       ops.mode = MTD_OOB_AUTO;
+                       ops.ooblen = 8; /* temp hack */
+               } else {
+                       ops.mode = MTD_OOB_RAW;
+                       ops.ooblen = YAFFS_BYTES_PER_SPARE;
+               }
+               ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+               ops.datbuf = (u8 *)data;
+               ops.ooboffs = 0;
+               ops.oobbuf = spareAsBytes;
+               retval = mtd->write_oob(mtd, addr, &ops);
+       }
+#else
+       __u8 *spareAsBytes = (__u8 *) spare;
+
+       if (data && spare) {
+               if (dev->useNANDECC)
+                       retval =
+                           mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                          &dummy, data, spareAsBytes,
+                                          &yaffs_oobinfo);
+               else
+                       retval =
+                           mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                          &dummy, data, spareAsBytes,
+                                          &yaffs_noeccinfo);
+       } else {
+               if (data)
+                       retval =
+                           mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+                                      data);
+               if (spare)
+                       retval =
+                           mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+                                          &dummy, spareAsBytes);
+       }
+#endif
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
+                             yaffs_Spare * spare)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       struct mtd_oob_ops ops;
+#endif
+       size_t dummy;
+       int retval = 0;
+
+       loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       __u8 spareAsBytes[8]; /* OOB */
+
+       if (data && !spare)
+               retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
+                               &dummy, data);
+       else if (spare) {
+               if (dev->useNANDECC) {
+                       ops.mode = MTD_OOB_AUTO;
+                       ops.ooblen = 8; /* temp hack */
+               } else {
+                       ops.mode = MTD_OOB_RAW;
+                       ops.ooblen = YAFFS_BYTES_PER_SPARE;
+               }
+               ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+               ops.datbuf = data;
+               ops.ooboffs = 0;
+               ops.oobbuf = spareAsBytes;
+               retval = mtd->read_oob(mtd, addr, &ops);
+               if (dev->useNANDECC)
+                       translate_oob2spare(spare, spareAsBytes);
+       }
+#else
+       __u8 *spareAsBytes = (__u8 *) spare;
+
+       if (data && spare) {
+               if (dev->useNANDECC) {  
+                       /* Careful, this call adds 2 ints */
+                       /* to the end of the spare data.  Calling function */
+                       /* should allocate enough memory for spare, */
+                       /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
+                       retval =
+                           mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                         &dummy, data, spareAsBytes,
+                                         &yaffs_oobinfo);
+               } else {
+                       retval =
+                           mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                         &dummy, data, spareAsBytes,
+                                         &yaffs_noeccinfo);
+               }
+       } else {
+               if (data)
+                       retval =
+                           mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+                                     data);
+               if (spare)
+                       retval =
+                           mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+                                         &dummy, spareAsBytes);
+       }
+#endif
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+       __u32 addr =
+           ((loff_t) blockNumber) * dev->nDataBytesPerChunk
+               * dev->nChunksPerBlock;
+       struct erase_info ei;
+       int retval = 0;
+
+       ei.mtd = mtd;
+       ei.addr = addr;
+       ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
+       ei.time = 1000;
+       ei.retries = 2;
+       ei.callback = NULL;
+       ei.priv = (u_long) dev;
+
+       /* Todo finish off the ei if required */
+
+       sema_init(&dev->sem, 0);
+
+       retval = mtd->erase(mtd, &ei);
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+int nandmtd_InitialiseNAND(yaffs_Device * dev)
+{
+       return YAFFS_OK;
+}
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif.h
new file mode 100644 (file)
index 0000000..f75e08c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF_H__
+#define __YAFFS_MTDIF_H__
+
+#include "yaffs_guts.h"
+
+int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
+                            const __u8 * data, const yaffs_Spare * spare);
+int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
+                             yaffs_Spare * spare);
+int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
+int nandmtd_InitialiseNAND(yaffs_Device * dev);
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1-compat.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1-compat.c
new file mode 100644 (file)
index 0000000..ebf6647
--- /dev/null
@@ -0,0 +1,434 @@
+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 <ian@brightstareng.com>)
+       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 <ian@brightstareng.com>
+To: David Goodenough <david.goodenough@linkchoose.co.uk>
+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 <alyf@alyf.net>,
+ Charles Manning <manningc2@actrix.gen.nz>
+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: 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);
+
+       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 --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.c
new file mode 100644 (file)
index 0000000..15b5a97
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * 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 --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif1.h
new file mode 100644 (file)
index 0000000..c4f6197
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.c
new file mode 100644 (file)
index 0000000..d927c76
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* 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 $";
+
+#include "yportenv.h"
+
+
+#include "yaffs_mtdif2.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+
+#include "yaffs_packedtags2.h"
+
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
+                                     const __u8 * data,
+                                     const yaffs_ExtendedTags * tags)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       struct mtd_oob_ops ops;
+#else
+       size_t dummy;
+#endif
+       int retval = 0;
+
+       loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+
+       yaffs_PackedTags2 pt;
+
+       T(YAFFS_TRACE_MTD,
+         (TSTR
+          ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
+           TENDSTR), chunkInNAND, data, tags));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       if (tags)
+               yaffs_PackTags2(&pt, tags);
+       else
+               BUG(); /* both tags and data should always be present */
+
+       if (data) {
+               ops.mode = MTD_OOB_AUTO;
+               ops.ooblen = sizeof(pt);
+               ops.len = dev->nDataBytesPerChunk;
+               ops.ooboffs = 0;
+               ops.datbuf = (__u8 *)data;
+               ops.oobbuf = (void *)&pt;
+               retval = mtd->write_oob(mtd, addr, &ops);
+       } else
+               BUG(); /* both tags and data should always be present */
+#else
+       if (tags) {
+               yaffs_PackTags2(&pt, tags);
+       }
+
+       if (data && tags) {
+               if (dev->useNANDECC)
+                       retval =
+                           mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                          &dummy, data, (__u8 *) & pt, NULL);
+               else
+                       retval =
+                           mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                          &dummy, data, (__u8 *) & pt, NULL);
+       } else {
+               if (data)
+                       retval =
+                           mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+                                      data);
+               if (tags)
+                       retval =
+                           mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
+                                          (__u8 *) & pt);
+
+       }
+#endif
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+                                      __u8 * data, yaffs_ExtendedTags * tags)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       struct mtd_oob_ops ops;
+#endif
+       size_t dummy;
+       int retval = 0;
+
+       loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+
+       yaffs_PackedTags2 pt;
+
+       T(YAFFS_TRACE_MTD,
+         (TSTR
+          ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
+           TENDSTR), chunkInNAND, data, tags));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
+       if (data && !tags)
+               retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
+                               &dummy, data);
+       else if (tags) {
+               ops.mode = MTD_OOB_AUTO;
+               ops.ooblen = sizeof(pt);
+               ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
+               ops.ooboffs = 0;
+               ops.datbuf = data;
+               ops.oobbuf = dev->spareBuffer;
+               retval = mtd->read_oob(mtd, addr, &ops);
+       }
+#else
+       if (data && tags) {
+               if (dev->useNANDECC) {
+                       retval =
+                           mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                         &dummy, data, dev->spareBuffer,
+                                         NULL);
+               } else {
+                       retval =
+                           mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+                                         &dummy, data, dev->spareBuffer,
+                                         NULL);
+               }
+       } else {
+               if (data)
+                       retval =
+                           mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+                                     data);
+               if (tags)
+                       retval =
+                           mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
+                                         dev->spareBuffer);
+       }
+#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;
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+       int retval;
+       T(YAFFS_TRACE_MTD,
+         (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
+
+       retval =
+           mtd->block_markbad(mtd,
+                              blockNo * dev->nChunksPerBlock *
+                              dev->nDataBytesPerChunk);
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+
+}
+
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+                           yaffs_BlockState * state, int *sequenceNumber)
+{
+       struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+       int retval;
+
+       T(YAFFS_TRACE_MTD,
+         (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
+       retval =
+           mtd->block_isbad(mtd,
+                            blockNo * dev->nChunksPerBlock *
+                            dev->nDataBytesPerChunk);
+
+       if (retval) {
+               T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
+
+               *state = YAFFS_BLOCK_STATE_DEAD;
+               *sequenceNumber = 0;
+       } else {
+               yaffs_ExtendedTags t;
+               nandmtd2_ReadChunkWithTagsFromNAND(dev,
+                                                  blockNo *
+                                                  dev->nChunksPerBlock, NULL,
+                                                  &t);
+
+               if (t.chunkUsed) {
+                       *sequenceNumber = t.sequenceNumber;
+                       *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+               } else {
+                       *sequenceNumber = 0;
+                       *state = YAFFS_BLOCK_STATE_EMPTY;
+               }
+       }
+       T(YAFFS_TRACE_MTD,
+         (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
+          *state));
+
+       if (retval == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_mtdif2.h
new file mode 100644 (file)
index 0000000..e70d751
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF2_H__
+#define __YAFFS_MTDIF2_H__
+
+#include "yaffs_guts.h"
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
+                                     const __u8 * data,
+                                     const yaffs_ExtendedTags * tags);
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+                                      __u8 * data, yaffs_ExtendedTags * tags);
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+                           yaffs_BlockState * state, int *sequenceNumber);
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.c
new file mode 100644 (file)
index 0000000..c33483c
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+const char *yaffs_nand_c_version =
+    "$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
+
+#include "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_tagsvalidity.h"
+
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+                                          __u8 * buffer,
+                                          yaffs_ExtendedTags * tags)
+{
+       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;
+
+       if (dev->readChunkWithTagsFromNAND)
+               result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
+                                                     tags);
+       else
+               result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
+                                                                       realignedChunkInNAND,
+                                                                       buffer,
+                                                                       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;
+}
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
+                                                  int chunkInNAND,
+                                                  const __u8 * buffer,
+                                                  yaffs_ExtendedTags * tags)
+{
+       chunkInNAND -= dev->chunkOffset;
+
+       
+       if (tags) {
+               tags->sequenceNumber = dev->sequenceNumber;
+               tags->chunkUsed = 1;
+               if (!yaffs_ValidateTags(tags)) {
+                       T(YAFFS_TRACE_ERROR,
+                         (TSTR("Writing uninitialised tags" TENDSTR)));
+                       YBUG();
+               }
+               T(YAFFS_TRACE_WRITE,
+                 (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
+                  tags->objectId, tags->chunkId));
+       } else {
+               T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
+               YBUG();
+       }
+
+       if (dev->writeChunkWithTagsToNAND)
+               return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
+                                                    tags);
+       else
+               return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
+                                                                      chunkInNAND,
+                                                                      buffer,
+                                                                      tags);
+}
+
+int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
+{
+       blockNo -= dev->blockOffset;
+
+;
+       if (dev->markNANDBlockBad)
+               return dev->markNANDBlockBad(dev, blockNo);
+       else
+               return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
+}
+
+int yaffs_QueryInitialBlockState(yaffs_Device * dev,
+                                                int blockNo,
+                                                yaffs_BlockState * state,
+                                                unsigned *sequenceNumber)
+{
+       blockNo -= dev->blockOffset;
+
+       if (dev->queryNANDBlock)
+               return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
+       else
+               return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
+                                                            state,
+                                                            sequenceNumber);
+}
+
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+                                 int blockInNAND)
+{
+       int result;
+
+       blockInNAND -= dev->blockOffset;
+
+
+       dev->nBlockErasures++;
+       result = dev->eraseBlockInNAND(dev, blockInNAND);
+
+       return result;
+}
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
+{
+       return dev->initialiseNAND(dev);
+}
+
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nand.h
new file mode 100644 (file)
index 0000000..8ed1a2d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
+                                          __u8 * buffer,
+                                          yaffs_ExtendedTags * tags);
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
+                                                  int chunkInNAND,
+                                                  const __u8 * buffer,
+                                                  yaffs_ExtendedTags * tags);
+
+int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
+
+int yaffs_QueryInitialBlockState(yaffs_Device * dev,
+                                                int blockNo,
+                                                yaffs_BlockState * state,
+                                                unsigned *sequenceNumber);
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+                                 int blockInNAND);
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+
+#endif
+
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nandemul2k.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_nandemul2k.h
new file mode 100644 (file)
index 0000000..13520e1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* Interface to emulated NAND functions (2k page size) */
+
+#ifndef __YAFFS_NANDEMUL2K_H__
+#define __YAFFS_NANDEMUL2K_H__
+
+#include "yaffs_guts.h"
+
+int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+                                       int chunkInNAND, const __u8 * data,
+                                       yaffs_ExtendedTags * tags);
+int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
+                                        int chunkInNAND, __u8 * data,
+                                        yaffs_ExtendedTags * tags);
+int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+                             yaffs_BlockState * state, int *sequenceNumber);
+int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+                               int blockInNAND);
+int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+int nandemul2k_GetBytesPerChunk(void);
+int nandemul2k_GetChunksPerBlock(void);
+int nandemul2k_GetNumberOfBlocks(void);
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.c
new file mode 100644 (file)
index 0000000..f480bf1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_packedtags1.h"
+#include "yportenv.h"
+
+void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
+{
+       pt->chunkId = t->chunkId;
+       pt->serialNumber = t->serialNumber;
+       pt->byteCount = t->byteCount;
+       pt->objectId = t->objectId;
+       pt->ecc = 0;
+       pt->deleted = (t->chunkDeleted) ? 0 : 1;
+       pt->unusedStuff = 0;
+       pt->shouldBeFF = 0xFFFFFFFF;
+
+}
+
+void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
+{
+       static const __u8 allFF[] =
+           { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff };
+
+       if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
+               t->blockBad = 0;
+               if (pt->shouldBeFF != 0xFFFFFFFF) {
+                       t->blockBad = 1;
+               }
+               t->chunkUsed = 1;
+               t->objectId = pt->objectId;
+               t->chunkId = pt->chunkId;
+               t->byteCount = pt->byteCount;
+               t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+               t->chunkDeleted = (pt->deleted) ? 0 : 1;
+               t->serialNumber = pt->serialNumber;
+       } else {
+               memset(t, 0, sizeof(yaffs_ExtendedTags));
+
+       }
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags1.h
new file mode 100644 (file)
index 0000000..627b2f8
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
+
+#ifndef __YAFFS_PACKEDTAGS1_H__
+#define __YAFFS_PACKEDTAGS1_H__
+
+#include "yaffs_guts.h"
+
+typedef struct {
+       unsigned chunkId:20;
+       unsigned serialNumber:2;
+       unsigned byteCount:10;
+       unsigned objectId:18;
+       unsigned ecc:12;
+       unsigned deleted:1;
+       unsigned unusedStuff:1;
+       unsigned shouldBeFF;
+
+} yaffs_PackedTags1;
+
+void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
+void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.c
new file mode 100644 (file)
index 0000000..6860876
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_tagsvalidity.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunkId */
+
+#define EXTRA_HEADER_INFO_FLAG 0x80000000
+#define EXTRA_SHRINK_FLAG      0x40000000
+#define EXTRA_SHADOWS_FLAG     0x20000000
+#define EXTRA_SPARE_FLAGS      0x10000000
+
+#define ALL_EXTRA_FLAGS                0xF0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK  ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
+
+static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
+{
+       T(YAFFS_TRACE_MTD,
+         (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
+          pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
+          pt->t.sequenceNumber));
+}
+
+static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
+{
+       T(YAFFS_TRACE_MTD,
+         (TSTR
+          ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
+           "%d del %d ser %d seq %d"
+           TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
+          t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
+          t->sequenceNumber));
+
+}
+
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
+{
+       pt->t.chunkId = t->chunkId;
+       pt->t.sequenceNumber = t->sequenceNumber;
+       pt->t.byteCount = t->byteCount;
+       pt->t.objectId = t->objectId;
+
+       if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
+               /* Store the extra header info instead */
+               /* We save the parent object in the chunkId */
+               pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
+                       | t->extraParentObjectId;
+               if (t->extraIsShrinkHeader) {
+                       pt->t.chunkId |= EXTRA_SHRINK_FLAG;
+               }
+               if (t->extraShadows) {
+                       pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
+               }
+
+               pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+               pt->t.objectId |=
+                   (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
+
+               if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
+                       pt->t.byteCount = t->extraEquivalentObjectId;
+               } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
+                       pt->t.byteCount = t->extraFileLength;
+               } else {
+                       pt->t.byteCount = 0;
+               }
+       }
+
+       yaffs_DumpPackedTags2(pt);
+       yaffs_DumpTags2(t);
+
+#ifndef YAFFS_IGNORE_TAGS_ECC
+       {
+               yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+                                       sizeof(yaffs_PackedTags2TagsPart),
+                                       &pt->ecc);
+       }
+#endif
+}
+
+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
+               {
+                       t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+               }
+#else
+               {
+                       yaffs_ECCOther ecc;
+                       int result;
+                       yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+                                               sizeof
+                                               (yaffs_PackedTags2TagsPart),
+                                               &ecc);
+                       result =
+                           yaffs_ECCCorrectOther((unsigned char *)&pt->t,
+                                                 sizeof
+                                                 (yaffs_PackedTags2TagsPart),
+                                                 &pt->ecc, &ecc);
+                       switch(result){
+                               case 0: 
+                                       t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; 
+                                       break;
+                               case 1: 
+                                       t->eccResult = YAFFS_ECC_RESULT_FIXED;
+                                       break;
+                               case -1:
+                                       t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
+                                       break;
+                               default:
+                                       t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
+                       }
+               }
+#endif
+               t->blockBad = 0;
+               t->chunkUsed = 1;
+               t->objectId = pt->t.objectId;
+               t->chunkId = pt->t.chunkId;
+               t->byteCount = pt->t.byteCount;
+               t->chunkDeleted = 0;
+               t->serialNumber = 0;
+               t->sequenceNumber = pt->t.sequenceNumber;
+
+               /* Do extra header info stuff */
+
+               if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
+                       t->chunkId = 0;
+                       t->byteCount = 0;
+
+                       t->extraHeaderInfoAvailable = 1;
+                       t->extraParentObjectId =
+                           pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
+                       t->extraIsShrinkHeader =
+                           (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
+                       t->extraShadows =
+                           (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
+                       t->extraObjectType =
+                           pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
+                       t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+
+                       if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
+                               t->extraEquivalentObjectId = pt->t.byteCount;
+                       } else {
+                               t->extraFileLength = pt->t.byteCount;
+                       }
+               }
+       }
+
+       yaffs_DumpPackedTags2(pt);
+       yaffs_DumpTags2(t);
+
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_packedtags2.h
new file mode 100644 (file)
index 0000000..7c4a72c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+typedef struct {
+       unsigned sequenceNumber;
+       unsigned objectId;
+       unsigned chunkId;
+       unsigned byteCount;
+} yaffs_PackedTags2TagsPart;
+
+typedef struct {
+       yaffs_PackedTags2TagsPart t;
+       yaffs_ECCOther ecc;
+} yaffs_PackedTags2;
+
+void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
+void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.c
new file mode 100644 (file)
index 0000000..0429838
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "yportenv.h"
+//#include <linux/string.h>
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) {              \
+       long i = (n) / sizeof (TYPE);                   \
+       register TYPE *pi = (TYPE *) (parmi);           \
+       register TYPE *pj = (TYPE *) (parmj);           \
+       do {                                            \
+               register TYPE   t = *pi;                \
+               *pi++ = *pj;                            \
+               *pj++ = t;                              \
+        } while (--i > 0);                             \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+       es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+       if (swaptype <= 1) 
+               swapcode(long, a, b, n)
+       else
+               swapcode(char, a, b, n)
+}
+
+#define swap(a, b)                                     \
+       if (swaptype == 0) {                            \
+               long t = *(long *)(a);                  \
+               *(long *)(a) = *(long *)(b);            \
+               *(long *)(b) = t;                       \
+       } else                                          \
+               swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n)       if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+       return cmp(a, b) < 0 ?
+              (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+              :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+yaffs_qsort(void *aa, size_t n, size_t es,
+       int (*cmp)(const void *, const void *))
+{
+       char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+       int d, r, swaptype, swap_cnt;
+       register char *a = aa;
+
+loop:  SWAPINIT(a, es);
+       swap_cnt = 0;
+       if (n < 7) {
+               for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+                       for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+       pm = (char *)a + (n / 2) * es;
+       if (n > 7) {
+               pl = (char *)a;
+               pn = (char *)a + (n - 1) * es;
+               if (n > 40) {
+                       d = (n / 8) * es;
+                       pl = med3(pl, pl + d, pl + 2 * d, cmp);
+                       pm = med3(pm - d, pm, pm + d, cmp);
+                       pn = med3(pn - 2 * d, pn - d, pn, cmp);
+               }
+               pm = med3(pl, pm, pn, cmp);
+       }
+       swap(a, pm);
+       pa = pb = (char *)a + es;
+
+       pc = pd = (char *)a + (n - 1) * es;
+       for (;;) {
+               while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+                       if (r == 0) {
+                               swap_cnt = 1;
+                               swap(pa, pb);
+                               pa += es;
+                       }
+                       pb += es;
+               }
+               while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+                       if (r == 0) {
+                               swap_cnt = 1;
+                               swap(pc, pd);
+                               pd -= es;
+                       }
+                       pc -= es;
+               }
+               if (pb > pc)
+                       break;
+               swap(pb, pc);
+               swap_cnt = 1;
+               pb += es;
+               pc -= es;
+       }
+       if (swap_cnt == 0) {  /* Switch to insertion sort */
+               for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+                       for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; 
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+
+       pn = (char *)a + n * es;
+       r = min(pa - (char *)a, pb - pa);
+       vecswap(a, pb - r, r);
+       r = min((long)(pd - pc), (long)(pn - pd - es));
+       vecswap(pb, pn - r, r);
+       if ((r = pb - pa) > es)
+               yaffs_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);*/
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_qsort.h
new file mode 100644 (file)
index 0000000..3ec7397
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_QSORT_H__
+#define __YAFFS_QSORT_H__
+
+extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
+                   int (*cmp)(const void *, const void *));
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.c
new file mode 100644 (file)
index 0000000..7622b1a
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+
+static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+                                    const __u8 * data,
+                                    const yaffs_Spare * spare);
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+                                   const yaffs_Spare * spare);
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
+#endif
+
+static const char yaffs_countBitsTable[256] = {
+       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+int yaffs_CountBits(__u8 x)
+{
+       int retVal;
+       retVal = yaffs_countBitsTable[x];
+       return retVal;
+}
+
+/********** Tags ECC calculations  *********/
+
+void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
+{
+       yaffs_ECCCalculate(data, spare->ecc1);
+       yaffs_ECCCalculate(&data[256], spare->ecc2);
+}
+
+void yaffs_CalcTagsECC(yaffs_Tags * tags)
+{
+       /* Calculate an ecc */
+
+       unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+       unsigned i, j;
+       unsigned ecc = 0;
+       unsigned bit = 0;
+
+       tags->ecc = 0;
+
+       for (i = 0; i < 8; i++) {
+               for (j = 1; j & 0xff; j <<= 1) {
+                       bit++;
+                       if (b[i] & j) {
+                               ecc ^= bit;
+                       }
+               }
+       }
+
+       tags->ecc = ecc;
+
+}
+
+int yaffs_CheckECCOnTags(yaffs_Tags * tags)
+{
+       unsigned ecc = tags->ecc;
+
+       yaffs_CalcTagsECC(tags);
+
+       ecc ^= tags->ecc;
+
+       if (ecc && ecc <= 64) {
+               /* TODO: Handle the failure better. Retire? */
+               unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+
+               ecc--;
+
+               b[ecc / 8] ^= (1 << (ecc & 7));
+
+               /* Now recvalc the ecc */
+               yaffs_CalcTagsECC(tags);
+
+               return 1;       /* recovered error */
+       } else if (ecc) {
+               /* Wierd ecc failure value */
+               /* TODO Need to do somethiong here */
+               return -1;      /* unrecovered error */
+       }
+
+       return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_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];
+}
+
+static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
+                                  yaffs_Tags * tagsPtr)
+{
+       yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
+       int result;
+
+       tu->asBytes[0] = sparePtr->tagByte0;
+       tu->asBytes[1] = sparePtr->tagByte1;
+       tu->asBytes[2] = sparePtr->tagByte2;
+       tu->asBytes[3] = sparePtr->tagByte3;
+       tu->asBytes[4] = sparePtr->tagByte4;
+       tu->asBytes[5] = sparePtr->tagByte5;
+       tu->asBytes[6] = sparePtr->tagByte6;
+       tu->asBytes[7] = sparePtr->tagByte7;
+
+       result = yaffs_CheckECCOnTags(tagsPtr);
+       if (result > 0) {
+               dev->tagsEccFixed++;
+       } else if (result < 0) {
+               dev->tagsEccUnfixed++;
+       }
+}
+
+static void yaffs_SpareInitialise(yaffs_Spare * spare)
+{
+       memset(spare, 0xFF, sizeof(yaffs_Spare));
+}
+
+static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
+                                 int chunkInNAND, const __u8 * data,
+                                 yaffs_Spare * spare)
+{
+       if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
+               T(YAFFS_TRACE_ERROR,
+                 (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
+                  chunkInNAND));
+               return YAFFS_FAIL;
+       }
+
+       dev->nPageWrites++;
+       return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
+}
+
+static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
+                                  int chunkInNAND,
+                                  __u8 * data,
+                                  yaffs_Spare * spare,
+                                  yaffs_ECCResult * eccResult,
+                                  int doErrorCorrection)
+{
+       int retVal;
+       yaffs_Spare localSpare;
+
+       dev->nPageReads++;
+
+       if (!spare && data) {
+               /* If we don't have a real spare, then we use a local one. */
+               /* Need this for the calculation of the ecc */
+               spare = &localSpare;
+       }
+
+       if (!dev->useNANDECC) {
+               retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
+               if (data && doErrorCorrection) {
+                       /* Do ECC correction */
+                       /* Todo handle any errors */
+                       int eccResult1, eccResult2;
+                       __u8 calcEcc[3];
+
+                       yaffs_ECCCalculate(data, calcEcc);
+                       eccResult1 =
+                           yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
+                       yaffs_ECCCalculate(&data[256], calcEcc);
+                       eccResult2 =
+                           yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
+
+                       if (eccResult1 > 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>yaffs ecc error fix performed on chunk %d:0"
+                                   TENDSTR), chunkInNAND));
+                               dev->eccFixed++;
+                       } else if (eccResult1 < 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>yaffs ecc error unfixed on chunk %d:0"
+                                   TENDSTR), chunkInNAND));
+                               dev->eccUnfixed++;
+                       }
+
+                       if (eccResult2 > 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>yaffs ecc error fix performed on chunk %d:1"
+                                   TENDSTR), chunkInNAND));
+                               dev->eccFixed++;
+                       } else if (eccResult2 < 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>yaffs ecc error unfixed on chunk %d:1"
+                                   TENDSTR), chunkInNAND));
+                               dev->eccUnfixed++;
+                       }
+
+                       if (eccResult1 || eccResult2) {
+                               /* We had a data problem on this page */
+                               yaffs_HandleReadDataError(dev, chunkInNAND);
+                       }
+
+                       if (eccResult1 < 0 || eccResult2 < 0)
+                               *eccResult = YAFFS_ECC_RESULT_UNFIXED;
+                       else if (eccResult1 > 0 || eccResult2 > 0)
+                               *eccResult = YAFFS_ECC_RESULT_FIXED;
+                       else
+                               *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+               }
+       } else {
+               /* Must allocate enough memory for spare+2*sizeof(int) */
+               /* for ecc results from device. */
+               struct yaffs_NANDSpare nspare;
+               retVal =
+                   dev->readChunkFromNAND(dev, chunkInNAND, data,
+                                          (yaffs_Spare *) & nspare);
+               memcpy(spare, &nspare, sizeof(yaffs_Spare));
+               if (data && doErrorCorrection) {
+                       if (nspare.eccres1 > 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>mtd ecc error fix performed on chunk %d:0"
+                                   TENDSTR), chunkInNAND));
+                       } else if (nspare.eccres1 < 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>mtd ecc error unfixed on chunk %d:0"
+                                   TENDSTR), chunkInNAND));
+                       }
+
+                       if (nspare.eccres2 > 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>mtd ecc error fix performed on chunk %d:1"
+                                   TENDSTR), chunkInNAND));
+                       } else if (nspare.eccres2 < 0) {
+                               T(YAFFS_TRACE_ERROR,
+                                 (TSTR
+                                  ("**>>mtd ecc error unfixed on chunk %d:1"
+                                   TENDSTR), chunkInNAND));
+                       }
+
+                       if (nspare.eccres1 || nspare.eccres2) {
+                               /* We had a data problem on this page */
+                               yaffs_HandleReadDataError(dev, chunkInNAND);
+                       }
+
+                       if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
+                               *eccResult = YAFFS_ECC_RESULT_UNFIXED;
+                       else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
+                               *eccResult = YAFFS_ECC_RESULT_FIXED;
+                       else
+                               *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+
+               }
+       }
+       return retVal;
+}
+
+#ifdef NOTYET
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+                                 int chunkInNAND)
+{
+
+       static int init = 0;
+       static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
+       static __u8 data[YAFFS_BYTES_PER_CHUNK];
+       /* Might as well always allocate the larger size for */
+       /* dev->useNANDECC == true; */
+       static __u8 spare[sizeof(struct yaffs_NANDSpare)];
+
+       dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
+
+       if (!init) {
+               memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
+               init = 1;
+       }
+
+       if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
+               return YAFFS_FAIL;
+       if (memcmp(cmpbuf, spare, 16))
+               return YAFFS_FAIL;
+
+       return YAFFS_OK;
+
+}
+#endif
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
+{
+       int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+       /* Mark the block for retirement */
+       yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+         (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
+
+       /* TODO:
+        * Just do a garbage collection on the affected block
+        * then retire the block
+        * NB recursion
+        */
+}
+
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
+{
+}
+
+static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
+                                    const __u8 * data,
+                                    const yaffs_Spare * spare)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
+                                   const yaffs_Spare * spare)
+{
+}
+
+static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
+{
+       int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+       /* Mark the block for retirement */
+       yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+       /* Delete the chunk */
+       yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+}
+
+static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
+                              const yaffs_Spare * s0, const yaffs_Spare * s1)
+{
+
+       if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
+           s0->tagByte0 != s1->tagByte0 ||
+           s0->tagByte1 != s1->tagByte1 ||
+           s0->tagByte2 != s1->tagByte2 ||
+           s0->tagByte3 != s1->tagByte3 ||
+           s0->tagByte4 != s1->tagByte4 ||
+           s0->tagByte5 != s1->tagByte5 ||
+           s0->tagByte6 != s1->tagByte6 ||
+           s0->tagByte7 != s1->tagByte7 ||
+           s0->ecc1[0] != s1->ecc1[0] ||
+           s0->ecc1[1] != s1->ecc1[1] ||
+           s0->ecc1[2] != s1->ecc1[2] ||
+           s0->ecc2[0] != s1->ecc2[0] ||
+           s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
+               return 0;
+       }
+
+       return 1;
+}
+#endif                         /* NOTYET */
+
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
+                                                   int chunkInNAND,
+                                                   const __u8 * data,
+                                                   const yaffs_ExtendedTags *
+                                                   eTags)
+{
+       yaffs_Spare spare;
+       yaffs_Tags tags;
+
+       yaffs_SpareInitialise(&spare);
+
+       if (eTags->chunkDeleted) {
+               spare.pageStatus = 0;
+       } else {
+               tags.objectId = eTags->objectId;
+               tags.chunkId = eTags->chunkId;
+               tags.byteCount = eTags->byteCount;
+               tags.serialNumber = eTags->serialNumber;
+
+               if (!dev->useNANDECC && data) {
+                       yaffs_CalcECC(data, &spare);
+               }
+               yaffs_LoadTagsIntoSpare(&spare, &tags);
+
+       }
+
+       return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
+}
+
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
+                                                    int chunkInNAND,
+                                                    __u8 * data,
+                                                    yaffs_ExtendedTags * eTags)
+{
+
+       yaffs_Spare spare;
+       yaffs_Tags tags;
+       yaffs_ECCResult eccResult;
+
+       static yaffs_Spare spareFF;
+       static int init;
+
+       if (!init) {
+               memset(&spareFF, 0xFF, sizeof(spareFF));
+               init = 1;
+       }
+
+       if (yaffs_ReadChunkFromNAND
+           (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
+               /* eTags may be NULL */
+               if (eTags) {
+
+                       int deleted =
+                           (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
+
+                       eTags->chunkDeleted = deleted;
+                       eTags->eccResult = eccResult;
+                       eTags->blockBad = 0;    /* We're reading it */
+                       /* therefore it is not a bad block */
+                       eTags->chunkUsed =
+                           (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
+                            0) ? 1 : 0;
+
+                       if (eTags->chunkUsed) {
+                               yaffs_GetTagsFromSpare(dev, &spare, &tags);
+
+                               eTags->objectId = tags.objectId;
+                               eTags->chunkId = tags.chunkId;
+                               eTags->byteCount = tags.byteCount;
+                               eTags->serialNumber = tags.serialNumber;
+                       }
+               }
+
+               return YAFFS_OK;
+       } else {
+               return YAFFS_FAIL;
+       }
+}
+
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+                                           int blockInNAND)
+{
+
+       yaffs_Spare spare;
+
+       memset(&spare, 0xff, sizeof(yaffs_Spare));
+
+       spare.blockStatus = 'Y';
+
+       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
+                              &spare);
+       yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
+                              NULL, &spare);
+
+       return YAFFS_OK;
+
+}
+
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+                                         int blockNo, yaffs_BlockState *
+                                         state,
+                                         int *sequenceNumber)
+{
+
+       yaffs_Spare spare0, spare1;
+       static yaffs_Spare spareFF;
+       static int init;
+       yaffs_ECCResult dummy;
+
+       if (!init) {
+               memset(&spareFF, 0xFF, sizeof(spareFF));
+               init = 1;
+       }
+
+       *sequenceNumber = 0;
+
+       yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
+                               &spare0, &dummy, 1);
+       yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
+                               &spare1, &dummy, 1);
+
+       if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
+               *state = YAFFS_BLOCK_STATE_DEAD;
+       else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
+               *state = YAFFS_BLOCK_STATE_EMPTY;
+       else
+               *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+
+       return YAFFS_OK;
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagscompat.h
new file mode 100644 (file)
index 0000000..c1edb6a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+#include "yaffs_guts.h"
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
+                                                   int chunkInNAND,
+                                                   const __u8 * data,
+                                                   const yaffs_ExtendedTags *
+                                                   tags);
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
+                                                    int chunkInNAND,
+                                                    __u8 * data,
+                                                    yaffs_ExtendedTags *
+                                                    tags);
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+                                           int blockNo);
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+                                         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 --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.c b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.c
new file mode 100644 (file)
index 0000000..9e0bd1c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "yaffs_tagsvalidity.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
+{
+       memset(tags, 0, sizeof(yaffs_ExtendedTags));
+       tags->validMarker0 = 0xAAAAAAAA;
+       tags->validMarker1 = 0x55555555;
+}
+
+int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
+{
+       return (tags->validMarker0 == 0xAAAAAAAA &&
+               tags->validMarker1 == 0x55555555);
+
+}
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffs_tagsvalidity.h
new file mode 100644 (file)
index 0000000..ba56727
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_TAGS_VALIDITY_H__
+#define __YAFFS_TAGS_VALIDITY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
+int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffsinterface.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yaffsinterface.h
new file mode 100644 (file)
index 0000000..0cfdfcf
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFSINTERFACE_H__
+#define __YAFFSINTERFACE_H__
+
+int yaffs_Initialise(unsigned nBlocks);
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yportenv.h b/target/linux/generic-2.6/files-2.6.25/fs/yaffs2/yportenv.h
new file mode 100644 (file)
index 0000000..8b80c6d
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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 Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+#if defined CONFIG_YAFFS_WINCE
+
+#include "ywinceenv.h"
+
+#elif  defined __KERNEL__
+
+#include "moduleconfig.h"
+
+/* Linux kernel */
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#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)
+
+#define Y_INLINE inline
+
+#define YAFFS_LOSTNFOUND_NAME          "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX                "obj"
+
+/* #define YPRINTF(x) printk x */
+#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
+#define YFREE(x)   kfree(x)
+#define YMALLOC_ALT(x) vmalloc(x)
+#define YFREE_ALT(x)   vfree(x)
+#define YMALLOC_DMA(x) YMALLOC(x)
+
+// KR - added for use in scan so processes aren't blocked indefinitely.
+#define YYIELD() schedule()
+
+#define YAFFS_ROOT_MODE                        0666
+#define YAFFS_LOSTNFOUND_MODE          0666
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
+#define Y_TIME_CONVERT(x) (x).tv_sec
+#else
+#define Y_CURRENT_TIME CURRENT_TIME
+#define Y_TIME_CONVERT(x) (x)
+#endif
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#define TENDSTR "\n"
+#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 */
+#include "ydirectenv.h"
+
+#elif defined CONFIG_YAFFS_UTIL
+
+/* Stuff for YAFFS utilities */
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "devextras.h"
+
+#define YMALLOC(x) malloc(x)
+#define YFREE(x)   free(x)
+#define YMALLOC_ALT(x) malloc(x)
+#define YFREE_ALT(x) free(x)
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x)     x
+#define yaffs_strcpy(a,b)    strcpy(a,b)
+#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
+#define yaffs_strlen(s)             strlen(s)
+#define yaffs_sprintf       sprintf
+#define yaffs_toupper(a)     toupper(a)
+
+#define Y_INLINE inline
+
+/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
+/* #define YALERT(s) YINFO(s) */
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+
+#define YAFFS_LOSTNFOUND_NAME          "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX                "obj"
+/* #define YPRINTF(x) printf x */
+
+#define YAFFS_ROOT_MODE                                0666
+#define YAFFS_LOSTNFOUND_MODE          0666
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#else
+/* Should have specified a configuration type */
+#error Unknown configuration
+
+#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.
+ */
+#define YAFFS_TRACE_OS                 0x00000002
+#define YAFFS_TRACE_ALLOCATE           0x00000004
+#define YAFFS_TRACE_SCAN               0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS         0x00000010
+#define YAFFS_TRACE_ERASE              0x00000020
+#define YAFFS_TRACE_GC                 0x00000040
+#define YAFFS_TRACE_WRITE              0x00000080
+#define YAFFS_TRACE_TRACING            0x00000100
+#define YAFFS_TRACE_DELETION           0x00000200
+#define YAFFS_TRACE_BUFFERS            0x00000400
+#define YAFFS_TRACE_NANDACCESS         0x00000800
+#define YAFFS_TRACE_GC_DETAIL          0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG         0x00002000
+#define YAFFS_TRACE_MTD                        0x00004000
+#define YAFFS_TRACE_CHECKPOINT         0x00008000
+
+#define YAFFS_TRACE_VERIFY             0x00010000
+#define YAFFS_TRACE_VERIFY_NAND                0x00020000
+#define YAFFS_TRACE_VERIFY_FULL                0x00040000
+#define YAFFS_TRACE_VERIFY_ALL         0x000F0000
+
+
+#define YAFFS_TRACE_ERROR              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)
+
+#ifndef CONFIG_YAFFS_WINCE
+#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
+#endif
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/include/linux/gpio_buttons.h b/target/linux/generic-2.6/files-2.6.25/include/linux/gpio_buttons.h
new file mode 100644 (file)
index 0000000..f5e6297
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  Definitions for the GPIO buttons interface driver
+ *
+ *  Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
+ *
+ *  This file was based on: /include/linux/gpio_keys.h
+ *     The original gpio_keys.h seems not to have a license.
+ *
+ *  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 _GPIO_BUTTONS_H_
+#define _GPIO_BUTTONS_H_
+
+struct gpio_button {
+       int     gpio;           /* GPIO line number */
+       int     active_low;
+       char    *desc;          /* button description */
+       int     type;           /* input event type (EV_KEY, EV_SW) */
+       int     code;           /* input event code (KEY_*, SW_*) */
+       int     count;
+       int     threshold;      /* count threshold */
+};
+
+struct gpio_buttons_platform_data {
+       struct gpio_button *buttons;
+       int     nbuttons;               /* number of buttons */
+       int     poll_interval;          /* polling interval */
+};
+
+#endif /* _GPIO_BUTTONS_H_ */
+
diff --git a/target/linux/generic-2.6/files-2.6.25/include/linux/gpio_dev.h b/target/linux/generic-2.6/files-2.6.25/include/linux/gpio_dev.h
new file mode 100644 (file)
index 0000000..3f3c9c7
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _GPIODEV_H__
+#define _GPIODEV_H__
+
+#define IOC_GPIODEV_MAGIC  'B'
+#define GPIO_GET        _IO(IOC_GPIODEV_MAGIC, 10)
+#define GPIO_SET        _IO(IOC_GPIODEV_MAGIC, 11)
+#define GPIO_CLEAR      _IO(IOC_GPIODEV_MAGIC, 12)
+#define GPIO_DIR_IN     _IO(IOC_GPIODEV_MAGIC, 13)
+#define GPIO_DIR_OUT    _IO(IOC_GPIODEV_MAGIC, 14)
+
+#endif
diff --git a/target/linux/generic-2.6/files-2.6.25/include/linux/spi/spi_gpio.h b/target/linux/generic-2.6/files-2.6.25/include/linux/spi/spi_gpio.h
new file mode 100644 (file)
index 0000000..8e7d4b1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * spi_gpio interface to platform code
+ *
+ * Copyright (c) 2008 Piotr Skamruk
+ *
+ * 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 _LINUX_SPI_SPI_GPIO
+#define _LINUX_SPI_SPI_GPIO
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+
+/** struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
+ * This structure holds information about a GPIO-based SPI device.
+ *
+ * @pin_clk: The GPIO pin number of the CLOCK pin.
+ *
+ * @pin_miso: The GPIO pin number of the MISO pin.
+ *
+ * @pin_mosi: The GPIO pin number of the MOSI pin.
+ *
+ * @pin_cs: The GPIO pin number of the CHIPSELECT pin.
+ *
+ * @cs_activelow: If true, the chip is selected when the CS line is low.
+ *
+ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
+ *                Note that doing no delay is not standards compliant,
+ *                but it might be needed to speed up transfers on some
+ *                slow embedded machines.
+ *
+ * @boardinfo_setup: This callback is called after the
+ *                   SPI master device was registered, but before the
+ *                   device is registered.
+ * @boardinfo_setup_data: Data argument passed to boardinfo_setup().
+ */
+struct spi_gpio_platform_data {
+       unsigned int pin_clk;
+       unsigned int pin_miso;
+       unsigned int pin_mosi;
+       unsigned int pin_cs;
+       bool cs_activelow;
+       bool no_spi_delay;
+       int (*boardinfo_setup)(struct spi_board_info *bi,
+                              struct spi_master *master,
+                              void *data);
+       void *boardinfo_setup_data;
+};
+
+#endif /* _LINUX_SPI_SPI_GPIO */
index caaf744..eb55130 100644 (file)
@@ -77,7 +77,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET,
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET,
-+      .hooknum        = NF_IP_PRE_ROUTING,
++      .hooknum        = NF_INET_PRE_ROUTING,
 +#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
 +      .priority       = NF_IP_PRI_MANGLE + 1
 +#else
 +#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
 +      .priority       = NF_IP_PRI_MANGLE + 1
 +#else
@@ -89,7 +89,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET,
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET,
-+      .hooknum        = NF_IP_POST_ROUTING,
++      .hooknum        = NF_INET_POST_ROUTING,
 +#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
 +      .priority       = NF_IP_PRI_LAST
 +#else
 +#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
 +      .priority       = NF_IP_PRI_LAST
 +#else
@@ -102,7 +102,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET6,
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET6,
-+      .hooknum        = NF_IP6_PRE_ROUTING,
++      .hooknum        = NF_INET_PRE_ROUTING,
 +#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
 +      .priority       = NF_IP6_PRI_MANGLE + 1
 +#else
 +#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
 +      .priority       = NF_IP6_PRI_MANGLE + 1
 +#else
@@ -114,7 +114,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET6,
 +      .hook           = imq_nf_hook,
 +      .owner          = THIS_MODULE,
 +      .pf             = PF_INET6,
-+      .hooknum        = NF_IP6_POST_ROUTING,
++      .hooknum        = NF_INET_POST_ROUTING,
 +#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
 +      .priority       = NF_IP6_PRI_LAST
 +#else
 +#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
 +      .priority       = NF_IP6_PRI_LAST
 +#else
@@ -398,7 +398,7 @@ Index: linux-2.6.25.1/drivers/net/imq.c
 +    .init = imq_init_module,
 +    .exit = imq_exit_module,
 +};
 +    .init = imq_init_module,
 +    .exit = imq_exit_module,
 +};
-+ 
++
 +static int __init imq_init(void)
 +{
 +    return register_pernet_device(&imq_net_ops);
 +static int __init imq_init(void)
 +{
 +    return register_pernet_device(&imq_net_ops);
@@ -735,7 +735,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/Kconfig
  
 +config IP_NF_TARGET_IMQ
 +       tristate "IMQ target support"
  
 +config IP_NF_TARGET_IMQ
 +       tristate "IMQ target support"
-+       depends on IP_NF_MANGLE
++       depends on IP_NF_MANGLE && IMQ
 +       help
 +         This option adds a `IMQ' target which is used to specify if and
 +         to which IMQ device packets should get enqueued/dequeued.
 +       help
 +         This option adds a `IMQ' target which is used to specify if and
 +         to which IMQ device packets should get enqueued/dequeued.
index c2bb992..641a95a 100644 (file)
@@ -484,10 +484,10 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +      uint    entitylen = 0;
 +      uint    lineoff;
 +      uint    linelen;
 +      uint    entitylen = 0;
 +      uint    lineoff;
 +      uint    linelen;
-+      
++
 +      if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
 +              return 0;
 +      if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
 +              return 0;
-+      
++
 +      *phdrsoff = *ptcpoff;
 +      while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) {
 +              if (linelen == 0) {
 +      *phdrsoff = *ptcpoff;
 +      while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) {
 +              if (linelen == 0) {
@@ -499,17 +499,17 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +                      INFOP("!! overrun !!\n");
 +                      break;
 +              }
 +                      INFOP("!! overrun !!\n");
 +                      break;
 +              }
-+              
++
 +              if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
 +                      *pcseqoff = lineoff;
 +                      *pcseqlen = linelen;
 +              if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
 +                      *pcseqoff = lineoff;
 +                      *pcseqlen = linelen;
-+              } 
++              }
 +
 +              if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
 +                      *transoff = lineoff;
 +                      *translen = linelen;
 +              }
 +
 +              if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
 +                      *transoff = lineoff;
 +                      *translen = linelen;
 +              }
-+              
++
 +              if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) {
 +                      uint off = lineoff+15;
 +                      SKIP_WSPACE(ptcp+lineoff, linelen, off);
 +              if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) {
 +                      uint off = lineoff+15;
 +                      SKIP_WSPACE(ptcp+lineoff, linelen, off);
@@ -517,7 +517,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +              }
 +      }
 +      *phdrslen = (*ptcpoff) - (*phdrsoff);
 +              }
 +      }
 +      *phdrslen = (*ptcpoff) - (*phdrsoff);
-+      
++
 +      return 1;
 +}
 +
 +      return 1;
 +}
 +
@@ -541,37 +541,37 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +{
 +      int     rc = 0;
 +      uint    off = 0;
 +{
 +      int     rc = 0;
 +      uint    off = 0;
-+      
++
 +      if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
 +          nf_strncasecmp(ptran, "Transport:", 10) != 0) {
 +              INFOP("sanity check failed\n");
 +              return 0;
 +      }
 +      if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
 +          nf_strncasecmp(ptran, "Transport:", 10) != 0) {
 +              INFOP("sanity check failed\n");
 +              return 0;
 +      }
-+      
++
 +      DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
 +      off += 10;
 +      SKIP_WSPACE(ptran, tranlen, off);
 +      DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
 +      off += 10;
 +      SKIP_WSPACE(ptran, tranlen, off);
-+      
++
 +      /* Transport: tran;field;field=val,tran;field;field=val,... */
 +      while (off < tranlen) {
 +              const char* pparamend;
 +              uint        nextparamoff;
 +      /* Transport: tran;field;field=val,tran;field;field=val,... */
 +      while (off < tranlen) {
 +              const char* pparamend;
 +              uint        nextparamoff;
-+              
++
 +              pparamend = memchr(ptran+off, ',', tranlen-off);
 +              pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
 +              nextparamoff = pparamend-ptran;
 +              pparamend = memchr(ptran+off, ',', tranlen-off);
 +              pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
 +              nextparamoff = pparamend-ptran;
-+              
++
 +              while (off < nextparamoff) {
 +                      const char* pfieldend;
 +                      uint        nextfieldoff;
 +              while (off < nextparamoff) {
 +                      const char* pfieldend;
 +                      uint        nextfieldoff;
-+                      
++
 +                      pfieldend = memchr(ptran+off, ';', nextparamoff-off);
 +                      nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
 +                      pfieldend = memchr(ptran+off, ';', nextparamoff-off);
 +                      nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
-+                 
++
 +                      if (strncmp(ptran+off, "client_port=", 12) == 0) {
 +                              u_int16_t   port;
 +                              uint        numlen;
 +                      if (strncmp(ptran+off, "client_port=", 12) == 0) {
 +                              u_int16_t   port;
 +                              uint        numlen;
-+                  
++
 +                              off += 12;
 +                              numlen = nf_strtou16(ptran+off, &port);
 +                              off += numlen;
 +                              off += 12;
 +                              numlen = nf_strtou16(ptran+off, &port);
 +                              off += numlen;
@@ -586,7 +586,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +                                              off += numlen;
 +                                              prtspexp->pbtype = pb_range;
 +                                              prtspexp->hiport = port;
 +                                              off += numlen;
 +                                              prtspexp->pbtype = pb_range;
 +                                              prtspexp->hiport = port;
-+                                              
++
 +                                              // If we have a range, assume rtp:
 +                                              // loport must be even, hiport must be loport+1
 +                                              if ((prtspexp->loport & 0x0001) != 0 ||
 +                                              // If we have a range, assume rtp:
 +                                              // loport must be even, hiport must be loport+1
 +                                              if ((prtspexp->loport & 0x0001) != 0 ||
@@ -606,20 +606,20 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +                                      rc = 1;
 +                              }
 +                      }
 +                                      rc = 1;
 +                              }
 +                      }
-+                      
++
 +                      /*
 +                       * Note we don't look for the destination parameter here.
 +                       * If we are using NAT, the NAT module will handle it.  If not,
 +                       * and the client is sending packets elsewhere, the expectation
 +                       * will quietly time out.
 +                       */
 +                      /*
 +                       * Note we don't look for the destination parameter here.
 +                       * If we are using NAT, the NAT module will handle it.  If not,
 +                       * and the client is sending packets elsewhere, the expectation
 +                       * will quietly time out.
 +                       */
-+                      
++
 +                      off = nextfieldoff;
 +              }
 +                      off = nextfieldoff;
 +              }
-+              
++
 +              off = nextparamoff;
 +      }
 +              off = nextparamoff;
 +      }
-+      
++
 +      return rc;
 +}
 +
 +      return rc;
 +}
 +
@@ -639,7 +639,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +                struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 +{
 +      struct ip_ct_rtsp_expect expinfo;
 +                struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 +{
 +      struct ip_ct_rtsp_expect expinfo;
-+      
++
 +      int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
 +      //struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
 +      //uint    tcplen = pktlen - iph->ihl * 4;
 +      int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */
 +      //struct  tcphdr* tcph = (void*)iph + iph->ihl * 4;
 +      //uint    tcplen = pktlen - iph->ihl * 4;
@@ -647,13 +647,13 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +      //uint    datalen = tcplen - tcph->doff * 4;
 +      uint    dataoff = 0;
 +      int ret = NF_ACCEPT;
 +      //uint    datalen = tcplen - tcph->doff * 4;
 +      uint    dataoff = 0;
 +      int ret = NF_ACCEPT;
-+      
++
 +      struct nf_conntrack_expect *exp;
 +      struct nf_conntrack_expect *exp;
-+      
++
 +      __be16 be_loport;
 +      __be16 be_loport;
-+      
++
 +      memset(&expinfo, 0, sizeof(expinfo));
 +      memset(&expinfo, 0, sizeof(expinfo));
-+      
++
 +      while (dataoff < datalen) {
 +              uint    cmdoff = dataoff;
 +              uint    hdrsoff = 0;
 +      while (dataoff < datalen) {
 +              uint    cmdoff = dataoff;
 +              uint    hdrsoff = 0;
@@ -663,13 +663,13 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +              uint    transoff = 0;
 +              uint    translen = 0;
 +              uint    off;
 +              uint    transoff = 0;
 +              uint    translen = 0;
 +              uint    off;
-+              
++
 +              if (!rtsp_parse_message(pdata, datalen, &dataoff,
 +                                      &hdrsoff, &hdrslen,
 +                                      &cseqoff, &cseqlen,
 +                                      &transoff, &translen))
 +                      break;      /* not a valid message */
 +              if (!rtsp_parse_message(pdata, datalen, &dataoff,
 +                                      &hdrsoff, &hdrslen,
 +                                      &cseqoff, &cseqlen,
 +                                      &transoff, &translen))
 +                      break;      /* not a valid message */
-+              
++
 +              if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
 +                      continue;   /* not a SETUP message */
 +              DEBUGP("found a setup message\n");
 +              if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
 +                      continue;   /* not a SETUP message */
 +              DEBUGP("found a setup message\n");
@@ -697,7 +697,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +
 +              nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
 +                      &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3,
 +
 +              nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
 +                      &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3,
-+                      IPPROTO_UDP, NULL, &be_loport); 
++                      IPPROTO_UDP, NULL, &be_loport);
 +
 +              exp->master = ct;
 +
 +
 +              exp->master = ct;
 +
@@ -739,7 +739,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +}
 +
 +static int help(struct sk_buff *skb, unsigned int protoff,
 +}
 +
 +static int help(struct sk_buff *skb, unsigned int protoff,
-+              struct nf_conn *ct, enum ip_conntrack_info ctinfo) 
++              struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 +{
 +      struct tcphdr _tcph, *th;
 +      unsigned int dataoff, datalen;
 +{
 +      struct tcphdr _tcph, *th;
 +      unsigned int dataoff, datalen;
@@ -747,7 +747,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +      int ret = NF_DROP;
 +
 +      /* Until there's been traffic both ways, don't look in packets. */
 +      int ret = NF_DROP;
 +
 +      /* Until there's been traffic both ways, don't look in packets. */
-+      if (ctinfo != IP_CT_ESTABLISHED && 
++      if (ctinfo != IP_CT_ESTABLISHED &&
 +          ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
 +              DEBUGP("conntrackinfo = %u\n", ctinfo);
 +              return NF_ACCEPT;
 +          ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
 +              DEBUGP("conntrackinfo = %u\n", ctinfo);
 +              return NF_ACCEPT;
@@ -758,7 +758,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +
 +      if (!th)
 +              return NF_ACCEPT;
 +
 +      if (!th)
 +              return NF_ACCEPT;
-+   
++
 +      /* No data ? */
 +      dataoff = protoff + th->doff*4;
 +      datalen = skb->len - dataoff;
 +      /* No data ? */
 +      dataoff = protoff + th->doff*4;
 +      datalen = skb->len - dataoff;
@@ -832,7 +832,7 @@ Index: linux-2.6.25.1/net/netfilter/nf_conntrack_rtsp.c
 +      }
 +
 +      rtsp_buffer = kmalloc(65536, GFP_KERNEL);
 +      }
 +
 +      rtsp_buffer = kmalloc(65536, GFP_KERNEL);
-+      if (!rtsp_buffer) 
++      if (!rtsp_buffer)
 +              return -ENOMEM;
 +
 +      /* If no port given, default to standard rtsp port */
 +              return -ENOMEM;
 +
 +      /* If no port given, default to standard rtsp port */
@@ -930,7 +930,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/nf_nat_rtsp.c
 +#include <linux/netfilter_mime.h>
 +
 +#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
 +#include <linux/netfilter_mime.h>
 +
 +#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
-+#if 0 
++#if 0
 +#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
 +#else
 +#define DEBUGP(fmt, args...)
 +#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
 +#else
 +#define DEBUGP(fmt, args...)
@@ -1241,7 +1241,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/nf_nat_rtsp.c
 +
 +static uint
 +help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
 +
 +static uint
 +help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
-+       unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 
++       unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
 +       struct nf_conntrack_expect* exp)
 +{
 +    char*   ptcp;
 +       struct nf_conntrack_expect* exp)
 +{
 +    char*   ptcp;
@@ -1296,7 +1296,7 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/nf_nat_rtsp.c
 +}
 +
 +static unsigned int
 +}
 +
 +static unsigned int
-+help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 
++help(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
 +     unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
 +     struct nf_conntrack_expect* exp)
 +{
 +     unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
 +     struct nf_conntrack_expect* exp)
 +{
@@ -1336,11 +1336,11 @@ Index: linux-2.6.25.1/net/ipv4/netfilter/nf_nat_rtsp.c
 +           NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
 +
 +    mr.rangesize = 1;
 +           NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
 +
 +    mr.rangesize = 1;
-+    // We don't want to manip the per-protocol, just the IPs. 
++    // We don't want to manip the per-protocol, just the IPs.
 +    mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
 +    mr.range[0].min_ip = mr.range[0].max_ip = newip;
 +
 +    mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
 +    mr.range[0].min_ip = mr.range[0].max_ip = newip;
 +
-+    nf_nat_setup_info(ct, &mr.range[0], NF_INET_PRE_ROUTING);
++    nf_nat_setup_info(ct, &mr.range[0], IP_NAT_MANIP_DST);
 +}
 +
 +
 +}
 +
 +
diff --git a/target/linux/generic-2.6/patches-2.6.25/420-gpiodev.patch b/target/linux/generic-2.6/patches-2.6.25/420-gpiodev.patch
new file mode 100644 (file)
index 0000000..4c252f5
--- /dev/null
@@ -0,0 +1,27 @@
+Index: linux-2.6.25/drivers/gpio/Kconfig
+===================================================================
+--- linux-2.6.25.orig/drivers/gpio/Kconfig     2008-04-27 23:35:57.000000000 +0100
++++ linux-2.6.25/drivers/gpio/Kconfig  2008-04-27 23:42:52.000000000 +0100
+@@ -2,6 +2,13 @@
+ # GPIO infrastructure and expanders
+ #
++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 HAVE_GPIO_LIB
+       bool
+       help
+Index: linux-2.6.25/drivers/gpio/Makefile
+===================================================================
+--- linux-2.6.25.orig/drivers/gpio/Makefile    2008-04-27 23:42:59.000000000 +0100
++++ linux-2.6.25/drivers/gpio/Makefile 2008-04-27 23:43:41.000000000 +0100
+@@ -7,3 +7,4 @@ obj-$(CONFIG_HAVE_GPIO_LIB)    += gpiolib.o
+ obj-$(CONFIG_GPIO_MCP23S08)   += mcp23s08.o
+ obj-$(CONFIG_GPIO_PCA953X)    += pca953x.o
+ obj-$(CONFIG_GPIO_PCF857X)    += pcf857x.o
++obj-$(CONFIG_GPIO_DEVICE)     += gpio_dev.o
This page took 0.767035 seconds and 4 git commands to generate.